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 inpublic/locales, src/locales, app/locales, then
locales. Pass a directory to be explicit:
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 omittingitems_one.
Exit codes
| Code | Meaning |
|---|---|
0 | No broken placeholders (clean, or warnings only) |
1 | At least one translation problem |
2 | Usage error (no command, no locales found, unknown source locale, …) |
Options
| Flag | Description |
|---|---|
--source <lang> | Source locale to compare against (default: en) |
--strict | Also fail (exit 1) on unsupported syntax and untranslated keys |
--quiet | Hide the per-locale lines for clean locales (untranslated still shown) |
--json | Machine-readable, version-tagged report |
--color / --no-color | Force color on or off (default: auto — color on a TTY) |
-h, --help | Show help |
In CI
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 .).