Skip to main content
astilba check validates that every locale keeps its placeholders intact. When a translator (or a machine) renders "You have {{count}} items" as "Vous avez des articles", the {{count}} is gone and i18next fails silently at runtime. check finds that — across every locale, in CI or locally — on top of the @astilba/core fidelity engine. It ships as the astilba package (MIT), a self-contained bin bundling @astilba/core and the i18next adapter — no runtime dependencies.

Usage

Zero-config: with no path it looks in public/locales, src/locales, app/locales, then locales. Pass a directory to be explicit:
npx astilba check ./locales --source en

What it reports

  • Translation problems — a target locale dropped, added, or changed a placeholder relative to the source ({{count}}, $t(ref), <b>…</b>). This is the one tier that fails the build.
  • Unsupported source syntax — ICU ({n, plural, …}); native i18next v4 renders it literally. A capability notice, not a translation bug.
  • Untranslated keys — present in the source, missing in a target (falls back to source). CLDR-plural-aware: a target with fewer plural categories than the source (e.g. Japanese, whose only cardinal category is other) is not flagged for omitting items_one.

Exit codes

CodeMeaning
0No broken placeholders (clean, or warnings only)
1At least one translation problem
2Usage error (no command, no locales found, unknown source locale, …)

Options

FlagDescription
--source <lang>Source locale to compare against (default: en)
--strictAlso fail (exit 1) on unsupported syntax and untranslated keys
--quietHide the per-locale lines for clean locales (untranslated still shown)
--jsonMachine-readable, version-tagged report
--color / --no-colorForce color on or off (default: auto — color on a TTY)
-h, --helpShow help

In CI

- run: npx astilba check
A non-zero exit fails the job, so a dropped placeholder blocks the merge.

Limitations (Phase 0)

check flags the forward direction — a target that drops a plural form the source language requires. It does not yet flag the reverse — a target missing a plural category its own language needs but the source language lacks (there is no source key to compare against). A custom i18next keySeparator is also not configurable yet (keys are flattened with .).