---
title: "verbatra translate"
description: "Übersetze jede Ziel-Locale einmal: Nur neue und geänderte Keys gehen an deinen Provider, dann schreibt der Befehl die Ergebnisse und beendet sich."
type: "reference"
---
# verbatra translate

Übersetze jede Ziel-Locale einmal: Nur neue und geänderte Keys gehen an deinen Provider, dann schreibt der Befehl die Ergebnisse und beendet sich.

Führe einen Übersetzungsdurchlauf über jede Ziel-Locale aus; danach beendet sich der Befehl. `translate` vergleicht die Quelle mit der [Lock-Datei](https://verbatra.kreitz-webdev.de/de/docs/the-lock-file.md), schickt nur neue oder geänderte Strings an den Provider, führt die [Integritätsprüfungen](https://verbatra.kreitz-webdev.de/de/docs/translation-safety.md) aus, schreibt die Locale-Dateien und aktualisiert das Lock. Einen unveränderten String sendet es nie zweimal. Ein echter Lauf ergänzt außerdem fehlende Einträge in einer vorhandenen `.gitignore`, siehe [.gitignore-Einträge](https://verbatra.kreitz-webdev.de/de/docs/cli.md#gitignore-einträge).

## Synopsis [#synopsis]

```bash
verbatra translate [flags]
```

## Beispiele [#beispiele]

```bash
# einmal übersetzen, mit der gefundenen Konfiguration
verbatra translate

# die Keys ansehen, die entfernt würden, ohne etwas auszugeben
verbatra translate --prune --dry-run

# eine Locale nach der anderen, wie es ein Free Tier mit Rate-Limit braucht
verbatra translate --locales de

# den Lauf schätzen und bepreisen, ohne etwas auszugeben
verbatra translate --estimate

# anhalten, bevor der Lauf 50000 Tokens überschreitet
verbatra translate --max-tokens 50000

# auch veraltete Keys neu übersetzen, die ein Mensch geschrieben hat
verbatra translate --include-human
```

## Flags [#flags]

| Flag | Argument | Standard | Wirkung |
| --- | --- | --- | --- |
| `--locales` | `<list>` | jede konfigurierte Ziel-Locale | nur diese kommagetrennte Teilmenge übersetzen; eine nicht konfigurierte Locale scheitert mit `UNKNOWN_LOCALE`, eine leere Liste mit `INVALID_LOCALES`, beide mit Exit `2` |
| `--dry-run` | keins | aus | melden, was ein Lauf ändern würde, ohne Provider-Aufruf und ohne Dateien zu schreiben; braucht keinen API-Key |
| `--prune` | keins | die `prune`-Option der Konfiguration, sonst aus | verwaiste Keys (in einer Zieldatei, nicht in der Quelle) aus der geschriebenen Datei und dem Lock entfernen |
| `--lock-timeout` | `<seconds>` | `600` | so lange auf eine gehaltene Schreibsperre einer Locale warten; eine Ganzzahl von `1` bis `3600` |
| `--concurrency` | `<n>` | `1` | bis zu `n` Ziel-Locales gleichzeitig übersetzen; eine Ganzzahl von `1` bis `100`, abgelehnt bei einem Token-Budget |
| `--max-tokens` | `<n>` | das `maxTokens` der Konfiguration | harte Token-Obergrenze für diesen Lauf, eine positive ganze Zahl (sonst `INVALID_MAX_TOKENS`); es gilt der niedrigere Wert von diesem Flag und `maxTokens` |
| `--no-cache` | keins | aus (Cache an) | den [Übersetzungsspeicher-Cache](https://verbatra.kreitz-webdev.de/de/docs/the-cache.md) (`verbatra.cache.json`) für diesen Lauf umgehen |
| `--include-human` | keins | aus | nur für diesen Lauf auch veraltete Keys neu übersetzen, die ein Mensch geschrieben oder importiert hat; [gepinnte Keys](https://verbatra.kreitz-webdev.de/de/docs/protecting-human-translations.md#keys-pinnen) bleiben unangetastet |
| `--estimate` | keins | aus | schätzen, was der Lauf senden und kosten würde, und dann beenden; impliziert `--dry-run` |

Nimmt außerdem die [globalen Flags](https://verbatra.kreitz-webdev.de/de/docs/cli.md#globale-flags) `--cwd`, `--config` und `--json`. Vor dem Lauf lädt `translate` die [Umgebungsdateien](https://verbatra.kreitz-webdev.de/de/docs/cli.md#umgebungsdateien).

## Verhalten [#verhalten]

<Callout type="warn">
Ein Lauf ohne `--dry-run` oder `--estimate` schickt jeden neuen oder geänderten String an den Provider, und ein gehosteter Provider rechnet ihn ab: Schätze den Lauf mit `--estimate` ab und deckle ihn mit `--max-tokens`.
</Callout>

<Callout type="warn">
Ein API-Key, der über einfaches `http://` (nicht Loopback) an einen selbst gehosteten Server geht, reist unverschlüsselt durchs Netz, siehe [Keys sind optional](https://verbatra.kreitz-webdev.de/de/docs/providers.md#keys-sind-optional).
</Callout>

### Dry Run [#dry-run]

`--dry-run` konstruiert keinen Provider, braucht also keinen API-Key und kann nichts kosten. Es liest Quell- und Zieldateien, vergleicht sie mit der Lock-Datei und meldet genau, was ein echter Lauf ändern würde. Es schreibt nichts (keine Locale-Datei, keine Lock-Aktualisierung, keinen Run-Status-Schnappschuss), liest und schreibt mit einem Maschinen-Provider den Cache nicht (unter Provider `none` liest es das Übersetzungsgedächtnis, siehe unten) und nimmt keine Schreibsperre, wartet also nie auf einen laufenden Lauf.

<Callout>
Standardmäßig löscht ein Lauf nichts: Verwaiste Keys werden gemeldet und bleiben stehen. `--prune` oder `prune: true` in der Config löscht genau diese Keys aus den Zieldateien und dem Lock; `--prune --dry-run` zeigt sie dir vorher.
</Callout>

### Kostenschätzung [#kostenschätzung]

<AvailableFrom version="0.11.0" />

`--estimate` ergänzt den Dry Run um eine Schätzung vor dem Lauf: wie viele Keys gesendet würden, wie viele Provider-Requests das wären und welche Menge der Provider abrechnet (Tokens bei einem LLM oder einem `openai-compatible`-Endpunkt, Quellzeichen bei DeepL, Google Cloud Translation oder LibreTranslate; ein selbst gehosteter Endpunkt oder Server wird nicht abgerechnet, die Schätzung meldet also keine API-Kosten). Ein Geldbetrag erscheint nur, wenn die Konfiguration einen `rates`-Block für Provider und Modell hat; sonst wird der fehlende Raten-Key benannt, statt `0.00` zu erfinden. Siehe [Kosten abschätzen](https://verbatra.kreitz-webdev.de/de/docs/estimating-cost.md).

### Eine Teilmenge der Locales [#eine-teilmenge-der-locales]

<AvailableFrom version="0.9.0" />

`--locales de,fr` beschränkt den Lauf auf einen Teil der konfigurierten Ziele. Die übrigen Locales behalten ihre Dateien, Lock-Einträge und Cache-Einträge. Nutze es bei einem Free Tier mit Rate-Limit, um eine Locale nach der anderen zu übersetzen, oder um eine einzelne partielle Locale neu laufen zu lassen. Der Run-Status-Schnappschuss beschreibt dann nur diese Teilmenge.

### Schreibsperren und Unterbrechungen [#schreibsperren-und-unterbrechungen]

Eine Locale wartet bis zu `--lock-timeout` auf eine belegte [Schreibsperre](https://verbatra.kreitz-webdev.de/de/docs/the-lock-file.md#die-schreibsperre) und scheitert dann mit `LOCK_CONTENDED`, während die übrigen Locales weiterlaufen. Eine Sperre, die ein nicht mehr laufender verbatra-Prozess auf diesem Rechner hinterlassen hat, wird sofort übernommen. Der Timeout begrenzt nur dieses Warten vor jedem Provider-Aufruf: Das Eintragen einer geschriebenen Datei in die Lock-Datei wartet immer bis zum Standard von zehn Minuten, damit keine geschriebene Datei unvermerkt bleibt. Ein Warten von mehr als einer Sekunde gibt auf stderr eine Zeile aus, die die Sperre und ihren Halter nennt (unter `--json` ein `lock-wait`-Datensatz), und `--quiet` lässt sie nicht weg. Strg-C oder SIGTERM gibt die Sperren des Laufs frei, bevor der Befehl endet.

### Token-Obergrenze [#token-obergrenze]

<AvailableFrom version="0.12.0" />

`--max-tokens` ist immer ein harter Stopp: Ein Provider-Request, der die Grenze überschreiten würde, wird zurückgehalten, egal was `budgetBehavior` sagt, und seine Keys stehen unter `budgetWithheld`. Die Grenze wird wie ein konfiguriertes [`maxTokens`-Budget](https://verbatra.kreitz-webdev.de/de/docs/config-file.md#maxtokens-und-budgetbehavior) gezählt und kann dieses Budget verschärfen, aber nie lockern. Ein Lauf, den die Grenze abgeschnitten hat, endet mit `1`. Führe vorher `--estimate` aus, um einen passenden Wert zu finden.

### Parallele Locales [#parallele-locales]

`--concurrency` wird mit Exit `2` abgelehnt, wenn ein Token-Budget gilt (aus `maxTokens` oder `--max-tokens`), weil sonst die Reihenfolge der Locales entscheiden würde, welche ihre restliche Arbeit verliert; ein Dry Run ist ausgenommen. Tritt ein Fehler für den ganzen Lauf, etwa eine beschädigte Lock-Datei, auf, während Locales laufen, startet keine weitere, und die laufenden werden fertig und geben ihre Sperren frei, bevor der Befehl mit `2` endet.

### Keys, die ein Mensch geschrieben hat [#keys-die-ein-mensch-geschrieben-hat]

<AvailableFrom version="0.12.0" />

Ein veralteter Key, dessen Wert ein Mensch geschrieben, importiert oder außerhalb von verbatra geändert hat, bleibt standardmäßig erhalten: Er steht unter `protected`, geht nicht an den Provider und bleibt für `verbatra check` veraltet. Eine Warnung auf stderr sagt, wie viele erhalten blieben (gepinnte Keys zählen nicht mit), und verweist auf `--include-human`, das sie für einen Lauf neu übersetzt (`humanEdits: "overwrite"`) und deshalb keine Warnung ausgibt. Geschützte Keys ändern den Exit-Code nicht, außer in einem rein menschlichen Projekt. Siehe [Menschliche Übersetzungen schützen](https://verbatra.kreitz-webdev.de/de/docs/protecting-human-translations.md).

### Rein menschliche Projekte [#rein-menschliche-projekte]

<AvailableFrom version="0.12.0" />

In einem [rein menschlichen](https://verbatra.kreitz-webdev.de/de/docs/human-only-workflow.md) Projekt (`provider: { id: "none" }`) wird kein Provider aufgerufen. Keys, die das Translation Memory abdeckt, werden geschrieben; jeder andere fehlende oder geänderte Key steht unter `unfilled` und führt zu Exit `3`; eine fehlgeschlagene oder partielle Locale gewinnt weiterhin mit `1`. Ein Dry Run liest hier das Memory, sodass sein Plan dieselben `cacheHits`- und `unfilled`-Keys zeigt, und `--estimate` meldet nichts Abgerechnetes; beide enden genauso mit Exit `3`. Ohne `--json` sagt eine Warnung auf stderr, wie viele Keys einen Menschen brauchen, und ein `next:`-Tipp verweist auf [`verbatra export`](https://verbatra.kreitz-webdev.de/de/docs/cli/export.md), womit du die `unfilled`-Keys übergibst.

### Fehlgeschlagene und partielle Locales [#fehlgeschlagene-und-partielle-locales]

<AvailableFrom version="0.9.0" />

Eine fehlgeschlagene Locale ist nicht fatal: Der Lauf wird fertig und endet mit `1`. Auch eine **partielle** Locale endet mit `1`: ihre Datei wurde geschrieben, aber es fehlen noch Keys, meist weil ein Provider-Teilbatch scheiterte oder das Integritäts-Gate eine Übersetzung ablehnte. Die menschenlesbare Ausgabe listet jeden abgelehnten Key unter `integrity-withheld` mit Grund (`placeholder`, `markup`, `icu`, `degenerate` oder `empty`); mit `--json` trägt jede Locale sie in `integrityRefusals`. Keys, die der Lauf zum Review markiert hat, folgen der Zahl `N needs-review` der Locale unter einer `needs-review:`-Zeile, jeweils mit ihren [Review-Gründen](https://verbatra.kreitz-webdev.de/de/docs/translation-safety.md#review-flags); mit `--json` stehen sie in `needsReview`.

### Nicht unterstützte Locales [#nicht-unterstützte-locales]

<AvailableFrom version="0.12.0" />

Eine Locale, die der konfigurierte DeepL- oder Google-Cloud-Translation-Provider nicht unterstützt, lehnt den ganzen Lauf mit `LOCALE_UNSUPPORTED_BY_PROVIDER` und Exit `2` ab, auch bei einem Dry Run und mit `--estimate`, bevor irgendetwas kostet. Lass sie mit `--locales` weg oder lies [Sprachunterstützung](https://verbatra.kreitz-webdev.de/de/docs/language-support.md#unterstützung-vor-einem-lauf-prüfen). Ein Glossar oder Ton, den der Provider nicht anwenden kann, ergibt nur einen Hinweis (`GLOSSARY_UNSUPPORTED_BY_PROVIDER`, `FORMALITY_UNSUPPORTED_BY_PROVIDER`), ebenso `LOCALE_UNVERIFIED_BY_PROVIDER` und bei einem LLM `LOCALE_NOT_WELL_TESTED`.

### JSON-Ausgabe [#json-ausgabe]

Schema: [`translate-envelope.json`](https://verbatra.kreitz-webdev.de/schema/v1/translate-envelope.json) validiert den ganzen Envelope; [Schemas](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md#schemas) listet die übrigen auf.

Mit `--json` trägt stdout einen [Envelope](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md#json-ausgabe), dessen `result` eine `RunSummary` ist; [RunSummary](https://verbatra.kreitz-webdev.de/de/docs/sdk/run-summary.md) listet jedes Feld auf, für den Lauf und für jede Locale.

### Rückmeldung im Terminal [#rückmeldung-im-terminal]

<AvailableFrom version="0.12.0" />

`translate` nennt vor dem Lauf die Locales und den Provider und gibt danach die Laufzeit, die verbrauchten Tokens und den nächsten Befehl aus. In einem interaktiven Terminal ist der Fortschritt eine Spinner-Zeile; wird stderr umgeleitet, ist jeder Schritt eine eigene Zeile:

```text output
verbatra: translating 2 locales with gemini/gemini-2.5-flash
verbatra: translating de
verbatra: de batch 1/1
verbatra: de: writing
verbatra: de done, 12 translated
verbatra: translating fr
verbatra: fr batch 1/1
verbatra: fr: writing
verbatra: fr done, 12 translated
verbatra: run finished, 2 locales processed
[ok] done in 4.2s, 1830 tokens
next: verbatra check (confirm every locale is in sync)
```

Ein Dry Run beginnt mit `dry run over 2 locales, no provider call`, eine Schätzung mit `estimating 2 locales, no provider call` und ein rein menschliches Projekt mit `filling 2 locales from the translation memory (provider none)`. Ein Dry Run oder eine Schätzung beendet jede Locale stattdessen mit `would translate`. Eine Locale, die nur einen Teil der Keys behalten hat, endet mit `partly done`, eine fehlgeschlagene mit `failed`, und die Schlusszeile nennt, wie viele fehlgeschlagen sind. Ein Dry Run schließt mit `dry run done in 4.2s, nothing written`. Eine Schätzung schließt mit `estimate done in 4.2s, nothing written` <AvailableFrom version="0.13.0" />. Diese Zeilen gehen auf stderr, und `--quiet` lässt sie weg. Siehe [Terminalausgabe](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md#terminalausgabe).

## Exit-Codes [#exit-codes]

| Code | Bedeutung |
| --- | --- |
| `0` | jede Ziel-Locale ist vollständig |
| `1` | der Lauf wurde fertig, aber eine Locale ist fehlgeschlagen oder partiell |
| `2` | konnte nicht laufen: ein Fehler in Konfiguration, Quelle, Format, Provider, Locale-Unterstützung oder Lock-Datei, oder ein Verwendungsfehler |
| `3` | rein menschliches Projekt: der Lauf (auch als Dry Run oder mit `--estimate`) war sauber, aber Keys warten auf eine menschliche Übersetzung |
| `130` | mit Strg-C (SIGINT) unterbrochen, nachdem die Schreibsperren freigegeben wurden |
| `143` | mit SIGTERM gestoppt, nachdem die Schreibsperren freigegeben wurden |

Bei einer Unterbrechung endet stderr mit `verbatra: interrupted (SIGINT), released locks`, oder unter `--json` mit dem Datensatz `{"type":"interrupted","signal":"SIGINT","locksReleased":true}`. Scheitert das Freigeben der Sperren oder ist es nach 5 Sekunden nicht fertig, sagt die Zeile das stattdessen (`could not release locks: <reason>` oder `lock release did not finish within 5s`), und der JSON-Datensatz trägt `"locksReleased":false` mit `"reason":"failed"` (plus `message`) oder `"reason":"timed-out"` (plus `deadlineMs`). Siehe [den Exit-Code-Vertrag](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md#exit-codes).

## Siehe auch [#siehe-auch]

- [So funktioniert es](https://verbatra.kreitz-webdev.de/de/docs/how-it-works.md) erklärt die Pipeline aus Lesen, Vergleichen, Übersetzen und Schreiben.
- [Der Cache](https://verbatra.kreitz-webdev.de/de/docs/the-cache.md) erklärt, was `--no-cache` umgeht.
- [Übersetzungssicherheit](https://verbatra.kreitz-webdev.de/de/docs/translation-safety.md) behandelt die Integritätsprüfungen und die Prüfwarteschlange.
- [`verbatra diff`](https://verbatra.kreitz-webdev.de/de/docs/cli/diff.md) zeigt dieselben ausstehenden Keys, nur lesend.
- [CI und Exit-Codes](https://verbatra.kreitz-webdev.de/de/docs/ci-and-exit-codes.md) zeigt, wie du in einer Pipeline auf diese Codes reagierst.
