changed CHANGELOG.md
 
@@ -1,12 +1,52 @@
1
1
# Changelog
2
2
3
+ ## Cldr v2.26.0
4
+
5
+ This is the changelog for Cldr v2.26.0 released on February 21st, 2022. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr/tags)
6
+
7
+ ### LanguageTag structure changes
8
+
9
+ * `Cldr.LanguageTag.t` has been revised with the `:cldr_locale_name` and `:rbnf_locale_name` now being atoms rather than binaries. This is unlikely to affect client code. The primary benefit, apart from a slightly improve
10
+
11
+ ### Bug Fixes
12
+
13
+ * Fix setting the default backend with `Cldr.put_default_backend/1` which wasn't actually being set.
14
+
15
+ * Fix `Config.message_formats` to default to an empty map, not an empty list.
16
+
17
+ * Fix `Cldr.Locale.parents/1` to return an `{:ok, list}` tuple on success rather than a bare list.
18
+
19
+ * Fix `<backend>.Cldr.Number.{Cardinal, Ordinal, Spellout}.pluralize/3` for non-integer `Decimal` numbers.
20
+
21
+ ### Enhancements
22
+
23
+ * Add `<backend>.Trans` module to support closer integration with the [trans](https://hex.pm/packages/trans) for database translations.
24
+
25
+ * Add `Cldr.Locale.fallback_locales/1` to return the list of recursively created parent locales, including the provided locale. This can be used to support resolving translations from a system that might be sparsely populated.
26
+
27
+ * Add `Cldr.Locale.fallback_locale_names/1` that returns the `:cldr_locale_name` component of the locales returned by `Cldr.Locale.fallback_locales/1`.
28
+
29
+ * Adds `Cldr.Locale.locale_from_territory/{1,2}` to derive a "best fit" locale for a given territory. Also adds `<backend>.Locale.locale_from_territory/1`.
30
+
31
+ * Adds `Cldr.Locale.locale_from_host/{2, 3}` to derive a "best fit" locale for a given host name. Also adds `<backend>.Locale.locale_from_host/2`.
32
+
33
+ * Adds `Cldr.Locale.territory_from_host/1` to return the territory for a given host name. Also adds `<backend>.Locale.territory_from_host/1`.
34
+
35
+ * Adds `Cldr.Locale.consider_as_tlds/0` to return a list of valid territory suffixes that are considered as generic TLDs instead. See https://developers.google.com/search/docs/advanced/crawling/managing-multi-regional-sites.
36
+
37
+ * Adds `Cldr.Locale.languages_for_territories/0` to return a mapping of territories to that territory's most spoken language.
38
+
39
+ * Adds `Cldr.put_gettext_locale/1` that sets the `gettext` locale for a given `t:Cldr.LanguageTag`.
40
+
41
+ * Adds `Cldr.TestHelper` module in `test/suport` to provide testing helpers. Initially provides `with_no_default_backend/1` function.
42
+
3
43
## Cldr v2.25.0
4
44
5
45
This is the changelog for Cldr v2.25.0 released on December 16th, 2021. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr/tags)
6
46
7
47
### Bug Fixes
8
48
9
- * Fixes configuring locales when the default locale is in posix form (ie like `en_GB`) as apposed to BCP47 form (ie `en-GB`). In fixing this bug, forming the normalised list of configured locales is now also standarised. Thanks to @gazzer82 for the report. Closes #165
49
+ * Fixes configuring locales when the default locale is in posix form (ie like `en_GB`) as apposed to BCP47 form (ie `en-GB`). In fixing this bug, forming the normalised list of configured locales is now also standarised. Thanks to @gazzer82 for the report. Closes #165.
10
50
11
51
### Enhancements
changed hex_metadata.config
 
@@ -13,8 +13,8 @@
13
13
<<"lib/cldr/config/rbnf_config.ex">>,<<"lib/cldr/exception.ex">>,
14
14
<<"lib/cldr/validity.ex">>,<<"lib/cldr/backend">>,
15
15
<<"lib/cldr/backend/compiler.ex">>,<<"lib/cldr/backend/cldr.ex">>,
16
- <<"lib/cldr/backend/locale.ex">>,<<"lib/cldr/protocol">>,
17
- <<"lib/cldr/protocol/display_name.ex">>,
16
+ <<"lib/cldr/backend/trans.ex">>,<<"lib/cldr/backend/locale.ex">>,
17
+ <<"lib/cldr/protocol">>,<<"lib/cldr/protocol/display_name.ex">>,
18
18
<<"lib/cldr/protocol/language_tag_chars.ex">>,
19
19
<<"lib/cldr/protocol/cldr_chars.ex">>,<<"lib/cldr/install.ex">>,
20
20
<<"lib/cldr/timezone.ex">>,<<"lib/cldr/validity">>,
 
@@ -23,8 +23,8 @@
23
23
<<"lib/cldr/validity/t.ex">>,<<"lib/cldr/validity/subdivision.ex">>,
24
24
<<"lib/cldr/validity/language.ex">>,<<"lib/cldr/gettext">>,
25
25
<<"lib/cldr/gettext/plural.ex">>,<<"lib/cldr/accept_language.ex">>,
26
- <<"lib/cldr/sigil.ex">>,<<"lib/cldr/substitution.ex">>,
27
- <<"lib/cldr/language_tag">>,<<"lib/cldr/language_tag/rfc5646">>,
26
+ <<"lib/cldr/substitution.ex">>,<<"lib/cldr/language_tag">>,
27
+ <<"lib/cldr/language_tag/rfc5646">>,
28
28
<<"lib/cldr/language_tag/rfc5646/rfc5646_grammar.ex">>,
29
29
<<"lib/cldr/language_tag/rfc5646/rfc5646_core.ex">>,
30
30
<<"lib/cldr/language_tag/rfc5646/rfc5646_helpers.ex">>,
 
@@ -33,7 +33,7 @@
33
33
<<"lib/cldr/language_tag/extensions/u.ex">>,
34
34
<<"lib/cldr/language_tag/extensions/t.ex">>,
35
35
<<"lib/cldr/language_tag/rfc5646_parser.ex">>,
36
- <<"lib/cldr/language_tag/parser.ex">>,
36
+ <<"lib/cldr/language_tag/sigil.ex">>,<<"lib/cldr/language_tag/parser.ex">>,
37
37
<<"lib/cldr/language_tag/rfc5646_parser.ex.exs">>,
38
38
<<"lib/cldr/language_tag.ex">>,<<"lib/cldr/plug">>,
39
39
<<"lib/cldr/plug/plug_put_session.ex">>,
 
@@ -71,10 +71,10 @@
71
71
{<<"licenses">>,[<<"Apache-2.0">>]}.
72
72
{<<"links">>,
73
73
[{<<"Changelog">>,
74
- <<"https://github.com/elixir-cldr/cldr/blob/v2.25.0/CHANGELOG.md">>},
74
+ <<"https://github.com/elixir-cldr/cldr/blob/v2.26.0/CHANGELOG.md">>},
75
75
{<<"GitHub">>,<<"https://github.com/elixir-cldr/cldr">>},
76
76
{<<"Readme">>,
77
- <<"https://github.com/elixir-cldr/cldr/blob/v2.25.0/README.md">>}]}.
77
+ <<"https://github.com/elixir-cldr/cldr/blob/v2.26.0/README.md">>}]}.
78
78
{<<"name">>,<<"ex_cldr">>}.
79
79
{<<"requirements">>,
80
80
[[{<<"app">>,<<"cldr_utils">>},
 
@@ -111,10 +111,10 @@
111
111
{<<"name">>,<<"gettext">>},
112
112
{<<"optional">>,true},
113
113
{<<"repository">>,<<"hexpm">>},
114
- {<<"requirement">>,<<"~> 0.13">>}],
114
+ {<<"requirement">>,<<"~> 0.19">>}],
115
115
[{<<"app">>,<<"plug">>},
116
116
{<<"name">>,<<"plug">>},
117
117
{<<"optional">>,true},
118
118
{<<"repository">>,<<"hexpm">>},
119
119
{<<"requirement">>,<<"~> 1.9">>}]]}.
120
- {<<"version">>,<<"2.25.0">>}.
120
+ {<<"version">>,<<"2.26.0">>}.
changed lib/cldr.ex
 
@@ -36,6 +36,8 @@ defmodule Cldr do
36
36
37
37
@type backend :: module()
38
38
39
+ defguard is_locale_name(locale_name) when is_atom(locale_name) or is_binary(locale_name)
40
+
39
41
alias Cldr.Config
40
42
alias Cldr.Locale
41
43
alias Cldr.Locale.Loader
 
