Skip to content

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.

verbatra translate

An example verbatra command-line session.

  1. 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.

verbatra.lock.json
{ "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. 1. Configure

    Source locale, targets, one provider.

  2. 2. Diff

    New, changed, unchanged or orphaned, against the lock.

  3. 3. Translate

    Only new and changed keys go out.

  4. 4. Verify and write

    Broken results are withheld, the rest written.

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 handoff
verbatra export
verbatra import translations.xlsx
keysourcetarget
cart.payPay nowBezahlen
cart.totalTotalGesamt
nav.homeHomeStart

See every locale's state in Verbatra Studio.

Coverage, flagged entries, in-place edits. No provider call.

Review translations in Studio
Verbatra Studio
The Verbatra Studio Review page listing five flagged entries across the de, es and fr locales, each row showing the key, its review reasons, and Edit, Approve and Reject actions.

Run it on save, in CI, or from a GitHub Action.

watch translates on change. check fails the pull request when a locale drifts.

Wire up CI
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 AI
npx skills@latest add verbatra/skills --skill verbatra-cli -y
verbatra mcp

llms.txtllms-full.txtMCP server docsverbatra/skills

What 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 check exits 1 when any locale is missing or stale, with --json for 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; tone sets 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.

Stop hand-syncing locale files.

npm i -D @verbatra/cli
Read the docs