alepha@docs:~/docs/cli/plugins$
cat 3-i18n.md | pretty
2 min read
Last commit:

#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.

#Quick Start

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

typescript
1import { defineConfig } from "alepha/cli/config";2import { i18n } from "alepha/cli/i18n";3 4export default defineConfig({5  plugins: [i18n()],6});
bash
alepha i18n check
bash
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.

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
 1import { defineConfig } from "alepha/cli/config"; 2import { i18n } from "alepha/cli/i18n"; 3  4export default defineConfig({ 5  plugins: [ 6    i18n({ 7      scan: ["src", ".vendor/@alepha/ui"], 8      dynamicPrefixes: ["archive.type.", "petitions.filter."], 9    }),10  ],11});

#Dynamic Keys

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

typescript
1tr(`archive.type.${kind}`)

The static scan can't see it, so every archive.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
1{2  "scripts": {3    "check:i18n": "alepha i18n check"4  }5}

The exit codes make it CI-friendly: 0 all keys referenced, 1 unused keys found, 2 no keys found at all.