Get startedAdd a language

Add a language

Add a new target locale to an existing verbatra project with a one-line config change and one translate run, while your existing locales stay untouched.

Adding a language is a one-line config change plus a run. verbatra sees the new locale as missing everything and fills it completely; your existing locales cost nothing, because the lock file still has them on record as current.

Add the locale to your config

Add it to targetLocales in verbatra.config.ts:

import { defineConfig } from "@verbatra/cli";

export default defineConfig({
  sourceLocale: "en",
  targetLocales: ["de", "fr"], // "fr" added
  format: "i18next-json",
  files: {
    pattern: "locales/{locale}.json",
  },
  provider: {
    id: "gemini",
    options: {
      model: "gemini-2.5-flash",
      maxOutputTokens: 4096,
    },
  },
});

Two rules, both enforced when the config loads: a target locale must not be the sourceLocale, and two entries must not collide case-insensitively (no de and DE in the same list).

Preview the work

Before spending a token, see what a run would do. diff is read-only and lists the pending keys per locale:

verbatra diff

The new locale has no target file yet, so verbatra treats it as empty and every source key shows up as missing; your existing locales list nothing, assuming their source strings have not changed. diff exits 1 while changes are pending, 0 once there are none. verbatra translate --dry-run gives you the same preview shaped as a run summary, with no provider call and no writes.

Translate

verbatra translate

The run translates every source key into the new locale and writes the file at your files.pattern (here locales/fr.json). A large source is split into sub-batches of at most 50 keys per provider request (configurable with maxBatchSize), so one oversized request cannot sink the whole locale.

This is the incremental behavior at work: only the new locale triggers provider calls. For each existing locale, verbatra diffs the source against that locale's baseline in verbatra.lock.json, finds no missing or changed keys, and sends nothing. Afterwards, verbatra check exits 0: every locale, including the new one, is in sync.

Languages with more plural categories

Some languages need more CLDR plural categories than your source has. English has two (one and other); Polish, Arabic, and Russian have more. By default verbatra translates the plural forms it finds in the source and does not invent the extras: the run still succeeds and emits a per-locale notice (code PLURAL_CATEGORIES_INCOMPLETE) naming the missing categories.

To have verbatra synthesize the missing forms instead, set generatePlurals: true in your config:

export default defineConfig({
  // ...
  generatePlurals: true,
});

Generation is supported for i18next-JSON projects translated by an LLM provider only; DeepL, the other formats, and unknown target languages fall back to the notice and never fail the run. Generated forms are integrity-checked like any translation and reported separately from translated keys in the run summary.

Maintaining the source locale

You only ever hand-maintain the source locale. To add strings, put them in the source file and run translate again: verbatra fills them into every target, including the one you just added.

Next

  • The lock file: why re-runs are cheap and what to commit.
  • Configuration: the full config schema, including glossary and tone.
  • Providers: provider options and where to get a key.
Edit on GitHub