Packages
ex_cldr
2.2.6
2.47.5
2.47.4
2.47.3
2.47.2
2.47.1
2.47.0
2.46.0
2.45.2
2.45.1
2.45.0
2.44.1
2.44.0
2.43.2
2.43.1
2.43.0
2.42.0
2.41.1
2.41.0
2.40.4
2.40.3
2.40.2
2.40.1
2.40.0
2.39.2
2.39.1
2.39.0
2.38.1
2.38.0
2.37.5
2.37.4
2.37.3
retired
2.37.2
2.37.1
2.37.0
2.36.0
2.35.1
2.35.0
retired
2.34.2
2.34.1
2.34.0
2.33.2
2.33.1
2.33.1-rc.0
2.33.0
2.32.1
2.32.0
2.31.0
2.30.0
2.29.0
2.28.0
2.27.1
2.27.0
retired
2.26.3
2.26.2
2.26.1
2.26.0
2.25.0
2.24.2
2.24.1
2.24.0
2.24.0-rc.6
2.24.0-rc.5
2.24.0-rc.4
2.24.0-rc.3
2.24.0-rc.2
2.24.0-rc.1
2.24.0-rc.0
2.23.2
2.23.1
2.23.0
2.22.1
2.22.0
2.21.0
2.20.0
2.20.0-rc.3
2.20.0-rc.2
2.20.0-rc.1
2.20.0-rc.0
2.19.1
2.19.0
2.18.2
2.18.1
2.18.0
2.18.0-rc.0
2.17.2
2.17.1
2.17.0
2.16.2
2.16.1
2.16.1-rc.0
2.16.0
2.15.0
2.14.1
2.14.0
2.14.0-rc.0
2.13.0
2.12.1
2.12.0
2.11.1
2.11.0
2.10.2
2.10.1
2.10.0
retired
2.9.0
2.8.1
2.8.0
2.7.2
2.7.1
2.7.0
2.6.2
2.6.1
2.6.0
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.2
2.3.1
2.3.0
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.3
retired
2.0.0-rc.2
retired
2.0.0-rc.1
retired
2.0.0-rc.0
retired
1.8.2
1.8.1
1.8.0
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.2
1.5.1
1.5.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
retired
1.4.0-rc.3
retired
1.4.0-rc.2
retired
1.4.0-rc.1
retired
1.4.0-rc.0
retired
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.0
1.0.0-rc.3
retired
1.0.0-rc.2
retired
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.13.1
0.13.0
0.12.2
retired
0.12.1
retired
0.12.0
retired
0.11.0
retired
0.10.0
retired
0.9.0
retired
0.8.3
retired
0.8.2
retired
0.8.1
retired
0.8.0
retired
0.7.0
retired
0.6.2
retired
0.6.1
retired
0.6.0
retired
0.5.2
retired
0.5.1
retired
0.5.0
retired
0.4.2
retired
0.4.1
retired
0.4.0
retired
0.3.0
retired
0.2.1
retired
0.2.0
retired
0.1.3
retired
0.1.2
retired
0.1.1
retired
0.1.0
retired
0.0.20
retired
0.0.19
retired
0.0.18
retired
0.0.17
retired
0.0.16
retired
0.0.15
retired
0.0.14
retired
0.0.13
retired
0.0.12
retired
0.0.11
retired
0.0.10
retired
0.0.8
retired
0.0.7
retired
0.0.6
retired
0.0.5
retired
0.0.4
retired
0.0.3
retired
Common Locale Data Repository (CLDR) functions for Elixir to localize and format numbers, dates, lists, messages, languages, territories and units with support for over 700 locales for internationalized (i18n) and localized (L10N) applications.
Current section
Files
Jump to
Current section
Files
lib/cldr/locale.ex
defmodule Cldr.Locale do
@moduledoc """
Functions to parse and normalize locale names into a structure
locale represented by a `Cldr.LanguageTag`.
CLDR represents localisation data organized into locales, with
each locale being identified by a locale name that is formatted
according to [RFC5646](https://tools.ietf.org/html/rfc5646).
In practise, the CLDR data utilizes a simple subset of locale name
formats being:
* a Language code such as `en` or `fr`
* a Language code and Tertitory code such as `en-GB`
* a Language code and Script such as `zh-Hant`
* and in only two cases a Language code, Territory code and Variant
such as `ca-ES-VALENCIA` and `en-US-POSIX`.
The RFC defines a language tag as:
> A language tag is composed from a sequence of one or more "subtags",
each of which refines or narrows the range of language identified by
the overall tag. Subtags, in turn, are a sequence of alphanumeric
characters (letters and digits), distinguished and separated from
other subtags in a tag by a hyphen ("-", [Unicode] U+002D)
Therefore `Cldr` uses the hyphen ("-", [Unicode] U+002D) as the subtag
separator. On certain platforms, including POSIX platforms, the
subtag separator is a "_" (underscore) rather than a "-" (hyphen). Where
appropriate, `Cldr` will transliterate any underscore into a hyphen before
parsing or processing.
### Locale name validity
When validating a locale name, `Cldr` will attempt to match the requested
locale name to a configured locale. Therefore `Cldr.Locale.new/2` may
return an `{:ok, language_tag}` tuple even when the locale returned does
not exactly match the requested locale name. For example, the following
attempts to create a locale matching the non-existent "english as spoken
in Spain" local name. Here `Cldr` will match to the nearest configured
locale, which in this case will be "en".
iex> Cldr.Locale.new("en-ES", TestBackend.Cldr)
{:ok, %Cldr.LanguageTag{
canonical_locale_name: "en-Latn-ES",
cldr_locale_name: "en",
extensions: %{},
gettext_locale_name: "en",
language: "en",
locale: %{},
private_use: [],
rbnf_locale_name: "en",
requested_locale_name: "en-ES",
script: "Latn",
territory: "ES",
transform: %{},
language_variant: nil
}}
### Matching locales to requested locale names
When attempting to match the requested locale name to a configured
locale, `Cldr` attempt to match against a set of reductions in the
following order and will return the first match:
* language, script, territory, variant
* language, territory, variant
* language, script, variant
* language, variant
* language, script, territory
* language, territory
* language, script
* language
* requested locale name
* nil
Therefore matching is tolerant of a request for unknown scripts,
territories and variants. Only the requested language is a
requirement to be matched to a configured locale.
### Substitutions for Obsolete and Deprecated locale names
CLDR provides data to help manage the transition from obsolete
or deprecated locale names to current names. For example, the
following requests the locale name "mo" which is the deprecated
code for "Moldovian". The replacement code is "ro" (Romanian).
iex> Cldr.Locale.new("mo", TestBackend.Cldr)
{:ok,
%Cldr.LanguageTag{canonical_locale_name: "ro-Latn-MD",
cldr_locale_name: "ro-MD", extensions: %{}, language: "ro",
locale: %{}, private_use: [], rbnf_locale_name: "ro",
requested_locale_name: "mo", script: "Latn", territory: "MD",
transform: %{}, language_variant: nil}}
### Likely subtags
CLDR also provides data to indetify the most likely subtags for a
requested locale name. This data is based on the default content data,
the population data, and the the suppress-script data in [BCP47]. It is
heuristically derived, and may change over time. For example, when
requesting the locale "en", the following is returned:
iex> Cldr.Locale.new("en", TestBackend.Cldr)
{:ok, %Cldr.LanguageTag{
canonical_locale_name: "en-Latn-US",
cldr_locale_name: "en",
extensions: %{},
gettext_locale_name: "en",
language: "en",
locale: %{},
private_use: [],
rbnf_locale_name: "en",
requested_locale_name: "en",
script: "Latn",
territory: "US",
transform: %{},
language_variant: nil
}}
Which shows that a the likely subtag for the script is "Latn" and the likely
territory is "US".
Using the example for Substitutions above, we can see the
result of combining substitutions and likely subtags for locale name "mo"
returns the current language code of "ro" as well as the likely
territory code of "MD" (Moldova).
### Unknown territory codes
Whilst `Cldr` is tolerant of invalid territory codes, it is also important
that such invalid codes not shadow the potential replacement of deprecated
codes nor the insertion of likely subtags. Therefore invalid territory
codes are ignored during this process. For example requesting a locale
name "en-XX" which requests the invalid territory "XX", the following
will be returned:
iex> Cldr.Locale.new("en-XX", TestBackend.Cldr)
{:ok, %Cldr.LanguageTag{
canonical_locale_name: "en-Latn-US",
cldr_locale_name: "en",
extensions: %{},
gettext_locale_name: "en",
language: "en",
locale: %{},
private_use: [],
rbnf_locale_name: "en",
requested_locale_name: "en",
script: "Latn",
territory: "US",
transform: %{},
language_variant: nil
}}
"""
alias Cldr.LanguageTag
import Cldr.Helpers
@typedoc "The name of a locale in a string format"
@type locale_name() :: String.t()
@type language :: String.t() | nil
@type script :: String.t() | nil
@type territory :: String.t() | nil
@type variant :: String.t() | nil
@type subtags :: [String.t(), ...] | []
@doc false
def define_locale_new(config) do
quote location: :keep do
defmodule Locale do
def new(locale_name), do: Cldr.Locale.new(locale_name, unquote(config.backend))
def new!(locale_name), do: Cldr.Locale.new!(locale_name, unquote(config.backend))
end
end
end
defdelegate new(locale_name, backend), to: __MODULE__, as: :canonical_language_tag
defdelegate new!(locale_name, backend), to: __MODULE__, as: :canonical_language_tag!
defdelegate locale_name_to_posix(locale_name), to: Cldr.Config
defdelegate locale_name_from_posix(locale_name), to: Cldr.Config
@doc """
Parses a locale name and returns a `Cldr.LanguageTag` struct
that represents a locale.
## Arguments
* `language_tag` is any language tag returned by `Cldr.Locale.new/2`
or any `locale_name` returned by `Cldr.known_locale_names/1`
* `backend` is any module that includes `use Cldr` and therefore
is a `Cldr` backend module
## Returns
* `{:ok, language_tag}` or
* `{:eror, reason}`
## Method
1. The language tag is parsed in accordance with [RFC5646](https://tools.ietf.org/html/rfc5646)
2. Any language, script or region aliases are replaced. This
will replace any obsolete elements with current versions
3. If a territory or script is not specified, a default is provided
using the CLDR information returned by `Cldr.Locale.likely_subtags/1`
4. A `Cldr` locale name is selected that is the nearest fit to the
requested locale.
## Example
iex> Cldr.Locale.canonical_language_tag("en", TestBackend.Cldr)
{
:ok,
%Cldr.LanguageTag{
canonical_locale_name: "en-Latn-US",
cldr_locale_name: "en",
extensions: %{},
gettext_locale_name: "en",
language: "en",
locale: %{},
private_use: [],
rbnf_locale_name: "en",
requested_locale_name: "en",
script: "Latn",
territory: "US",
transform: %{},
language_variant: nil
}
}
"""
def canonical_language_tag(locale_name, backend)
when is_binary(locale_name) do
if locale_name in backend.known_locale_names do
Cldr.validate_locale(locale_name, backend)
else
case LanguageTag.parse(locale_name) do
{:ok, language_tag} ->
canonical_language_tag(language_tag, backend)
{:error, reason} ->
{:error, reason}
end
end
end
def canonical_language_tag(%LanguageTag{} = language_tag, backend) do
supress_requested_locale_substitution? = !language_tag.language
canonical_tag =
language_tag
|> check_valid_territory
|> put_requested_locale_name(supress_requested_locale_substitution?)
|> substitute_aliases
|> add_likely_subtags
canonical_tag =
canonical_tag
|> Map.put(:canonical_locale_name, locale_name_from(canonical_tag))
|> put_cldr_locale_name(backend)
|> put_rbnf_locale_name(backend)
|> put_gettext_locale_name(backend)
{:ok, canonical_tag}
end
@doc """
Parses a locale name and returns a `Cldr.LanguageTag` struct
that represents a locale or raises on error.
## Arguments
* `language_tag` is any language tag returned by `Cldr.Locale.new/2`
or any `locale_name` returned by `Cldr.known_locale_names/1`
* `backend` is any module that includes `use Cldr` and therefore
is a `Cldr` backend module
See `Cldr.Locale.canonical_language_tag/2` for more information.
"""
@spec canonical_language_tag!(locale_name | Cldr.LanguageTag.t(), Cldr.backend()) ::
Cldr.LanguageTag.t() | none()
def canonical_language_tag!(language_tag, backend) do
case canonical_language_tag(language_tag, backend) do
{:ok, canonical_tag} -> canonical_tag
{:error, {exception, reason}} -> raise exception, reason
end
end
@spec put_requested_locale_name(Cldr.LanguageTag.t(), boolean()) :: Cldr.LanguageTag.t()
defp put_requested_locale_name(language_tag, true) do
language_tag
end
defp put_requested_locale_name(language_tag, false) do
Map.put(language_tag, :requested_locale_name, locale_name_from(language_tag))
end
@spec put_cldr_locale_name(Cldr.LanguageTag.t(), Cldr.backend()) :: Cldr.LanguageTag.t()
defp put_cldr_locale_name(%LanguageTag{} = language_tag, backend) do
cldr_locale_name = cldr_locale_name(language_tag, backend)
%{language_tag | cldr_locale_name: cldr_locale_name}
end
@spec put_rbnf_locale_name(Cldr.LanguageTag.t(), Cldr.backend()) :: Cldr.LanguageTag.t()
defp put_rbnf_locale_name(%LanguageTag{} = language_tag, backend) do
rbnf_locale_name = rbnf_locale_name(language_tag, backend)
%{language_tag | rbnf_locale_name: rbnf_locale_name}
end
@spec put_gettext_locale_name(Cldr.LanguageTag.t(), Cldr.backend()) :: Cldr.LanguageTag.t()
def put_gettext_locale_name(%LanguageTag{} = language_tag, backend) do
gettext_locale_name = gettext_locale_name(language_tag, backend)
%{language_tag | gettext_locale_name: gettext_locale_name}
end
@spec cldr_locale_name(Cldr.LanguageTag.t(), Cldr.backend()) :: locale_name() | nil
defp cldr_locale_name(%LanguageTag{} = language_tag, backend) do
first_match(language_tag, &Cldr.known_locale_name(&1, backend)) ||
Cldr.known_locale_name(language_tag.requested_locale_name, backend) || nil
end
@spec rbnf_locale_name(Cldr.LanguageTag.t(), Cldr.backend()) :: locale_name | nil
defp rbnf_locale_name(%LanguageTag{} = language_tag, backend) do
first_match(language_tag, &Cldr.known_rbnf_locale_name(&1, backend))
end
@spec gettext_locale_name(Cldr.LanguageTag.t(), Cldr.backend()) :: locale_name | nil
defp gettext_locale_name(%LanguageTag{} = language_tag, backend) do
language_tag
|> first_match(&known_gettext_locale_name(&1, backend))
|> locale_name_to_posix
end
@spec known_gettext_locale_name(locale_name(), Cldr.backend() | Cldr.Config.t()) ::
locale_name() | false
def known_gettext_locale_name(locale_name, backend) when is_atom(backend) do
gettext_locales = backend.known_gettext_locale_names
Enum.find(gettext_locales, &Kernel.==(&1, locale_name)) || false
end
# This clause is only called at compile time when we're
# building a backend. In normal use is should not be used.
@doc false
def known_gettext_locale_name(locale_name, config) when is_map(config) do
gettext_locales = Cldr.Config.known_gettext_locale_names(config)
Enum.find(gettext_locales, &Kernel.==(&1, locale_name)) || false
end
defp first_match(
%LanguageTag{
language: language,
script: script,
territory: territory,
language_variant: variant
},
fun
)
when is_function(fun) do
# Including variant
# Not including variant
fun.(locale_name_from(language, script, territory, variant)) ||
fun.(locale_name_from(language, nil, territory, variant)) ||
fun.(locale_name_from(language, script, nil, variant)) ||
fun.(locale_name_from(language, nil, nil, variant)) ||
fun.(locale_name_from(language, script, territory, nil)) ||
fun.(locale_name_from(language, nil, territory, nil)) ||
fun.(locale_name_from(language, script, nil, nil)) ||
fun.(locale_name_from(language, nil, nil, nil)) || nil
end
@doc """
Normalize the casing of a locale name.
## Options
* `locale_name` is any valid locale name returned by `Cldr.known_locale_names/1`
or a `Cldr.LanguageTag` struct
## Returns
* The normalized locale name as a `String.t`
## Method
Locale names are case insensitive but certain common
casing is followed in practise:
* lower case for a language
* capital case for a script
* upper case for a region/territory
**Note** this function is intended to support only the CLDR
locale names which have a format that is a subset of the full
langauge tag specification.
For proper parsing of local names and language tags, see
`Cldr.Locale.canonical_language_tag/2`
## Examples
iex> Cldr.Locale.normalize_locale_name "zh_hant"
"zh-Hant"
iex> Cldr.Locale.normalize_locale_name "en_us"
"en-US"
iex> Cldr.Locale.normalize_locale_name "EN"
"en"
iex> Cldr.Locale.normalize_locale_name "ca_es_valencia"
"ca-ES-VALENCIA"
"""
@spec normalize_locale_name(locale_name) :: locale_name
def normalize_locale_name(locale_name) when is_binary(locale_name) do
case String.split(locale_name, ~r/[-_]/) do
[lang, other] ->
if String.length(other) == 4 do
String.downcase(lang) <> "-" <> String.capitalize(other)
else
String.downcase(lang) <> "-" <> String.upcase(other)
end
[lang, script, region] ->
# Its a lang-script-region
# Its lang-region-variant
if String.length(script) == 4 do
String.downcase(lang) <>
"-" <> String.capitalize(script) <> "-" <> String.upcase(region)
else
String.downcase(lang) <> "-" <> String.upcase(script) <> "-" <> String.upcase(region)
end
[lang] ->
String.downcase(lang)
_ ->
locale_name_from_posix(locale_name)
end
end
@doc """
Return a locale name from a `Cldr.LanguageTag`
## Options
* `locale_name` is any `Cldr.LanguageTag` struct returned by
`Cldr.Locale.new!/2`
## Example
iex> Cldr.Locale.locale_name_from Cldr.Locale.new!("en", TestBackend.Cldr)
"en-Latn-US"
"""
@spec locale_name_from(Cldr.LanguageTag.t()) :: locale_name()
def locale_name_from(%LanguageTag{
language: language,
script: script,
territory: territory,
language_variant: variant
}) do
locale_name_from(language, script, territory, variant)
end
@doc """
Return a locale name by combining language, script, territory and variant
parameters
## Arguments
* `language`, `script`, `territory` and `variant` are string
representations, or `nil`, of the language subtags
## Returns
* The locale name constructed from the non-nil arguments joined
by a "-"
## Example
iex> Cldr.Locale.locale_name_from("en", "Latn", "001", nil)
"en-Latn-001"
"""
@spec locale_name_from(language(), script(), territory(), variant()) :: locale_name()
def locale_name_from(language, script, territory, variant) do
[language, script, territory, variant]
|> Enum.reject(&is_nil/1)
|> Enum.join("-")
end
@doc """
Substitute deprectated subtags with a `Cldr.LanguageTag` with their
non-deprecated alternatives.
## Arguments
* `language_tag` is any language tag returned by `Cldr.Locale.new/2`
## Method
* Replace any deprecated subtags with their canonical values using the alias
data. Use the first value in the replacement list, if
it exists. Language tag replacements may have multiple parts, such as
`sh` âžž `sr_Latn` or `mo` âžž `ro_MD`. In such a case, the original script and/or
region/territory are retained if there is one. Thus `sh_Arab_AQ` âžž `sr_Arab_AQ`, not
`sr_Latn_AQ`.
* Remove the script code 'Zzzz' and the territory code 'ZZ' if they occur.
* Get the components of the cleaned-up source tag (languages, scripts, and
regions/territories), plus any variants and extensions.
## Example
iex> Cldr.Locale.substitute_aliases Cldr.LanguageTag.Parser.parse!("mo")
%Cldr.LanguageTag{
canonical_locale_name: nil,
cldr_locale_name: nil,
extensions: %{},
gettext_locale_name: nil,
language: "ro",
locale: %{},
private_use: [],
rbnf_locale_name: nil,
requested_locale_name: "mo",
script: nil,
territory: "MD",
transform: %{},
language_variant: nil
}
"""
def substitute_aliases(%LanguageTag{} = language_tag) do
language_tag
|> substitute(:language)
|> substitute(:script)
|> substitute(:territory)
|> merge_language_tags(language_tag)
|> remove_unknown(:script)
|> remove_unknown(:territory)
end
defp substitute(%LanguageTag{language: language}, :language) do
aliases(language, :language) || %LanguageTag{}
end
defp substitute(%LanguageTag{script: script} = language_tag, :script) do
%{language_tag | script: aliases(script, :script) || script}
end
defp substitute(%LanguageTag{territory: territory} = language_tag, :territory) do
%{language_tag | territory: aliases(territory, :region) || territory}
end
defp merge_language_tags(alias_tag, original_language_tag) do
Map.merge(alias_tag, original_language_tag, fn
:language, v_alias, v_original ->
if empty?(v_alias), do: v_original, else: v_alias
_k, v_alias, v_original ->
if empty?(v_original), do: v_alias, else: v_original
end)
end
defp remove_unknown(%LanguageTag{script: "Zzzz"} = language_tag, :script) do
%{language_tag | script: nil}
end
defp remove_unknown(%LanguageTag{} = language_tag, :script), do: language_tag
defp remove_unknown(%LanguageTag{territory: "ZZ"} = language_tag, :territory) do
%{language_tag | territory: nil}
end
defp remove_unknown(%LanguageTag{} = language_tag, :territory), do: language_tag
@doc """
Replace empty subtags within a `t:Cldr.LanguageTag.t/0` with the most likely
subtag.
## Options
* `language_tag` is any language tag returned by `Cldr.Locale.new/2`
A subtag is called empty if it has a missing script or territory subtag, or it is
a base language subtag with the value `und`. In the description below,
a subscript on a subtag x indicates which tag it is from: x<sub>s</sub> is in the
source, x<sub>m</sub> is in a match, and x<sub>r</sub> is in the final result.
## Lookup
Lookup each of the following in order, and stops on the first match:
* language<sub>s</sub>-script<sub>s</sub>-region<sub>s</sub>
* language<sub>s</sub>-region<sub>s</sub>
* language<sub>s</sub>-script<sub>s</sub>
* language<sub>s</sub>
* und-script<sub>s</sub>
## Returns
* If there is no match,either return
* an error value, or
* the match for `und`
* Otherwise there is a match = language<sub>m</sub>-script<sub>m</sub>-region<sub>m</sub>
* Let x<sub>r</sub> = x<sub>s</sub> if x<sub>s</sub> is not empty, and x<sub>m</sub> otherwise.
* Return the language tag composed of language<sub>r</sub>-script<sub>r</sub>-region<sub>r</sub> + variants + extensions .
## Example
iex> Cldr.Locale.add_likely_subtags Cldr.LanguageTag.parse!("zh-SG")
%Cldr.LanguageTag{
canonical_locale_name: nil,
cldr_locale_name: nil,
language_subtags: [],
extensions: %{},
gettext_locale_name: nil,
language: "zh",
locale: %{},
private_use: [],
rbnf_locale_name: nil,
requested_locale_name: "zh-SG",
script: "Hans",
territory: "SG",
transform: %{},
language_variant: nil
}
"""
def add_likely_subtags(
%LanguageTag{language: language, script: script, territory: territory} = language_tag
) do
subtags =
likely_subtags(locale_name_from(language, script, territory, nil)) ||
likely_subtags(locale_name_from(language, nil, territory, nil)) ||
likely_subtags(locale_name_from(language, script, nil, nil)) ||
likely_subtags(locale_name_from(language, nil, nil, nil)) ||
likely_subtags(locale_name_from("und", script, nil, nil)) ||
likely_subtags(locale_name_from("und", nil, nil, nil))
Map.merge(subtags, language_tag, fn _k, v1, v2 -> if empty?(v2), do: v1, else: v2 end)
end
@doc """
Returns an error tuple for an invalid locale.
## Arguments
* `locale_name` is any locale name returned by `Cldr.known_locale_names/1`
## Returns
* `{:error, {Cldr.UnknownLocaleError, message}}`
## Examples
iex> Cldr.Locale.locale_error :invalid
{Cldr.UnknownLocaleError, "The locale :invalid is not known."}
"""
@spec locale_error(locale_name() | LanguageTag.t()) :: {Cldr.UnknownLocaleError, String.t()}
def locale_error(%LanguageTag{requested_locale_name: requested_locale_name}) do
locale_error(requested_locale_name)
end
def locale_error(locale_name) do
{Cldr.UnknownLocaleError, "The locale #{inspect(locale_name)} is not known."}
end
@doc """
Returns an error tuple for an invalid gettext locale.
## Options
* `locale_name` is any locale name returned by `Cldr.known_gettext_locale_names/1`
## Returns
* `{:error, {Cldr.UnknownLocaleError, message}}`
## Examples
iex> Cldr.Locale.gettext_locale_error :invalid
{Cldr.UnknownLocaleError, "The gettext locale :invalid is not known."}
"""
@spec gettext_locale_error(locale_name() | LanguageTag.t()) ::
{Cldr.UnknownLocaleError, String.t()}
def gettext_locale_error(%LanguageTag{gettext_locale_name: gettext_locale_name}) do
gettext_locale_error(gettext_locale_name)
end
def gettext_locale_error(locale_name) do
{Cldr.UnknownLocaleError, "The gettext locale #{inspect(locale_name)} is not known."}
end
@doc """
Returns the map of likely subtags.
Note that not all locales are guaranteed
to have likely subtags.
## Example
Cldr.Locale.likely_subtags
%{
"bez" => %Cldr.LanguageTag{
canonical_locale_name: nil,
cldr_locale_name: nil,
extensions: %{},
language: "bez",
locale: %{},
private_use: [],
rbnf_locale_name: nil,
requested_locale_name: nil,
script: "Latn",
territory: "TZ",
transform: %{},
language_variant: nil
},
"fuf" => %Cldr.LanguageTag{
canonical_locale_name: nil,
cldr_locale_name: nil,
extensions: %{},
language: "fuf",
locale: %{},
private_use: [],
rbnf_locale_name: nil,
requested_locale_name: nil,
script: "Latn",
territory: "GN",
transform: %{},
language_variant: nil
},
...
"""
@likely_subtags Cldr.Config.likely_subtags()
def likely_subtags do
@likely_subtags
end
@doc """
Returns the likely substags, as a `Cldr.LanguageTag`,
for a given locale name.
## Options
* `locale` is any valid locale name returned by `Cldr.known_locale_names/1`
or a `Cldr.LanguageTag` struct
## Examples
iex> Cldr.Locale.likely_subtags "en"
%Cldr.LanguageTag{
canonical_locale_name: nil,
cldr_locale_name: nil,
extensions: %{},
gettext_locale_name: nil,
language: "en",
locale: %{},
private_use: [],
rbnf_locale_name: nil,
requested_locale_name: "en-Latn-US",
script: "Latn",
territory: "US",
transform: %{},
language_variant: nil
}
"""
@spec likely_subtags(locale_name) :: LanguageTag.t() | nil
def likely_subtags(locale_name) when is_binary(locale_name) do
Map.get(likely_subtags(), locale_name)
end
def likely_subtags(%LanguageTag{requested_locale_name: requested_locale_name}) do
likely_subtags(requested_locale_name)
end
@doc """
Return a map of the known aliases for Language, Script and Territory
"""
@aliases Cldr.Config.aliases()
@spec aliases :: map()
def aliases do
@aliases
end
@doc """
Return a map of the aliases for a given alias key and type
## Options
* `type` is one of `[:language, :region, :script, :variant, :zone]`
* `key` is the substitution key (a language, region, script, variant or zone)
"""
@alias_keys Map.keys(@aliases)
@spec aliases(locale_name(), atom()) :: map() | nil
def aliases(key, type) when type in @alias_keys do
aliases()
|> Map.get(type)
|> Map.get(key)
end
@doc """
Returns an error tuple for an invalid locale alias.
## Options
* `locale_name` is any locale name returned by `Cldr.known_locale_names/1`
"""
@spec alias_error(locale_name() | LanguageTag.t(), String.t()) ::
{Cldr.UnknownLocaleError, String.t()}
def alias_error(locale_name, alias_name) when is_binary(locale_name) do
{
Cldr.UnknownLocaleError,
"The locale #{inspect(locale_name)} and its " <>
"alias #{inspect(alias_name)} are not known."
}
end
def alias_error(%LanguageTag{requested_locale_name: requested_locale_name}, alias_name) do
alias_error(requested_locale_name, alias_name)
end
defp check_valid_territory(%LanguageTag{territory: nil} = language_tag), do: language_tag
defp check_valid_territory(%LanguageTag{territory: territory} = language_tag) do
territory =
try do
code = String.to_existing_atom(territory)
if code in Cldr.known_territories(), do: territory, else: nil
rescue
ArgumentError ->
nil
end
%{language_tag | territory: territory}
end
end