Localize.Nif (Localize v0.5.0)

Copy Markdown View Source

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. Additional functions for number, date/time, and unit formatting will be added as the library grows.

The NIF is opt-in and requires:

  1. ICU system libraries installed (ICU 75+ with MF2 support).

  2. The elixir_make dependency.

  3. Enable the NIF via either:

    • Environment variable: LOCALIZE_NIF=true mix compile
    • Application config in config.exs: config :localize, :nif, true

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.

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

available?()

@spec available?() :: boolean()

Returns whether the NIF backend is available.

Returns

  • true if the NIF shared library was loaded successfully.

  • false if the NIF is not compiled or ICU libraries are missing.

Examples

iex> is_boolean(Localize.Nif.available?())
true

collation_available?()

@spec collation_available?() :: boolean()

Returns whether the collation NIF function is available.

Returns

  • true if the collation NIF function was loaded successfully.

  • false if the NIF is not compiled or ICU libraries are missing.

mf2_format(message, locale \\ "en", args \\ %{})

@spec mf2_format(String.t(), String.t(), map() | String.t()) ::
  {:ok, String.t()} | {:error, String.t()}

Formats a MessageFormat 2 message string using ICU.

Arguments are passed as a map of %{name => value} and encoded to JSON for the NIF.

Arguments

  • message is an MF2 message string.

  • locale is a locale identifier string. The default is "en".

  • args is a map of variable bindings. The default is %{}.

Returns

  • {:ok, formatted_string} on success.

  • {:error, reason} on failure.

mf2_validate(message)

@spec mf2_validate(String.t()) :: {:ok, String.t()} | {:error, String.t()}

Validates a MessageFormat 2 message string using ICU's parser.

Arguments

  • message is an MF2 message string.

Returns

  • {:ok, normalized_pattern} if the message is valid.

  • {:error, reason} if the message is invalid.

nif_collation_cmp(string_a, string_b, strength, backwards, alternate, case_first, case_level, normalization, numeric, reorder_bin)

Compare two strings using ICU collation with full option support.

This is the raw NIF function. Use Localize.Collation.Nif.nif_compare/3 for the higher-level 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), or 1 (greater than).

number_format(number, locale, options \\ [])

@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

  • number is a number (integer, float, or Decimal).

  • locale is a locale identifier string (e.g., "en-US", "de").

  • options is a keyword list of options.

Options

  • :currency is an ISO 4217 currency code string (e.g., "USD").

  • :min_fraction_digits is the minimum fractional digits.

  • :max_fraction_digits is the maximum fractional digits.

  • :notation is one of "standard", "scientific", "compact".

  • :use_grouping is a boolean for grouping separators.

Returns

  • {:ok, formatted_string} or {:error, reason}.

plural_rule(number, locale, type \\ :cardinal)

@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

  • number is a number (integer, float, or Decimal) to classify.

  • locale is a locale identifier string (e.g., "en", "ar").

  • type is :cardinal or :ordinal.

Returns

  • {:ok, category} where category is 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}

unit_format(number, unit, locale, options \\ [])

@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

  • number is a number (integer, float, or Decimal).

  • unit is an ICU unit identifier string (e.g., "meter", "mile-per-hour").

  • locale is a locale identifier string.

  • options is a keyword list of options.

Options

  • :style is "long", "short", or "narrow". Default is "long".

Returns

  • {:ok, formatted_string} or {:error, reason}.