Localize.Message (Localize v0.9.0)

Copy Markdown View Source

Implements ICU MessageFormat 2 with functions to parse and interpolate messages.

Summary

Functions

Formats a message into a canonical form.

Formats a message into a canonical form or raises if the message cannot be parsed.

Format an MF2 message into a string.

Formats a message and returns the result or raises on error.

Format an MF2 message into an iolist.

Formats a message into a list of text and markup nodes preserving markup structure.

Returns the Jaro distance between two messages.

Returns the Jaro distance between two messages or raises.

Types

backend()

@type backend() :: :nif | :elixir

bindings()

@type bindings() :: list() | map()

message()

@type message() :: binary()

options()

@type options() :: Keyword.t()

safe_node()

@type safe_node() ::
  {:text, String.t()}
  | {:markup, String.t(), %{required(String.t()) => term()}, [safe_node()]}

Functions

canonical_message(message, options \\ [])

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

Formats a message into a canonical form.

This allows for messages to be compared directly, or using jaro_distance/3.

Arguments

  • message is an MF2 message in binary form.

  • options is a keyword list of options. The default is [].

Options

  • :trim determines if the message is trimmed of whitespace before formatting. The default is true.

Returns

  • {:ok, canonical_message} as a string.

  • {:error, reason} on parse error.

Examples

iex> Localize.Message.canonical_message("{{Hello {$name}!}}")
{:ok, "{{Hello {$name}!}}"}

canonical_message!(message, options \\ [])

@spec canonical_message!(String.t(), Keyword.t()) :: String.t() | no_return()

Formats a message into a canonical form or raises if the message cannot be parsed.

Arguments

  • message is an MF2 message in binary form.

  • options is a keyword list of options. See canonical_message/2.

Returns

  • The canonical message as a string.

Examples

iex> Localize.Message.canonical_message!("{{Hello {$name}!}}")
"{{Hello {$name}!}}"

format(message, bindings \\ %{}, options \\ [])

@spec format(String.t(), bindings(), options()) ::
  {:ok, String.t()} | {:error, Exception.t()}

Format an MF2 message into a string.

The ICU MessageFormat 2 uses message patterns with variable-element placeholders enclosed in {curly braces}. The argument syntax can include formatting details via annotation functions.

Arguments

  • message is an MF2 message string.

  • bindings is a map or keyword list of arguments that are used to replace placeholders in the message.

  • options is a keyword list of options.

Options

  • :locale is any valid locale name or a t:Localize.LanguageTag struct.

  • :trim determines if the message is trimmed of whitespace before formatting. The default is false.

  • :backend determines which formatting engine to use. Accepts :nif or :elixir. When set to :nif, the ICU NIF is used if available, otherwise falls back to the pure-Elixir interpreter. The default is :elixir.

  • :functions is a map of %{String.t() => module()} that registers custom MF2 formatting functions for this call. Each module must implement the Localize.Message.Function behaviour. Per-call functions take precedence over application-level functions registered via config :localize, :mf2_functions. See Localize.Message.Function for details.

Returns

Examples

iex> Localize.Message.format("{{Hello {$name}!}}", %{"name" => "World"})
{:ok, "Hello World!"}

format!(message, bindings \\ %{}, options \\ [])

@spec format!(String.t(), bindings(), options()) :: String.t() | no_return()

Formats a message and returns the result or raises on error.

Same as format/3 but returns the formatted string directly or raises an exception.

Arguments

  • message is an MF2 message string.

  • bindings is a map or keyword list of arguments.

  • options is a keyword list of options. See format/3.

Returns

  • The formatted string.

Examples

iex> Localize.Message.format!("{{Hello {$name}!}}", %{"name" => "World"})
"Hello World!"

format_to_iolist(message, bindings \\ %{}, options \\ [])

@spec format_to_iolist(String.t(), bindings(), options()) ::
  {:ok, list(), list(), list()}
  | {:error, list(), list(), list()}
  | {:error, String.t()}
  | {:format_error, String.t()}

