Locale-aware formatting, validation, and data access built on the Unicode CLDR repository.
Localize consolidates the functionality of the ex_cldr_* library
family into a single package with no compile-time backend
configuration. All CLDR data is loaded at runtime from ETF and JSON
files and cached in :persistent_term on first access.
Primary usage modules
Localize.Number— format numbers, decimals, percentages, and currencies.Localize.Date— format dates using CLDR calendar patterns.Localize.Time— format times using CLDR calendar patterns.Localize.DateTime— format date-times with combined date and time patterns.Localize.Interval— format date, time, and datetime intervals.Localize.Unit— format units of measure with plural-aware patterns (e.g., "3 kilometers", "1.5 hours").Localize.List— format lists with locale-appropriate conjunctions and disjunctions (e.g., "a, b, and c").Localize.Currency— currency metadata, validation, and territory-to-currency mapping.Localize.Territory— territory display names, containment, subdivisions, and emoji flags.Localize.Language— language display names.Localize.Collation— locale-sensitive string sorting using the Unicode Collation Algorithm.Localize.Locale.LocaleDisplay— full locale display names (e.g., "English (United States)").Localize.Calendar— calendar era names, day/month names, and day period names.
Locale management
Localize maintains a per-process current locale and an application-wide default locale:
get_locale/0— returns the current process locale, falling back todefault_locale/0.put_locale/1— sets the current process locale.with_locale/2— executes a function with a temporary locale.default_locale/0— returns the application-wide default, resolved from environment variables and application config.put_default_locale/1— overrides the application-wide default.
All formatting functions default their :locale option to
get_locale/0 when no locale is explicitly provided.
This module
This module also provides text formatting helpers (quote/2,
ellipsis/2), validators for locales, territories, scripts,
calendars, number systems, currencies, and measurement systems,
and accessors for known locale names and territory lists.
Optional NIF
An optional NIF-based implementation of selected algorithms
(currently Unicode normalisation and collation sort-key generation)
can be enabled by setting LOCALIZE_NIF=true at compile time. See
Localize.Nif for details.
Summary
Types
A locale identifier atom or a language tag struct.
A locale identifier. That is, known to CLDR
Functions
Returns a list of all known CLDR locale name atoms.
Returns a list of all known CLDR locale ID atoms at or above the given coverage level.
Returns whether a locale name is available in the CLDR repository.
Returns the application-wide default locale as a
Localize.LanguageTag.t/0.
Adds locale-specific ellipsis characters to a string or between two strings.
Returns the locale for the current process as a
Localize.LanguageTag.t/0.
Returns a list of all known CLDR calendar types as atoms.
Returns a list of all known CLDR number system atoms.
Returns the list of canonical measurement system atoms.
Sets the application-wide default locale.
Sets the locale for the current process.
Sets the list of supported locales in :persistent_term.
Wraps a string in locale-specific quotation marks.
Returns the list of supported locales configured via
config :localize, supported_locales: [...] or
Localize.all_locale_ids/0.
Formats value as a localized string.
Formats value as a localized string with the given options.
Same as to_string/1 but returns the formatted string directly
or raises on error.
Same as to_string/2 but returns the formatted string directly
or raises on error.
Validates a calendar name.
Validates a locale identifier or language tag.
Validates a measurement system type.
Validates a number system name.
Validates a script code.
Validates a territory code.
Validates a territory subdivision code.
Returns the CLDR version this build of Localize targets.
Executes a function with a temporary process locale.
Types
@type locale() :: locale_id() | Localize.LanguageTag.t()
A locale identifier atom or a language tag struct.
@type locale_id() :: atom()
A locale identifier. That is, known to CLDR
Functions
@spec all_locale_ids() :: [atom()]
Returns a list of all known CLDR locale name atoms.
Returns
- A list of locale name atoms.
Examples
iex> locales = Localize.all_locale_ids()
iex> :en in locales
true
@spec all_locale_ids(:basic | :moderate | :modern) :: [atom()]
Returns a list of all known CLDR locale ID atoms at or above the given coverage level.
CLDR assigns each locale a coverage level of :basic,
:moderate, or :modern. A locale at the :modern level is
also included when requesting :moderate or :basic. A locale
at :moderate is also included when requesting :basic.
Arguments
levelis one of:basic,:moderate, or:modern.
Returns
- A sorted list of locale ID atoms.
Examples
iex> locales = Localize.all_locale_ids(:modern)
iex> :en in locales
true
iex> length(Localize.all_locale_ids(:basic)) >= length(Localize.all_locale_ids(:modern))
true
Returns whether a locale name is available in the CLDR repository.
Arguments
locale_nameis a locale identifier atom or string.
Returns
trueif the locale is available in CLDR.falseotherwise.
Examples
iex> Localize.available_locale_id?(:en)
true
iex> Localize.available_locale_id?(:zzzz)
false
@spec default_locale() :: Localize.LanguageTag.t()
Returns the application-wide default locale as a
Localize.LanguageTag.t/0.
The default locale is resolved once on first access using the following precedence chain:
A value previously set via
put_default_locale/1.The
LOCALIZE_DEFAULT_LOCALEenvironment variable.The
:default_localekey in the:localizeapplication environment (e.g.,config :localize, default_locale: :fr).The
LANGenvironment variable (e.g.,"en_US.UTF-8"), with the charset suffix stripped.:enas a final fallback.
The resolved locale is validated via validate_locale/1 and
cached in :persistent_term so subsequent calls are free. If
any source provides an invalid locale, a warning is logged and
the next source in the chain is tried.
Returns
Examples
iex> %Localize.LanguageTag{} = Localize.default_locale()
iex> Localize.default_locale().cldr_locale_id
:en
@spec ellipsis(String.t() | [String.t()], Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}
Adds locale-specific ellipsis characters to a string or between two strings.
Uses the CLDR ellipsis patterns for the given locale.
Arguments
stringis either a single string or a list of two strings to join with an ellipsis between them.optionsis a keyword list of options.
Options
:localeis a locale identifier atom, string, or aLocalize.LanguageTag.t/0. The default is:en.:locationdetermines where the ellipsis is placed. Valid values are:after(append),:before(prepend), and:between(medial, requires a two-element list). The default is:afterfor a single string and:betweenfor a list.:formatis either:sentenceor:word. The:wordformat includes a space between the text and the ellipsis. The default is:sentence.
Returns
{:ok, ellipsized_string}with locale-specific ellipsis applied.{:error, exception}if the locale data cannot be loaded.
Examples
iex> Localize.ellipsis("And so on")
{:ok, "And so on…"}
iex> Localize.ellipsis("And so on", location: :before)
{:ok, "…And so on"}
iex> Localize.ellipsis(["start", "end"])
{:ok, "start…end"}
iex> Localize.ellipsis("And so on", format: :word)
{:ok, "And so on …"}
@spec get_locale() :: Localize.LanguageTag.t()
Returns the locale for the current process as a
Localize.LanguageTag.t/0.
If no locale has been set for the current process via
put_locale/1, returns default_locale/0.
Returns
Examples
iex> %Localize.LanguageTag{} = Localize.get_locale()
iex> Localize.get_locale().cldr_locale_id
:en
@spec known_calendars() :: [atom(), ...]
Returns a list of all known CLDR calendar types as atoms.
The calendar types are internal CLDR values to identify localized month and day names, era names and other calendarical data.
The calendars defined in the localzie_calendars embed the appropriate CLDR calendar type to support localization.
Returns
- A list of calendar type atoms.
Examples
iex> Localize.known_calendars()
[:gregorian, :buddhist, :chinese, :coptic, :dangi, :ethiopic,
:ethiopic_amete_alem, :hebrew, :indian, :islamic, :islamic_civil,
:islamic_rgsa, :islamic_tbla, :islamic_umalqura, :japanese, :persian, :roc]
@spec known_number_systems() :: [atom()]
Returns a list of all known CLDR number system atoms.
Returns
- A list of number system atoms.
Examples
iex> systems = Localize.known_number_systems()
iex> :latn in systems
true
@spec measurement_systems() :: [atom()]
Returns the list of canonical measurement system atoms.
The canonical names are derived from bcp47/measure.xml and
mapped to the short forms :metric, :us, and :uk.
Returns
- A list of measurement system atoms.
Examples
iex> Localize.measurement_systems()
[:metric, :uk, :us]
@spec put_default_locale(Localize.LanguageTag.t() | atom() | String.t()) :: {:ok, Localize.LanguageTag.t()} | {:error, Exception.t()}
Sets the application-wide default locale.
The locale is validated via validate_locale/1 and the
resulting Localize.LanguageTag.t/0 is cached in
:persistent_term. This value is used as the fallback when
no process-level locale has been set via put_locale/1.
Arguments
localeis a locale identifier atom, string, or aLocalize.LanguageTag.t/0.
Returns
{:ok, language_tag}on success.{:error, exception}if the locale is not valid.
Examples
iex> {:ok, tag} = Localize.put_default_locale(:fr)
iex> tag.cldr_locale_id
:fr
iex> Localize.default_locale().cldr_locale_id
:fr
iex> {:ok, _} = Localize.put_default_locale(:en)
@spec put_locale(Localize.LanguageTag.t() | atom() | String.t()) :: {:ok, Localize.LanguageTag.t()} | {:error, Exception.t()}
Sets the locale for the current process.
The locale is validated via validate_locale/1 and stored
in the process dictionary as a Localize.LanguageTag.t/0.
It is used as the default by all formatting functions in this
process. It does not propagate to spawned processes — use
with_locale/2 or explicitly pass the locale when spawning
tasks.
Arguments
localeis a locale identifier atom, string, or aLocalize.LanguageTag.t/0.
Returns
{:ok, language_tag}on success. The previous locale (ornil) can be retrieved from the process dictionary before calling this function if needed.{:error, exception}if the locale is not valid.
Examples
iex> {:ok, _} = Localize.put_locale(:de)
iex> Localize.get_locale().cldr_locale_id
:de
iex> {:ok, _} = Localize.put_locale(:en)
@spec put_supported_locales([atom()]) :: :ok
Sets the list of supported locales in :persistent_term.
This function does not modify the application configuration.
It directly updates the runtime cache that supported_locales/0
reads from.
Arguments
localesis a list of locale ID atoms.
Returns
:ok.
Examples
iex> original = Localize.supported_locales()
iex> Localize.put_supported_locales([:en, :fr, :de])
:ok
iex> Localize.put_supported_locales(original)
:ok
iex> original = Localize.supported_locales()
iex> Localize.put_supported_locales([:en, :fr, :de])
:ok
iex> Localize.supported_locales()
[:en, :fr, :de]
iex> Localize.put_supported_locales(original)
:ok
@spec quote(String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}
Wraps a string in locale-specific quotation marks.
Uses the CLDR delimiters data for the given locale to apply the appropriate opening and closing quotation marks.
Arguments
stringis the text to quote.optionsis a keyword list of options.
Options
:localeis a locale identifier atom, string, or aLocalize.LanguageTag.t/0. The default is:en.:styleis either:defaultor:variant. The default style uses the primary quotation marks for the locale. The:variantstyle uses the alternate (nested) quotation marks.
Returns
{:ok, quoted_string}wherequoted_stringhas locale-specific quotation marks added.{:error, exception}if the locale data cannot be loaded.
Examples
iex> Localize.quote("Hello")
{:ok, "“Hello”"}
iex> Localize.quote("Hello", style: :variant)
{:ok, "‘Hello’"}
@spec supported_locales() :: [atom()]
Returns the list of supported locales configured via
config :localize, supported_locales: [...] or
Localize.all_locale_ids/0.
The returned list contains canonical CLDR locale ID atoms, resolved and validated at application startup.
Returns
- A list of locale ID atoms.
@spec to_string(term()) :: {:ok, String.t()} | {:error, Exception.t()}
Formats value as a localized string.
Delegates to Localize.Chars.to_string/1. Equivalent to
calling Localize.to_string(value, []).
Built-in locale-aware implementations exist for Integer,
Float, Decimal, Date, Time, DateTime, NaiveDateTime,
Range, BitString, List, Localize.Unit, Localize.Duration,
Localize.LanguageTag, and Localize.Currency. Any other type
falls through to Kernel.to_string/1, so atoms, charlists,
booleans, and nil produce the same output they would from
Kernel.to_string/1. Types with no String.Chars implementation
either (tuples, plain maps, PIDs, references, anonymous functions)
raise Protocol.UndefinedError.
See Localize.Chars for the full list and instructions on
adding implementations for your own types.
Kernel.to_string/1 shadowing
Kernel.to_string/1 is auto-imported into every module. If
you import Localize in your own code, the import shadows
the kernel function inside that module. Use the qualified
form Localize.to_string/1 (recommended) or
import Localize, except: [to_string: 1, to_string: 2].
Returns
{:ok, formatted_string}on success.{:error, exception}on failure.
Examples
iex> Localize.to_string(1234.5, locale: :de)
{:ok, "1.234,5"}
iex> Localize.to_string(~D[2025-07-10], locale: :en)
{:ok, "Jul 10, 2025"}
@spec to_string(term(), Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}
Formats value as a localized string with the given options.
Delegates to Localize.Chars.to_string/2. See to_string/1
for the list of supported types and the Kernel.to_string/1
shadowing note.
Arguments
valueis any term that has aLocalize.Charsimplementation.optionsis a keyword list of options forwarded to the underlying formatter. Every implementation accepts at least:locale.
Returns
{:ok, formatted_string}on success.{:error, exception}on failure.
Examples
iex> Localize.to_string(1234.5, locale: :en)
{:ok, "1,234.5"}
iex> {:ok, unit} = Localize.Unit.new(42, "kilometer")
iex> Localize.to_string(unit, format: :short, locale: :en)
{:ok, "42 km"}
Same as to_string/1 but returns the formatted string directly
or raises on error.
Examples
iex> Localize.to_string!(1234.5, locale: :de)
"1.234,5"
Same as to_string/2 but returns the formatted string directly
or raises on error.
Examples
iex> Localize.to_string!(~D[2025-07-10], locale: :de, format: :long)
"10. Juli 2025"
@spec validate_calendar(atom() | String.t()) :: {:ok, atom()} | {:error, Exception.t()}
Validates a calendar name.
Checks the calendar against the list of known CLDR calendars.
The string "gregory" is accepted as an alias for :gregorian.
Arguments
calendaris a calendar name atom or string.
Returns
{:ok, calendar_atom}wherecalendar_atomis the normalised calendar atom.{:error, exception}if the calendar is not known.
Examples
iex> Localize.validate_calendar(:gregorian)
{:ok, :gregorian}
iex> Localize.validate_calendar("persian")
{:ok, :persian}
iex> Localize.validate_calendar(:unknown)
{:error, %Localize.UnknownCalendarError{calendar: :unknown}}
@spec validate_locale(Localize.LanguageTag.t() | String.t() | atom()) :: {:ok, Localize.LanguageTag.t()} | {:error, Exception.t()}
Validates a locale identifier or language tag.
Ensures that the given locale can be resolved to a known CLDR
locale. When given a binary locale identifier, it is parsed into
a Localize.LanguageTag.t/0. When given an existing language tag
whose :cldr_locale_id is not yet populated, a best-match
resolution is attempted using Localize.LanguageTag.best_match/3.
POSIX-style locale names (e.g. "pt_BR", "zh_Hans") are
accepted — underscores are normalized to hyphens before parsing.
Locale resolution
The :cldr_locale_id field on the returned language tag is
derived by matching the parsed tag against a list of candidate
locale IDs:
If
config :localize, supported_locales: [...]is configured, the candidate list is the resolved supported locales. This restricts matching to only the locales your application explicitly supports.If
:supported_localesis not configured, the candidate list is all CLDR locale IDs.
Validated locale results are cached in an ETS table so repeated calls with the same identifier are fast (~1µs).
Always returns a result
This function uses the CLDR locale matching algorithm, which
is designed to always return a result when the candidate
list is non-empty — even if the match is very distant. For
example, validate_locale("xyzzy") will succeed and return
some CLDR locale (typically the first candidate), not an error.
This is the correct CLDR behaviour for user-facing locale
negotiation (a distant match is better than no match), but it
means the returned locale may not be what the caller expected.
For strict validation (e.g. resolving configuration values),
use Localize.LanguageTag.best_match/3 with a threshold of
0 to accept only exact matches after likely-subtag
resolution.
Arguments
localeis a locale identifier binary, an atom, or aLocalize.LanguageTag.t/0.
Returns
{:ok, language_tag}wherelanguage_tagis aLocalize.LanguageTag.t/0with a populated:cldr_locale_id.{:error, Localize.InvalidLocaleError.t()}if the locale identifier cannot be parsed into a valid language tag.{:error, Localize.UnknownLocaleError.t()}if the locale parses successfully but does not match any known CLDR locale (or any supported locale, when configured).
Examples
iex> {:ok, tag} = Localize.validate_locale("en")
iex> tag.cldr_locale_id
:en
iex> {:ok, tag} = Localize.validate_locale("pt_BR")
iex> tag.cldr_locale_id
:pt
@spec validate_measurement_system(atom() | String.t()) :: {:ok, atom()} | {:error, Exception.t()}
Validates a measurement system type.
Accepts canonical names (:metric, :us, :uk) as well as
aliases defined in CLDR (:imperial, :ussystem, :uksystem).
Aliases are resolved to the canonical short name.
Arguments
systemis a measurement system atom or string.
Returns
{:ok, canonical_atom}wherecanonical_atomis the canonical measurement system atom.{:error, exception}if the measurement system is not known.
Examples
iex> Localize.validate_measurement_system(:metric)
{:ok, :metric}
iex> Localize.validate_measurement_system("us")
{:ok, :us}
iex> Localize.validate_measurement_system(:imperial)
{:ok, :uk}
iex> Localize.validate_measurement_system(:ussystem)
{:ok, :us}
iex> Localize.validate_measurement_system(:klingon)
{:error, %Localize.UnknownMeasurementSystemError{measurement_system: :klingon}}
@spec validate_number_system(atom() | String.t()) :: {:ok, atom()} | {:error, Exception.t()}
Validates a number system name.
Checks the number system against the list of known CLDR number systems.
Arguments
number_systemis a number system name atom or string.
Returns
{:ok, number_system_atom}wherenumber_system_atomis the normalised number system atom.{:error, exception}if the number system is not known.
Examples
iex> Localize.validate_number_system(:latn)
{:ok, :latn}
iex> Localize.validate_number_system("arab")
{:ok, :arab}
iex> Localize.validate_number_system(:unknown)
{:error, %Localize.UnknownNumberSystemError{number_system: :unknown}}
@spec validate_script(atom() | String.t()) :: {:ok, atom()} | {:error, Exception.t()}
Validates a script code.
Normalises the script code (capitalised form, e.g., "Latn")
and checks it against the CLDR validity data.
Arguments
scriptis a script code atom or string.
Returns
{:ok, script_atom}wherescript_atomis the normalised script atom.{:error, exception}if the script is not known.
Examples
iex> Localize.validate_script(:Latn)
{:ok, :Latn}
iex> Localize.validate_script("latn")
{:ok, :Latn}
iex> Localize.validate_script(:Xyzq)
{:error, %Localize.UnknownScriptError{script: :Xyzq}}
@spec validate_territory(atom() | String.t() | integer()) :: {:ok, atom()} | {:error, Exception.t()}
Validates a territory code.
Normalises the territory code and checks it against the CLDR
validity data. Integer codes are zero-padded (e.g., 1 becomes
"001"). String codes are uppercased.
Arguments
territoryis a territory code atom, string, or integer.
Returns
{:ok, territory_atom}whereterritory_atomis the normalised territory atom.{:error, exception}if the territory is not known.
Examples
iex> Localize.validate_territory(:US)
{:ok, :US}
iex> Localize.validate_territory("us")
{:ok, :US}
iex> Localize.validate_territory(:ZZZZ)
{:error, %Localize.UnknownTerritoryError{territory: :ZZZZ}}
@spec validate_territory_subdivision(atom() | String.t()) :: {:ok, atom()} | {:error, Exception.t()}
Validates a territory subdivision code.
Normalises the subdivision code (lowercased) and checks it against the CLDR validity data.
Arguments
subdivisionis a subdivision code atom or string.
Returns
{:ok, subdivision_atom}wheresubdivision_atomis the normalised subdivision atom.{:error, exception}if the subdivision is not known.
Examples
iex> Localize.validate_territory_subdivision(:usca)
{:ok, :usca}
iex> Localize.validate_territory_subdivision("gbeng")
{:ok, :gbeng}
iex> Localize.validate_territory_subdivision(:zzzzz)
{:error, %Localize.UnknownSubdivisionError{subdivision: :zzzzz}}
@spec version() :: Version.t()
Returns the CLDR version this build of Localize targets.
The version is a Version.t/0 whose major and minor components
come from priv/localize/version (the CLDR release version) and
whose patch component comes from priv/localize/localize_patch_version
(Localize's per-release patch counter).
The value is read once on first access and cached in
:persistent_term.
Returns
- A
Version.t/0representing the CLDR version.
Examples
iex> %Version{} = Localize.version()
@spec with_locale(Localize.LanguageTag.t() | atom() | String.t(), (-> result)) :: result when result: any()
Executes a function with a temporary process locale.
Sets the process locale to locale, executes fun, then
restores the previous locale regardless of whether fun
raises or throws.
Arguments
localeis a locale identifier atom, string, or aLocalize.LanguageTag.t/0.funis a zero-arity function to execute.
Returns
The return value of
fun.Raises if the locale is not valid.
Examples
iex> Localize.with_locale(:ja, fn -> Localize.get_locale().cldr_locale_id end)
:ja
iex> Localize.get_locale().cldr_locale_id
:en