Intro
Translation keys in source and keys in locale JSON drift apart quietly. Most teams patch it with per-repo scripts, stack-specific plugins, or a TMS they do not want in every pipeline.
i18nprune is an MIT, Node.js 18+ toolkit built around one idea: one deterministic TypeScript core exposed as a CLI, programmatic SDK, and optional hosted report/share apps — with automation-first --json output.
This article covers what actually ships today: multi-runtime hosts, cross-platform CLI behavior, locale layouts, translation providers, safe defaults, and the pattern-based extractor that powers validate/sync/cleanup.
One core, many runtimes
@i18nprune/core owns extraction, cache policy, locale IO, issue codes, and all runXxx operations. Hosts own presentation only.
| Host | Adapter import | Typical tier |
|---|---|---|
| CLI / Node scripts | @i18nprune/core/runtime/node |
Read + write locale files |
| Browser tooling | @i18nprune/core/runtime/web |
Analyze / preview |
| Workers / edge | @i18nprune/core/runtime/edge |
Analyze + share ingest |
The CLI is a thin Commander host. The same validate result shape appears in CI JSON, SDK embeds, and worker-backed share flows — parity snapshot tests guard regressions.
Cross-platform CLI
The installable binary targets Linux, macOS, and Windows:
- Cache under
~/.i18nprune(orI18NPRUNE_HOME) - Documented path semantics and doctor warnings for Windows reserved names and long paths
- API output uses forward slashes; on-disk IO uses host
path.join
Locale layouts and init presets
Three topologies in config:
-
flat_file— e.g.locales/en.json -
locale_per_dir— e.g.messages/en/common.json -
feature_bundle— e.g.messages/auth/en.json
i18nprune init --yes scaffolds config with presets for i18next, next-intl, react-intl, lingui, next-i18next, or generic layouts.
Translation providers and safe mutation defaults
Five provider ids ship today: google, deepl, llm, libre, mymemory. Discover with:
i18nprune providers --json
Policy routing and fallback are config-driven. generate --resume fills missing leaves only — not full re-translation.
Safe defaults:
-
cache.profile: balanced(override withsafeorfast, or--cache-profile) -
sync --dry-runpreviews shape changes - Disk writes require global
--yes -
--jsonruns non-interactively on supported commands
CI: the --json contract
i18nprune validate --json | jq -e '.ok'
Envelope fields: ok, kind, data, issues, meta.apiVersion: "1". Issue codes such as i18nprune.validate.missing_literal_keys are stable API — display copy can change; codes should not.
Extended preflight:
i18nprune doctor --json --strict
Extraction: what we actually built
i18nprune uses an advanced pattern-based extractor (not a single naive regex on t(). Three layers cooperate:
-
Import binding resolver — expands configured
functionsfrom ESM/CJS imports, namespaces (i18n.t), and aliases (t as renameT). -
Per-file const maps —
`${NS}.segment`resolves using constants in that file only (duplicateNSacross files does not collide). - Template rebuild + classification — mixed templates fuse static prefixes with runtime holes; dynamic sites are reported, not guessed into locale JSON.
This design targets ~99%+ on literal and const-resolved template keys (near 100% on plain string-literal keys) in typical JS/TS projects while staying conservative on runtime-only expressions — so cleanup and sync do not silently delete keys you still need.
Stack fixtures in the repo exercise Next, Vue, SvelteKit, Nuxt, and Remix patterns.
Roadmap: optional TypeScript AST assist as an opt-in strictness mode on top of the fast default path. IDE extension reuses the same core (coming soon).
Commands you run day to day
| Command | Role |
|---|---|
validate |
Literal keys in source vs source locale; dynamic site counts |
sync |
Align target locale shape; --dry-run first |
missing |
Scaffold missing paths with placeholders |
generate / --resume
|
Provider-backed translation |
cleanup |
Remove keys not in code scan; optional --rg guard |
report |
HTML / JSON / CSV / text project health |
share upload |
Prepared snapshot or report to hosted worker |
sync and cleanup measure different datasets — both are documented; counts can diverge by design.
SDK embed (no subprocess)
import { resolveContext, runValidate } from '@i18nprune/core';
import { createNodeRuntimeAdapters } from '@i18nprune/core/runtime/node';
const ctx = await resolveContext({
projectRoot: process.cwd(),
adapters: createNodeRuntimeAdapters(),
});
const { payload, issues } = await runValidate(ctx, {});
Subpath exports (/validate, /sync, /generate, …) support smaller bundles. Examples: examples/sdk/ in the repo.
Reports and sharing
i18nprune report --format html --out ./i18n-report.html
i18nprune share upload --project --yes
Hosted viewers: report.i18nprune.dev · web.i18nprune.dev. Worker OpenAPI: worker.i18nprune.dev/docs.
Conclusion
If you need a multi-runtime, cross-platform i18n gate with deterministic JSON for CI, incremental generate, and optional hosted review links — i18nprune is built for that path. Lead with what ships; check the releases portal and git timeline for ongoing changes.
Links
- GitHub: https://github.com/zamdevio/i18nprune
- Docs: https://docs.i18nprune.dev
- Home: https://i18nprune.dev
- Web workspace: https://web.i18nprune.dev
- Report viewer: https://report.i18nprune.dev
- Worker API: https://worker.i18nprune.dev/docs
- Releases: https://releases.i18nprune.dev
- Build timeline: https://git.i18nprune.dev
Questions welcome — especially real-world CI integration stories.













