---
title: "Add a language"
description: "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."
type: "how-to"
---
# 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.

Use this when a project already translates into some languages and you want one more. It takes a one-line config change and one run. verbatra sees the new locale as missing every key and fills it; your existing locales cost nothing, because the lock file still has them on record as current.

You need a working project: a config, a source locale file, and a provider key. If you do not have one yet, start with the [quickstart](https://verbatra.kreitz-webdev.de/docs/quickstart.md).

## Add the locale to your config [#add-the-locale-to-your-config]

Add the code to `targetLocales` in `verbatra.config.ts`:

```ts title="verbatra.config.ts"
import { defineConfig } from "@verbatra/cli";

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

### Locale code rules [#locale-code-rules]

<AvailableFrom version="0.12.0" />

Write the code in BCP 47 form, with a hyphen: `pt-BR`, not `pt_BR`. If your files use underscores, keep writing `pt-BR` and set `files.localeStyle` to `posix`; verbatra keeps the `pt_BR.json` file name. The config load rejects an invalid code, the source locale, and two codes that differ only in case. See [Locale codes](https://verbatra.kreitz-webdev.de/docs/config-file.md#locale-codes) for the full rules, and run [`verbatra doctor`](https://verbatra.kreitz-webdev.de/docs/cli/doctor.md) to see whether a provider supports the new language.

## Preview the work [#preview-the-work]

See what a run would do before you spend anything:

```bash
verbatra diff --locales fr
```

The new locale has no file yet, so every source key is listed as missing. Leave out `--locales` to confirm your other locales list nothing. `diff` calls no provider and writes nothing. For a cost figure, run `verbatra translate --estimate`; see [Estimate cost before a run](https://verbatra.kreitz-webdev.de/docs/estimating-cost.md).

## Translate [#translate]

```bash
verbatra translate
```

The run translates every source key into the new locale and writes the file at your `files.pattern`, here `locales/fr.json`. Only the new locale triggers provider calls: the other locales have no missing or changed keys against their lock baseline, so nothing is sent for them.

If the run keeps nothing for the new locale, because every key failed a check, its provider requests failed, or a token budget withheld them, no file is created. The keys stay missing and the next run retries them.

Afterwards, `verbatra check` exits `0` when every locale, the new one included, is in sync.

## Languages with more plural categories [#languages-with-more-plural-categories]

Some languages need more plural forms than your source has. English has `one` and `other`; Polish needs four, Arabic six, and French adds `many`. By default verbatra translates the forms your source has and does not invent the others: the run succeeds and reports a `PLURAL_CATEGORIES_INCOMPLETE` notice naming what is missing.

### Generate the missing forms [#generate-the-missing-forms]

<AvailableFrom version="0.3.0" />

If you use i18next JSON with an LLM provider, you can let verbatra write the missing forms:

```ts title="verbatra.config.ts"
export default defineConfig({
  // ...
  generatePlurals: true,
});
```

Generated forms pass the same integrity checks as any translation.

### Forms from CLDR [#forms-from-cldr]

<AvailableFrom version="0.12.0" />

Which forms a language needs comes from the CLDR plural rules built into Node.js, for every language, ordinals included. The ICU formats (next-intl and ARB) keep a whole plural in one value, so they need no generation: the provider is asked for exactly the arms the target language uses. See [`generatePlurals`](https://verbatra.kreitz-webdev.de/docs/config-file.md#generateplurals) for what falls back to the notice, and [Plurals](https://verbatra.kreitz-webdev.de/docs/language-support.md#plurals) for how verbatra decides which forms a language needs.

## Keep maintaining the source only [#keep-maintaining-the-source-only]

You edit only the source locale from now on. Add a string there and run `translate` again: verbatra fills it into every target, including the one you just added.

## Related [#related]

- [`verbatra translate`](https://verbatra.kreitz-webdev.de/docs/cli/translate.md) and [`verbatra diff`](https://verbatra.kreitz-webdev.de/docs/cli/diff.md): every flag used on this page.
- [The config file](https://verbatra.kreitz-webdev.de/docs/config-file.md#locales-and-files): `targetLocales`, `files.pattern` and `files.localeStyle`.
- [Languages and locales](https://verbatra.kreitz-webdev.de/docs/language-support.md): which languages each provider covers, scripts, regional variants and right-to-left text.
- [The lock file](https://verbatra.kreitz-webdev.de/docs/the-lock-file.md): why existing locales cost nothing on a re-run.
