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.
Same as format_to_safe_list/3 but raises on error.
Returns the Jaro distance between two messages.
Returns the Jaro distance between two messages or raises.
Parses an MF2 message and returns it formatted with ANSI colour codes for terminal display.
Parses an MF2 message and returns it formatted as HTML with
per-token <span> wrappers for syntax highlighting.
Parses an MF2 message and returns a classified token stream for syntax highlighting.
Types
Functions
@spec canonical_message(String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, Localize.ParseError.t()}
Formats a message into a canonical form.
This allows for messages to be compared directly, or using
jaro_distance/3.
Arguments
messageis an MF2 message in binary form.optionsis a keyword list of options. The default is[].
Options
:trimdetermines if the message is trimmed of whitespace before formatting. The default istrue.
Returns
{:ok, canonical_message}as a string.{:error, reason}on parse error.
Examples
iex> Localize.Message.canonical_message("{{Hello {$name}!}}")
{:ok, "{{Hello {$name}!}}"}
Formats a message into a canonical form or raises if the message cannot be parsed.
Arguments
messageis an MF2 message in binary form.optionsis a keyword list of options. Seecanonical_message/2.
Returns
- The canonical message as a string.
Examples
iex> Localize.Message.canonical_message!("{{Hello {$name}!}}")
"{{Hello {$name}!}}"
@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
messageis an MF2 message string.bindingsis a map or keyword list of arguments that are used to replace placeholders in the message.optionsis a keyword list of options.
Options
:localeis any valid locale name or at:Localize.LanguageTagstruct.:trimdetermines if the message is trimmed of whitespace before formatting. The default isfalse.:backenddetermines which formatting engine to use. Accepts:nifor:elixir. When set to:nif, the ICU NIF is used if available, otherwise falls back to the pure-Elixir interpreter. The default is:elixir.:functionsis a map of%{String.t() => module()}that registers custom MF2 formatting functions for this call. Each module must implement theLocalize.Message.Functionbehaviour. Per-call functions take precedence over application-level functions registered viaconfig :localize, :mf2_functions. SeeLocalize.Message.Functionfor details.
Returns
{:ok, formatted_message}on success.{:error, exception}whereexceptionis aLocalize.BindErrorfor unbound variables or aLocalize.FormatErrorfor formatting failures.
Examples
iex> Localize.Message.format("{{Hello {$name}!}}", %{"name" => "World"})
{:ok, "Hello World!"}
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
messageis an MF2 message string.bindingsis a map or keyword list of arguments.optionsis a keyword list of options. Seeformat/3.
Returns
- The formatted string.
Examples
iex> Localize.Message.format!("{{Hello {$name}!}}", %{"name" => "World"})
"Hello World!"
@spec format_to_iolist(String.t(), bindings(), options()) :: {:ok, list(), list(), list()} | {:error, list(), list(), list()} | {:error, Localize.ParseError.t()} | {:format_error, String.t()}
Format an MF2 message into an iolist.
Arguments
messageis an MF2 message string.bindingsis a map or keyword list of arguments that are used to replace placeholders in the message.optionsis a keyword list of options.
Options
:localeis any valid locale name or a language tag struct.:trimdetermines if the message is trimmed of whitespace before formatting. The default isfalse.
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"], []}
@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
messageis an MF2 message in binary form.bindingsis a map or keyword list of variable bindings. The default is%{}.optionsis a keyword list of options. The default is[].
Options
:localeis a locale name or aLocalize.LanguageTag.t/0. The default isLocalize.get_locale/0.:trimdetermines if the message is trimmed of whitespace before formatting. The default isfalse.:functionsis a map of custom MF2 function modules. SeeLocalize.Message.Function.
Returns
{:ok, nodes}on success, wherenodesis a list ofsafe_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", %{}, []}]}
Same as format_to_safe_list/3 but raises on error.
@spec jaro_distance(String.t(), String.t(), Keyword.t()) :: {:ok, float()} | {:error, Localize.ParseError.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
message1is an MF2 message in binary form.message2is an MF2 message in binary form.optionsis a keyword list of options. The default is[].
Options
:trimdetermines if the message is trimmed of whitespace before formatting. The default isfalse.
Returns
{:ok, distance}wheredistanceis a float between 0.0 and 1.0.{:error, reason}on parse error.
Examples
iex> Localize.Message.jaro_distance("{{Hello}}", "{{Hello}}")
{:ok, 1.0}
Returns the Jaro distance between two messages or raises.
Same as jaro_distance/3 but returns the distance directly.
Arguments
message1is an MF2 message in binary form.message2is an MF2 message in binary form.optionsis 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
@spec to_ansi(String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, Localize.ParseError.t()}
Parses an MF2 message and returns it formatted with ANSI colour codes for terminal display.
Arguments
messageis an MF2 message in binary form.optionsis a keyword list.
Options
:trim— whitespace trim before parse (defaulttrue).:palette— a map overriding the default class-to-colour mapping. SeeLocalize.Message.Formatter.ANSI.
Returns
{:ok, ansi_string}on success.{:error, reason}if the message cannot be parsed.
@spec to_html(String.t(), Keyword.t()) :: {:ok, String.t()} | {:error, Localize.ParseError.t()}
Parses an MF2 message and returns it formatted as HTML with
per-token <span> wrappers for syntax highlighting.
Arguments
messageis an MF2 message in binary form.optionsis a keyword list.
Options
:trim— whitespace trim before parse (defaulttrue).:standalone— wraps the output in a<pre><code>block (defaultfalse).:wrapper_tag,:wrapper_class,:span_tag,:class_prefix— seeLocalize.Message.Formatter.HTMLfor details.
Returns
{:ok, html}on success.{:error, reason}if the message cannot be parsed.
@spec to_tokens(String.t(), Keyword.t()) :: {:ok, [Localize.Message.Highlighter.token()]} | {:error, Localize.ParseError.t()}
Parses an MF2 message and returns a classified token stream for syntax highlighting.
Each token is a {class, text} tuple where class is one of the
atoms documented in Localize.Message.Highlighter. Concatenating
every token's text yields the canonical MF2 message.
Use this when you want to produce your own rendered output. For
HTML or ANSI output, prefer to_html/2 or to_ansi/2.
Arguments
messageis an MF2 message in binary form.optionsis a keyword list. The:trimoption (defaulttrue) strips leading and trailing whitespace before parsing.
Returns
{:ok, tokens}wheretokensis a list of{class, text}tuples.{:error, reason}if the message cannot be parsed.
Examples
iex> {:ok, tokens} = Localize.Message.to_tokens("Hello {$name}!")
iex> Enum.map(tokens, &elem(&1, 0))
[:text, :punctuation_bracket, :variable, :punctuation_bracket, :text]