Search documentation of Localize

# Localize.Message.Interpreter (Localize v0.39.0)

Copy Markdown View Source

Interprets a MessageFormat 2 AST and produces formatted output.

The AST is produced by `Localize.Message.Parser` and uses tuples like `{:text, "..."}`, `{:expression, operand, function, attrs}`, `{:complex, declarations, body}`, `{:match, selectors, variants}`, etc.

## Supported MF2 Functions

The following functions are available in MF2 expressions:

### Stable (per MF2 specification)

- `:number` — format a number using locale-aware decimal formatting.

- `:integer` — format a number as an integer (truncates fractional part).

- `:string` — format a value as a string (identity for strings).

- `:currency` — format a number as a currency amount. Requires a `currency` option (ISO 4217 code).

- `:percent` — format a number as a percentage.

### Draft

- `:date` — format a date using CLDR date patterns.

- `:time` — format a time using CLDR time patterns.

- `:datetime` — format a datetime using CLDR datetime patterns.

- `:unit` — format a number with a unit of measure.

### Localize extensions (not in the MF2 specification)

- `:list` — format a list operand as a locale-aware conjunction or disjunction by delegating to `Localize.List.to_string/2`. Each element is itself formatted via `Localize.Chars`, so a list of dates, numbers, units, etc. picks up the message's locale and any forwarded options. Accepts a `style` (or `type`) option whose value is one of `"and"`, `"and-short"`, `"and-narrow"`, `"or"`, `"or-short"`, `"or-narrow"`, `"unit"`, `"unit-short"`, `"unit-narrow"`. The default is `"and"` (the CLDR `:standard` list style).

## Custom function registry

When a function name is not matched by any built-in function above, the interpreter looks for a custom function module in two places (in order of precedence):

1. The per-call `:functions` option on `Localize.Message.format/3`.
2. The application-level `config :localize, :mf2_functions` map.

Custom function modules must implement the `Localize.Message.Function` behaviour. See that module's documentation for details and examples.

If no custom function is found, the interpreter falls back to `Kernel.to_string/1` on the operand value.

## Summary

### Types

format_error_payload()

Structured payload carried inside a `{:format_error, payload}` tuple.

### Functions

format_list(ast, bindings \\ %{}, options \\ [])

Formats a parsed MF2 AST with the given bindings.

format_structured(ast, bindings \\ %{}, options \\ [])

Format an AST into a list of `safe_node()` tuples that preserve markup structure as nested regions.

## Types

# format_error_payload()

    @type format_error_payload() ::
      {:unbalanced_markup, :unclosed | {:mismatched_close, String.t()}}
      | {:formatter_failed, Exception.t() | String.t()}

Structured payload carried inside a `{:format_error, payload}` tuple.

- `{:unbalanced_markup, sub}` where `sub` is `:unclosed` or `{:mismatched_close, name}` — markup nesting violation.

- `{:formatter_failed, term()}` — a function formatter raised or returned an error. The term is the original exception or string detail produced by the formatter.

## Functions

# format_list(ast, bindings \\ %{}, options \\ [])

    @spec format_list(term(), map() | list(), Keyword.t()) ::
      {:ok, list(), list(), list()}
      | {:error, list(), list(), list()}
      | {:format_error, format_error_payload()}

Formats a parsed MF2 AST with the given bindings.

### Arguments

- `ast` is a parsed MF2 message AST as returned by `Localize.Message.Parser.parse/1`.

- `bindings` is a map or keyword list of variable bindings. String keys are NFC-normalized to match parser output.

- `options` is a keyword list of options including `:locale`.

### Returns

- `{:ok, iolist, bound, unbound}` on success, where `bound` is the list of variable names that were resolved and `unbound` is empty.

- `{:error, iolist, bound, unbound}` when one or more variables could not be resolved. The `iolist` contains a partial result.

# format_structured(ast, bindings \\ %{}, options \\ [])

    @spec format_structured(term(), map() | list(), Keyword.t()) ::
      {:ok, list(), list(), list()}
      | {:error, list(), list(), list()}
      | {:format_error, format_error_payload()}

Format an AST into a list of `safe_node()` tuples that preserve markup structure as nested regions.

Unlike `format_list/3` which drops markup, this function produces a flat list of `{:text, String.t()}` and `{:markup, name, options, children}` tuples. This is the foundation for HTML/HEEX renderers in companion packages.

### Returns

- `{:ok, nodes, bound, unbound}` on success.

- `{:error, nodes, bound, unbound}` when one or more variables could not be resolved (partial result in `nodes`).

- `{:format_error, reason}` on formatting error (including unbalanced markup).