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

Implements [ICU MessageFormat 2](https://unicode.org/reports/tr35/tr35-messageFormat.html)
with functions to parse and interpolate messages.

# `backend`

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

# `bindings`

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

# `message`

```elixir
@type message() :: binary()
```

# `options`

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

# `canonical_message`

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

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

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

* `{:ok, formatted_message}` on success.

* `{:error, exception}` where `exception` is a `Localize.BindError`
  for unbound variables or a `Localize.FormatError` for formatting
  failures.

### Examples

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

# `format!`

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

```elixir
@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"], []}

# `jaro_distance`

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

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

---

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