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

Implements sigils for ICU MessageFormat 2 messages.

Two sigils are provided:

* `~M` — validates and canonicalises an MF2 message at compile time.
  Useful for static messages that need a stable canonical form (for
  example, as keys in a translation table or seed data).

* `~t` — compile-time translation sigil. Combines Gettext lookup with
  MF2 interpolation. Elixir-style `#{expr}` interpolations become
  MF2 `{$name}` placeholders with bindings derived automatically from
  the interpolated expression. Requires the calling module to opt in
  via `use Localize.Message.Sigils, backend: MyApp.Gettext`.

## Compile-time validation

Both sigils parse the message at compile time. A syntax error fails
compilation and the raised `CompileError` points at the exact line
and column of the error *inside the sigil body*, adjusted to the
sigil's source location so editors can jump directly to the
offending character (including inside multi-line heredoc sigils).

## Using `~t`

    defmodule MyAppWeb.HomeLive do
      use Localize.Message.Sigils,
        backend: MyApp.Gettext,
        sigils: [domain: "messages"]

      def render(assigns) do
        ~H"""
        <h1>{~t"Hello, #{@user.name}!"}</h1>
        """
      end
    end

At compile time, `~t"Hello, #{@user.name}!"` becomes:

    Gettext.Macros.dpgettext_with_backend(
      MyApp.Gettext,
      "messages",
      nil,
      "Hello, {$user_name}!",
      %{user_name: @user.name}
    )

The msgid stored in the `.po` file is the MF2-canonical form with
`{$name}` placeholders, so translators can use MF2 features
(selectors, formatters, markup) per-locale.

## Gettext backend requirements

The configured backend MUST use MF2-aware interpolation:

    defmodule MyApp.Gettext do
      use Gettext.Backend,
        otp_app: :my_app,
        interpolation: Localize.Gettext.Interpolation
    end

Without this, `{$name}` placeholders are returned literally because
the default Gettext interpolation only recognises `%{name}`.

## Binding key derivation

Binding names are derived from the interpolated expression:

* `#{name}` — variable → `name`.

* `#{@count}` — Phoenix assign → `count`.

* `#{fruit.name}` — dot access → `fruit_name`.

* `#{String.upcase(x)}` — remote call → `string_upcase`.

* `#{key = expr}` — explicit key. Always overrides automatic
  derivation. Use this for collisions or complex expressions.

Identical expressions interpolated twice share a single binding.
Different expressions that derive the same key raise a compile error.

# `__using__`
*macro* 

Configures the calling module to use the `~t` sigil.

### Options

* `:backend` — the Gettext backend module. Required.

* `:sigils` — a keyword list of sigil-level options:

    * `:domain` — default Gettext domain. The default is `:default`,
      which resolves to the backend's configured default domain.

    * `:context` — default Gettext message context. The default is `nil`.

### Examples

    use Localize.Message.Sigils,
      backend: MyApp.Gettext,
      sigils: [domain: "messages"]

# `sigil_M`
*macro* 

Handles the sigil `~M` for ICU MessageFormat 2 message strings.

It returns a canonically formatted string without interpolations and
without escape characters, except for the escaping of the closing
sigil character itself.

A canonically formatted string is pretty-printed by default returning
a potentially multi-line string. This is intended to produce a result
which is easier to comprehend for translators.

### Modifiers

* `p` (default) — pretty-print the message with indentation.

* `u` — return a non-pretty-printed (compact) string.

### Examples

    iex> import Localize.Message.Sigils
    iex> ~M(An ICU message)
    "An ICU message"

# `sigil_t`
*macro* 

Handles the sigil `~t` for compile-time MF2 translation.

Rewrites Elixir `#{expr}` interpolations as MF2 `{$name}` placeholders
with bindings derived from the interpolated expressions. The resulting
msgid is canonicalised and routed through `Gettext`, which performs
both the translation lookup and the MF2 interpolation (via the
configured `Localize.Gettext.Interpolation` module).

The calling module must opt in with:

    use Localize.Message.Sigils, backend: MyApp.Gettext

Modifiers are reserved for a future release and are rejected at
compile time.

See the `Localize.Message.Sigils` moduledoc for binding-derivation
rules and a full example.

---

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