# `Localize.Message.Interpreter`
[🔗](https://github.com/elixir-localize/localize/blob/v0.39.0/lib/localize/message/interpreter.ex#L1)

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.

# `format_error_payload`

```elixir
@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.

# `format_list`

```elixir
@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`

```elixir
@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).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
