intl-ai
v0.7.0
Published
AI-powered build-time i18n translation CLI
Downloads
0
Readme
intl-ai
AI-powered i18n translation, shipped as a single binary
Documentation · Roadmap · Discussions · Report an issue
intl-ai translates your locale files with any AI provider, at build time or on demand. One Rust binary, no Node dependency, no runtime code. A lockfile tracks per-key provenance and review state, so AI output never silently overwrites human work.

Why intl-ai
Most i18n translation workflows are manual (copy JSON, open a translation tool, paste back) or runtime-heavy (call an AI API on every page load). intl-ai runs at build time so translations are baked in before your app ships.
- Zero runtime overhead. Translations happen during the build, not in the browser or on the server.
- Any stack. The binary reads and writes
locale_dir/{locale}.json|yamlfiles, so it pairs with i18next, next-intl, vue-i18n, react-intl, Paraglide, and anything else that consumes flat locale files. - Any AI provider. An OpenAI-compatible HTTP endpoint, or a local agent CLI (
claude-code,opencode,codex,crush,gemini) for keyless dev. - Lockfile-tracked origins.
intl-ai.lock.d/records whether each translation was written by a human or generated by AI, plus a review bit, so you always know what to trust. - Additive by default.
fillwrites missing keys only. Existing values (human or AI) are never touched unless you pass--stale,--regenerate, or--include-human. - ICU MessageFormat, hardline. Generated output is always ICU MessageFormat (
{name},plural/select/selectordinal,#): that constraint is what makes machine validation of AI output possible. Other placeholder syntaxes are out of scope. - Shift-left validation.
fill --validatere-prompts the provider with check feedback until output is ICU-clean;checkfails CI on missing, stale, or invalid translations.
Install
Shell (Linux, macOS, Windows/WSL)
curl -fsSL https://intl-ai.illo.fyi/install.sh | bashPowerShell (Windows)
irm https://github.com/sigilco/intl-ai/releases/latest/download/intl-ai-installer.ps1 | iexHomebrew
brew install sigilco/tap-intl-ai/intl-aimise
mise use npm:intl-ai@latestnpm / npx
npm install -g intl-ai
npx intl-ai --helpIntegrations
The binary is the core. These scoped packages are thin shims that drive it from your build tool, so integration is drop-in:
| Package | Stack | What it does |
| ------------------- | -------------------------------------------- | ----------------------------------------------------------- |
| @intl-ai/unplugin | Vite, Webpack, Rollup, esbuild, Rspack, Farm | Runs intl-ai fill on build start and check as a CI gate |
| @intl-ai/next | Next.js (webpack and Turbopack) | withIntlAi() config wrapper; same fill/check wiring |
| @intl-ai/expo | Expo / React Native | Config plugin that runs intl-ai fill during prebuild |
Each shim installs intl-ai as a dependency and exposes the same quality controls as the CLI (fill validation, judge threshold, --fail-on severities) as plugin options. For stacks without a shim (Flutter, Xcode/SwiftPM, Gradle, MSBuild, generic npm scripts), run the binary directly in the lifecycle hook your stack provides; see the per-stack recipes in the docs.
Community integrations
The packages above are tier-1: maintained in this repo and versioned in lockstep with the binary. Integrations for other stacks (a Flutter plugin, a Gradle task, an Xcode build phase, a Metro wrapper) are community-supported: owned by their authors, listed in the docs. If you build one, the community integrations guide covers the shim contract (resolve the binary, spawn at the right lifecycle, expose the quality controls) and how to get listed.
Quick start
intl-ai init # writes intl-ai.toml + a replay cassette
# edit intl-ai.toml: set locale_dir, source, targets, provider
intl-ai fill # translate missing keys
intl-ai check # audit: missing, stale, invalid, unreviewedA minimal config:
locale_dir = "locales"
source = "en"
targets = ["fr", "de"]
[provider]
kind = "http"
model = "your-model"
api_key = "${env:OPENAI_API_KEY}"Or go keyless with a local agent CLI:
[provider]
kind = "command"
agent = "claude-code"Commands
| Command | What it does |
| ---------------------------------------- | --------------------------------------------------------------------- |
| intl-ai init | Scaffold intl-ai.toml and a replay cassette |
| intl-ai fill | Translate missing keys (additive by default) |
| intl-ai check | Read-only audit: missing, stale, invalid, modified, extra, unreviewed |
| intl-ai status | Per-locale inventory counts |
| intl-ai mark <keys> --origin ai\|human | Set key provenance (or --absent for tombstones) |
| intl-ai review / unreview | Set or clear the review bit on keys |
| intl-ai lockfile check\|fmt\|merge | Validate, normalize, or merge lockfile shards |
| intl-ai config validate\|schema | Validate a config file or emit the JSON Schema |
Every command accepts --format json for agent and CI consumption.
Configuration
intl-ai reads intl-ai.toml, intl-ai.json, intl-ai.yaml, or intl-ai.yml, discovered by walking ancestors to the .git boundary. Override with --config PATH or --config - (TOML on stdin).
- Provider kinds:
http(OpenAI-compatible chat completions),command(local agent CLI preset or free-form command),replay(deterministic cassette for tests). ${env:VAR}and${file:PATH}interpolation,extendsfor shared base config,INTL_AI_*env overlay.intl-ai config validatechecks a config file;intl-ai config schemaemits the JSON Schema (also on SchemaStore) for editor autocomplete.
See Configuration for the full schema.
Lockfile and review workflow
intl-ai.lock.d/<locale>.toml holds one sorted TOML block per key: source hash, written value, origin (ai or human), and reviewed. Commit it — it is a text format designed for git diffs and merges (intl-ai lockfile merge resolves conflicts union-style, human wins).
- A value that differs from what AI last wrote counts as human-owned:
fillwill not touch it, and a stale source marks it as acheckfinding, never an auto-rewrite. intl-ai review/unreviewmanage the review bit;check --fail-on unreviewedis the human-in-the-loop gate for CI.
CI
intl-ai check --fail-on missing,stale,invalid exits 10 when findings fire and prints a JSON report under --format json. Run it after fill (or standalone) in your pipeline.
Migration
Coming from the 0.4.x @intl-ai/* npm packages:
- Install the binary (see Install above). If you used
@intl-ai/unpluginor@intl-ai/next, upgrade to the new major version instead of dropping the dependency: the scoped packages are now thin shims that run the binary for you. - Rename
intl-ai.config.ts/.jsontointl-ai.toml(config keys are now snake_case:api_key,locale_dir,source/targetsinstead ofdefaultLocale/locales). - Delete
intl-ai.lock.jsonand runintl-ai fillonce: existing keys are recorded as human-owned (never overwritten) and freshintl-ai.lock.d/shards are written. If you want the 0.4.x provenance imported instead, do it by hand or hand the migration guide to an agent. --forceis gone: usefill --stale(AI-owned stale keys) orfill --regenerate(all AI-owned keys);--include-humanadditionally covers human-owned values.
The TypeScript implementation is frozen on the legacy branch. @intl-ai/api and @intl-ai/cli stay deprecated; @intl-ai/unplugin, @intl-ai/next, and @intl-ai/expo are re-released as binary-driven shims.