@@ -133,12 +135,12 @@ defmodule Cldr do
133
135
%Cldr.LanguageTag{
134
136
backend: TestBackend.Cldr,
135
137
canonical_locale_name: "pl",
136
- cldr_locale_name: "pl",
138
+ cldr_locale_name: :pl,
137
139
extensions: %{},
138
140
language: "pl",
139
141
locale: %{},
140
142
private_use: [],
141
- rbnf_locale_name: "pl",
143
+ rbnf_locale_name: :pl,
142
144
territory: :PL,
143
145
requested_locale_name: "pl",
144
146
script: :Latn,
 
@@ -198,14 +200,14 @@ defmodule Cldr do
198
200
%Cldr.LanguageTag{
199
201
backend: TestBackend.Cldr,
200
202
canonical_locale_name: "en",
201
- cldr_locale_name: "en",
203
+ cldr_locale_name: :en,
202
204
language_subtags: [],
203
205
extensions: %{},
204
206
gettext_locale_name: "en",
205
207
language: "en",
206
208
locale: %{},
207
209
private_use: [],
208
- rbnf_locale_name: "en",
210
+ rbnf_locale_name: :en,
209
211
requested_locale_name: "en",
210
212
script: :Latn,
211
213
territory: :US,
 
@@ -223,7 +225,7 @@ defmodule Cldr do
223
225
224
226
def put_locale(backend \\ nil, locale)
225
227
226
- def put_locale(nil, locale) when is_binary(locale) do
228
+ def put_locale(nil, locale) when is_locale_name(locale) do
227
229
backend = default_backend!()
228
230
229
231
with {:ok, locale} <- backend.validate_locale(locale) do
 
@@ -231,9 +233,9 @@ defmodule Cldr do
231
233
end
232
234
end
233
235
234
- def put_locale(backend, locale) when is_atom(backend) and is_binary(locale) do
236
+ def put_locale(backend, locale_name) when is_atom(backend) and is_locale_name(locale_name) do
235
237
with {:ok, backend} <- validate_backend(backend),
236
- {:ok, locale} <- backend.validate_locale(locale) do
238
+ {:ok, locale} <- backend.validate_locale(locale_name) do
237
239
put_locale(locale)
238
240
end
239
241
end
 
@@ -253,6 +255,57 @@ defmodule Cldr do
253
255
put_locale(locale)
254
256
end
255
257
258
+ if Code.ensure_loaded?(Gettext) do
259
+ @doc """
260
+ Set the current process's Gettext locale from a
261
+ `t:Cldr.LanguageTag`.
262
+
263
+ ## Arguments
264
+
265
+ * `locale` is a `Cldr.LanguageTag` struct returned by `Cldr.Locale.new!/2`.
266
+
267
+ ## Returns
268
+
269
+ * `{:ok, gettext_locale_name}` or
270
+
271
+ * `{:error, {exception, reason}}`
272
+
273
+ ## Behaviour
274
+
275
+ 1. If the `locale.gettext_locale_name` is `nil` then an error
276
+ is returned.
277
+
278
+ 2. The `gettext` locale for the `gettext_backend` configured for the
279
+ CLDR backend defined by the `t:Cldr.LanguageTag` is set.
280
+
281
+ ## Examples
282
+
283
+ iex> import Cldr.LanguageTag.Sigil
284
+ iex> Cldr.put_gettext_locale(~l"en")
285
+ {:ok, "en"}
286
+
287
+ iex> import Cldr.LanguageTag.Sigil
288
+ iex> Cldr.put_gettext_locale(~l"de")
289
+ {:error,
290
+ {Cldr.UnknownLocaleError,
291
+ "Locale #Cldr.LanguageTag<de [validated]> does not map to a known gettext locale name"}}
292
+
293
+ """
294
+ @spec put_gettext_locale(LanguageTag.t()) ::
295
+ {:ok, binary() | nil} | {:error, {module(), String.t()}}
296
+
297
+ def put_gettext_locale(%LanguageTag{gettext_locale_name: nil} = locale) do
298
+ {:error, {Cldr.UnknownLocaleError, "Locale #{inspect locale} does not map to a known gettext locale name"}}
299
+ end
300
+
301
+ def put_gettext_locale(%LanguageTag{gettext_locale_name: gettext_locale_name} = locale) do
302
+ gettext_backend = locale.backend.__cldr__(:gettext)
303
+ _ = Gettext.put_locale(gettext_backend, gettext_locale_name)
304
+ {:ok, gettext_locale_name}
305
+ end
306
+
307
+ end
308
+
256
309
@doc """
257
310
Set's the system default locale.
258
311
 
@@ -321,14 +374,14 @@ defmodule Cldr do
321
374
%Cldr.LanguageTag{
322
375
backend: TestBackend.Cldr,
323
376
canonical_locale_name: "en-001",
324
- cldr_locale_name: "en-001",
377
+ cldr_locale_name: :"en-001",
325
378
language_subtags: [],
326
379
extensions: %{},
327
380
gettext_locale_name: "en",
328
381
language: "en",
329
382
locale: %{},
330
383
private_use: [],
331
- rbnf_locale_name: "en",
384
+ rbnf_locale_name: :en,
332
385
requested_locale_name: "en-001",
333
386
script: :Latn,
334
387
territory: :"001",
 
@@ -372,14 +425,14 @@ defmodule Cldr do
372
425
%Cldr.LanguageTag{
373
426
backend: TestBackend.Cldr,
374
427
canonical_locale_name: "en-001",
375
- cldr_locale_name: "en-001",
428
+ cldr_locale_name: :"en-001",
376
429
language_subtags: [],
377
430
extensions: %{},
378
431
gettext_locale_name: "en",
379
432
language: "en",
380
433
locale: %{},
381
434
private_use: [],
382
- rbnf_locale_name: "en",
435
+ rbnf_locale_name: :en,
383
436
requested_locale_name: "en-001",
384
437
script: :Latn,
385
438
territory: :"001",
 
@@ -460,7 +513,7 @@ defmodule Cldr do
460
513
## Arguments
461
514
462
515
* `backend` is any module that includes `use Cldr` and therefore
463
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`
516
+ is a `Cldr` backend module.
464
517
465
518
## Returns
466
519
 
@@ -471,6 +524,7 @@ defmodule Cldr do
471
524
"""
472
525
def put_default_backend(backend) do
473
526
with {:ok, backend} <- validate_backend(backend) do
527
+ :ok = Application.put_env(Cldr.Config.app_name(), :default_backend, backend)
474
528
{:ok, backend}
475
529
end
476
530
end
 
@@ -539,7 +593,8 @@ defmodule Cldr do
539
593
540
594
## Arguments
541
595
542
- * `backend` is any module
596
+ * `backend` is any module name that may be a
597
+ `CLDR` backend module.
543
598
544
599
## Returns
545
600
 
@@ -594,8 +649,8 @@ defmodule Cldr do
594
649
or a `Cldr.LanguageTag` struct returned by `Cldr.Locale.new!/2`
595
650
596
651
* `backend` is any module that includes `use Cldr` and therefore
597
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
598
- Note that `Cldr.default_backend/0` will raise an exception if
652
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
653
+ Note that `Cldr.default_backend!/0` will raise an exception if
599
654
no `:default_backend` is configured under the `:ex_cldr` key in
600
655
`config.exs`.
601
656
 
@@ -607,18 +662,18 @@ defmodule Cldr do
607
662
608
663
## Examples
609
664
610
- iex> Cldr.validate_locale("en", TestBackend.Cldr)
665
+ iex> Cldr.validate_locale(:en, TestBackend.Cldr)
611
666
{:ok,
612
667
%Cldr.LanguageTag{
613
668
backend: TestBackend.Cldr,
614
669
canonical_locale_name: "en",
615
- cldr_locale_name: "en",
670
+ cldr_locale_name: :en,
616
671
extensions: %{},
617
672
gettext_locale_name: "en",
618
673
language: "en",
619
674
locale: %{},
620
675
private_use: [],
621
- rbnf_locale_name: "en",
676
+ rbnf_locale_name: :en,
622
677
requested_locale_name: "en",
623
678
script: :Latn,
624
679
territory: :US,
 
@@ -626,11 +681,30 @@ defmodule Cldr do
626
681
language_variants: []
627
682
}}
628
683
684
+ iex> Cldr.validate_locale(:af, TestBackend.Cldr)
685
+ {:ok,
686
+ %Cldr.LanguageTag{
687
+ backend: TestBackend.Cldr,
688
+ canonical_locale_name: "af",
689
+ cldr_locale_name: :af,
690
+ extensions: %{},
691
+ gettext_locale_name: nil,
692
+ language: "af",
693
+ locale: %{},
694
+ private_use: [],
695
+ rbnf_locale_name: :af,
696
+ requested_locale_name: "af",
697
+ script: :Latn,
698
+ territory: :ZA,
699
+ transform: %{},
700
+ language_variants: []
701
+ }}
702
+
629
703
iex> Cldr.validate_locale("zzz", TestBackend.Cldr)
630
704
{:error, {Cldr.InvalidLanguageError, "The language \\"zzz\\" is invalid"}}
631
705
632
706
"""
633
- @spec validate_locale(Locale.locale_name() | LanguageTag.t(), backend()) ::
707
+ @spec validate_locale(Locale.locale_name() | LanguageTag.t() | String.t(), backend()) ::
634
708
{:ok, LanguageTag.t()} | {:error, {module(), String.t()}}
635
709
636
710
def validate_locale(locale, backend \\ nil)
 
@@ -671,8 +745,8 @@ defmodule Cldr do
671
745
## Arguments
672
746
673
747
* `backend` is any module that includes `use Cldr` and therefore
674
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
675
- Note that `Cldr.default_backend/0` will raise an exception if
748
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
749
+ Note that `Cldr.default_backend!/0` will raise an exception if
676
750
no `:default_backend` is configured under the `:ex_cldr` key in
677
751
`config.exs`.
678
752
 
@@ -693,8 +767,8 @@ defmodule Cldr do
693
767
## Arguments
694
768
695
769
* `backend` is any module that includes `use Cldr` and therefore
696
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
697
- Note that `Cldr.default_backend/0` will raise an exception if
770
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
771
+ Note that `Cldr.default_backend!/0` will raise an exception if
698
772
no `:default_backend` is configured under the `:ex_cldr` key in
699
773
`config.exs`.
700
774
 
@@ -717,8 +791,8 @@ defmodule Cldr do
717
791
## Arguments
718
792
719
793
* `backend` is any module that includes `use Cldr` and therefore
720
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
721
- Note that `Cldr.default_backend/0` will raise an exception if
794
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
795
+ Note that `Cldr.default_backend!/0` will raise an exception if
722
796
no `:default_backend` is configured under the `:ex_cldr` key in
723
797
`config.exs`.
724
798
 
@@ -755,8 +829,8 @@ defmodule Cldr do
755
829
## Arguments
756
830
757
831
* `backend` is any module that includes `use Cldr` and therefore
758
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
759
- Note that `Cldr.default_backend/0` will raise an exception if
832
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
833
+ Note that `Cldr.default_backend!/0` will raise an exception if
760
834
no `:default_backend` is configured under the `:ex_cldr` key in
761
835
`config.exs`.
762
836
 
@@ -778,23 +852,25 @@ defmodule Cldr do
778
852
* `locale` is any valid locale name returned by `Cldr.known_locale_names/1`
779
853
780
854
* `backend` is any module that includes `use Cldr` and therefore
781
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
782
- Note that `Cldr.default_backend/0` will raise an exception if
855
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
856
+ Note that `Cldr.default_backend!/0` will raise an exception if
783
857
no `:default_backend` is configured under the `:ex_cldr` key in
784
858
`config.exs`.
785
859
786
860
## Examples
787
861
788
- iex> Cldr.known_locale_name("en-AU", TestBackend.Cldr)
789
- "en-AU"
862
+ iex> Cldr.known_locale_name(:"en-AU", TestBackend.Cldr)
863
+ :"en-AU"
790
864
791
- iex> Cldr.known_locale_name("en-SA", TestBackend.Cldr)
865
+ iex> Cldr.known_locale_name(:"en-SA", TestBackend.Cldr)
792
866
nil
793
867
794
868
"""
795
- @spec known_locale_name(Locale.locale_name(), backend()) :: String.t() | nil
869
+ @spec known_locale_name(Locale.locale_name() | String.t(), backend()) :: atom() | nil
870
+
796
871
def known_locale_name(locale_name, backend \\ default_backend!())
797
- when is_binary(locale_name) do
872
+
873
+ def known_locale_name(locale_name, backend) when is_atom(locale_name) do
798
874
if name = backend.known_locale_name(locale_name) do
799
875
name
800
876
else
 
@@ -802,6 +878,14 @@ defmodule Cldr do
802
878
end
803
879
end
804
880
881
+ # TODO remove when we get to Cldr 3.0
882
+ def known_locale_name(locale_name, backend) when is_binary(locale_name) do
883
+ locale_name = String.to_existing_atom(locale_name)
884
+ known_locale_name(locale_name, backend)
885
+ rescue ArgumentError ->
886
+ nil
887
+ end
888
+
805
889
@doc """
806
890
Returns a boolean indicating if the specified locale
807
891
name is configured and available in Cldr.
 
@@ -811,23 +895,22 @@ defmodule Cldr do
811
895
* `locale` is any valid locale name returned by `Cldr.known_locale_names/1`
812
896
813
897
* `backend` is any module that includes `use Cldr` and therefore
814
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
815
- Note that `Cldr.default_backend/0` will raise an exception if
898
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
899
+ Note that `Cldr.default_backend!/0` will raise an exception if
816
900
no `:default_backend` is configured under the `:ex_cldr` key in
817
901
`config.exs`.
818
902
819
903
## Examples
820
904
821
- iex> Cldr.known_locale_name?("en", TestBackend.Cldr)
905
+ iex> Cldr.known_locale_name?(:en, TestBackend.Cldr)
822
906
true
823
907
824
- iex> Cldr.known_locale_name?("!!", TestBackend.Cldr)
908
+ iex> Cldr.known_locale_name?(:"!!", TestBackend.Cldr)
825
909
false
826
910
827
911
"""
828
912
@spec known_locale_name?(Locale.locale_name(), backend()) :: boolean
829
- def known_locale_name?(locale_name, backend \\ default_backend!())
830
- when is_binary(locale_name) do
913
+ def known_locale_name?(locale_name, backend \\ default_backend!()) when is_atom(locale_name) do
831
914
locale_name in backend.known_locale_names
832
915
end
833
916
 
@@ -841,23 +924,22 @@ defmodule Cldr do
841
924
* `locale` is any valid locale name returned by `Cldr.known_locale_names/1`
842
925
843
926
* `backend` is any module that includes `use Cldr` and therefore
844
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
845
- Note that `Cldr.default_backend/0` will raise an exception if
927
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
928
+ Note that `Cldr.default_backend!/0` will raise an exception if
846
929
no `:default_backend` is configured under the `:ex_cldr` key in
847
930
`config.exs`.
848
931
849
932
## Examples
850
933
851
- iex> Cldr.known_rbnf_locale_name?("en", TestBackend.Cldr)
934
+ iex> Cldr.known_rbnf_locale_name?(:en, TestBackend.Cldr)
852
935
true
853
936
854
- iex> Cldr.known_rbnf_locale_name?("!!", TestBackend.Cldr)
937
+ iex> Cldr.known_rbnf_locale_name?(:"!!", TestBackend.Cldr)
855
938
false
856
939
857
940
"""
858
941
@spec known_rbnf_locale_name?(Locale.locale_name(), backend()) :: boolean
859
- def known_rbnf_locale_name?(locale_name, backend \\ default_backend!())
860
- when is_binary(locale_name) do
942
+ def known_rbnf_locale_name?(locale_name, backend \\ default_backend!()) do
861
943
locale_name in backend.known_rbnf_locale_names
862
944
end
863
945
 
@@ -870,8 +952,8 @@ defmodule Cldr do
870
952
* `locale` is any valid locale name returned by `Cldr.known_locale_names/1`
871
953
872
954
* `backend` is any module that includes `use Cldr` and therefore
873
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
874
- Note that `Cldr.default_backend/0` will raise an exception if
955
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
956
+ Note that `Cldr.default_backend!/0` will raise an exception if
875
957
no `:default_backend` is configured under the `:ex_cldr` key in
876
958
`config.exs`.
877
959
 
@@ -884,7 +966,7 @@ defmodule Cldr do
884
966
false
885
967
886
968
"""
887
- @spec known_gettext_locale_name?(Locale.locale_name(), backend) :: boolean
969
+ @spec known_gettext_locale_name?(String.t(), backend) :: boolean
888
970
def known_gettext_locale_name?(locale_name, backend \\ default_backend!())
889
971
when is_binary(locale_name) do
890
972
locale_name in backend.known_gettext_locale_names
 
@@ -900,23 +982,22 @@ defmodule Cldr do
900
982
* `locale` is any valid locale name returned by `Cldr.known_locale_names/1`
901
983
902
984
* `backend` is any module that includes `use Cldr` and therefore
903
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
904
- Note that `Cldr.default_backend/0` will raise an exception if
985
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
986
+ Note that `Cldr.default_backend!/0` will raise an exception if
905
987
no `:default_backend` is configured under the `:ex_cldr` key in
906
988
`config.exs`.
907
989
908
990
## Examples
909
991
910
- iex> Cldr.known_rbnf_locale_name("en", TestBackend.Cldr)
911
- "en"
992
+ iex> Cldr.known_rbnf_locale_name(:en, TestBackend.Cldr)
993
+ :en
912
994
913
- iex> Cldr.known_rbnf_locale_name("en-SA", TestBackend.Cldr)
995
+ iex> Cldr.known_rbnf_locale_name(:"en-SA", TestBackend.Cldr)
914
996
false
915
997
916
998
"""
917
999
@spec known_rbnf_locale_name(Locale.locale_name(), backend()) :: String.t() | false
918
- def known_rbnf_locale_name(locale_name, backend \\ default_backend!())
919
- when is_binary(locale_name) do
1000
+ def known_rbnf_locale_name(locale_name, backend \\ default_backend!()) do
920
1001
if backend.known_rbnf_locale_name?(locale_name) do
921
1002
locale_name
922
1003
else
 
@@ -934,8 +1015,8 @@ defmodule Cldr do
934
1015
* `locale` is any valid locale name returned by `Cldr.known_locale_names/1`
935
1016
936
1017
* `backend` is any module that includes `use Cldr` and therefore
937
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
938
- Note that `Cldr.default_backend/0` will raise an exception if
1018
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
1019
+ Note that `Cldr.default_backend!/0` will raise an exception if
939
1020
no `:default_backend` is configured under the `:ex_cldr` key in
940
1021
`config.exs`.
941
1022
 
@@ -948,7 +1029,7 @@ defmodule Cldr do
948
1029
false
949
1030
950
1031
"""
951
- @spec known_gettext_locale_name(Locale.locale_name(), backend()) :: String.t() | false
1032
+ @spec known_gettext_locale_name(String.t(), backend()) :: String.t() | false
952
1033
def known_gettext_locale_name(locale_name, backend \\ default_backend!())
953
1034
when is_binary(locale_name) do
954
1035
backend.known_gettext_locale_name(locale_name)
 
@@ -969,22 +1050,28 @@ defmodule Cldr do
969
1050
970
1051
## Examples
971
1052
972
- iex> Cldr.available_locale_name?("en-AU")
1053
+ iex> Cldr.available_locale_name?(:"en-AU")
973
1054
true
974
1055
975
- iex> Cldr.available_locale_name?("en-SA")
1056
+ iex> Cldr.available_locale_name?(:"en-SA")
976
1057
false
977
1058
978
1059
"""
1060
+ @all_locale_names Config.all_locale_names()
1061
+
979
1062
@spec available_locale_name?(Locale.locale_name() | LanguageTag.t()) :: boolean
980
- def available_locale_name?(locale_name) when is_binary(locale_name) do
981
- locale_name in Config.all_locale_names()
1063
+ def available_locale_name?(locale_name) when is_atom(locale_name) do
1064
+ locale_name in @all_locale_names
982
1065
end
983
1066
984
1067
def available_locale_name?(%LanguageTag{cldr_locale_name: cldr_locale_name}) do
985
1068
available_locale_name?(cldr_locale_name)
986
1069
end
987
1070
1071
+ def available_locale_name?(_other) do
1072
+ false
1073
+ end
1074
+
988
1075
@doc """
989
1076
Add locale-specific quotation marks around a string.
990
1077
 
@@ -993,8 +1080,8 @@ defmodule Cldr do
993
1080
* `string` is any valid Elixir string
994
1081
995
1082
* `backend` is any module that includes `use Cldr` and therefore
996
- is a `Cldr` backend module. The default is `Cldr.default_backend/0`.
997
- Note that `Cldr.default_backend/0` will raise an exception if
1083
+ is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
1084
+ Note that `Cldr.default_backend!/0` will raise an exception if
998
1085
no `:default_backend` is configured under the `:ex_cldr` key in
999
1086
`config.exs`.
1000
1087
 
@@ -1444,7 +1531,7 @@ defmodule Cldr do
1444
1531
1445
1532
"""
1446
1533
@spec validate_territory(atom() | String.t()) ::
1447
- {:ok, atom()} | {:error, {module(), String.t()}}
1534
+ {:ok, Locale.territory_code()} | {:error, {module(), String.t()}}
1448
1535
1449
1536
def validate_territory(territory) when is_atom(territory) and territory in @known_territories do
1450
1537
{:ok, territory}
 
@@ -1631,7 +1718,7 @@ defmodule Cldr do
1631
1718
{:ok, [:CA, :"021", :"019", :"001"]}
1632
1719
1633
1720
"""
1634
- def territory_chain(locale_name, backend) when is_binary(locale_name) and is_atom(backend) do
1721
+ def territory_chain(locale_name, backend) when is_atom(backend) do
1635
1722
with {:ok, locale} <- validate_locale(locale_name, backend) do
1636
1723
territory_chain(locale)
1637
1724
end
changed lib/cldr/accept_language.ex
 
@@ -98,14 +98,14 @@ defmodule Cldr.AcceptLanguage do
98
98
%Cldr.LanguageTag{
99
99
backend: TestBackend.Cldr,
100
100
canonical_locale_name: "da",
101
- cldr_locale_name: "da",
101
+ cldr_locale_name: :da,
102
102
language_subtags: [],
103
103
extensions: %{},
104
104
gettext_locale_name: nil,
105
105
language: "da",
106
106
locale: %{},
107
107
private_use: [],
108
- rbnf_locale_name: "da",
108
+ rbnf_locale_name: :da,
109
109
requested_locale_name: "da",
110
110
script: :Latn,
111
111
territory: :DK,
 
@@ -116,14 +116,14 @@ defmodule Cldr.AcceptLanguage do
116
116
%Cldr.LanguageTag{
117
117
backend: TestBackend.Cldr,
118
118
canonical_locale_name: "zh-TW",
119
- cldr_locale_name: "zh-Hant",
119
+ cldr_locale_name: :"zh-Hant",
120
120
language_subtags: [],
121
121
extensions: %{},
122
122
gettext_locale_name: nil,
123
123
language: "zh",
124
124
locale: %{},
125
125
private_use: [],
126
- rbnf_locale_name: "zh-Hant",
126
+ rbnf_locale_name: :"zh-Hant",
127
127
requested_locale_name: "zh-TW",
128
128
script: :Hant,
129
129
territory: :TW,
 
@@ -144,14 +144,14 @@ defmodule Cldr.AcceptLanguage do
144
144
%Cldr.LanguageTag{
145
145
backend: TestBackend.Cldr,
146
146
canonical_locale_name: "da",
147
- cldr_locale_name: "da",
147
+ cldr_locale_name: :da,
148
148
language_subtags: [],
149
149
extensions: %{},
150
150
gettext_locale_name: nil,
151
151
language: "da",
152
152
locale: %{},
153
153
private_use: [],
154
- rbnf_locale_name: "da",
154
+ rbnf_locale_name: :da,
155
155
requested_locale_name: "da",
156
156
script: :Latn,
157
157
territory: :DK,
 
@@ -162,14 +162,14 @@ defmodule Cldr.AcceptLanguage do
162
162
%Cldr.LanguageTag{
163
163
backend: TestBackend.Cldr,
164
164
canonical_locale_name: "zh-TW",
165
- cldr_locale_name: "zh-Hant",
165
+ cldr_locale_name: :"zh-Hant",
166
166
language_subtags: [],
167
167
extensions: %{},
168
168
gettext_locale_name: nil,
169
169
language: "zh",
170
170
locale: %{},
171
171
private_use: [],
172
- rbnf_locale_name: "zh-Hant",
172
+ rbnf_locale_name: :"zh-Hant",
173
173
requested_locale_name: "zh-TW",
174
174
script: :Hant,
175
175
territory: :TW,
 
@@ -237,14 +237,14 @@ defmodule Cldr.AcceptLanguage do
237
237
%Cldr.LanguageTag{
238
238
backend: TestBackend.Cldr,
239
239
canonical_locale_name: "da",
240
- cldr_locale_name: "da",
240
+ cldr_locale_name: :da,
241
241
language_subtags: [],
242
242
extensions: %{},
243
243
gettext_locale_name: nil,
244
244
language: "da",
245
245
locale: %{},
246
246
private_use: [],
247
- rbnf_locale_name: "da",
247
+ rbnf_locale_name: :da,
248
248
requested_locale_name: "da",
249
249
script: :Latn,
250
250
territory: :DK,
 
@@ -255,14 +255,14 @@ defmodule Cldr.AcceptLanguage do
255
255
%Cldr.LanguageTag{
256
256
backend: TestBackend.Cldr,
257
257
canonical_locale_name: "zh-TW",
258
- cldr_locale_name: "zh-Hant",
258
+ cldr_locale_name: :"zh-Hant",
259
259
language_subtags: [],
260
260
extensions: %{},
261
261
gettext_locale_name: nil,
262
262
language: "zh",
263
263
locale: %{},
264
264
private_use: [],
265
- rbnf_locale_name: "zh-Hant",
265
+ rbnf_locale_name: :"zh-Hant",
266
266
requested_locale_name: "zh-TW",
267
267
script: :Hant,
268
268
territory: :TW,
 
@@ -281,14 +281,14 @@ defmodule Cldr.AcceptLanguage do
281
281
%Cldr.LanguageTag{
282
282
backend: TestBackend.Cldr,
283
283
canonical_locale_name: "da",
284
- cldr_locale_name: "da",
284
+ cldr_locale_name: :da,
285
285
language_subtags: [],
286
286
extensions: %{},
287
287
gettext_locale_name: nil,
288
288
language: "da",
289
289
locale: %{},
290
290
private_use: [],
291
- rbnf_locale_name: "da",
291
+ rbnf_locale_name: :da,
292
292
requested_locale_name: "da",
293
293
script: :Latn,
294
294
territory: :DK,
 
@@ -299,14 +299,14 @@ defmodule Cldr.AcceptLanguage do
299
299
%Cldr.LanguageTag{
300
300
backend: TestBackend.Cldr,
301
301
canonical_locale_name: "zh-TW",
302
- cldr_locale_name: "zh-Hant",
302
+ cldr_locale_name: :"zh-Hant",
303
303
language_subtags: [],
304
304
extensions: %{},
305
305
gettext_locale_name: nil,
306
306
language: "zh",
307
307
locale: %{},
308
308
private_use: [],
309
- rbnf_locale_name: "zh-Hant",
309
+ rbnf_locale_name: :"zh-Hant",
310
310
requested_locale_name: "zh-TW",
311
311
script: :Hant,
312
312
territory: :TW,
 
@@ -345,14 +345,14 @@ defmodule Cldr.AcceptLanguage do
345
345
%Cldr.LanguageTag{
346
346
backend: TestBackend.Cldr,
347
347
canonical_locale_name: "zh-TW",
348
- cldr_locale_name: "zh-Hant",
348
+ cldr_locale_name: :"zh-Hant",
349
349
language_subtags: [],
350
350
extensions: %{},
351
351
gettext_locale_name: nil,
352
352
language: "zh",
353
353
locale: %{},
354
354
private_use: [],
355
- rbnf_locale_name: "zh-Hant",
355
+ rbnf_locale_name: :"zh-Hant",
356
356
requested_locale_name: "zh-TW",
357
357
script: :Hant,
358
358
territory: :TW,
 
@@ -360,19 +360,19 @@ defmodule Cldr.AcceptLanguage do
360
360
language_variants: []
361
361
}}
362
362
363
- iex(4)> Cldr.AcceptLanguage.best_match("da;q=0.1,zh-TW;q=0.3", TestBackend.Cldr)
363
+ iex> Cldr.AcceptLanguage.best_match("da;q=0.1,zh-TW;q=0.3", TestBackend.Cldr)
364
364
{:ok,
365
365
%Cldr.LanguageTag{
366
366
backend: TestBackend.Cldr,
367
367
canonical_locale_name: "zh-TW",
368
- cldr_locale_name: "zh-Hant",
368
+ cldr_locale_name: :"zh-Hant",
369
369
language_subtags: [],
370
370
extensions: %{},
371
371
gettext_locale_name: nil,
372
372
language: "zh",
373
373
locale: %{},
374
374
private_use: [],
375
- rbnf_locale_name: "zh-Hant",
375
+ rbnf_locale_name: :"zh-Hant",
376
376
requested_locale_name: "zh-TW",
377
377
script: :Hant,
378
378
territory: :TW,
changed lib/cldr/backend/cldr.ex
 
@@ -14,8 +14,12 @@ defmodule Cldr.Backend do
14
14
in this module or in `Gettext`.
15
15
16
16
"""
17
- @omit_locales ["und"]
18
- @known_locale_names Cldr.Locale.Loader.known_locale_names(config) -- @omit_locales
17
+
18
+ alias Cldr.{Locale, Config, LanguageTag}
19
+
20
+ @omit_locales [Config.root_locale_name()]
21
+ @known_locale_names Locale.Loader.known_locale_names(config) -- @omit_locales
22
+
19
23
def known_locale_names do
20
24
@known_locale_names
21
25
end
 
@@ -29,14 +33,14 @@ defmodule Cldr.Backend do
29
33
%Cldr.LanguageTag{
30
34
backend: #{inspect(__MODULE__)},
31
35
canonical_locale_name: "en-001",
32
- cldr_locale_name: "en-001",
36
+ cldr_locale_name: :"en-001",
33
37
language_subtags: [],
34
38
extensions: %{},
35
39
gettext_locale_name: "en",
36
40
language: "en",
37
41
locale: %{},
38
42
private_use: [],
39
- rbnf_locale_name: "en",
43
+ rbnf_locale_name: :en,
40
44
requested_locale_name: "en-001",
41
45
script: :Latn,
42
46
territory: :"001",
 
@@ -46,12 +50,12 @@ defmodule Cldr.Backend do
46
50
47
51
"""
48
52
@default_locale config
49
- |> Cldr.Config.default_locale_name()
50
- |> Cldr.Config.language_tag()
53
+ |> Config.default_locale_name()
54
+ |> Config.language_tag()
51
55
|> Map.put(:backend, __MODULE__)
52
56
53
57
@compile {:inline, default_locale: 0}
54
- @spec default_locale :: Cldr.LanguageTag.t() | no_return()
58
+ @spec default_locale :: LanguageTag.t() | no_return()
55
59
def default_locale do
56
60
Cldr.Locale.put_gettext_locale_name(@default_locale)
57
61
end
 
@@ -66,10 +70,9 @@ defmodule Cldr.Backend do
66
70
:"001"
67
71
68
72
"""
69
- @default_territory @default_locale |> Cldr.Locale.territory_from_locale()
70
- @spec default_territory() :: Cldr.Locale.territory()
73
+ @spec default_territory() :: Locale.territory_code()
71
74
def default_territory do
72
- @default_territory
75
+ Cldr.Locale.territory_from_locale(@default_locale)
73
76
end
74
77
75
78
@doc """
 
@@ -81,7 +84,7 @@ defmodule Cldr.Backend do
81
84
return an empty list.
82
85
83
86
"""
84
- @unknown_locale_names Cldr.Config.unknown_locale_names(config)
87
+ @unknown_locale_names Config.unknown_locale_names(config)
85
88
@spec unknown_locale_names() :: [Locale.locale_name()]
86
89
def unknown_locale_names do
87
90
@unknown_locale_names
 
@@ -92,7 +95,8 @@ defmodule Cldr.Backend do
92
95
formats (RBNF).
93
96
94
97
"""
95
- @known_rbnf_locale_names Cldr.Locale.Loader.known_rbnf_locale_names(config)
98
+ @known_rbnf_locale_names Locale.Loader.known_rbnf_locale_names(config)
99
+
96
100
@spec known_rbnf_locale_names() :: [Locale.locale_name()]
97
101
def known_rbnf_locale_names do
98
102
@known_rbnf_locale_names
 
@@ -104,8 +108,9 @@ defmodule Cldr.Backend do
104
108
with `Cldr` locale names.
105
109
106
110
"""
107
- @known_gettext_locale_names Cldr.Config.known_gettext_locale_names(config)
108
- @spec known_gettext_locale_names() :: [Locale.locale_name()]
111
+ @known_gettext_locale_names Config.known_gettext_locale_names(config)
112
+
113
+ @spec known_gettext_locale_names() :: [String.t()]
109
114
def known_gettext_locale_names do
110
115
@known_gettext_locale_names
111
116
end
 
@@ -120,15 +125,15 @@ defmodule Cldr.Backend do
120
125
121
126
## Examples
122
127
123
- iex> #{inspect(__MODULE__)}.known_locale_name?("en")
128
+ iex> #{inspect(__MODULE__)}.known_locale_name?(:en)
124
129
true
125
130
126
- iex> #{inspect(__MODULE__)}.known_locale_name?("!!")
131
+ iex> #{inspect(__MODULE__)}.known_locale_name?(:"!!")
127
132
false
128
133
129
134
"""
130
135
@spec known_locale_name?(Locale.locale_name()) :: boolean
131
- def known_locale_name?(locale_name) when is_binary(locale_name) do
136
+ def known_locale_name?(locale_name) when is_atom(locale_name) do
132
137
locale_name in known_locale_names()
133
138
end
134
139
 
@@ -143,15 +148,15 @@ defmodule Cldr.Backend do
143
148
144
149
## Examples
145
150
146
- iex> #{inspect(__MODULE__)}.known_rbnf_locale_name?("en")
151
+ iex> #{inspect(__MODULE__)}.known_rbnf_locale_name?(:en)
147
152
true
148
153
149
- iex> #{inspect(__MODULE__)}.known_rbnf_locale_name?("!!")
154
+ iex> #{inspect(__MODULE__)}.known_rbnf_locale_name?(:"!!")
150
155
false
151
156
152
157
"""
153
158
@spec known_rbnf_locale_name?(Locale.locale_name()) :: boolean
154
- def known_rbnf_locale_name?(locale_name) when is_binary(locale_name) do
159
+ def known_rbnf_locale_name?(locale_name) when is_atom(locale_name) do
155
160
locale_name in known_rbnf_locale_names()
156
161
end
157
162
 
@@ -161,7 +166,8 @@ defmodule Cldr.Backend do
161
166
162
167
## Arguments
163
168
164
- * `locale` is any valid locale name returned by `#{inspect(__MODULE__)}.known_locale_names/0`
169
+ * `locale` is any valid locale name returned by
170
+ `#{inspect(__MODULE__)}.known_locale_names/0`
165
171
166
172
## Examples
167
173
 
@@ -172,7 +178,7 @@ defmodule Cldr.Backend do
172
178
false
173
179
174
180
"""
175
- @spec known_gettext_locale_name?(Locale.locale_name()) :: boolean
181
+ @spec known_gettext_locale_name?(String.t()) :: boolean
176
182
def known_gettext_locale_name?(locale_name) when is_binary(locale_name) do
177
183
locale_name in known_gettext_locale_names()
178
184
end
 
@@ -186,19 +192,20 @@ defmodule Cldr.Backend do
186
192
187
193
## Arguments
188
194
189
- * `locale` is any valid locale name returned by `#{inspect(__MODULE__)}.known_locale_names/0`
195
+ * `locale` is any valid locale name returned by
196
+ `#{inspect(__MODULE__)}.known_locale_names/0`
190
197
191
198
## Examples
192
199
193
- iex> #{inspect(__MODULE__)}.known_locale_name "en-AU"
194
- "en-AU"
200
+ iex> #{inspect(__MODULE__)}.known_locale_name :"en-AU"
201
+ :"en-AU"
195
202
196
- iex> #{inspect(__MODULE__)}.known_locale_name "en-SA"
203
+ iex> #{inspect(__MODULE__)}.known_locale_name :"en-SA"
197
204
false
198
205
199
206
"""
200
207
@spec known_locale_name(Locale.locale_name()) :: String.t() | false
201
- def known_locale_name(locale_name) when is_binary(locale_name) do
208
+ def known_locale_name(locale_name) when is_atom(locale_name) do
202
209
if known_locale_name?(locale_name) do
203
210
locale_name
204
211
else
 
@@ -213,19 +220,20 @@ defmodule Cldr.Backend do
213
220
214
221
## Arguments
215
222
216
- * `locale` is any valid locale name returned by `#{inspect(__MODULE__)}.known_locale_names/0`
223
+ * `locale` is any valid locale name returned by
224
+ `#{inspect(__MODULE__)}.known_locale_names/0`
217
225
218
226
## Examples
219
227
220
- iex> #{inspect(__MODULE__)}.known_rbnf_locale_name "en"
221
- "en"
228
+ iex> #{inspect(__MODULE__)}.known_rbnf_locale_name :en
229
+ :en
222
230
223
- iex> #{inspect(__MODULE__)}.known_rbnf_locale_name "en-SA"
231
+ iex> #{inspect(__MODULE__)}.known_rbnf_locale_name :"en-SA"
224
232
false
225
233
226
234
"""
227
235
@spec known_rbnf_locale_name(Locale.locale_name()) :: String.t() | false
228
- def known_rbnf_locale_name(locale_name) when is_binary(locale_name) do
236
+ def known_rbnf_locale_name(locale_name) when is_atom(locale_name) do
229
237
if known_rbnf_locale_name?(locale_name) do
230
238
locale_name
231
239
else
 
@@ -252,7 +260,7 @@ defmodule Cldr.Backend do
252
260
false
253
261
254
262
"""
255
- @spec known_gettext_locale_name(Locale.locale_name()) :: String.t() | false
263
+ @spec known_gettext_locale_name(String.t()) :: String.t() | false
256
264
def known_gettext_locale_name(locale_name) when is_binary(locale_name) do
257
265
if known_gettext_locale_name?(locale_name) do
258
266
locale_name
 
@@ -272,12 +280,12 @@ defmodule Cldr.Backend do
272
280
%Cldr.LanguageTag{
273
281
backend: #{__MODULE__},
274
282
canonical_locale_name: "pl",
275
- cldr_locale_name: "pl",
283
+ cldr_locale_name: :pl,
276
284
extensions: %{},
277
285
language: "pl",
278
286
locale: %{},
279
287
private_use: [],
280
- rbnf_locale_name: "pl",
288
+ rbnf_locale_name: :pl,
281
289
territory: :PL,
282
290
requested_locale_name: "pl",
283
291
script: :Latn,
 
@@ -310,14 +318,14 @@ defmodule Cldr.Backend do
310
318
%Cldr.LanguageTag{
311
319
backend: #{inspect(__MODULE__)},
312
320
canonical_locale_name: "en",
313
- cldr_locale_name: "en",
321
+ cldr_locale_name: :en,
314
322
language_subtags: [],
315
323
extensions: %{},
316
324
gettext_locale_name: "en",
317
325
language: "en",
318
326
locale: %{},
319
327
private_use: [],
320
- rbnf_locale_name: "en",
328
+ rbnf_locale_name: :en,
321
329
requested_locale_name: "en",
322
330
script: :Latn,
323
331
territory: :US,
 
@@ -358,7 +366,7 @@ defmodule Cldr.Backend do
358
366
iex> #{inspect(__MODULE__)}.quote "Quoted String"
359
367
"“Quoted String”"
360
368
361
- iex> #{inspect(__MODULE__)}.quote "Quoted String", locale: "ja"
369
+ iex> #{inspect(__MODULE__)}.quote "Quoted String", locale: :ja
362
370
"「Quoted String」"
363
371
364
372
"""
 
@@ -408,13 +416,13 @@ defmodule Cldr.Backend do
408
416
iex> #{inspect(__MODULE__)}.ellipsis "And furthermore"
409
417
"And furthermore…"
410
418
411
- iex> #{inspect(__MODULE__)}.ellipsis ["And furthermore", "there is much to be done"], locale: "ja"
419
+ iex> #{inspect(__MODULE__)}.ellipsis ["And furthermore", "there is much to be done"], locale: :ja
412
420
"And furthermore…there is much to be done"
413
421
414
422
iex> #{inspect(__MODULE__)}.ellipsis "And furthermore", format: :word
415
423
"And furthermore …"
416
424
417
- iex> #{inspect(__MODULE__)}.ellipsis ["And furthermore", "there is much to be done"], locale: "ja", format: :word
425
+ iex> #{inspect(__MODULE__)}.ellipsis ["And furthermore", "there is much to be done"], locale: :ja, format: :word
418
426
"And furthermore … there is much to be done"
419
427
420
428
"""
 
@@ -505,18 +513,18 @@ defmodule Cldr.Backend do
505
513
506
514
## Examples
507
515
508
- iex> #{inspect(__MODULE__)}.validate_locale("en")
516
+ iex> #{inspect(__MODULE__)}.validate_locale(:en)
509
517
{:ok,
510
518
%Cldr.LanguageTag{
511
519
backend: #{inspect(__MODULE__)},
512
520
canonical_locale_name: "en",
513
- cldr_locale_name: "en",
521
+ cldr_locale_name: :en,
514
522
extensions: %{},
515
523
gettext_locale_name: "en",
516
524
language: "en",
517
525
locale: %{},
518
526
private_use: [],
519
- rbnf_locale_name: "en",
527
+ rbnf_locale_name: :en,
520
528
requested_locale_name: "en",
521
529
script: :Latn,
522
530
territory: :US,
 
@@ -530,13 +538,13 @@ defmodule Cldr.Backend do
530
538
%Cldr.LanguageTag{
531
539
backend: #{inspect(__MODULE__)},
532
540
canonical_locale_name: "en-001",
533
- cldr_locale_name: "en-001",
541
+ cldr_locale_name: :"en-001",
534
542
extensions: %{},
535
543
gettext_locale_name: "en",
536
544
language: "en",
537
545
locale: %{},
538
546
private_use: [],
539
- rbnf_locale_name: "en",
547
+ rbnf_locale_name: :en,
540
548
requested_locale_name: "en-001",
541
549
script: :Latn,
542
550
territory: :"001",
 
@@ -548,7 +556,7 @@ defmodule Cldr.Backend do
548
556
{:error, {Cldr.InvalidLanguageError, "The language \\"zzz\\" is invalid"}}
549
557
550
558
"""
551
- @spec validate_locale(Locale.locale_name() | LanguageTag.t()) ::
559
+ @spec validate_locale(Locale.locale_name() | LanguageTag.t() | String.t()) ::
552
560
{:ok, LanguageTag.t()} | {:error, {module(), String.t()}}
553
561
554
562
def validate_locale(%LanguageTag{cldr_locale_name: nil} = locale) do
 
@@ -573,6 +581,19 @@ defmodule Cldr.Backend do
573
581
end
574
582
end
575
583
584
+ def validate_locale(locale_name) when is_atom(locale_name) do
585
+ locale =
586
+ locale_name
587
+ |> Atom.to_string()
588
+ |> validate_locale
589
+
590
+ case locale do
591
+ {:error, {Cldr.UnknownLocaleError, _}} -> {:error, Locale.locale_error(locale_name)}
592
+ {:error, reason} -> {:error, reason}
593
+ {:ok, locale} -> {:ok, locale}
594
+ end
595
+ end
596
+
576
597
def validate_locale(locale) do
577
598
{:error, Locale.locale_error(locale)}
578
599
end
 
@@ -602,6 +623,7 @@ defmodule Cldr.Backend do
602
623
# are not supported in Erlang's re
603
624
604
625
@remove_compounds Regex.compile!("{.*}", [:ungreedy])
626
+
605
627
for locale_name <- Cldr.Locale.Loader.known_locale_names(config) do
606
628
lenient_parse =
607
629
locale_name
 
@@ -632,6 +654,7 @@ defmodule Cldr.Backend do
632
654
# parsed language tag for performance reasons and only
633
655
# add the gettext locale name (if there is one) and the
634
656
# backend module.
657
+
635
658
for locale_name <- Cldr.Locale.Loader.known_locale_names(config),
636
659
not is_nil(Cldr.Config.language_tag(locale_name)) do
637
660
 
@@ -641,7 +664,10 @@ defmodule Cldr.Backend do
641
664
|> Cldr.Locale.put_gettext_locale_name(config)
642
665
|> Map.put(:backend, __MODULE__)
643
666
644
- locale_name = String.downcase(locale_name)
667
+ locale_name =
668
+ locale_name
669
+ |> Atom.to_string()
670
+ |> String.downcase()
645
671
646
672
defp do_validate_locale(unquote(locale_name)) do
647
673
{:ok, unquote(Macro.escape(language_tag))}
changed lib/cldr/backend/compiler.ex
 
@@ -45,6 +45,7 @@ defmodule Cldr.Backend.Compiler do
45
45
46
46
unquote(Cldr.Backend.define_backend_functions(config))
47
47
unquote(Cldr.Locale.Backend.define_locale_backend(config))
48
+ unquote(Cldr.Trans.Backend.define_locale_backend(config))
48
49
unquote(Cldr.Number.PluralRule.define_ordinal_and_cardinal_modules(config))
49
50
unquote(Cldr.Number.PluralRule.define_plural_ranges(config))
50
51
unquote(Cldr.Config.define_provider_modules(config))
changed lib/cldr/backend/locale.ex
 
@@ -14,8 +14,10 @@ defmodule Cldr.Locale.Backend do
14
14
"""
15
15
end
16
16
17
- def new(locale_name), do: Cldr.Locale.new(locale_name, unquote(config.backend))
18
- def new!(locale_name), do: Cldr.Locale.new!(locale_name, unquote(config.backend))
17
+ alias Cldr.{Locale, LanguageTag}
18
+
19
+ def new(locale_name), do: Locale.new(locale_name, unquote(config.backend))
20
+ def new!(locale_name), do: Locale.new!(locale_name, unquote(config.backend))
19
21
20
22
@doc """
21
23
Returns the territory from a language tag or
 
@@ -41,17 +43,17 @@ defmodule Cldr.Locale.Backend do
41
43
:GB
42
44
43
45
"""
44
- @spec territory_from_locale(Cldr.LanguageTag.t() | Cldr.Locale.locale_name()) ::
45
- Cldr.Locale.territory()
46
+ @spec territory_from_locale(LanguageTag.t() | Locale.locale_name()) ::
47
+ Locale.territory_code()
46
48
47
49
@doc since: "2.18.2"
48
50
49
- def territory_from_locale(locale) when is_binary(locale) do
50
- Cldr.Locale.territory_from_locale(locale, unquote(config.backend))
51
+ def territory_from_locale(%LanguageTag{} = locale) do
52
+ Locale.territory_from_locale(locale)
51
53
end
52
54
53
- def territory_from_locale(%LanguageTag{} = locale) do
54
- Cldr.Locale.territory_from_locale(locale)
55
+ def territory_from_locale(locale) do
56
+ Locale.territory_from_locale(locale, unquote(config.backend))
55
57
end
56
58
57
59
@doc """
 
@@ -79,17 +81,332 @@ defmodule Cldr.Locale.Backend do
79
81
"""
80
82
@doc since: "2.19.0"
81
83
82
- @spec timezone_from_locale(Cldr.LanguageTag.t() | Cldr.Locale.locale_name()) ::
84
+ @spec timezone_from_locale(LanguageTag.t() | Locale.locale_name()) ::
83
85
String.t() | {:error, {module(), String.t()}}
84
86
85
- def timezone_from_locale(locale) when is_binary(locale) do
86
- Cldr.Locale.timezone_from_locale(locale, unquote(config.backend))
87
- end
88
-
89
87
def timezone_from_locale(%LanguageTag{} = locale) do
90
- Cldr.Locale.timezone_from_locale(locale)
88
+ Locale.timezone_from_locale(locale)
91
89
end
92
90
91
+ def timezone_from_locale(locale) do
92
+ Locale.timezone_from_locale(locale, unquote(config.backend))
93
+ end
94
+
95
+ @doc """
96
+ Returns the "best fit" locale for a given territory.
97
+
98
+ Using the population percentage data from CLDR, the
99
+ language most commonly spoken in the given territory
100
+ is used to form a locale name which is then validated
101
+ against the given backend.
102
+
103
+ First a territory-specific locale is validated and if
104
+ that fails, the base language only is validate.
105
+
106
+ For example, if the territory is `AU` then then the
107
+ language most spoken is "en". First, the locale "en-AU"
108
+ is validated and if that fails, "en" is validated.
109
+
110
+ ## Arguments
111
+
112
+ * `territory` is any ISO 3166 Alpha-2 territory
113
+ code that can be validated by `Cldr.validate_territory/1`
114
+
115
+ ## Returns
116
+
117
+ * `{:ok, language_tag}` or
118
+
119
+ * `{:error, {exception, reason}}`
120
+
121
+ ## Examples
122
+
123
+ iex> #{inspect(__MODULE__)}.locale_for_territory(:AU)
124
+ #{config.backend}.validate_locale(:"en-AU")
125
+
126
+ iex> #{inspect(__MODULE__)}.locale_for_territory(:US)
127
+ #{config.backend}.validate_locale(:"en-US")
128
+
129
+ iex> #{inspect(__MODULE__)}.locale_for_territory(:ZZ)
130
+ {:error, {Cldr.UnknownTerritoryError, "The territory :ZZ is unknown"}}
131
+
132
+ """
133
+ @doc since: "2.26.0"
134
+ @spec locale_for_territory(Locale.territory_code()) ::
135
+ {:ok, LanguageTag.t()} | {:error, {module(), String.t()}}
136
+
137
+ def locale_for_territory(territory) do
138
+ Locale.locale_for_territory(territory)
139
+ end
140
+
141
+ @doc """
142
+ Returns a "best fit" locale for a host name.
143
+
144
+ ## Arguments
145
+
146
+ * `host` is any valid host name
147
+
148
+ * `options` is a keyword list of options. The default
149
+ is `[]`.
150
+
151
+ ## Options
152
+
153
+ * `:tlds` is a list of territory codes as upper-cased
154
+ atoms that are to be considered as top-level domains.
155
+ See `Cldr.Locale.locale_from_host/2` for the default
156
+ list.
157
+
158
+ ## Returns
159
+
160
+ * `{:ok, langauge_tag}` or
161
+
162
+ * `{:error, {exception, reason}}`
163
+
164
+ ## Notes
165
+
166
+ Certain top-level domains have become associated with content
167
+ underlated to the territory for who the domain is registered.
168
+ Therefore Google (and perhaps others) do not associate these
169
+ TLDs as belonging to the territory but rather are considered
170
+ generic top-level domain names.
171
+
172
+ ## Examples
173
+
174
+ iex> #{inspect(__MODULE__)}.locale_from_host "a.b.com.au"
175
+ #{config.backend}.validate_locale(:"en-AU")
176
+
177
+ iex> #{inspect(__MODULE__)}.locale_from_host("a.b.com.tv")
178
+ {:error,
179
+ {Cldr.UnknownLocaleError, "No locale was identified for territory \\"tv\\""}}
180
+
181
+ iex> #{inspect(__MODULE__)}.locale_from_host("a.b.com")
182
+ {:error,
183
+ {Cldr.UnknownLocaleError, "No locale was identified for territory \\"com\\""}}
184
+
185
+ """
186
+ @doc since: "2.26.0"
187
+ @spec locale_from_host(String.t(), Keyword.t()) ::
188
+ {:ok, LanguageTag.t()} | {:error, {module(), String.t()}}
189
+
190
+ def locale_from_host(host, options \\ []) do
191
+ Locale.locale_from_host(host, unquote(config.backend), options)
192
+ end
193
+
194
+ @doc """
195
+ Returns the last segment of a host that might
196
+ be a territory.
197
+
198
+ ## Arguments
199
+
200
+ * `host` is any valid host name
201
+
202
+ ## Returns
203
+
204
+ * `{:ok, territory}` or
205
+
206
+ * `{:error, {exception, reason}}`
207
+
208
+ ## Examples
209
+
210
+ iex> Cldr.Locale.territory_from_host("a.b.com.au")
211
+ {:ok, :AU}
212
+
213
+ iex> Cldr.Locale.territory_from_host("a.b.com")
214
+ {:error,
215
+ {Cldr.UnknownLocaleError, "No locale was identified for territory \\"com\\""}}
216
+
217
+ """
218
+ @doc since: "2.26.0"
219
+ @spec territory_from_host(String.t()) ::
220
+ {:ok, Locale.territory_code()} | {:error, {module(), String.t()}}
221
+
222
+ def territory_from_host(host) do
223
+ Cldr.Locale.territory_from_host(host)
224
+ end
225
+
226
+ @doc """
227
+ Returns the list of fallback locales, starting
228
+ with the provided locale.
229
+
230
+ Fallbacks are a list of locate names which can
231
+ be used to resolve translation or other localization
232
+ data if such localised data does not exist for
233
+ this specific locale. After locale-specific fallbacks
234
+ are determined, the the default locale and its fallbacks
235
+ are added to the chain.
236
+
237
+ ## Arguments
238
+
239
+ * `locale` is any `LanguageTag.t`
240
+
241
+ ## Returns
242
+
243
+ * `{:ok, list_of_locales}` or
244
+
245
+ * `{:error, {exception, reason}}`
246
+
247
+ ## Examples
248
+
249
+ In these examples the default locale is `:"en-001"`.
250
+
251
+ #{inspect __MODULE__}.fallback_locales(#{inspect __MODULE__}.new!("fr-CA"))
252
+ => {:ok,
253
+ [#Cldr.LanguageTag<fr-CA [validated]>, #Cldr.LanguageTag<fr [validated]>,
254
+ #Cldr.LanguageTag<en [validated]>]}
255
+
256
+ # Fallbacks are typically formed by progressively
257
+ # stripping variant, territory and script from the
258
+ # given locale name. But not always - there are
259
+ # certain fallbacks that take a different path.
260
+
261
+ #{inspect __MODULE__}.fallback_locales(#{inspect __MODULE__}.new!("nb"))
262
+ => {:ok,
263
+ [#Cldr.LanguageTag<nb [validated]>, #Cldr.LanguageTag<no [validated]>,
264
+ #Cldr.LanguageTag<en [validated]>]}
265
+
266
+ """
267
+ @spec fallback_locales(LanguageTag.t() | Cldr.Locale.locale_reference) ::
268
+ {:ok, [LanguageTag.t(), ...]} | {:error, {module(), binary()}}
269
+
270
+ @doc since: "2.26.0"
271
+ def fallback_locales(%LanguageTag{} = locale) do
272
+ Cldr.Locale.fallback_locales(locale)
273
+ end
274
+
275
+ @doc """
276
+ Returns the list of fallback locales, starting
277
+ with the provided locale name.
278
+
279
+ Fallbacks are a list of locate names which can
280
+ be used to resolve translation or other localization
281
+ data if such localised data does not exist for
282
+ this specific locale. After locale-specific fallbacks
283
+ are determined, the the default locale and its fallbacks
284
+ are added to the chain.
285
+
286
+ ## Arguments
287
+
288
+ * `locale_name` is any locale name returned by
289
+ `#{inspect config.backend}.known_locale_names/0`
290
+
291
+ ## Returns
292
+
293
+ * `{:ok, list_of_locales}` or
294
+
295
+ * `{:error, {exception, reason}}`
296
+
297
+ ## Examples
298
+
299
+ In these examples the default locale is `:"en-001"`.
300
+
301
+ #{inspect __MODULE__}.fallback_locales(:"fr-CA")
302
+ => {:ok,
303
+ [#Cldr.LanguageTag<fr-CA [validated]>, #Cldr.LanguageTag<fr [validated]>,
304
+ #Cldr.LanguageTag<en [validated]>]}
305
+
306
+ # Fallbacks are typically formed by progressively
307
+ # stripping variant, territory and script from the
308
+ # given locale name. But not always - there are
309
+ # certain fallbacks that take a different path.
310
+
311
+ #{inspect __MODULE__}.fallback_locales(:nb))
312
+ => {:ok,
313
+ [#Cldr.LanguageTag<nb [validated]>, #Cldr.LanguageTag<no [validated]>,
314
+ #Cldr.LanguageTag<en [validated]>]}
315
+
316
+ """
317
+
318
+ @doc since: "2.26.0"
319
+ def fallback_locales(locale_name) do
320
+ Cldr.Locale.fallback_locales(locale_name, unquote(config.backend))
321
+ end
322
+
323
+ @doc """
324
+ Returns the list of fallback locale names, starting
325
+ with the provided locale.
326
+
327
+ Fallbacks are a list of locate names which can
328
+ be used to resolve translation or other localization
329
+ data if such localised data does not exist for
330
+ this specific locale. After locale-specific fallbacks
331
+ are determined, the the default locale and its fallbacks
332
+ are added to the chain.
333
+
334
+ ## Arguments
335
+
336
+ * `locale` is any `Cldr,LangaugeTag.t`
337
+
338
+ ## Returns
339
+
340
+ * `{:ok, list_of_locale_names}` or
341
+
342
+ * `{:error, {exception, reason}}`
343
+
344
+ ## Examples
345
+
346
+ In these examples the default locale is `:"en-001"`.
347
+
348
+ iex> #{inspect __MODULE__}.fallback_locale_names(#{inspect __MODULE__}.new!("fr-CA"))
349
+ {:ok, [:"fr-CA", :fr, :"en-001", :en]}
350
+
351
+ # Fallbacks are typically formed by progressively
352
+ # stripping variant, territory and script from the
353
+ # given locale name. But not always - there are
354
+ # certain fallbacks that take a different path.
355
+
356
+ iex> #{inspect __MODULE__}.fallback_locale_names(#{inspect __MODULE__}.new!("nb"))
357
+ {:ok, [:nb, :no, :"en-001", :en]}
358
+
359
+ """
360
+ @spec fallback_locale_names(LanguageTag.t() | Cldr.Locale.locale_reference) ::
361
+ {:ok, [Cldr.Locale.locale_name, ...]} | {:error, {module(), binary()}}
362
+
363
+ @doc since: "2.26.0"
364
+ def fallback_locale_names(%LanguageTag{} = locale) do
365
+ Cldr.Locale.fallback_locale_names(locale)
366
+ end
367
+
368
+ @doc """
369
+ Returns the list of fallback locale names, starting
370
+ with the provided locale name.
371
+
372
+ Fallbacks are a list of locate names which can
373
+ be used to resolve translation or other localization
374
+ data if such localised data does not exist for
375
+ this specific locale. After locale-specific fallbacks
376
+ are determined, the the default locale and its fallbacks
377
+ are added to the chain.
378
+
379
+ ## Arguments
380
+
381
+ * `locale_name` is any locale name returned by
382
+ `#{inspect config.backend}.known_locale_names/0`
383
+
384
+ ## Returns
385
+
386
+ * `{:ok, list_of_locale_names}` or
387
+
388
+ * `{:error, {exception, reason}}`
389
+
390
+ ## Examples
391
+
392
+ In these examples the default locale is `:"en-001"`.
393
+
394
+ iex> #{inspect __MODULE__}.fallback_locale_names(:"fr-CA")
395
+ {:ok, [:"fr-CA", :fr, :"en-001", :en]}
396
+
397
+ # Fallbacks are typically formed by progressively
398
+ # stripping variant, territory and script from the
399
+ # given locale name. But not always - there are
400
+ # certain fallbacks that take a different path.
401
+
402
+ iex> #{inspect __MODULE__}.fallback_locale_names(:nb)
403
+ {:ok, [:nb, :no, :"en-001", :en]}
404
+
405
+ """
406
+ @doc since: "2.26.0"
407
+ def fallback_locale_names(locale_name) do
408
+ Cldr.Locale.fallback_locale_names(locale_name, unquote(config.backend))
409
+ end
93
410
end
94
411
end
95
412
end
added lib/cldr/backend/trans.ex
 
@@ -0,0 +1,81 @@
1
+ defmodule Cldr.Trans.Backend do
2
+ @moduledoc false
3
+
4
+ def define_locale_backend(config) do
5
+ quote location: :keep, bind_quoted: [config: Macro.escape(config), backend: config.backend] do
6
+ defmodule Trans do
7
+ @moduledoc false
8
+ if Cldr.Config.include_module_docs?(config.generate_docs) do
9
+ @moduledoc """
10
+ Backend module to generate translation schemas
11
+ for user of the [trans](https://hex.pm/packages/trans)
12
+ library.
13
+
14
+ WHen defining structured translations for Ecto schemas
15
+ the `Trans` documentation shows the following example
16
+
17
+ defmodule MyApp.Article do
18
+ use Ecto.Schema
19
+ use Trans, translates: [:title, :body]
20
+
21
+ schema "articles" do
22
+ field :title, :string
23
+ field :body, :string
24
+ embeds_one :translations, Translations, on_replace: :update, primary_key: false do
25
+ embeds_one :es, MyApp.Article.Translation, on_replace: :update
26
+ embeds_one :fr, MyApp.Article.Translation, on_replace: :update
27
+ end
28
+ end
29
+ end
30
+
31
+ Using the `translate/3` macro in this module, the following
32
+ will configure structued translations for all locales configured
33
+ in this backend. An example is:
34
+
35
+ defmodule MyApp.Article do
36
+ use Ecto.Schema
37
+ use Trans, translates: [:title, :body]
38
+ use MyApp.Cldr.Trans
39
+
40
+ schema "articles" do
41
+ field :title, :string
42
+ field :body, :string
43
+
44
+ # The translation module name and the options
45
+ # may be ommitted - the defaults are those shown
46
+ translations :translations, Translations, on_replace: :update, primary_key: false
47
+ end
48
+ end
49
+
50
+ """
51
+ end
52
+
53
+ defmacro __using__(_opts) do
54
+ backend = unquote(backend)
55
+
56
+ quote do
57
+ import unquote(backend).Trans
58
+ end
59
+ end
60
+
61
+ @doc false
62
+ def default_trans_options do
63
+ [on_replace: :update, primary_key: false]
64
+ end
65
+
66
+ defmacro translations(field_name, translation_module, options \\ []) do
67
+ options = Keyword.merge(unquote(backend).Trans.default_trans_options(), options)
68
+ backend = unquote(backend)
69
+
70
+ quote do
71
+ embeds_one unquote(field_name), Translations, unquote(options) do
72
+ for locale_name <- unquote(backend).known_locale_names() do
73
+ embeds_one locale_name, unquote(translation_module), on_replace: :update
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
changed lib/cldr/config/config.ex
 
@@ -26,7 +26,7 @@ defmodule Cldr.Config do
26
26
otp_app: nil,
27
27
generate_docs: true,
28
28
supress_warnings: false,
29
- message_formats: [],
29
+ message_formats: %{},
30
30
force_locale_download: false
31
31
32
32
@type t :: %__MODULE__{
 
@@ -50,7 +50,7 @@ defmodule Cldr.Config do
50
50
51
51
@type number_system :: atom() | String.t()
52
52
53
- @default_locale_name "en-001"
53
+ @default_locale_name :"en-001"
54
54
55
55
@cldr_modules [
56
56
"number_formats",
 
@@ -72,7 +72,7 @@ defmodule Cldr.Config do
72
72
"subdivisions"
73
73
]
74
74
75
- @root_locale_name "und"
75
+ @root_locale_name :und
76
76
77
77
@doc false
78
78
# Integer keys cater for 60 year cycles and 239 japanese eras
 
@@ -345,6 +345,7 @@ defmodule Cldr.Config do
345
345
@default_locale_name
346
346
347
347
locale_name_from_posix(default)
348
+ |> String.to_atom
348
349
end
349
350
350
351
@doc """
 
@@ -432,6 +433,7 @@ defmodule Cldr.Config do
432
433
Path.join(cldr_data_dir(), @available_locales_file)
433
434
|> File.read!()
434
435
|> json_library().decode!
436
+ |> Enum.map(&String.to_atom/1)
435
437
|> Enum.sort()
436
438
end
437
439
 
@@ -541,7 +543,7 @@ defmodule Cldr.Config do
541
543
if inherited = Map.get(parent_locales(), locale_name) do
542
544
inherited
543
545
else
544
- {:ok, locale} = Cldr.LanguageTag.Parser.parse(locale_name)
546
+ {:ok, locale} = Cldr.LanguageTag.Parser.parse(to_string(locale_name))
545
547
first_match(locale.language, locale.script, locale.territory, fun)
546
548
end
547
549
end
 
@@ -967,7 +969,7 @@ defmodule Cldr.Config do
967
969
@spec known_number_systems_like(Locale.locale_name(), number_system(), t()) ::
968
970
{:ok, list()} | {:error, {module(), String.t()}}
969
971
970
- def known_number_systems_like(locale_name, number_system, config) do
972
+ def known_number_systems_like(locale_name, number_system, config) when is_atom(locale_name) do
971
973
with {:ok, %{digits: digits}} <- number_system_for(locale_name, number_system, config),
972
974
{:ok, symbols} <- number_symbols_for(locale_name, number_system, config),
973
975
{:ok, names} <- number_system_names_for(locale_name, config) do
 
@@ -1015,13 +1017,14 @@ defmodule Cldr.Config do
1015
1017
1016
1018
## Example
1017
1019
1018
- iex> Cldr.Config.number_systems_for("en", %Cldr.Config{locales: ["en", "de"]})
1020
+ iex> Cldr.Config.number_systems_for(:en, %Cldr.Config{locales: ["en", "de"]})
1019
1021
{:ok, %{default: :latn, native: :latn}}
1022
+
1020
1023
"""
1021
1024
@spec number_systems_for(Locale.locale_name(), t()) ::
1022
1025
{:ok, map()} | {:error, {module(), String.t()}}
1023
1026
1024
- def number_systems_for(locale_name, %__MODULE__{} = config) do
1027
+ def number_systems_for(locale_name, %__MODULE__{} = config) when is_atom(locale_name) do
1025
1028
if known_locale_name(locale_name, config) do
1026
1029
number_systems =
1027
1030
locale_name
 
@@ -1040,7 +1043,7 @@ defmodule Cldr.Config do
1040
1043
1041
1044
## Example
1042
1045
1043
- iex> Cldr.Config.number_systems_for!("de", %Cldr.Config{locales: ["en", "de"]})
1046
+ iex> Cldr.Config.number_systems_for!(:de, %Cldr.Config{locales: ["en", "de"]})
1044
1047
%{default: :latn, native: :latn}
1045
1048
1046
1049
"""
 
@@ -1058,7 +1061,7 @@ defmodule Cldr.Config do
1058
1061
1059
1062
## Example
1060
1063
1061
- iex> Cldr.Config.number_system_for("th", :thai, %Cldr.Config{locales: ["th", "de"]})
1064
+ iex> Cldr.Config.number_system_for(:th, :thai, %Cldr.Config{locales: ["th", "de"]})
1062
1065
{:ok, %{digits: "๐๑๒๓๔๕๖๗๘๙", type: :numeric}}
1063
1066
1064
1067
"""
 
@@ -1076,7 +1079,7 @@ defmodule Cldr.Config do
1076
1079
1077
1080
## Example
1078
1081
1079
- iex> Cldr.Config.number_system_names_for("th", %Cldr.Config{locales: ["en", "th"]})
1082
+ iex> Cldr.Config.number_system_names_for(:th, %Cldr.Config{locales: ["en", "th"]})
1080
1083
{:ok, [:latn, :thai]}
1081
1084
1082
1085
"""
 
@@ -1136,16 +1139,16 @@ defmodule Cldr.Config do
1136
1139
1137
1140
## Examples
1138
1141
1139
- iex> Cldr.Config.system_name_from(:default, "en", TestBackend.Cldr)
1142
+ iex> Cldr.Config.system_name_from(:default, :en, TestBackend.Cldr)
1140
1143
{:ok, :latn}
1141
1144
1142
- iex> Cldr.Config.system_name_from("latn", "en", TestBackend.Cldr)
1145
+ iex> Cldr.Config.system_name_from("latn", :en, TestBackend.Cldr)
1143
1146
{:ok, :latn}
1144
1147
1145
- iex> Cldr.Config.system_name_from(:native, "en", TestBackend.Cldr)
1148
+ iex> Cldr.Config.system_name_from(:native, :en, TestBackend.Cldr)
1146
1149
{:ok, :latn}
1147
1150
1148
- iex> Cldr.Config.system_name_from(:nope, "en", TestBackend.Cldr)
1151
+ iex> Cldr.Config.system_name_from(:nope, :en, TestBackend.Cldr)
1149
1152
{
1150
1153
:error,
1151
1154
{Cldr.UnknownNumberSystemError, "The number system :nope is unknown"}
 
@@ -1442,24 +1445,30 @@ defmodule Cldr.Config do
1442
1445
## Examples
1443
1446
1444
1447
iex> Cldr.Config.expand_locale_names(["en-A+"])
1445
- ["en", "en-AE", "en-AG", "en-AI", "en-AS", "en-AT", "en-AU"]
1448
+ [:en, :"en-AE", :"en-AG", :"en-AI", :"en-AS", :"en-AT", :"en-AU"]
1446
1449
1447
1450
iex> Cldr.Config.expand_locale_names(["fr-*"])
1448
- ["fr", "fr-BE", "fr-BF", "fr-BI", "fr-BJ", "fr-BL", "fr-CA", "fr-CD", "fr-CF",
1449
- "fr-CG", "fr-CH", "fr-CI", "fr-CM", "fr-DJ", "fr-DZ", "fr-GA", "fr-GF",
1450
- "fr-GN", "fr-GP", "fr-GQ", "fr-HT", "fr-KM", "fr-LU", "fr-MA", "fr-MC",
1451
- "fr-MF", "fr-MG", "fr-ML", "fr-MQ", "fr-MR", "fr-MU", "fr-NC", "fr-NE",
1452
- "fr-PF", "fr-PM", "fr-RE", "fr-RW", "fr-SC", "fr-SN", "fr-SY", "fr-TD",
1453
- "fr-TG", "fr-TN", "fr-VU", "fr-WF", "fr-YT"]
1451
+ [
1452
+ :fr, :"fr-BE", :"fr-BF", :"fr-BI", :"fr-BJ", :"fr-BL", :"fr-CA",
1453
+ :"fr-CD", :"fr-CF", :"fr-CG", :"fr-CH", :"fr-CI", :"fr-CM", :"fr-DJ",
1454
+ :"fr-DZ", :"fr-GA", :"fr-GF", :"fr-GN", :"fr-GP", :"fr-GQ", :"fr-HT",
1455
+ :"fr-KM", :"fr-LU", :"fr-MA", :"fr-MC", :"fr-MF", :"fr-MG", :"fr-ML",
1456
+ :"fr-MQ", :"fr-MR", :"fr-MU", :"fr-NC", :"fr-NE", :"fr-PF", :"fr-PM",
1457
+ :"fr-RE", :"fr-RW", :"fr-SC", :"fr-SN", :"fr-SY", :"fr-TD", :"fr-TG",
1458
+ :"fr-TN", :"fr-VU", :"fr-WF", :"fr-YT"
1459
+ ]
1460
+
1454
1461
"""
1455
1462
@wildcard_matchers ["*", "+", ".", "["]
1456
- @spec expand_locale_names([Locale.locale_name(), ...]) :: [Locale.locale_name(), ...]
1463
+ @spec expand_locale_names([Locale.locale_name() | String.t(), ...]) :: [Locale.locale_name(), ...]
1457
1464
def expand_locale_names(locale_names) do
1458
1465
Enum.map(locale_names, fn locale_name ->
1466
+ locale_name = to_string(locale_name)
1467
+
1459
1468
if String.contains?(locale_name, @wildcard_matchers) do
1460
1469
case Regex.compile(locale_name) do
1461
1470
{:ok, regex} ->
1462
- Enum.filter(all_locale_names(), &Regex.match?(regex, &1))
1471
+ Enum.filter(all_locale_names(), &match_name?(regex, &1))
1463
1472
1464
1473
{:error, reason} ->
1465
1474
raise ArgumentError,
 
@@ -1471,15 +1480,19 @@ defmodule Cldr.Config do
1471
1480
end)
1472
1481
|> List.flatten()
1473
1482
|> Enum.map(fn locale_name ->
1474
- case String.split(locale_name, "-") do
1475
- [language] -> language
1476
- [language | _rest] -> [language, locale_name]
1483
+ case String.split(to_string(locale_name), "-") do
1484
+ [language] -> String.to_atom(language)
1485
+ [language | _rest] -> [String.to_atom(language), locale_name]
1477
1486
end
1478
1487
end)
1479
1488
|> List.flatten()
1480
1489
|> Enum.uniq()
1481
1490
end
1482
1491
1492
+ defp match_name?(regex, locale_name) do
1493
+ Regex.match?(regex, Atom.to_string(locale_name))
1494
+ end
1495
+
1483
1496
def canonical_name(locale_name) do
1484
1497
name =
1485
1498
locale_name
 
@@ -1491,7 +1504,7 @@ defmodule Cldr.Config do
1491
1504
1492
1505
defp known_locales_map do
1493
1506
all_locale_names()
1494
- |> Enum.map(fn x -> {String.downcase(x), x} end)
1507
+ |> Enum.map(fn x -> {Atom.to_string(x) |> String.downcase(), x} end)
1495
1508
|> Map.new()
1496
1509
end
1497
1510
 
@@ -1511,7 +1524,7 @@ defmodule Cldr.Config do
1511
1524
* `{:error, :not_found}`
1512
1525
1513
1526
"""
1514
- @spec locale_path(String.t(), Cldr.backend() | t()) ::
1527
+ @spec locale_path(Cldr.Locale.locale_name() | String.t(), Cldr.backend() | t()) ::
1515
1528
{:ok, String.t()} | {:error, :not_found}
1516
1529
1517
1530
def locale_path(locale, %{data_dir: _} = config) do
 
@@ -1745,7 +1758,9 @@ defmodule Cldr.Config do
1745
1758
{:error, {Cldr.UnknownTerritoryError, "The territory \\"abc\\" is unknown"}}
1746
1759
1747
1760
"""
1748
- @spec territory(Cldr.Locale.territory() | String.t()) :: %{} | {:error, {module(), String.t()}}
1761
+ @spec territory(Locale.territory_reference() | String.t()) ::
1762
+ %{} | {:error, {module(), String.t()}}
1763
+
1749
1764
def territory(territory) do
1750
1765
with {:ok, territory_code} <- Cldr.validate_territory(territory) do
1751
1766
territories()
 
@@ -1756,6 +1771,37 @@ defmodule Cldr.Config do
1756
1771
@deprecated "Use Cldr.Config.territories/1"
1757
1772
defdelegate territory_info(territory), to: __MODULE__, as: :territory
1758
1773
1774
+ @doc """
1775
+ Return the mapping from a territory to a language tag.
1776
+
1777
+ This is used to derive a locale from a territory.
1778
+
1779
+ """
1780
+ def language_tag_for_territory do
1781
+ territories()
1782
+ |> Enum.map(fn {territory, data} ->
1783
+ {territory, Map.get(data, :language_population, %{})}
1784
+ end)
1785
+ |> Enum.map(fn {territory, data} ->
1786
+ {territory, extract_population(data) |> Enum.sort(&population_sorter/2) |> get_head}
1787
+ end)
1788
+ |> Map.new()
1789
+ end
1790
+
1791
+ defp extract_population(data) do
1792
+ Enum.map(data, fn
1793
+ {language, population} -> {language, population.population_percent}
1794
+ end)
1795
+ |> Enum.reject(&is_nil/1)
1796
+ end
1797
+
1798
+ defp population_sorter(a, b) do
1799
+ elem(a, 1) >= elem(b, 1)
1800
+ end
1801
+
1802
+ defp get_head([]), do: nil
1803
+ defp get_head([{language, _percent} | _rest]), do: language
1804
+
1759
1805
@doc """
1760
1806
Returns a map of locale names to
1761
1807
its parent locale name.
 
@@ -1770,6 +1816,8 @@ defmodule Cldr.Config do
1770
1816
|> Path.join("parent_locales.json")
1771
1817
|> File.read!()
1772
1818
|> json_library().decode!
1819
+ |> Cldr.Map.atomize_keys()
1820
+ |> Cldr.Map.atomize_values()
1773
1821
end
1774
1822
1775
1823
@doc """
 
@@ -1808,7 +1856,7 @@ defmodule Cldr.Config do
1808
1856
|> File.read!()
1809
1857
|> json_library().decode!
1810
1858
|> Enum.map(fn {k, v} ->
1811
- {k, struct(Cldr.LanguageTag, normalize_territory_and_region(v))}
1859
+ {String.to_atom(k), struct(Cldr.LanguageTag, normalize_territory_and_region(v))}
1812
1860
end)
1813
1861
|> Map.new()
1814
1862
end
 
@@ -2071,7 +2119,7 @@ defmodule Cldr.Config do
2071
2119
:islamic_rgsa, :islamic_tbla, :islamic_umalqura, :japanese, :persian, :roc]
2072
2120
2073
2121
"""
2074
- def calendars_for_locale(locale_name, %{} = config) when is_binary(locale_name) do
2122
+ def calendars_for_locale(locale_name, %{} = config) when is_atom(locale_name) do
2075
2123
Cldr.maybe_log("Cldr.Config getting calendar data for locale #{inspect(locale_name)}")
2076
2124
2077
2125
locale_name
 
@@ -2081,6 +2129,12 @@ defmodule Cldr.Config do
2081
2129
|> Map.keys()
2082
2130
end
2083
2131
2132
+ def calendars_for_locale(locale_name, %{} = config) when is_binary(locale_name) do
2133
+ locale_name
2134
+ |> String.to_existing_atom()
2135
+ |> calendars_for_locale(config)
2136
+ end
2137
+
2084
2138
def calendars_for_locale(locale_name, backend) when is_atom(backend) do
2085
2139
calendars_for_locale(locale_name, backend.__cldr__(:config))
2086
2140
end
 
@@ -2191,6 +2245,7 @@ defmodule Cldr.Config do
2191
2245
locale_name =
2192
2246
locale_name
2193
2247
|> locale_name_from_posix
2248
+ |> String.to_atom
2194
2249
2195
2250
module = Module.concat(backend, Rbnf) |> Module.concat(ruleset_module)
2196
2251
{module, function, locale_name}
 
@@ -2211,7 +2266,11 @@ defmodule Cldr.Config do
2211
2266
"""
2212
2267
def locale_name_from_posix(nil), do: nil
2213
2268
def locale_name_from_posix(name) when is_binary(name), do: String.replace(name, "_", "-")
2214
- def locale_name_from_posix(other), do: other
2269
+ def locale_name_from_posix(name) when is_atom(name) do
2270
+ name
2271
+ |> Atom.to_string()
2272
+ |> locale_name_from_posix()
2273
+ end
2215
2274
2216
2275
@doc """
2217
2276
Transforms a locale name from the CLDR format to the Posix format
 
@@ -2308,8 +2367,9 @@ defmodule Cldr.Config do
2308
2367
end
2309
2368
2310
2369
defp remove_gettext_only_locales(%{locales: locales, gettext: gettext} = config) do
2370
+ locales = if locales == :all, do: all_locale_names(), else: locales
2311
2371
gettext_locales = known_gettext_locale_names(config)
2312
- unknown_locales = Enum.filter(gettext_locales, &(&1 not in all_locale_names()))
2372
+ unknown_locales = Enum.filter(gettext_locales, &(String.to_atom(&1) not in all_locale_names()))
2313
2373
2314
2374
case unknown_locales do
2315
2375
[] ->
 
@@ -2477,9 +2537,6 @@ defmodule Cldr.Config do
2477
2537
locales = configured_locale_names(config)
2478
2538
default = default_locale_name(config)
2479
2539
2480
- # locales = config[:locales] || [config[:default_locale] || @default_locale_name]
2481
- # default = config[:default_locale] || hd(locales)
2482
-
2483
2540
locales =
2484
2541
(locales ++ gettext ++ [default, @root_locale_name])
2485
2542
|> Enum.reject(&is_nil/1)
 
@@ -2502,7 +2559,7 @@ defmodule Cldr.Config do
2502
2559
end)
2503
2560
|> Enum.sort(&plural_sorter/2)
2504
2561
2505
- {locale, sorted_rules}
2562
+ {String.to_atom(locale), sorted_rules}
2506
2563
end
2507
2564
2508
2565
defp plural_sorter({:zero, _}, _), do: true
changed lib/cldr/config/rbnf_config.ex
 
@@ -88,7 +88,7 @@ defmodule Cldr.Rbnf.Config do
88
88
[:OrdinalRules, :SpelloutRules]
89
89
90
90
"""
91
- @spec for_locale(Locale.locale_name()) ::
91
+ @spec for_locale(Locale.locale_name() | String.t()) ::
92
92
{:ok, map()} | {:error, {Cldr.Rbnf.NotAvailable, String.t()}}
93
93
94
94
# TODO Use fallback paths to find RBNF data
changed lib/cldr/gettext/plural.ex
 
@@ -75,7 +75,8 @@ defmodule Cldr.Gettext.Plural do
75
75
@doc """
76
76
Returns the number of plural forms for a given locale.
77
77
78
- * `locale` is either a locale name in the list `#{unquote(inspect(backend))}.known_locale_names/0` or
78
+ * `locale` is either a locale name in the list
79
+ `#{unquote(inspect(backend))}.known_locale_names/0` or
79
80
a `%LanguageTag{}` as returned by `Cldr.Locale.new/2`
80
81
81
82
## Examples
 
@@ -87,18 +88,25 @@ defmodule Cldr.Gettext.Plural do
87
88
2
88
89
89
90
"""
90
- @spec nplurals(Locale.locale_name()) :: pos_integer() | no_return()
91
+ @spec nplurals(Locale.locale_name() | String.t()) :: pos_integer() | no_return()
91
92
92
93
def nplurals(%LanguageTag{cldr_locale_name: cldr_locale_name}) do
93
94
nplurals(cldr_locale_name)
94
95
end
95
96
96
- def nplurals(locale_name) when is_binary(locale_name) do
97
+ def nplurals(locale_name) when is_atom(locale_name) do
97
98
gettext_nplurals()
98
99
|> Map.fetch!(locale_name)
99
100
|> Enum.count()
100
101
end
101
102
103
+ def nplurals(locale_name) when is_binary(locale_name) do
104
+ locale_name = String.to_existing_atom(locale_name)
105
+ nplurals(locale_name)
106
+ rescue ArgumentError ->
107
+ raise KeyError, "Key #{inspect locale_name} not found"
108
+ end
109
+
102
110
@doc """
103
111
Returns the plural form of a number for a given
104
112
locale.
 
@@ -130,7 +138,7 @@ defmodule Cldr.Gettext.Plural do
130
138
1
131
139
132
140
"""
133
- @spec plural(Locale.locale_name() | LanguageTag.t(), number()) ::
141
+ @spec plural(String.t() | LanguageTag.t(), number()) ::
134
142
0 | pos_integer() | no_return()
135
143
136
144
def plural(%LanguageTag{cldr_locale_name: cldr_locale_name} = locale, n) do
 
@@ -141,7 +149,7 @@ defmodule Cldr.Gettext.Plural do
141
149
|> Keyword.get(rule)
142
150
end
143
151
144
- def plural(locale_name, n) when is_binary(locale_name) do
152
+ def plural(locale_name, n) do
145
153
with {:ok, locale} <- unquote(backend).validate_locale(locale_name) do
146
154
plural(locale, n)
147
155
else
changed lib/cldr/language_tag.ex
 
@@ -152,7 +152,8 @@ defmodule Cldr.LanguageTag do
152
152
"""
153
153
import Kernel, except: [to_string: 1]
154
154
155
- alias Cldr.LanguageTag.Parser
155
+ alias Cldr.Locale
156
+ alias Cldr.LanguageTag.{Parser, U, T}
156
157
157
158
if Code.ensure_loaded?(Jason) do
158
159
@derive Jason.Encoder
 
@@ -175,19 +176,19 @@ defmodule Cldr.LanguageTag do
175
176
backend: nil
176
177
177
178
@type t :: %__MODULE__{
178
- language: String.t(),
179
+ language: Locale.language(),
179
180
language_subtags: [String.t()],
180
- script: Cldr.Locale.script(),
181
- territory: Cldr.Locale.territory(),
182
- language_variants: [String.t()] | [],
183
- locale: Cldr.LanguageTag.U.t() | %{},
184
- transform: map(),
181
+ script: Locale.script(),
182
+ territory: Locale.territory_code(),
183
+ language_variants: [String.t()],
184
+ locale: U.t() | %{},
185
+ transform: T.t() | %{},
185
186
extensions: map(),
186
187
private_use: [String.t()],
187
188
requested_locale_name: String.t(),
188
189
canonical_locale_name: String.t(),
189
- cldr_locale_name: String.t() | nil,
190
- rbnf_locale_name: String.t() | nil,
190
+ cldr_locale_name: Locale.locale_name(),
191
+ rbnf_locale_name: Locale.locale_name(),
191
192
gettext_locale_name: String.t() | nil,
192
193
backend: Cldr.backend()
193
194
}
 
@@ -206,6 +207,7 @@ defmodule Cldr.LanguageTag do
206
207
* `{:error, reason}`
207
208
208
209
"""
210
+ @spec parse(String.t()) :: {:ok, t()} | {:error, {module(), String.t()}}
209
211
def parse(locale_name) when is_binary(locale_name) do
210
212
Parser.parse(locale_name)
211
213
end
 
@@ -224,7 +226,7 @@ defmodule Cldr.LanguageTag do
224
226
* raises an exception
225
227
226
228
"""
227
- @spec parse!(Cldr.Locale.locale_name()) :: t() | none()
229
+ @spec parse!(String.t()) :: t() | none()
228
230
def parse!(locale_string) when is_binary(locale_string) do
229
231
Parser.parse!(locale_string)
230
232
end
added lib/cldr/language_tag/sigil.ex
 
@@ -0,0 +1,87 @@
1
+ defmodule Cldr.LanguageTag.Sigil do
2
+ @moduledoc """
3
+ Implements a `sigil_l/2` macro to
4
+ constructing `t:Cldr.LanguageTag` structs.
5
+
6
+ """
7
+
8
+ @doc """
9
+ Handles sigil `~l` for language tags.
10
+
11
+ ## Arguments
12
+
13
+ * `locale_name` is either a [BCP 47](https://unicode-org.github.io/cldr/ldml/tr35.html#Identifiers)
14
+ locale name as a string or
15
+
16
+ * `locale_name` | `backend` where backend is a backend module name
17
+
18
+ ## Options
19
+
20
+ * `u` Will parse the locale but will not add
21
+ likely subtags and its not guaranteed that this
22
+ language tag is known to the backend module.
23
+
24
+ ## Returns
25
+
26
+ * a `t:Cldr.LanguageTag` struct or
27
+
28
+ * raises an exception
29
+
30
+ ## Examples
31
+
32
+ iex> import Cldr.LanguageTag.Sigil
33
+ iex> ~l(en-US-u-ca-gregory)
34
+ #Cldr.LanguageTag<en-US-u-ca-gregory [validated]>
35
+
36
+ iex> import Cldr.LanguageTag.Sigil
37
+ iex> ~l(en-US-u-ca-gregory|MyApp.Cldr)
38
+ #Cldr.LanguageTag<en-US-u-ca-gregory [validated]>
39
+
40
+ """
41
+ defmacro sigil_l(locale_name, 'u') do
42
+ {:<<>>, [_], [locale_name]} = locale_name
43
+
44
+ case parse_locale(String.split(locale_name, "|")) do
45
+ {:ok, locale_name} ->
46
+ quote do
47
+ unquote(Macro.escape(locale_name))
48
+ end
49
+
50
+ {:error, {exception, reason}} ->
51
+ raise exception, reason
52
+ end
53
+ end
54
+
55
+ defmacro sigil_l(locale_name, _opts) do
56
+ {:<<>>, [_], [locale_name]} = locale_name
57
+
58
+ case validate_locale(String.split(locale_name, "|")) do
59
+ {:ok, locale_name} ->
60
+ quote do
61
+ unquote(Macro.escape(locale_name))
62
+ end
63
+
64
+ {:error, {exception, reason}} ->
65
+ raise exception, reason
66
+ end
67
+ end
68
+
69
+ defp validate_locale([locale_name, backend]) do
70
+ backend = Module.concat([backend])
71
+ Cldr.validate_locale(locale_name, backend)
72
+ end
73
+
74
+ defp validate_locale([locale_name]) do
75
+ Cldr.validate_locale(locale_name)
76
+ end
77
+
78
+ @opts [add_likely_subtags: false]
79
+ defp parse_locale([locale_name, backend]) do
80
+ backend = Module.concat([backend])
81
+ Cldr.Locale.canonical_language_tag(locale_name, backend, @opts)
82
+ end
83
+
84
+ defp parse_locale([locale_name]) do
85
+ Cldr.Locale.canonical_language_tag(locale_name, Cldr.default_backend!(), @opts)
86
+ end
87
+ end
changed lib/cldr/locale.ex
 
@@ -47,13 +47,13 @@ defmodule Cldr.Locale do
47
47
{:ok, %Cldr.LanguageTag{
48
48
backend: TestBackend.Cldr,
49
49
canonical_locale_name: "en-ES",
50
- cldr_locale_name: "en",
50
+ cldr_locale_name: :en,
51
51
extensions: %{},
52
52
gettext_locale_name: "en",
53
53
language: "en",
54
54
locale: %{},
55
55
private_use: [],
56
- rbnf_locale_name: "en",
56
+ rbnf_locale_name: :en,
57
57
requested_locale_name: "en-ES",
58
58
script: :Latn,
59
59
territory: :ES,
 
@@ -98,12 +98,12 @@ defmodule Cldr.Locale do
98
98
language_subtags: [],
99
99
language_variants: [],
100
100
locale: %{}, private_use: [],
101
- rbnf_locale_name: "ro",
101
+ rbnf_locale_name: :ro,
102
102
requested_locale_name: "mo",
103
103
script: :Latn,
104
104
transform: %{},
105
105
canonical_locale_name: "ro",
106
- cldr_locale_name: "ro",
106
+ cldr_locale_name: :ro,
107
107
territory: :RO
108
108
}}
109
109
 
@@ -119,13 +119,13 @@ defmodule Cldr.Locale do
119
119
{:ok, %Cldr.LanguageTag{
120
120
backend: TestBackend.Cldr,
121
121
canonical_locale_name: "en",
122
- cldr_locale_name: "en",
122
+ cldr_locale_name: :en,
123
123
extensions: %{},
124
124
gettext_locale_name: "en",
125
125
language: "en",
126
126
locale: %{},
127
127
private_use: [],
128
- rbnf_locale_name: "en",
128
+ rbnf_locale_name: :en,
129
129
requested_locale_name: "en",
130
130
script: :Latn,
131
131
territory: :US,
 
@@ -151,13 +151,13 @@ defmodule Cldr.Locale do
151
151
{:ok, %Cldr.LanguageTag{
152
152
backend: TestBackend.Cldr,
153
153
canonical_locale_name: "en-XX",
154
- cldr_locale_name: "en",
154
+ cldr_locale_name: :en,
155
155
extensions: %{},
156
156
gettext_locale_name: "en",
157
157
language: "en",
158
158
locale: %{},
159
159
private_use: [],
160
- rbnf_locale_name: "en",
160
+ rbnf_locale_name: :en,
161
161
requested_locale_name: "en-XX",
162
162
script: :Latn,
163
163
territory: :XX,
 
@@ -190,7 +190,7 @@ defmodule Cldr.Locale do
190
190
%Cldr.LanguageTag{
191
191
backend: MyApp.Cldr,
192
192
canonical_locale_name: "en-AU-u-cf-account-tz-ausyd",
193
- cldr_locale_name: "en-AU",
193
+ cldr_locale_name: :"en-AU",
194
194
extensions: %{},
195
195
gettext_locale_name: "en",
196
196
language: "en",
 
@@ -225,7 +225,7 @@ defmodule Cldr.Locale do
225
225
vt: nil
226
226
},
227
227
private_use: '',
228
- rbnf_locale_name: "en",
228
+ rbnf_locale_name: :en,
229
229
requested_locale_name: "en-AU",
230
230
script: :Latn,
231
231
territory: :AU,
 
@@ -239,17 +239,23 @@ defmodule Cldr.Locale do
239
239
240
240
import Cldr.Helpers, only: [empty?: 1]
241
241
242
- @typedoc "The name of a locale in a string format"
243
- @type locale_name() :: String.t()
242
+ @typedoc "The name of a locale"
243
+ @type locale_name() :: atom()
244
244
245
- @typedoc "The name of a language a string format"
245
+ @typedoc "A reference to a locale"
246
+ @type locale_reference :: LanguageTag.t() | locale_name() | String.t()
247
+
248
+ @typedoc "The name of a language"
246
249
@type language :: String.t() | nil
247
250
248
- @typedoc "The name of a script in an atom format"
251
+ @typedoc "The name of a script"
249
252
@type script :: atom() | String.t() | nil
250
253
251
- @typedoc "The name of a territory in an atom format"
252
- @type territory :: atom() | String.t() | nil
254
+ @typedoc "The name of a territory"
255
+ @type territory_reference :: atom() | String.t() | nil
256
+
257
+ @typedoc "A territory code as an ISO3166 Alpha-2 in atom form"
258
+ @type territory_code :: atom()
253
259
254
260
@typedoc "The list of language variants as strings"
255
261
@type variants :: [String.t()] | []
 
@@ -257,8 +263,9 @@ defmodule Cldr.Locale do
257
263
@typedoc "The list of language subtags as strings"
258
264
@type subtags :: [String.t(), ...] | []
259
265
260
- @root_locale "und"
261
- @root_rbnf_locale_name "und"
266
+ @root_locale Cldr.Config.root_locale_name()
267
+ @root_language Atom.to_string(@root_locale)
268
+ @root_rbnf_locale_name Cldr.Config.root_locale_name()
262
269
263
270
defdelegate new(locale_name, backend), to: __MODULE__, as: :canonical_language_tag
264
271
defdelegate new!(locale_name, backend), to: __MODULE__, as: :canonical_language_tag!
 
@@ -295,15 +302,36 @@ defmodule Cldr.Locale do
295
302
Returns a list of all the parent locales
296
303
for a given locale.
297
304
305
+ ## Examples
306
+
307
+ Cldr.Locale.parents "fr-ca"
308
+ => {:ok, [#Cldr.LanguageTag<fr [validated]>, #Cldr.LanguageTag<en [validated]>]}
309
+
298
310
"""
299
- @spec parents(LanguageTag.t()) :: list(LanguageTag.t())
300
- def parents(%LanguageTag{} = locale, acc \\ []) do
311
+ @spec parents(LanguageTag.t()) ::
312
+ {:ok, list(LanguageTag.t())} | {:error, {module(), String.t()}}
313
+
314
+ def parents(locale, acc \\ [])
315
+
316
+ def parents(%LanguageTag{} = locale, acc) do
301
317
case parent(locale) do
302
- {:error, _} -> Enum.reverse(acc)
318
+ {:error, _} -> {:ok, Enum.reverse(acc)}
303
319
{:ok, locale} -> parents(locale, [locale | acc])
304
320
end
305
321
end
306
322
323
+ def parents(locale, []) do
324
+ with {:ok, locale} <- Cldr.validate_locale(locale, Cldr.default_backend!()) do
325
+ parents(locale)
326
+ end
327
+ end
328
+
329
+ def parents(locale, backend) when is_atom(backend) do
330
+ with {:ok, locale} <- Cldr.validate_locale(locale, backend) do
331
+ parents(locale)
332
+ end
333
+ end
334
+
307
335
@doc """
308
336
Returns the parent for a given locale.
309
337
 
@@ -340,9 +368,7 @@ defmodule Cldr.Locale do
340
368
if parent = Map.get(parent_locale_map(), child.cldr_locale_name) do
341
369
Cldr.validate_locale(parent, backend)
342
370
else
343
- {:ok, locale} = Cldr.LanguageTag.parse(child.cldr_locale_name)
344
-
345
- locale
371
+ child
346
372
|> find_parent(backend)
347
373
|> return_parent_or_default(child, backend)
348
374
|> transfer_extensions(child)
 
@@ -352,7 +378,7 @@ defmodule Cldr.Locale do
352
378
@spec parent(locale_name(), Cldr.backend()) ::
353
379
{:ok, LanguageTag.t()} | {:error, {module(), binary()}}
354
380
355
- def parent(locale_name, backend \\ Cldr.default_backend!()) when is_binary(locale_name) do
381
+ def parent(locale_name, backend \\ Cldr.default_backend!()) do
356
382
with {:ok, locale} <- Cldr.validate_locale(locale_name, backend) do
357
383
parent(locale)
358
384
end
 
@@ -375,16 +401,31 @@ defmodule Cldr.Locale do
375
401
|> known_locale(backend)
376
402
end
377
403
378
- defp known_locale(locale_name, _tags \\ [], backend) do
404
+ defp known_locale(locale_name, tags \\ [], backend)
405
+
406
+ defp known_locale(nil, _tags, _backend) do
407
+ nil
408
+ end
409
+
410
+ defp known_locale(locale_name, tags, backend) when is_binary(locale_name) do
411
+ locale_name = String.to_existing_atom(locale_name)
412
+ known_locale(locale_name, tags, backend)
413
+ rescue ArgumentError ->
414
+ nil
415
+ end
416
+
417
+ defp known_locale(locale_name, _tags, backend) when is_atom(locale_name) do
379
418
Enum.find(backend.known_locale_names(), &(locale_name == &1))
380
419
end
381
420
382
421
def known_rbnf_locale_name(locale_name, _tags \\ [], backend) do
422
+ locale_name = String.to_existing_atom(locale_name)
383
423
Cldr.known_rbnf_locale_name(locale_name, backend)
424
+ rescue ArgumentError ->
425
+ nil
384
426
end
385
427
386
- # If the language of the parent then return an error
387
- defp return_parent_or_default(parent, child, backend) when is_nil(parent) do
428
+ defp return_parent_or_default(parent, %LanguageTag{cldr_locale_name: parent} = child, backend) do
388
429
default_locale = Cldr.default_locale(backend)
389
430
390
431
if child.language == default_locale.language do
 
@@ -410,6 +451,433 @@ defmodule Cldr.Locale do
410
451
{Cldr.NoParentError, "The locale #{inspect(locale_name)} has no parent locale"}
411
452
end
412
453
454
+ @doc """
455
+ Returns the list of fallback locales, starting the
456
+ the provided locale.
457
+
458
+ Fallbacks are a list of locate names which can
459
+ be used to resolve translation or other localization
460
+ data if such localised data does not exist for
461
+ this specific locale. After locale-specific fallbacks
462
+ are determined, the the default locale and its fallbacks
463
+ are added to the chain.
464
+
465
+ ## Arguments
466
+
467
+ * `locale` is any `LanguageTag.t`
468
+
469
+ ## Returns
470
+
471
+ * `{:ok, list_of_locales}` or
472
+
473
+ * `{:error, {exception, reason}}`
474
+
475
+ ## Examples
476
+
477
+ In these examples the default locale is `:"en-001"`.
478
+
479
+ Cldr.Locale.fallback_locales(Cldr.Locale.new!("fr-CA", MyApp.Cldr))
480
+ => {:ok,
481
+ [#Cldr.LanguageTag<fr-CA [validated]>, #Cldr.LanguageTag<fr [validated]>,
482
+ #Cldr.LanguageTag<en [validated]>]}
483
+
484
+ # Fallbacks are typically formed by progressively
485
+ # stripping variant, territory and script from the
486
+ # given locale name. But not always - there are
487
+ # certain fallbacks that take a different path.
488
+
489
+ Cldr.Locale.fallback_locales(Cldr.Locale.new!("nb", MyApp.Cldr))
490
+ => {:ok,
491
+ [#Cldr.LanguageTag<nb [validated]>, #Cldr.LanguageTag<no [validated]>,
492
+ #Cldr.LanguageTag<en [validated]>]}
493
+
494
+ """
495
+ @spec fallback_locales(LanguageTag.t()) ::
496
+ {:ok, [LanguageTag.t(), ...]} | {:error, {module(), binary()}}
497
+
498
+ @doc since: "2.26.0"
499
+ def fallback_locales(%LanguageTag{} = locale) do
500
+ with {:ok, parents} <- parents(locale) do
501
+ {:ok, [locale | parents]}
502
+ end
503
+ end
504
+
505
+ @doc """
506
+ Returns the list of fallback locales, starting the
507
+ the provided locale.
508
+
509
+ Fallbacks are a list of locate names which can
510
+ be used to resolve translation or other localization
511
+ data if such localised data does not exist for
512
+ this specific locale. After locale-specific fallbacks
513
+ are determined, the the default locale and its fallbacks
514
+ are added to the chain.
515
+
516
+ ## Arguments
517
+
518
+ * `locale_name` is any locale name returned by
519
+ `Cldr.known_locale_names/1`
520
+
521
+ * `backend` is any module that includes `use Cldr` and therefore
522
+ is a `Cldr` backend module. The default is
523
+ `Cldr.default_locale/0`.
524
+
525
+ ## Returns
526
+
527
+ * `{:ok, list_of_locales}` or
528
+
529
+ * `{:error, {exception, reason}}`
530
+
531
+ ## Examples
532
+
533
+ In these examples the default locale is `:"en-001"`.
534
+
535
+ Cldr.Locale.fallback_locales(:"fr-CA")
536
+ => {:ok,
537
+ [#Cldr.LanguageTag<fr-CA [validated]>, #Cldr.LanguageTag<fr [validated]>,
538
+ #Cldr.LanguageTag<en [validated]>]}
539
+
540
+ # Fallbacks are typically formed by progressively
541
+ # stripping variant, territory and script from the
542
+ # given locale name. But not always - there are
543
+ # certain fallbacks that take a different path.
544
+
545
+ Cldr.Locale.fallback_locales(:nb)
546
+ => {:ok,
547
+ [#Cldr.LanguageTag<nb [validated]>, #Cldr.LanguageTag<no [validated]>,
548
+ #Cldr.LanguageTag<en [validated]>]}
549
+
550
+ """
551
+ @spec fallback_locales(locale_reference, Cldr.backend) ::
552
+ {:ok, [LanguageTag.t(), ...]} | {:error, {module(), binary()}}
553
+
554
+ @doc since: "2.26.0"
555
+ def fallback_locales(locale_name, backend \\ Cldr.default_backend!()) do
556
+ with {:ok, locale} <- Cldr.validate_locale(locale_name, backend) do
557
+ fallback_locales(locale)
558
+ end
559
+ end
560
+
561
+ @doc """
562
+ Returns the list of fallback locale names, starting the
563
+ the provided locale.
564
+
565
+ Fallbacks are a list of locate names which can
566
+ be used to resolve translation or other localization
567
+ data if such localised data does not exist for
568
+ this specific locale. After locale-specific fallbacks
569
+ are determined, the the default locale and its fallbacks
570
+ are added to the chain.
571
+
572
+ ## Arguments
573
+
574
+ * `locale` is any `LanguageTag.t`
575
+
576
+ ## Returns
577
+
578
+ * `{:ok, list_of_locale_names}` or
579
+
580
+ * `{:error, {exception, reason}}`
581
+
582
+ ## Examples
583
+
584
+ In these examples the default locale is `:"en-001"`.
585
+
586
+ iex> Cldr.Locale.fallback_locale_names(Cldr.Locale.new!("fr-CA", MyApp.Cldr))
587
+ {:ok, [:"fr-CA", :fr, :"en-001", :en]}
588
+
589
+ # Fallbacks are typically formed by progressively
590
+ # stripping variant, territory and script from the
591
+ # given locale name. But not always - there are
592
+ # certain fallbacks that take a different path.
593
+
594
+ iex> Cldr.Locale.fallback_locale_names(Cldr.Locale.new!("nb", MyApp.Cldr))
595
+ {:ok, [:nb, :no, :"en-001", :en]}
596
+
597
+ """
598
+ @spec fallback_locale_names(LanguageTag.t()) ::
599
+ {:ok, [locale_name, ...]} | {:error, {module(), binary()}}
600
+
601
+ @doc since: "2.26.0"
602
+ def fallback_locale_names(%LanguageTag{} = locale) do
603
+ with {:ok, fallbacks} <- fallback_locales(locale) do
604
+ locale_names = Enum.map(fallbacks, &Map.get(&1, :cldr_locale_name))
605
+ {:ok, locale_names}
606
+ end
607
+ end
608
+
609
+ @doc """
610
+ Returns the list of fallback locale names, starting the
611
+ the provided locale name.
612
+
613
+ Fallbacks are a list of locate names which can
614
+ be used to resolve translation or other localization
615
+ data if such localised data does not exist for
616
+ this specific locale. After locale-specific fallbacks
617
+ are determined, the the default locale and its fallbacks
618
+ are added to the chain.
619
+
620
+ ## Arguments
621
+
622
+ * `locale_name` is any locale name returned by
623
+ `Cldr.known_locale_names/1`
624
+
625
+ * `backend` is any module that includes `use Cldr` and therefore
626
+ is a `Cldr` backend module. The default is
627
+ `Cldr.default_locale/0`.
628
+
629
+ ## Returns
630
+
631
+ * `{:ok, list_of_locale_names}` or
632
+
633
+ * `{:error, {exception, reason}}`
634
+
635
+ ## Examples
636
+
637
+ In these examples the default locale is `:"en-001"`.
638
+
639
+ iex> Cldr.Locale.fallback_locale_names(:"fr-CA")
640
+ {:ok, [:"fr-CA", :fr, :"en-001", :en]}
641
+
642
+ # Fallbacks are typically formed by progressively
643
+ # stripping variant, territory and script from the
644
+ # given locale name. But not always - there are
645
+ # certain fallbacks that take a different path.
646
+
647
+ iex> Cldr.Locale.fallback_locale_names(:nb)
648
+ {:ok, [:nb, :no, :"en-001", :en]}
649
+
650
+ """
651
+ @spec fallback_locale_names(locale_reference, Cldr.backend()) ::
652
+ {:ok, [locale_name, ...]} | {:error, {module(), binary()}}
653
+
654
+ @doc since: "2.26.0"
655
+ def fallback_locale_names(locale_name, backend \\ Cldr.default_backend!()) do
656
+ with {:ok, locale} <- Cldr.validate_locale(locale_name, backend) do
657
+ fallback_locale_names(locale)
658
+ end
659
+ end
660
+
661
+ @doc """
662
+ Returns a map of a territory code to its
663
+ most-spoken language.
664
+
665
+ ## Example
666
+
667
+ Cldr.Locale.languages_for_territories()
668
+ => %{
669
+ AQ: "und",
670
+ PE: "es",
671
+ SR: "nl",
672
+ NU: "en",
673
+ ...
674
+ }
675
+
676
+ """
677
+ @language_for_territory Cldr.Config.language_tag_for_territory()
678
+ @doc since: "2.26.0"
679
+ def languages_for_territories do
680
+ @language_for_territory
681
+ end
682
+
683
+ @doc """
684
+ Returns the "best fit" locale for a given territory.
685
+
686
+ Using the population percentage data from CLDR, the
687
+ language most commonly spoken in the given territory
688
+ is used to form a locale name which is then validated
689
+ against the given backend.
690
+
691
+ First a territory-specific locale is validated and if
692
+ that fails, the base language only is validate.
693
+
694
+ For example, if the territory is `AU` then then the
695
+ language most spoken is "en". First, the locale "en-AU"
696
+ is validated and if that fails, "en" is validated.
697
+
698
+ ## Arguments
699
+
700
+ * `territory` is any ISO 3166 Alpha-2 territory
701
+ code that can be validated by `Cldr.validate_territory/1`
702
+
703
+ * `backend` is any module that includes `use Cldr` and therefore
704
+ is a `Cldr` backend module.
705
+
706
+ ## Returns
707
+
708
+ * `{:ok, language_tag}` or
709
+
710
+ * `{:error, {exception, reason}}`
711
+
712
+ ## Examples
713
+
714
+ iex> Cldr.Locale.locale_for_territory(:AU, TestBackend.Cldr)
715
+ Cldr.validate_locale(:"en-AU", TestBackend.Cldr)
716
+
717
+ iex> Cldr.Locale.locale_for_territory(:US, TestBackend.Cldr)
718
+ Cldr.validate_locale(:"en-US", TestBackend.Cldr)
719
+
720
+ iex> Cldr.Locale.locale_for_territory(:ZZ)
721
+ {:error, {Cldr.UnknownTerritoryError, "The territory :ZZ is unknown"}}
722
+
723
+ """
724
+ @doc since: "2.26.0"
725
+ @spec locale_for_territory(territory_code(), Cldr.backend()) ::
726
+ {:ok, LanguageTag.t()} | {:error, {module(), String.t()}}
727
+
728
+ def locale_for_territory(territory, backend \\ Cldr.default_backend!()) do
729
+ with {:ok, territory} <- Cldr.validate_territory(territory) do
730
+ case Map.get(languages_for_territories(), territory) do
731
+ nil ->
732
+ {:error, no_locale_for_territory_error(territory)}
733
+ language ->
734
+ validate_locale(language, territory, backend)
735
+ end
736
+ end
737
+ end
738
+
739
+ # See first if there is a territory specific version of this
740
+ # language, otherwise the base language itself
741
+
742
+ defp validate_locale(language, nil, backend) do
743
+ Cldr.validate_locale(language, backend)
744
+ end
745
+
746
+ defp validate_locale(language, territory, backend) do
747
+ case Cldr.validate_locale("#{language}-#{to_string(territory)}", backend) do
748
+ {:ok, locale} -> {:ok, locale}
749
+ {:error, _} -> validate_locale(language, nil, backend)
750
+ end
751
+ end
752
+
753
+ @consider_as_tld [
754
+ :AD, :AS, :BZ, :CC, :CD, :CO, :DJ, :FM, :IO, :LA, :ME, :MS, :NU, :SC, :SR, :SU, :TV, :TK, :WS
755
+ ]
756
+
757
+ @doc """
758
+ Returns a list of territory top-level domains that are
759
+ considered to be generic top level domains.
760
+
761
+ See https://developers.google.com/search/docs/advanced/crawling/managing-multi-regional-sites
762
+ for an explanation of why some valid territory suffixxes
763
+ are considered as TLDs.
764
+
765
+ ## Example
766
+
767
+ iex> Cldr.Locale.consider_as_tlds
768
+ [:AD, :AS, :BZ, :CC, :CD, :CO, :DJ, :FM, :IO, :LA, :ME, :MS, :NU, :SC, :SR, :SU, :TV, :TK, :WS]
769
+
770
+ """
771
+ def consider_as_tlds do
772
+ @consider_as_tld
773
+ end
774
+
775
+ @doc """
776
+ Returns a "best fit" locale for a host name.
777
+
778
+ ## Arguments
779
+
780
+ * `host` is any valid host name
781
+
782
+ * `backend` is any module that includes `use Cldr` and therefore
783
+ is a `Cldr` backend module.
784
+
785
+ * `options` is a keyword list of options. The default
786
+ is `[]`.
787
+
788
+ ## Options
789
+
790
+ * `:tlds` is a list of territory codes as upper-cased
791
+ atoms that are to be considered as top-level domains.
792
+ The default list is `consider_as_tlds/0`.
793
+
794
+ ## Returns
795
+
796
+ * `{:ok, langauge_tag}` or
797
+
798
+ * `{:error, {exception, reason}}`
799
+
800
+ ## Notes
801
+
802
+ Certain top-level domains have become associated with content
803
+ underlated to the territory for who the domain is registered.
804
+ Therefore Google (and perhaps others) do not associate these
805
+ TLDs as belonging to the territory but rather are considered
806
+ generic top-level domain names.
807
+
808
+ ## Examples
809
+
810
+ iex> Cldr.Locale.locale_from_host "a.b.com.au", TestBackend.Cldr
811
+ Cldr.validate_locale(:"en-AU", TestBackend.Cldr)
812
+
813
+ iex> Cldr.Locale.locale_from_host "a.b.com.tv", TestBackend.Cldr
814
+ {:error,
815
+ {Cldr.UnknownLocaleError, "No locale was identified for territory \\"tv\\""}}
816
+
817
+ iex> Cldr.Locale.locale_from_host "a.b.com", TestBackend.Cldr
818
+ {:error,
819
+ {Cldr.UnknownLocaleError, "No locale was identified for territory \\"com\\""}}
820
+
821
+ """
822
+ @doc since: "2.26.0"
823
+ @spec locale_from_host(String.t(), Cldr.backend(), Keyword.t()) ::
824
+ {:ok, LanguageTag.t()} | {:error, {module(), String.t()}}
825
+
826
+ def locale_from_host(host, backend, options \\ []) do
827
+ tld_list = Keyword.get(options, :tlds, consider_as_tlds())
828
+
829
+ with {:ok, territory} <- territory_from_host(host) do
830
+ if territory in tld_list do
831
+ {:error, no_locale_for_territory_error(territory)}
832
+ else
833
+ locale_for_territory(territory, backend)
834
+ end
835
+ end
836
+ end
837
+
838
+ @doc """
839
+ Returns the last segment of a host that might
840
+ be a territory.
841
+
842
+ ## Arguments
843
+
844
+ * `host` is any valid host name
845
+
846
+ ## Returns
847
+
848
+ * `{:ok, territory}` or
849
+
850
+ * `{:error, {exception, reason}}`
851
+
852
+ ## Examples
853
+
854
+ iex> Cldr.Locale.territory_from_host("a.b.com.au")
855
+ {:ok, :AU}
856
+
857
+ iex> Cldr.Locale.territory_from_host("a.b.com")
858
+ {:error,
859
+ {Cldr.UnknownLocaleError, "No locale was identified for territory \\"com\\""}}
860
+
861
+ """
862
+ @doc since: "2.26.0"
863
+ @spec territory_from_host(String.t()) ::
864
+ {:ok, territory_code()} | {:error, {module(), String.t()}}
865
+
866
+ def territory_from_host(host) do
867
+ territory =
868
+ host
869
+ |> String.split(".")
870
+ |> Enum.reverse()
871
+ |> hd()
872
+
873
+ try do
874
+ territory = String.upcase(territory) |> String.to_existing_atom()
875
+ Cldr.validate_territory(territory)
876
+ rescue ArgumentError ->
877
+ {:error, no_locale_for_territory_error(territory)}
878
+ end
879
+ end
880
+
413
881
@doc """
414
882
Returns the effective territory for a locale.
415
883
 
@@ -470,7 +938,7 @@ defmodule Cldr.Locale do
470
938
however it is correctly parsed to support future use.
471
939
472
940
"""
473
- @spec territory_from_locale(LanguageTag.t() | locale_name()) :: Cldr.Locale.territory()
941
+ @spec territory_from_locale(LanguageTag.t() | locale_name() | String.t()) :: territory_code()
474
942
475
943
@doc since: "2.18.2"
476
944
 
@@ -482,7 +950,7 @@ defmodule Cldr.Locale do
482
950
language_tag.territory || Cldr.default_territory()
483
951
end
484
952
485
- def territory_from_locale(locale_name) when is_binary(locale_name) do
953
+ def territory_from_locale(locale_name) do
486
954
territory_from_locale(locale_name, Cldr.default_backend!())
487
955
end
488
956
 
@@ -549,12 +1017,12 @@ defmodule Cldr.Locale do
549
1017
550
1018
"""
551
1019
552
- @spec territory_from_locale(locale_name(), Cldr.backend()) ::
553
- territory() | {:error, {module(), String.t()}}
1020
+ @spec territory_from_locale(locale_reference() | String.t(), Cldr.backend()) ::
1021
+ territory_code() | {:error, {module(), String.t()}}
554
1022
555
1023
@doc since: "2.18.2"
556
1024
557
- def territory_from_locale(locale, backend) when is_binary(locale) do
1025
+ def territory_from_locale(locale, backend) do
558
1026
with {:ok, locale} <- Cldr.validate_locale(locale, backend) do
559
1027
territory_from_locale(locale)
560
1028
end
 
@@ -586,7 +1054,7 @@ defmodule Cldr.Locale do
586
1054
587
1055
"""
588
1056
589
- @spec timezone_from_locale(LanguageTag.t() | locale_name()) ::
1057
+ @spec timezone_from_locale(LanguageTag.t() | locale_name() | String.t()) ::
590
1058
String.t() | {:error, {module(), String.t()}}
591
1059
592
1060
@doc since: "2.19.0"
 
@@ -607,7 +1075,7 @@ defmodule Cldr.Locale do
607
1075
end
608
1076
end
609
1077
610
- def timezone_from_locale(locale_name) when is_binary(locale_name) do
1078
+ def timezone_from_locale(locale_name) do
611
1079
timezone_from_locale(locale_name, Cldr.default_backend!())
612
1080
end
613
1081
 
@@ -630,19 +1098,19 @@ defmodule Cldr.Locale do
630
1098
iex> Cldr.Locale.timezone_from_locale "en-US-u-tz-ausyd", TestBackend.Cldr
631
1099
"Australia/Sydney"
632
1100
633
- iex> Cldr.Locale.timezone_from_locale "en-AU", TestBackend.Cldr
1101
+ iex> Cldr.Locale.timezone_from_locale :"en-AU", TestBackend.Cldr
634
1102
{:error,
635
1103
{Cldr.AmbiguousTimezoneError,
636
1104
"Cannot determine the timezone since the territory :AU has 24 timezone IDs"}}
637
1105
638
1106
"""
639
1107
640
- @spec timezone_from_locale(locale_name(), Cldr.backend()) ::
1108
+ @spec timezone_from_locale(locale_name() | String.t(), Cldr.backend()) ::
641
1109
String.t() | {:error, {module(), String.t()}}
642
1110
643
1111
@doc since: "2.19.0"
644
1112
645
- def timezone_from_locale(locale, backend) when is_binary(locale) do
1113
+ def timezone_from_locale(locale, backend) do
646
1114
with {:ok, locale} <- Cldr.validate_locale(locale, backend) do
647
1115
timezone_from_locale(locale)
648
1116
end
 
@@ -707,13 +1175,13 @@ defmodule Cldr.Locale do
707
1175
%Cldr.LanguageTag{
708
1176
backend: TestBackend.Cldr,
709
1177
canonical_locale_name: "en",
710
- cldr_locale_name: "en",
1178
+ cldr_locale_name: :en,
711
1179
extensions: %{},
712
1180
gettext_locale_name: "en",
713
1181
language: "en",
714
1182
locale: %{},
715
1183
private_use: [],
716
- rbnf_locale_name: "en",
1184
+ rbnf_locale_name: :en,
717
1185
requested_locale_name: "en",
718
1186
script: :Latn,
719
1187
territory: :US,
 
@@ -723,7 +1191,7 @@ defmodule Cldr.Locale do
723
1191
}
724
1192
725
1193
"""
726
- @spec canonical_language_tag(locale_name | Cldr.LanguageTag.t(), Cldr.backend(), Keyword.t()) ::
1194
+ @spec canonical_language_tag(locale_name | Cldr.LanguageTag.t() | String.t(), Cldr.backend(), Keyword.t()) ::
727
1195
{:ok, Cldr.LanguageTag.t()} | {:error, {module(), String.t()}}
728
1196
729
1197
def canonical_language_tag(locale_name, backend, options \\ [])
 
@@ -738,9 +1206,28 @@ defmodule Cldr.Locale do
738
1206
end
739
1207
end
740
1208
741
- def canonical_language_tag(%LanguageTag{cldr_locale_name: locale} = tag, _backend, _options)
742
- when is_binary(locale) do
743
- {:ok, tag}
1209
+ def canonical_language_tag(locale_name, backend, options) when is_atom(locale_name) do
1210
+ case Map.fetch(Cldr.Config.all_language_tags(), locale_name) do
1211
+ {:ok, language_tag} ->
1212
+ canonical_language_tag(language_tag, backend, options)
1213
+
1214
+ :error ->
1215
+ canonical_language_tag(locale_name, backend, options)
1216
+ end
1217
+ end
1218
+
1219
+ unvalidated_match = quote do
1220
+ %LanguageTag{cldr_locale_name: var!(locale_name), canonical_locale_name: var!(canonical_name)}
1221
+ end
1222
+
1223
+ def canonical_language_tag(unquote(unvalidated_match) = language_tag, backend, _options)
1224
+ when not is_nil(locale_name) and not is_nil(canonical_name) do
1225
+ language_tag =
1226
+ language_tag
1227
+ |> put_backend(backend)
1228
+ |> put_gettext_locale_name()
1229
+
1230
+ {:ok, language_tag}
744
1231
end
745
1232
746
1233
def canonical_language_tag(%LanguageTag{} = language_tag, backend, options) do
 
@@ -998,7 +1485,7 @@ defmodule Cldr.Locale do
998
1485
999
1486
defp remove_unknown(%LanguageTag{} = language_tag, :script), do: language_tag
1000
1487
1001
- defp remove_unknown(%LanguageTag{territory: "ZZ"} = language_tag, :territory) do
1488
+ defp remove_unknown(%LanguageTag{territory: :ZZ} = language_tag, :territory) do
1002
1489
%{language_tag | territory: nil}
1003
1490
end
1004
1491
 
@@ -1055,7 +1542,7 @@ defmodule Cldr.Locale do
1055
1542
end
1056
1543
1057
1544
@spec rbnf_locale_name(Cldr.LanguageTag.t()) :: locale_name | nil
1058
- defp rbnf_locale_name(%LanguageTag{language: @root_locale}) do
1545
+ defp rbnf_locale_name(%LanguageTag{language: @root_language}) do
1059
1546
@root_rbnf_locale_name
1060
1547
end
1061
1548
 
@@ -1235,7 +1722,7 @@ defmodule Cldr.Locale do
1235
1722
1236
1723
## Returns
1237
1724
1238
- * The locale name constructed from the non-nil arguments joined
1725
+ * The atom locale name constructed from the non-nil arguments joined
1239
1726
by a "-"
1240
1727
1241
1728
## Example
 
@@ -1247,8 +1734,8 @@ defmodule Cldr.Locale do
1247
1734
"en-001"
1248
1735
1249
1736
"""
1250
- @spec locale_name_from(language(), script(), territory(), variants(), boolean) ::
1251
- locale_name()
1737
+ @spec locale_name_from(language(), script(), territory_reference(), variants(), boolean) ::
1738
+ String.t()
1252
1739
1253
1740
def locale_name_from(language, script, territory, variants, omit_singular_script? \\ true) do
1254
1741
[language, script, territory, variants]
 
@@ -1596,59 +2083,6 @@ defmodule Cldr.Locale do
1596
2083
end)
1597
2084
end
1598
2085
1599
- @doc """
1600
- Returns an error tuple for an invalid locale.
1601
-
1602
- ## Arguments
1603
-
1604
- * `locale_name` is any locale name returned by `Cldr.known_locale_names/1`
1605
-
1606
- ## Returns
1607
-
1608
- * `{:error, {Cldr.UnknownLocaleError, message}}`
1609
-
1610
- ## Examples
1611
-
1612
- iex> Cldr.Locale.locale_error :invalid
1613
- {Cldr.UnknownLocaleError, "The locale :invalid is not known."}
1614
-
1615
- """
1616
- @spec locale_error(locale_name() | LanguageTag.t()) :: {Cldr.UnknownLocaleError, String.t()}
1617
- def locale_error(%LanguageTag{requested_locale_name: requested_locale_name}) do
1618
- locale_error(requested_locale_name)
1619
- end
1620
-
1621
- def locale_error(locale_name) do
1622
- {Cldr.UnknownLocaleError, "The locale #{inspect(locale_name)} is not known."}
1623
- end
1624
-
1625
- @doc """
1626
- Returns an error tuple for an invalid gettext locale.
1627
-
1628
- ## Options
1629
-
1630
- * `locale_name` is any locale name returned by `Cldr.known_gettext_locale_names/1`
1631
-
1632
- ## Returns
1633
-
1634
- * `{:error, {Cldr.UnknownLocaleError, message}}`
1635
-
1636
- ## Examples
1637
-
1638
- iex> Cldr.Locale.gettext_locale_error :invalid
1639
- {Cldr.UnknownLocaleError, "The gettext locale :invalid is not known."}
1640
-
1641
- """
1642
- @spec gettext_locale_error(locale_name() | LanguageTag.t()) ::
1643
- {Cldr.UnknownLocaleError, String.t()}
1644
- def gettext_locale_error(%LanguageTag{gettext_locale_name: gettext_locale_name}) do
1645
- gettext_locale_error(gettext_locale_name)
1646
- end
1647
-
1648
- def gettext_locale_error(locale_name) do
1649
- {Cldr.UnknownLocaleError, "The gettext locale #{inspect(locale_name)} is not known."}
1650
- end
1651
-
1652
2086
@doc """
1653
2087
Returns the map of likely subtags.
1654
2088
 
@@ -1658,8 +2092,8 @@ defmodule Cldr.Locale do
1658
2092
## Example
1659
2093
1660
2094
Cldr.Locale.likely_subtags
1661
- %{
1662
- "bez" => %Cldr.LanguageTag{
2095
+ => %{
2096
+ bez; %Cldr.LanguageTag{
1663
2097
backend: TestBackend.Cldr,
1664
2098
canonical_locale_name: nil,
1665
2099
cldr_locale_name: nil,
 
@@ -1674,7 +2108,7 @@ defmodule Cldr.Locale do
1674
2108
transform: %{},
1675
2109
language_variants: []
1676
2110
},
1677
- "fuf" => %Cldr.LanguageTag{
2111
+ fuf: %Cldr.LanguageTag{
1678
2112
canonical_locale_name: nil,
1679
2113
cldr_locale_name: nil,
1680
2114
extensions: %{},
 
@@ -1707,7 +2141,7 @@ defmodule Cldr.Locale do
1707
2141
1708
2142
## Examples
1709
2143
1710
- iex> Cldr.Locale.likely_subtags "en"
2144
+ iex> Cldr.Locale.likely_subtags :en
1711
2145
%Cldr.LanguageTag{
1712
2146
backend: nil,
1713
2147
canonical_locale_name: nil,
 
@@ -1726,8 +2160,9 @@ defmodule Cldr.Locale do
1726
2160
}
1727
2161
1728
2162
"""
1729
- @spec likely_subtags(locale_name) :: LanguageTag.t() | nil
1730
- def likely_subtags(locale_name) when is_binary(locale_name) do
2163
+ @spec likely_subtags(locale_name | String.t()) :: LanguageTag.t() | nil
2164
+
2165
+ def likely_subtags(locale_name) when is_atom(locale_name) do
1731
2166
Map.get(likely_subtags(), locale_name)
1732
2167
end
1733
2168
 
@@ -1735,6 +2170,14 @@ defmodule Cldr.Locale do
1735
2170
likely_subtags(requested_locale_name)
1736
2171
end
1737
2172
2173
+ def likely_subtags(locale_name) when is_binary(locale_name) do
2174
+ locale_name
2175
+ |> String.to_existing_atom()
2176
+ |> likely_subtags()
2177
+ rescue ArgumentError ->
2178
+ nil
2179
+ end
2180
+
1738
2181
@doc """
1739
2182
Return a map of the known aliases for Language, Script and Territory
1740
2183
"""
 
@@ -1755,9 +2198,10 @@ defmodule Cldr.Locale do
1755
2198
1756
2199
"""
1757
2200
@alias_keys Map.keys(@aliases)
1758
- @spec aliases(locale_name(), atom()) :: String.t() | list(String.t()) | LanguageTag.t() | nil
2201
+ @spec aliases(locale_name() | String.t(), atom()) ::
2202
+ String.t() | list(String.t()) | LanguageTag.t() | nil
1759
2203
1760
- def aliases(key, :region = type) do
2204
+ def aliases(key, :region = type) when is_atom(key) do
1761
2205
aliases()
1762
2206
|> Map.get(type)
1763
2207
|> Map.get(to_string(key))
 
@@ -1769,6 +2213,14 @@ defmodule Cldr.Locale do
1769
2213
|> Map.get(key)
1770
2214
end
1771
2215
2216
+ def aliases(key, type) when is_binary(key) do
2217
+ key
2218
+ |> String.to_existing_atom()
2219
+ |> aliases(type)
2220
+ rescue ArgumentError ->
2221
+ nil
2222
+ end
2223
+
1772
2224
defp validate_subtags(language_tag) do
1773
2225
with {:ok, language_tag} <- validate(language_tag, :language),
1774
2226
{:ok, language_tag} <- validate(language_tag, :script),
 
@@ -1806,33 +2258,45 @@ defmodule Cldr.Locale do
1806
2258
end
1807
2259
end
1808
2260
2261
+ @doc false
2262
+ def locale_error(%LanguageTag{requested_locale_name: requested_locale_name}) do
2263
+ locale_error(requested_locale_name)
2264
+ end
2265
+
2266
+ def locale_error(locale_name) do
2267
+ {Cldr.UnknownLocaleError, "The locale #{inspect(locale_name)} is not known."}
2268
+ end
2269
+
2270
+ @doc false
2271
+ def gettext_locale_error(%LanguageTag{gettext_locale_name: gettext_locale_name}) do
2272
+ gettext_locale_error(gettext_locale_name)
2273
+ end
2274
+
2275
+ def gettext_locale_error(locale_name) do
2276
+ {Cldr.UnknownLocaleError, "The gettext locale #{inspect(locale_name)} is not known."}
2277
+ end
2278
+
2279
+ @doc false
1809
2280
def invalid_language_error(language) do
1810
2281
{Cldr.InvalidLanguageError, "The language #{inspect(language)} is invalid"}
1811
2282
end
1812
2283
2284
+ @doc false
1813
2285
def invalid_script_error(script) do
1814
2286
{Cldr.InvalidScriptError, "The script #{inspect(script)} is invalid"}
1815
2287
end
1816
2288
2289
+ @doc false
1817
2290
def invalid_territory_error(territory) do
1818
2291
{Cldr.InvalidTerritoryError, "The territory #{inspect(territory)} is invalid"}
1819
2292
end
1820
2293
2294
+ @doc false
1821
2295
def invalid_variant_error(variant) do
1822
2296
{Cldr.InvalidVariantError, "The variant #{inspect(variant)} is invalid"}
1823
2297
end
1824
2298
1825
- @doc """
1826
- Returns an error tuple for an invalid locale alias.
1827
-
1828
- ## Options
1829
-
1830
- * `locale_name` is any locale name returned by `Cldr.known_locale_names/1`
1831
-
1832
- """
1833
- @spec alias_error(locale_name() | LanguageTag.t(), String.t()) ::
1834
- {Cldr.UnknownLocaleError, String.t()}
1835
-
2299
+ @doc false
1836
2300
def alias_error(locale_name, alias_name) when is_binary(locale_name) do
1837
2301
{
1838
2302
Cldr.UnknownLocaleError,
 
@@ -1841,7 +2305,20 @@ defmodule Cldr.Locale do
1841
2305
}
1842
2306
end
1843
2307
2308
+ @doc false
1844
2309
def alias_error(%LanguageTag{requested_locale_name: requested_locale_name}, alias_name) do
1845
2310
alias_error(requested_locale_name, alias_name)
1846
2311
end
2312
+
2313
+ @doc false
2314
+ def no_locale_for_territory_error(territory) when is_binary(territory) do
2315
+ {Cldr.UnknownLocaleError, "No locale was identified for territory #{inspect territory}"}
2316
+ end
2317
+
2318
+ def no_locale_for_territory_error(territory) when is_atom(territory) do
2319
+ territory
2320
+ |> Atom.to_string()
2321
+ |> String.downcase()
2322
+ |> no_locale_for_territory_error()
2323
+ end
1847
2324
end
changed lib/cldr/locale/cache.ex
 
@@ -37,11 +37,11 @@ defmodule Cldr.Locale.Cache do
37
37
process_alive?(:cldr_locale_cache)
38
38
end
39
39
40
- defp process_alive?(:can_await_module_compilation?) do
41
- Code.ensure_loaded?(Code) &&
42
- function_exported?(Code, :can_await_module_compilation?, 0) &&
43
- apply(Code, :can_await_module_compilation?, [])
44
- end
40
+ defp process_alive?(:can_await_module_compilation?) do
41
+ Code.ensure_loaded?(Code) &&
42
+ function_exported?(Code, :can_await_module_compilation?, 0) &&
43
+ apply(Code, :can_await_module_compilation?, [])
44
+ end
45
45
46
46
defp process_alive?(name) do
47
47
case Process.get(name) do
changed lib/cldr/locale/loader.ex
 
@@ -22,6 +22,11 @@ defmodule Cldr.Locale.Loader do
22
22
Returns a list of all locales that are configured and available
23
23
in the CLDR repository.
24
24
25
+ ## Examples
26
+
27
+ iex> Cldr.Locale.Loader.known_locale_names %Cldr.Config{locales: ["en", "de"]}
28
+ [:de, :en, :und]
29
+
25
30
"""
26
31
@spec known_locale_names(Config.t() | Cldr.backend()) :: [Locale.locale_name()]
27
32
def known_locale_names(backend) when is_atom(backend) do
 
@@ -29,13 +34,8 @@ defmodule Cldr.Locale.Loader do
29
34
|> known_locale_names
30
35
end
31
36
32
- def known_locale_names(%Config{locales: :all}) do
33
- Cldr.Config.all_locale_names()
34
- |> Enum.sort()
35
- end
36
-
37
- def known_locale_names(%Config{locales: locales}) do
38
- locales
37
+ def known_locale_names(%Config{} = config) do
38
+ Cldr.Config.configured_locale_names(config)
39
39
end
40
40
41
41
@doc """
 
@@ -61,26 +61,26 @@ defmodule Cldr.Locale.Loader do
61
61
during production run there is no file access or decoding.
62
62
63
63
"""
64
- @spec get_locale(Cldr.Locale.locale_name(), config_or_backend :: Config.t() | Cldr.backend()) ::
64
+ @spec get_locale(Locale.locale_name(), config_or_backend :: Config.t() | Cldr.backend()) ::
65
65
map() | no_return()
66
66
67
- def get_locale(locale, %{data_dir: _} = config) do
67
+ def get_locale(locale, %{data_dir: _} = config) when is_atom(locale) do
68
68
do_get_locale(locale, config)
69
69
end
70
70
71
- def get_locale(locale, backend) when is_atom(backend) do
71
+ def get_locale(locale, backend) when is_atom(locale) and is_atom(backend) do
72
72
do_get_locale(locale, backend.__cldr__(:config))
73
73
end
74
74
75
75
@doc false
76
- def do_get_locale(locale, config) do
76
+ def do_get_locale(locale, config) when is_atom(locale) do
77
77
{:ok, path} =
78
78
case Config.locale_path(locale, config) do
79
79
{:ok, path} ->
80
80
{:ok, path}
81
81
82
82
{:error, :not_found} ->
83
- raise RuntimeError, message: "Locale definition was not found for #{locale}"
83
+ raise RuntimeError, message: "Locale definition was not found for #{inspect locale}"
84
84
end
85
85
86
86
do_get_locale(locale, path, Cldr.Locale.Cache.compiling?())
 
@@ -115,7 +115,7 @@ defmodule Cldr.Locale.Loader do
115
115
end
116
116
117
117
@doc false
118
- def do_get_locale(locale, path, true) do
118
+ def do_get_locale(locale, path, true) when is_atom(locale) do
119
119
Cldr.Locale.Cache.get_locale(locale, path)
120
120
end
changed lib/cldr/plural_rules/plural_rule.ex
 
@@ -93,7 +93,7 @@ defmodule Cldr.Number.PluralRule do
93
93
"`type: :ordinal` are the only valid options"
94
94
end
95
95
96
- quote location: :keep do
96
+ quote location: :keep, generated: true do
97
97
alias Cldr.Math
98
98
alias Cldr.LanguageTag
99
99
alias Cldr.Locale
 
@@ -233,25 +233,25 @@ defmodule Cldr.Number.PluralRule do
233
233
234
234
## Examples
235
235
236
- iex> #{inspect(__MODULE__)}.pluralize 1, "en", %{one: "one"}
236
+ iex> #{inspect(__MODULE__)}.pluralize 1, :en, %{one: "one"}
237
237
"one"
238
238
239
- iex> #{inspect(__MODULE__)}.pluralize 2, "en", %{one: "one"}
239
+ iex> #{inspect(__MODULE__)}.pluralize 2, :en, %{one: "one"}
240
240
nil
241
241
242
- iex> #{inspect(__MODULE__)}.pluralize 2, "en", %{one: "one", two: "two"}
242
+ iex> #{inspect(__MODULE__)}.pluralize 2, :en, %{one: "one", two: "two"}
243
243
"two"
244
244
245
- iex> #{inspect(__MODULE__)}.pluralize 22, "en", %{one: "one", two: "two", other: "other"}
245
+ iex> #{inspect(__MODULE__)}.pluralize 22, :en, %{one: "one", two: "two", other: "other"}
246
246
"two"
247
247
248
- iex> #{inspect(__MODULE__)}.pluralize Decimal.new(1), "en", %{one: "one"}
248
+ iex> #{inspect(__MODULE__)}.pluralize Decimal.new(1), :en, %{one: "one"}
249
249
"one"
250
250
251
- iex> #{inspect(__MODULE__)}.pluralize Decimal.new(2), "en", %{one: "one"}
251
+ iex> #{inspect(__MODULE__)}.pluralize Decimal.new(2), :en, %{one: "one"}
252
252
nil
253
253
254
- iex> #{inspect(__MODULE__)}.pluralize Decimal.new(2), "en", %{one: "one", two: "two"}
254
+ iex> #{inspect(__MODULE__)}.pluralize Decimal.new(2), :en, %{one: "one", two: "two"}
255
255
"two"
256
256
257
257
iex> #{inspect(__MODULE__)}.pluralize 1..10, "ar", %{one: "one", few: "few", other: "other"}
 
@@ -264,12 +264,7 @@ defmodule Cldr.Number.PluralRule do
264
264
end
265
265
266
266
@default_substitution :other
267
- @spec pluralize(
268
- Math.number_or_decimal() | %Range{},
269
- LanguageTag.t() | Locale.locale_name(),
270
- %{}
271
- ) ::
272
- any()
267
+ @spec pluralize(Math.number_or_decimal() | Range.t(), Locale.locale_reference(), %{}) :: any()
273
268
274
269
def pluralize(%Range{first: first, last: last}, locale_name, substitutions) do
275
270
with {:ok, language_tag} <- @backend.validate_locale(locale_name) do
 
@@ -283,7 +278,8 @@ defmodule Cldr.Number.PluralRule do
283
278
end
284
279
end
285
280
286
- def pluralize(number, locale_name, substitutions) when is_binary(locale_name) do
281
+ def pluralize(number, locale_name, substitutions)
282
+ when is_atom(locale_name) or is_binary(locale_name) do
287
283
with {:ok, language_tag} <- @backend.validate_locale(locale_name) do
288
284
pluralize(number, language_tag, substitutions)
289
285
end
 
@@ -301,18 +297,16 @@ defmodule Cldr.Number.PluralRule do
301
297
|> do_pluralize(locale, substitutions)
302
298
end
303
299
304
- def pluralize(%Decimal{sign: sign, coef: coef, exp: exp} = number, locale, substitutions)
300
+ def pluralize(%Decimal{sign: sign, coef: coef, exp: exp}, locale, substitutions)
305
301
when is_integer(coef) and exp > 0 do
306
- number
307
- |> Decimal.to_integer()
308
- |> do_pluralize(locale, substitutions)
302
+ number = %Decimal{sign: sign, coef: coef * 10, exp: exp - 1}
303
+ pluralize(number, locale, substitutions)
309
304
end
310
305
311
- def pluralize(%Decimal{sign: sign, coef: coef, exp: exp} = number, locale, substitutions)
306
+ def pluralize(%Decimal{sign: sign, coef: coef, exp: exp}, locale, substitutions)
312
307
when is_integer(coef) and exp < 0 and rem(coef, 10) == 0 do
313
- number
314
- |> Decimal.to_integer()
315
- |> do_pluralize(locale, substitutions)
308
+ number = %Decimal{sign: sign, coef: Kernel.div(coef, 10), exp: exp + 1}
309
+ pluralize(number, locale, substitutions)
316
310
end
317
311
318
312
def pluralize(%Decimal{} = number, %LanguageTag{} = locale, %{} = substitutions) do
 
@@ -344,7 +338,7 @@ defmodule Cldr.Number.PluralRule do
344
338
plural_rules()[cldr_locale_name] || plural_rules()[language]
345
339
end
346
340
347
- def plural_rules_for(locale_name) when is_binary(locale_name) do
341
+ def plural_rules_for(locale_name) do
348
342
with {:ok, locale} <- @backend.validate_locale(locale_name) do
349
343
plural_rules_for(locale)
350
344
end
 
@@ -441,18 +435,12 @@ defmodule Cldr.Number.PluralRule do
441
435
442
436
def plural_rule(number, locale, rounding \\ Math.default_rounding())
443
437
444
- def plural_rule(number, locale_name, rounding) when is_binary(locale_name) do
445
- with {:ok, locale} <- @backend.validate_locale(locale_name) do
446
- plural_rule(number, locale, rounding)
447
- end
448
- end
449
-
450
- def plural_rule(number, locale, rounding) when is_binary(number) do
438
+ def plural_rule(number, %LanguageTag{} = locale, rounding) when is_binary(number) do
451
439
plural_rule(Decimal.new(number), locale, rounding)
452
440
end
453
441
454
442
# Plural rule for an integer
455
- def plural_rule(number, locale, _rounding) when is_integer(number) do
443
+ def plural_rule(number, %LanguageTag{} = locale, _rounding) when is_integer(number) do
456
444
n = abs(number)
457
445
i = n
458
446
v = 0
 
@@ -464,7 +452,7 @@ defmodule Cldr.Number.PluralRule do
464
452
end
465
453
466
454
# For a compact integer
467
- def plural_rule({number, e}, locale, _rounding) when is_integer(number) do
455
+ def plural_rule({number, e}, %LanguageTag{} = locale, _rounding) when is_integer(number) do
468
456
n = abs(number)
469
457
i = n
470
458
v = 0
 
@@ -475,7 +463,7 @@ defmodule Cldr.Number.PluralRule do
475
463
end
476
464
477
465
# Plural rule for a float
478
- def plural_rule(number, locale, rounding)
466
+ def plural_rule(number, %LanguageTag{} = locale, rounding)
479
467
when is_float(number) and is_integer(rounding) and rounding > 0 do
480
468
# Testing shows that this is working but just in case we
481
469
# can go back to casting the number to a decimal and
 
@@ -492,7 +480,7 @@ defmodule Cldr.Number.PluralRule do
492
480
end
493
481
494
482
# Plural rule for a compact float
495
- def plural_rule({number, e}, locale, rounding)
483
+ def plural_rule({number, e}, %LanguageTag{} = locale, rounding)
496
484
when is_float(number) and is_integer(rounding) and rounding > 0 do
497
485
# Testing shows that this is working but just in case we
498
486
# can go back to casting the number to a decimal and
 
@@ -508,7 +496,7 @@ defmodule Cldr.Number.PluralRule do
508
496
end
509
497
510
498
# Plural rule for a %Decimal{}
511
- def plural_rule(%Decimal{} = number, locale, rounding)
499
+ def plural_rule(%Decimal{} = number, %LanguageTag{} = locale, rounding)
512
500
when is_integer(rounding) and rounding > 0 do
513
501
# n absolute value of the source number (integer and decimals).
514
502
n = Decimal.abs(number)
 
@@ -541,7 +529,7 @@ defmodule Cldr.Number.PluralRule do
541
529
end
542
530
543
531
# Plural rule for a compact %Decimal{}
544
- def plural_rule({%Decimal{} = number, e}, locale, rounding)
532
+ def plural_rule({%Decimal{} = number, e}, %LanguageTag{} = locale, rounding)
545
533
when is_integer(rounding) and rounding > 0 do
546
534
# n absolute value of the source number (integer and decimals).
547
535
n = Decimal.abs(number)
 
@@ -571,6 +559,12 @@ defmodule Cldr.Number.PluralRule do
571
559
572
560
do_plural_rule(locale, n, i, v, w, f, t, e)
573
561
end
562
+
563
+ def plural_rule(number, locale_name, rounding) do
564
+ with {:ok, locale} <- @backend.validate_locale(locale_name) do
565
+ plural_rule(number, locale, rounding)
566
+ end
567
+ end
574
568
end
575
569
end
576
570
 
@@ -718,7 +712,7 @@ defmodule Cldr.Number.PluralRule do
718
712
}
719
713
else
720
714
language_tag
721
- |> Map.put(:cldr_locale_name, language_tag.language)
715
+ |> Map.put(:cldr_locale_name, String.to_atom(language_tag.language))
722
716
|> do_plural_rule(n, i, v, w, f, t, e)
723
717
end
724
718
end
removed lib/cldr/sigil.ex
 
@@ -1,87 +0,0 @@
1
- defmodule Cldr.LanguageTag.Sigil do
2
- @moduledoc """
3
- Implements a `sigil_l/2` macro to
4
- constructing `t:Cldr.LanguageTag` structs.
5
-
6
- """
7
-
8
- @doc """
9
- Handles sigil `~l` for language tags.
10
-
11
- ## Arguments
12
-
13
- * `locale_name` is either a [BCP 47](https://unicode-org.github.io/cldr/ldml/tr35.html#Identifiers)
14
- locale name as a string or
15
-
16
- * `locale_name` | `backend` where backend is a backend module name
17
-
18
- ## Options
19
-
20
- * `u` Will parse the locale but will not add
21
- likely subtags and its not guaranteed that this
22
- language tag is known to the backend module.
23
-
24
- ## Returns
25
-
26
- * a `t:Cldr.LanguageTag` struct or
27
-
28
- * raises an exception
29
-
30
- ## Examples
31
-
32
- iex> import Cldr.LanguageTag.Sigil
33
- iex> ~l(en-US-u-ca-gregory)
34
- #Cldr.LanguageTag<en-US-u-ca-gregory [validated]>
35
-
36
- iex> import Cldr.LanguageTag.Sigil
37
- iex> ~l(en-US-u-ca-gregory|MyApp.Cldr)
38
- #Cldr.LanguageTag<en-US-u-ca-gregory [validated]>
39
-
40
- """
41
- defmacro sigil_l(locale_name, 'u') do
42
- {:<<>>, [_], [locale_name]} = locale_name
43
-
44
- case parse_locale(String.split(locale_name, "|")) do
45
- {:ok, locale_name} ->
46
- quote do
47
- unquote(Macro.escape(locale_name))
48
- end
49
-
50
- {:error, {exception, reason}} ->
51
- raise exception, reason
52
- end
53
- end
54
-
55
- defmacro sigil_l(locale_name, _opts) do
56
- {:<<>>, [_], [locale_name]} = locale_name
57
-
58
- case validate_locale(String.split(locale_name, "|")) do
59
- {:ok, locale_name} ->
60
- quote do
61
- unquote(Macro.escape(locale_name))
62
- end
63
-
64
- {:error, {exception, reason}} ->
65
- raise exception, reason
66
- end
67
- end
68
-
69
- defp validate_locale([locale_name, backend]) do
70
- backend = Module.concat([backend])
71
- Cldr.validate_locale(locale_name, backend)
72
- end
73
-
74
- defp validate_locale([locale_name]) do
75
- Cldr.validate_locale(locale_name)
76
- end
77
-
78
- @opts [add_likely_subtags: false]
79
- defp parse_locale([locale_name, backend]) do
80
- backend = Module.concat([backend])
81
- Cldr.Locale.canonical_language_tag(locale_name, backend, @opts)
82
- end
83
-
84
- defp parse_locale([locale_name]) do
85
- Cldr.Locale.canonical_language_tag(locale_name, Cldr.default_backend!(), @opts)
86
- end
87
- end
changed mix.exs
 
@@ -1,7 +1,7 @@
1
1
defmodule Cldr.Mixfile do
2
2
use Mix.Project
3
3
4
- @version "2.25.0"
4
+ @version "2.26.0"
5
5
6
6
def project do
7
7
[
 
@@ -45,13 +45,14 @@ defmodule Cldr.Mixfile do
45
45
defp deps do
46
46
[
47
47
{:cldr_utils, "~> 2.17"},
48
+
48
49
{:decimal, "~> 1.6 or ~> 2.0"},
49
50
{:castore, "~> 0.1", optional: true},
50
51
{:certifi, "~> 2.5", optional: true},
51
52
{:jason, "~> 1.0", optional: true},
52
53
{:ex_doc, "~> 0.18", only: [:release, :dev]},
53
54
{:nimble_parsec, "~> 0.5 or ~> 1.0", optional: true},
54
- {:gettext, "~> 0.13", optional: true},
55
+ {:gettext, "~> 0.19", optional: true},
55
56
{:stream_data, "~> 0.4", only: :test},
56
57
{:dialyxir, "~> 1.0", only: [:dev], runtime: false, optional: true},
57
58
{:plug, "~> 1.9", optional: true},