Format an MF2 message into an iolist.

Arguments

  • message is an MF2 message string.

  • bindings is a map or keyword list of arguments that are used to replace placeholders in the message.

  • options is a keyword list of options.

Options

  • :locale is any valid locale name or a language tag struct.

  • :trim determines if the message is trimmed of whitespace before formatting. The default is false.

Returns

  • {:ok, iolist, bound, unbound} on success.

  • {:error, iolist, bound, unbound} when bindings are missing.

  • {:format_error, reason} on format error.

Examples

iex> Localize.Message.format_to_iolist("{{Hello {$name}!}}", %{"name" => "World"})
{:ok, ["Hello ", "World", "!"], ["name"], []}

format_to_safe_list(message, bindings \\ %{}, options \\ [])

@spec format_to_safe_list(String.t(), bindings(), options()) ::
  {:ok, [safe_node()]} | {:error, Exception.t()}

Formats a message into a list of text and markup nodes preserving markup structure.

Unlike format/3, which strips markup tags from the output, this function returns a nested tree of {:text, String.t()} and {:markup, name, options, children} tuples. This is the foundation for HTML/HEEX renderers in companion packages.

The caller is responsible for turning markup nodes into actual output (HTML elements, function components, etc.). Text nodes are returned as raw strings — escaping is the renderer's responsibility.

Arguments

  • message is an MF2 message in binary form.

  • bindings is a map or keyword list of variable bindings. The default is %{}.

  • options is a keyword list of options. The default is [].

Options

Returns

  • {:ok, nodes} on success, where nodes is a list of safe_node() tuples.

  • {:error, exception} on parse or format error, including unbalanced markup or unbound variables.

Examples

iex> Localize.Message.format_to_safe_list(
...>   "Hello {$name}, click {#link href=|/home|}here{/link}!",
...>   %{"name" => "Kip"}
...> )
{:ok, [
  {:text, "Hello Kip, click "},
  {:markup, "link", %{"href" => "/home"}, [{:text, "here"}]},
  {:text, "!"}
]}

iex> Localize.Message.format_to_safe_list("Just text")
{:ok, [{:text, "Just text"}]}

iex> Localize.Message.format_to_safe_list("{#br/}")
{:ok, [{:markup, "br", %{}, []}]}

format_to_safe_list!(message, bindings \\ %{}, options \\ [])

@spec format_to_safe_list!(String.t(), bindings(), options()) :: [safe_node()]

Same as format_to_safe_list/3 but raises on error.

jaro_distance(message1, message2, options \\ [])

@spec jaro_distance(String.t(), String.t(), Keyword.t()) ::
  {:ok, float()} | {:error, String.t()}

Returns the Jaro distance between two messages.

This allows for fuzzy matching of messages which can be helpful when a message string is changed but the semantics remain the same.

Arguments

  • message1 is an MF2 message in binary form.

  • message2 is an MF2 message in binary form.

  • options is a keyword list of options. The default is [].

Options

  • :trim determines if the message is trimmed of whitespace before formatting. The default is false.

Returns

  • {:ok, distance} where distance is a float between 0.0 and 1.0.

  • {:error, reason} on parse error.

Examples

iex> Localize.Message.jaro_distance("{{Hello}}", "{{Hello}}")
{:ok, 1.0}

jaro_distance!(message1, message2, options \\ [])

@spec jaro_distance!(String.t(), String.t(), Keyword.t()) :: float() | no_return()

Returns the Jaro distance between two messages or raises.

Same as jaro_distance/3 but returns the distance directly.

Arguments

  • message1 is an MF2 message in binary form.

  • message2 is an MF2 message in binary form.

  • options is a keyword list of options.

Returns

  • A float distance between 0.0 and 1.0.

Examples

iex> Localize.Message.jaro_distance!("{{Hello}}", "{{Hello}}")
1.0