Optional NIF interface to ICU4C for high-performance locale operations.
This module provides NIF bindings for ICU4C functions including MessageFormat 2.0 parsing and formatting, number formatting, plural rules, unit formatting and collation.
The stable way to use the NIF backend is the backend: :nif option
on the corresponding public formatting functions (for example
Localize.Number.to_string/2 and Localize.Message.format/3); the
individual functions in this module are a low-level surface whose
signatures may change with the underlying ICU API.
The NIF is opt-in and requires:
ICU system libraries installed (ICU 75+ with MF2 support).
The
elixir_makedependency.Enable the NIF via either:
- Environment variable:
LOCALIZE_NIF=true mix compile - Application config in
config.exs:config :localize, :nif, true
- Environment variable:
The config key must be set in config.exs (not runtime.exs) because
it is evaluated at compile time to include the :elixir_make compiler.
If the NIF is not available, available?/0 returns false and the
pure Elixir implementations are used automatically.
Summary
Functions
Returns whether the NIF backend is available.
Returns whether the collation NIF function is available.
Formats a MessageFormat 2 message string using ICU.
Validates a MessageFormat 2 message string using ICU's parser.
Compare two strings using ICU collation with full option support.
Formats a number using ICU4C's NumberFormatter.
Returns the plural category for a number using ICU's PluralRules.
Formats a number with a unit using ICU4C's NumberFormatter.
Functions
@spec available?() :: boolean()
Returns whether the NIF backend is available.
Returns
trueif the NIF shared library was loaded successfully.falseif the NIF is not compiled or ICU libraries are missing.
Examples
iex> is_boolean(Localize.Nif.available?())
true
@spec collation_available?() :: boolean()
Returns whether the collation NIF function is available.
The collation functions are part of the same shared library as the
rest of the NIF, so they are available exactly when available?/0
is true.
Returns
trueif the collation NIF function was loaded successfully.falseif the NIF is not compiled or ICU libraries are missing.
Examples
iex> is_boolean(Localize.Nif.collation_available?())
true
@spec mf2_format(String.t(), String.t(), map() | String.t()) :: {:ok, String.t()} | {:error, String.t() | Exception.t()}
Formats a MessageFormat 2 message string using ICU.
The arguments reach ICU as a flat JSON object, so each value must be
one that crosses unchanged: a string, an integer within 64 bits or a
float. Localize.Message.format/3 with backend: :nif formats a
message whose bindings hold anything else with the Elixir interpreter.
Arguments
messageis an MF2 message string.localeis a locale identifier string. The default is"en".argsis a map of argument names to values, or the same map as a JSON object. The default is%{}.
Returns
{:ok, formatted_string}on success.{:error, reason}if ICU cannot format the message.{:error, exception}if an argument the message uses is missing, if any argument is not a string, a 64-bit integer or a float, ifargsis neither a map nor a JSON object, or ifmessageorlocaleis not a string.
Examples
The NIF is optional, so the example calls it only where it is loaded.
iex> if Localize.Nif.available?() do
...> Localize.Nif.mf2_format("Hello {$name}!", "en", %{"name" => "World"})
...> else
...> {:ok, "Hello World!"}
...> end
{:ok, "Hello World!"}
Validates a MessageFormat 2 message string using ICU's parser.
Arguments
messageis an MF2 message string.
Returns
{:ok, normalized_pattern}if the message is valid.{:error, reason}if the message is invalid.
Examples
The NIF is optional, so the example calls it only where it is loaded.
iex> if Localize.Nif.available?() do
...> Localize.Nif.mf2_validate("Hello {$name}!")
...> else
...> {:ok, "{{Hello {$name}!}}"}
...> end
{:ok, "{{Hello {$name}!}}"}
@spec nif_collation_cmp( binary(), binary(), integer(), integer(), integer(), integer(), integer(), integer(), integer(), binary() ) :: -1 | 0 | 1
Compare two strings using ICU collation with full option support.
This is the raw NIF function. Use Localize.Collation.compare/3
for the public interface that handles option encoding.
Arguments
string_a- the first string to compare.string_b- the second string to compare.strength- ICU strength enum value, or -1 for default.backwards- ICU backwards enum value, or -1 for default.alternate- ICU alternate enum value, or -1 for default.case_first- ICU case_first enum value, or -1 for default.case_level- ICU case_level enum value, or -1 for default.normalization- ICU normalization enum value, or -1 for default.numeric- ICU numeric enum value, or -1 for default.reorder_bin- binary of packed big-endian int32 reorder codes.
Returns
- An integer:
-1(less than),0(equal), or1(greater than).
Examples
The NIF is optional, so the example calls it only where it is loaded.
iex> if Localize.Nif.available?() do
...> Localize.Nif.nif_collation_cmp("a", "b", -1, -1, -1, -1, -1, -1, -1, <<>>)
...> else
...> -1
...> end
-1
@spec number_format(number() | Decimal.t(), String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, String.t()}
Formats a number using ICU4C's NumberFormatter.
This provides a reference implementation for cross-validating
the pure Elixir number formatting in Localize.Number.
Arguments
numberis a number (integer, float, or Decimal).localeis a locale identifier string (e.g.,"en-US","de").optionsis a keyword list of options.
Options
:currencyis an ISO 4217 currency code string (e.g.,"USD").:min_fraction_digitsis the minimum fractional digits.:max_fraction_digitsis the maximum fractional digits.:notationis one of"standard","scientific","compact".:use_groupingis a boolean for grouping separators.
Returns
{:ok, formatted_string}or{:error, reason}.
Examples
The NIF is optional, so the example calls it only where it is loaded.
iex> if Localize.Nif.available?() do
...> Localize.Nif.number_format(1234.5, "de")
...> else
...> {:ok, "1.234,5"}
...> end
{:ok, "1.234,5"}
@spec plural_rule(number() | Decimal.t(), String.t(), :cardinal | :ordinal) :: {:ok, atom()} | {:error, String.t()}
Returns the plural category for a number using ICU's PluralRules.
Arguments
numberis a number (integer, float, or Decimal) to classify.localeis a locale identifier string (e.g.,"en","ar").typeis:cardinalor:ordinal.
Returns
{:ok, category}wherecategoryis one of:zero,:one,:two,:few,:many, or:other.{:error, reason}if ICU cannot determine the plural category.
Examples
When the NIF is available:
Localize.Nif.plural_rule(1, "en", :cardinal)
#=> {:ok, :one}
Localize.Nif.plural_rule(2, "en", :ordinal)
#=> {:ok, :two}
@spec unit_format(number() | Decimal.t(), String.t(), String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, String.t()}
Formats a number with a unit using ICU4C's NumberFormatter.
Arguments
numberis a number (integer, float, or Decimal).unitis an ICU unit identifier string (e.g.,"meter","mile-per-hour").localeis a locale identifier string.optionsis a keyword list of options.
Options
:styleis"long","short", or"narrow". Default is"long".
Returns
{:ok, formatted_string}or{:error, reason}.
Examples
The NIF is optional, so the example calls it only where it is loaded.
iex> if Localize.Nif.available?() do
...> Localize.Nif.unit_format(3, "meter", "en", style: "short")
...> else
...> {:ok, "3 m"}
...> end
{:ok, "3 m"}