# I18n Plugin

Find dead translation keys before they pile up. The i18n plugin statically scans your project for `$dictionary(...)` declarations and reports every key that is never referenced anywhere in the source tree - plus two placeholder checks (see below).

## Quick Start

Register the plugin in `alepha.config.ts` with the `i18n()` helper:

```typescript check filename=alepha.config.ts
import { defineConfig } from "alepha/cli/config";
import { i18n } from "alepha/cli/i18n";

export default defineConfig({
  plugins: [i18n()],
});
```

```bash
alepha i18n check
```

```txt
Checked 412 keys across 187 files (3 dictionary files).

✗ Unused translations (2):
  - profile.legacy.title
  - profile.legacy.subtitle
```

## What It Does

The check extracts every key declared in your `$dictionary(...)` calls, then looks for a quoted-literal reference to each key anywhere else in the scanned files. Keys with no reference are reported and the command exits non-zero - wire it into your verify pipeline so removing a feature can't silently strand its translations. The report also prints an `exempt (dynamic prefixes)` count so exemptions stay visible.

Two more checks run in the same pass:

- **Bad placeholders**: entries using `{0}`-style placeholders that never interpolate; Alepha's interpolation syntax is `$1`, `$2`.
- **Missing arguments**: `tr()` calls passing fewer arguments than the entry's `$N` placeholders expect.

If no translation keys are found at all, the command exits with code `2` and a warning - that usually means the dictionary location changed and the scan is looking in the wrong place.

## Configuration

`i18n()` accepts the following options:

| Option            | Type       | Default   | Description                                                                                                                     |
| ----------------- | ---------- | --------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `scan`            | `string[]` | `["src"]` | Directories (relative to the project root) to scan for dictionaries and key usage                                               |
| `dynamicPrefixes` | `string[]` | `[]`      | Key prefixes constructed at runtime - exempted from the check                                                                   |
| `exclude`         | `string[]` | `[]`      | Extra path substrings to exclude, on top of the defaults (`node_modules`, `dist`, `__tests__`, `.spec.*`, `.test.*`, `.alepha`) |

```typescript check filename=alepha.config.ts
import { defineConfig } from "alepha/cli/config";
import { i18n } from "alepha/cli/i18n";

export default defineConfig({
  plugins: [
    i18n({
      scan: ["src", ".vendor/@alepha/ui"],
      dynamicPrefixes: ["folio.type.", "feedback.filter."],
    }),
  ],
});
```

## Dynamic Keys

A key built with a template literal has no quoted-literal reference:

```typescript
tr(`folio.type.${kind}`);
```

The static scan can't see it, so every `folio.type.*` key would be reported as unused. Add the prefix to `dynamicPrefixes` to exempt them.

> **Audit your prefixes**
>
> Keep the `dynamicPrefixes` list short and re-check it when a feature is removed - a stale prefix is a place where dead keys can hide.

## In the Verify Pipeline

Add a `check:i18n` script to your app and let CI run it:

```json filename=package.json
{
  "scripts": {
    "check:i18n": "alepha i18n check"
  }
}
```

The exit codes make it CI-friendly: `0` clean, `1` unused keys, bad placeholders, or missing arguments found, `2` no keys found at all.
