Cldr v2.20.0-rc.0 Cldr.Locale View Source
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.
In practise, the CLDR data utilizes a simple subset of locale name formats being:
a Language code such as
en
orfr
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
anden-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{
backend: TestBackend.Cldr,
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{
backend: TestBackend.Cldr,
extensions: %{},
gettext_locale_name: nil,
language: "ro",
language_subtags: [],
language_variant: nil,
locale: %{}, private_use: [],
rbnf_locale_name: "ro",
requested_locale_name: "mo",
script: "Latn",
transform: %{},
canonical_locale_name: "ro-Latn-RO",
cldr_locale_name: "ro",
territory: :RO
}}
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{
backend: TestBackend.Cldr,
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{
backend: TestBackend.Cldr,
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
}}
Locale extensions
Unicode defines the U extension which support defining the requested treatment of CLDR data formats. For example, a locale name can configure the requested:
- calendar to be used for dates
- collation
- currency
- currency format
- number system
- first day of the week
- 12-hour or 24-hour time
- time zone
- and many other items
For example, the following locale name will request the use of the timezone Australia/Sydney
,
and request the use of accounting
format when formatting currencies:
iex> MyApp.Cldr.validate_locale "en-AU-u-tz-ausyd-cf-account"
{
:ok,
%Cldr.LanguageTag{
backend: MyApp.Cldr,
canonical_locale_name: "en-Latn-AU",
cldr_locale_name: "en-AU",
extensions: %{},
gettext_locale_name: "en",
language: "en",
language_subtags: '',
language_variant: nil,
locale: %Cldr.LanguageTag.U{
alternative_collation: nil,
backward_level2: nil,
calendar: nil,
case_first: nil,
case_level: nil,
collation: nil,
currency: nil,
currency_format: :accounting,
emoji_style: nil,
first_day_of_week: nil,
hiragana_quarternary: nil,
hour_cycle: nil,
line_break_style: nil,
line_break_word: nil,
measurement_system: nil,
normalization: nil,
number_system: nil,
numeric: nil,
region_override: nil,
reorder: nil,
sentence_break_supression: nil,
strength: nil,
subdivision: nil,
timezone: "ausyd",
variable_top: nil,
variant: nil
},
private_use: '',
rbnf_locale_name: "en",
requested_locale_name: "en-AU",
script: "Latn",
territory: :AU,
transform: %{}
}
}
Link to this section Summary
Types
The name of a locale in a string format
Functions
Replace empty subtags within a Cldr.LanguageTag.t/0
with the most likely
subtag.
Returns an error tuple for an invalid locale alias.
Return a map of the known aliases for Language, Script and Territory
Return a map of the aliases for a given alias key and type
Parses a locale name and returns a Cldr.LanguageTag
struct
that represents a locale.
Parses a locale name and returns a Cldr.LanguageTag
struct
that represents a locale or raises on error.
Returns an error tuple for an invalid gettext locale.
Returns the map of likely subtags.
Returns the likely substags, as a Cldr.LanguageTag
,
for a given locale name.
Returns an error tuple for an invalid locale.
Return a locale name from a Cldr.LanguageTag
Return a locale name by combining language, script, territory and variant parameters
See Cldr.Config.locale_name_from_posix/1
.
See Cldr.Config.locale_name_to_posix/1
.
Normalize the casing of a locale name.
Returns the parent for a given locale.
Returns mappings between a locale and its parent.
Returns a list of all the parent locales for a given locale.
Substitute deprectated subtags with a Cldr.LanguageTag
with their
non-deprecated alternatives.
Returns the effective territory for a locale.
Returns the effective territory for a locale.
Returns the effective time zone for a locale.
Returns the effective time zone for a locale.
Link to this section Types
Link to this section Functions
Replace empty subtags within a Cldr.LanguageTag.t/0
with the most likely
subtag.
Options
language_tag
is any language tag returned byCldr.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{
backend: nil,
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
}
Specs
alias_error(locale_name() | Cldr.LanguageTag.t(), String.t()) :: {Cldr.UnknownLocaleError, String.t()}
Returns an error tuple for an invalid locale alias.
Options
locale_name
is any locale name returned byCldr.known_locale_names/1
Specs
aliases() :: map()
Return a map of the known aliases for Language, Script and Territory
Specs
aliases(locale_name(), atom()) :: map() | nil
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)
Parses a locale name and returns a Cldr.LanguageTag
struct
that represents a locale.
Arguments
language_tag
is any language tag returned byCldr.Locale.new/2
or anylocale_name
returned byCldr.known_locale_names/1
backend
is any module that includesuse Cldr
and therefore is aCldr
backend module
Returns
{:ok, language_tag}
or{:eror, reason}
Method
The language tag is parsed in accordance with RFC5646
Any language, script or region aliases are replaced. This will replace any obsolete elements with current versions
If a territory or script is not specified, a default is provided using the CLDR information returned by
Cldr.Locale.likely_subtags/1
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{
backend: TestBackend.Cldr,
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
}
}
Specs
canonical_language_tag!(locale_name() | Cldr.LanguageTag.t(), Cldr.backend()) :: Cldr.LanguageTag.t() | none()
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 byCldr.Locale.new/2
or anylocale_name
returned byCldr.known_locale_names/1
backend
is any module that includesuse Cldr
and therefore is aCldr
backend module
See Cldr.Locale.canonical_language_tag/2
for more information.
Specs
gettext_locale_error(locale_name() | Cldr.LanguageTag.t()) :: {Cldr.UnknownLocaleError, String.t()}
Returns an error tuple for an invalid gettext locale.
Options
locale_name
is any locale name returned byCldr.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."}
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{
backend: TestBackend.Cldr,
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
},
...
Specs
likely_subtags(locale_name()) :: Cldr.LanguageTag.t() | nil
Returns the likely substags, as a Cldr.LanguageTag
,
for a given locale name.
Options
locale
is any valid locale name returned byCldr.known_locale_names/1
or aCldr.LanguageTag
struct
Examples
iex> Cldr.Locale.likely_subtags "en"
%Cldr.LanguageTag{
backend: nil,
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
}
Specs
locale_error(locale_name() | Cldr.LanguageTag.t()) :: {Cldr.UnknownLocaleError, String.t()}
Returns an error tuple for an invalid locale.
Arguments
locale_name
is any locale name returned byCldr.known_locale_names/1
Returns
{:error, {Cldr.UnknownLocaleError, message}}
Examples
iex> Cldr.Locale.locale_error :invalid
{Cldr.UnknownLocaleError, "The locale :invalid is not known."}
Specs
locale_name_from(Cldr.LanguageTag.t()) :: locale_name()
Return a locale name from a Cldr.LanguageTag
Options
locale_name
is anyCldr.LanguageTag
struct returned byCldr.Locale.new!/2
Example
iex> Cldr.Locale.locale_name_from Cldr.Locale.new!("en", TestBackend.Cldr)
"en-Latn-US"
Specs
locale_name_from( language(), script(), Cldr.territory() | territory(), variant() ) :: locale_name()
Return a locale name by combining language, script, territory and variant parameters
Arguments
language
,script
,territory
andvariant
are string representations, ornil
, 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"
iex> Cldr.Locale.locale_name_from("en", "Latn", :"001", nil)
"en-Latn-001"
See Cldr.Config.locale_name_from_posix/1
.
See Cldr.Config.locale_name_to_posix/1
.
Specs
normalize_locale_name(locale_name()) :: locale_name()
Normalize the casing of a locale name.
Options
locale_name
is any valid locale name returned byCldr.known_locale_names/1
or aCldr.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"
Specs
parent(Cldr.LanguageTag.t()) :: {:ok, Cldr.LanguageTag.t()} | {:error, {module(), binary()}}
Returns the parent for a given locale.
The function implements locale inheritance in accordance with CLDR's inheritance rules.
Only locales that are configured are returned. That is, there may be a different parent locale in CLDR but unless those locales are configured they are not candidates to be parents in this context. The contract is to return either a known locale or an error.
Inheritance
Inheritance starts by looking for a parent locale via
Cldr.Config.parent_locales/0
.If not found, strip in turn the variant, script and territory while checking to see if a base locale for the given language exists.
If no parent language exists then move to the default locale and its inheritance chain.
As a last resort, use the
root
locale.
Specs
parent(locale_name(), Cldr.backend()) :: {:ok, Cldr.LanguageTag.t()} | {:error, {module(), binary()}}
Returns mappings between a locale and its parent.
The mappings exist only where normal inheritance rules are not applied.
Returns a list of all the parent locales for a given locale.
Specs
put_gettext_locale_name(Cldr.LanguageTag.t(), Cldr.backend()) :: Cldr.LanguageTag.t()
Substitute deprectated subtags with a Cldr.LanguageTag
with their
non-deprecated alternatives.
Arguments
language_tag
is any language tag returned byCldr.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
ormo
➞ro_MD
. In such a case, the original script and/or region/territory are retained if there is one. Thussh_Arab_AQ
➞sr_Arab_AQ
, notsr_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{
backend: nil,
canonical_locale_name: nil,
cldr_locale_name: nil,
extensions: %{},
gettext_locale_name: nil,
language: "ro",
language_subtags: [],
language_variant: nil,
locale: %{}, private_use: [],
rbnf_locale_name: nil,
requested_locale_name: "mo",
script: nil, transform: %{},
territory: nil
}
Specs
territory_from_locale(Cldr.LanguageTag.t() | locale_name()) :: Cldr.territory()
Returns the effective territory for a locale.
Arguments
language_tag
is any language tag returned byCldr.Locale.new/2
or anylocale_name
returned byCldr.known_locale_names/1
. If the parameter is alocale_name
then a default backend must be configured inconfig.exs
or an exception will be raised.
Returns
- The territory to be used for localization purposes.
Examples
iex> Cldr.Locale.territory_from_locale "en-US"
:US
iex> Cldr.Locale.territory_from_locale "en-US-u-rg-cazzzz"
:CA
iex> Cldr.Locale.territory_from_locale "en-US-u-rg-xxxxx"
:US
Notes
A locale can reflect the desired territory to be used when determining region-specific defaults for items such as:
- default currency,
- default calendar and week data,
- default time cycle, and
- default measurement system and unit preferences
Territory information is stored in the locale in up to three different places:
The
:territory
extracted from the locale name or defined by default for a given language. This is the typical use case when locale names such asen-US
ores-AR
are used.In some cases it might be desirable to override the territory derived from the locale name. For example, the default territory for the language "en" is "US" but it may be desired to apply the defaults for the territory "AU" instead, without otherwise changing the localization intent. In this case the U extension is used to define a regional override.
Similarly, the [regional subdivision identifier] (https://unicode.org/reports/tr35/#UnicodeSubdivisionIdentifier) can be used to influence localization decisions. This identifier is not currently used in
ex_cldr
and dependent libraries however it is correctly parsed to support future use.
Specs
territory_from_locale(locale_name(), Cldr.backend()) :: Cldr.territory() | {:error, {module(), String.t()}}
Returns the effective territory for a locale.
Arguments
locale_name
is any locale name returned byCldr.known_locale_names/1
.backend
is any module that includesuse Cldr
and therefore is aCldr
backend module.
Returns
- The territory to be used for localization purposes or
{:error, {exception, reason}}
.
Examples
iex> Cldr.Locale.territory_from_locale "en-US", TestBackend.Cldr
:US
iex> Cldr.Locale.territory_from_locale "en-US-u-rg-cazzzz", TestBackend.Cldr
:CA
iex> Cldr.Locale.territory_from_locale "en-US-u-rg-xxxxx", TestBackend.Cldr
:US
Notes
A locale can reflect the desired territory to be used when determining region-specific defaults for items such as:
- default currency,
- default calendar and week data,
- default time cycle, and
- default measurement system and unit preferences
Territory information is stored in the locale in up to three different places:
The
:territory
extracted from the locale name or defined by default for a given language. This is the typical use case when locale names such asen-US
ores-AR
are used.In some cases it might be desirable to override the territory derived from the locale name. For example, the default territory for the language "en" is "US" but it may be desired to apply the defaults for the territory "AU" instead, without otherwise changing the localization intent. In this case the U extension is used to define a regional override.
Similarly, the [regional subdivision identifier] (https://unicode.org/reports/tr35/#UnicodeSubdivisionIdentifier) can be used to influence localization decisions. This identifier is not currently used in
ex_cldr
and dependent libraries however it is correctly parsed to support future use.
Specs
timezone_from_locale(Cldr.LanguageTag.t() | locale_name()) :: String.t() | {:error, {module(), String.t()}}
Returns the effective time zone for a locale.
Arguments
language_tag
is any language tag returned byCldr.Locale.new/2
or anylocale_name
returned byCldr.known_locale_names/1
. If the parameter is alocale_name
then a default backend must be configured inconfig.exs
or an exception will be raised.
Returns
- The time zone ID as a
String.t
or{:error, {exception, reason}}
Examples
iex> Cldr.Locale.timezone_from_locale "en-US-u-tz-ausyd"
"Australia/Sydney"
iex> Cldr.Locale.timezone_from_locale "en-AU"
{:error,
{Cldr.AmbiguousTimezoneError,
"Cannot determine the timezone since the territory :AU has 24 timezone IDs"}}
Specs
timezone_from_locale(locale_name(), Cldr.backend()) :: String.t() | {:error, {module(), String.t()}}
Returns the effective time zone for a locale.
Arguments
locale_name
is any name returned byCldr.known_locale_names/1
backend
is any module that includesuse Cldr
and therefore is aCldr
backend module
Returns
- The time zone ID as a
String.t
or{:error, {exception, reason}}
Examples
iex> Cldr.Locale.timezone_from_locale "en-US-u-tz-ausyd", TestBackend.Cldr
"Australia/Sydney"
iex> Cldr.Locale.timezone_from_locale "en-AU", TestBackend.Cldr
{:error,
{Cldr.AmbiguousTimezoneError,
"Cannot determine the timezone since the territory :AU has 24 timezone IDs"}}