# `AshGettext.Installer`
[🔗](https://github.com/Undeadlol1/ash_gettext/blob/v0.1.0/lib/ash_gettext/installer.ex#L1)

The source rewrites `mix ash_gettext.install` performs, as pure functions.

Opting a domain into translation is mechanical: add the extension, add a
`gettext do` block naming the host's backend. Doing that by hand across a real
app is a dozen near-identical edits, each a chance to miss one — and a domain
that gets missed keeps emitting untranslated errors with nothing to notice.

The work lives here rather than in the Mix task so it can be tested as
`string in, string out`: no igniter, no project, no filesystem. The task is a
thin shell that reads files, calls these, and writes them back.

## What cannot be generated

The resolver module itself. `locale_resolver` is written into every domain,
but reading a user's language needs to know where the host keeps it on the
actor, which a generic library must not assume. A generated stub would have to
return `nil`, and every translation would silently fall back to the default
language. So the host writes the module, and the build fails until it exists.

# `result`

```elixir
@type result() :: %{content: String.t(), changed?: boolean(), status: status()}
```

# `status`

```elixir
@type status() :: :installed | :already_installed | :unrecognised
```

What happened to one domain.

`:unrecognised` matters as much as the other two: a domain whose `use` call
this cannot find comes back byte-for-byte unchanged, and without a status that
is indistinguishable from "already done". A caller must be able to say so out
loud rather than report a silent success.

# `already_installed?`

```elixir
@spec already_installed?(String.t()) :: boolean()
```

Whether this source already opts into `AshGettext.Domain`.

# `default_resolver`

```elixir
@spec default_resolver(String.t()) :: String.t()
```

The resolver module name used when none is given: the backend's parent
namespace plus `LocaleResolver`, so `MyApp.Gettext` gives
`MyApp.LocaleResolver`.

# `gettext_block`

```elixir
@spec gettext_block(keyword()) :: String.t()
```

The `gettext do` block for a domain, as source text.

Only what differs from the DSL defaults is written: `backend` always,
`locale_resolver` always, and `text_domain` when it is not `"ash"`. Repeating a default would pin it, so a later change to
the library's default would silently skip every installed domain.

# `install_domain`

```elixir
@spec install_domain(String.t(), keyword()) :: result()
```

Add the `AshGettext.Domain` extension and a `gettext do` block to a domain.

Returns the source unchanged when the domain already has the extension, so
running the installer twice is safe.

## Options

  * `:backend` — required; the host's Gettext backend module, as a string.
  * `:text_domain` — the gettext text domain. Defaults to `"ash"`, and
    is then left out of the block.
  * `:resolver` — a locale resolver module name. Defaults to
    `default_resolver/1` of the backend.

# `install_resource`

```elixir
@spec install_resource(String.t()) :: result()
```

Add the `AshGettext.Resource` extension to a resource.

A domain's `gettext do` block does nothing on its own: the error handler is
installed by the *resource* extension, so a migration that wires only domains
changes no behaviour at all. This is the other half.

Resources are never otherwise touched — no attribute, action or policy.

---

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