Translate only what changed.
verbatra diffs your source locale against a committed lock file, sends only the new and changed keys to the provider you choose, and leaves every other key untouched.
npm i -D @verbatra/cli- Latest release
- @verbatra/cli 0.11.1
- File formats
- 14
- Providers
- 6
- License
- MIT
Works with the locale files you already have.
Every run is a diff, not a rewrite.
An example verbatra command-line session.
- verbatra translate
- diff en.json · 2 new · 1 changed · 117 unchanged
- de 3 translated · 117 untouched · 0 withheld
- es 3 translated · 117 untouched · 0 withheld
- fr 3 translated · 117 untouched · 0 withheld
- ✓ 9 keys translated in 1.8s · 351 untouched · lock updated
The lock file
One hash per key per locale, committed next to your files.
{ "de": {"inbox.title": "a1b2c3d4e5f6a7b8","inbox.count": "9f8e7d6c5b4a3210"} }
Written, and only that
de.json after the run.
{ "inbox": { "title": "Posteingang",new "count": "{count} neue Nachrichten"kept }}Refused before it reaches the file
Withheld, never written, sent again next run.
- key
- inbox.count
- candidate
- "Neue Nachrichten"
- missing
- {count}
- reason
- placeholder
- kept
- "{count} neue Nachrichten"
1. Configure
Source locale, targets, one provider.
2. Diff
New, changed, unchanged or orphaned, against the lock.
3. Translate
Only new and changed keys go out.
4. Verify and write
Broken results are withheld, the rest written.
Six providers, one interface.
Switch by changing one line of config.
Hover or tab through the cards.
The rest of the translation loop, in the same tool.
Hand a workbook to translators, import it back.
Export, get it back filled in, import through the same gate.
Read about the Excel handoffverbatra exportverbatra import translations.xlsx| key | source | target |
|---|---|---|
| cart.pay | Pay now | Bezahlen |
| cart.total | Total | Gesamt |
| nav.home | Home | Start |
See every locale's state in Verbatra Studio.
Coverage, flagged entries, in-place edits. No provider call.
Review translations in Studio
Run it on save, in CI, or from a GitHub Action.
watch translates on change. check fails the pull request when a locale drifts.
verbatra check --json{ "command": "check",
"result": { "inSync": false, "locales": [
{ "locale": "de", "missing": 0, "stale": 2 }
] } }Or hand it to your agent.
An MCP server, plus installable skills for the CLI, MCP and Studio.
Start with AInpx skills@latest add verbatra/skills --skill verbatra-cli -yverbatra mcpWhat you actually get.
This page's German, Spanish and French come from it.
- You pay for the keys you changed.
- Only new and changed keys go to the provider, and every run prints its token count per locale.
de: 2 translated, 281 unchanged, 468 tokens (394 in, 74 out)a run on this site's messages- A broken placeholder never reaches production.
- A candidate that drops a placeholder, breaks ICU or unbalances markup is withheld, never written, and sent again next run.
de: 1 translated, 0 unchanged, 1 integrity-withheldthe same gate guards Studio edits and imports- Locale drift fails the pull request.
verbatra checkexits 1 when any locale is missing or stale, with--jsonfor CI.- docs-i18n-check.ymlthis site runs it on every pull request
- Your terms and register stay fixed.
- A glossary binds how listed terms are translated;
tonesets formal, informal or neutral address. - glossary: { verbatra: "verbatra" }, tone: "informal"this site's verbatra.config.ts
- Every translation is a git diff.
- Locale files and the lock are plain text in your repo, and nothing is removed without
--prune. - verbatra.lock.jsonone hash per key per target locale
- People and other tools can take over.
- Excel export and import for translators, TMX for translation memory, generated TypeScript types for your keys.
- export, import, tmx, typesfour of the fourteen commands
Frequently asked questions
JSON for i18next, vue-i18n, next-intl, and ngx-translate, plus XLIFF, YAML, Flutter ARB, Java/Spring .properties, Apple .strings and Xcode String Catalogs, Android strings.xml, gettext .po/.pot files, INI, and .NET .resx. That covers React, Next.js, Vue, Nuxt, Angular, SvelteKit, Astro, Node.js, Spring, Flutter, iOS, macOS, Android, and any gettext-based stack. verbatra reads the files you already have; there is no verbatra-specific format to migrate to.
It keeps a committed lock file that records what was already translated. Each run diffs your source locale against that lock and sends only the new or changed keys to your provider. Unchanged keys are never touched, so a typical run costs a handful of strings, not your whole catalog.
Six, behind one interface: Anthropic, OpenAI, and Gemini (LLMs), DeepL and Google Cloud Translation (machine translation), and openai-compatible, which points verbatra at a local or self-hosted server like Ollama, LM Studio, or vLLM. You pick one by id in your config and can switch later by editing that one line. Gemini has a real free tier, and a local model costs nothing per call.
Every result passes a placeholder and ICU integrity check before it is written. A translation that drops, invents, or reorders a placeholder, or produces invalid ICU message syntax, is withheld rather than saved to your locale file. The same gate applies to edits and retranslations made in Verbatra Studio.
verbatra itself is free and open source under the MIT license. The only cost is your provider's usage, which you control: it translates only what changed, and you can run it for free on Gemini's free tier or a local OpenAI-compatible model.