Inhaltsverzeichnis
JSON-Übersetzungsdateien: Formate, Struktur und Best Practices für i18n
Fast jede Webanwendung, die in mehr als einer Sprache verfügbar ist, speichert Übersetzungen in JSON-Dateien. Das Format ist allgegenwärtig, aber die Konventionen dafür sind nicht einheitlich. Verschiedene Frameworks erwarten unterschiedliche Strukturen: ein flaches Schlüssel-Wert-Objekt, einen tief verschachtelten Namespace-Baum, eine Nachricht mit eingebetteter ICU-Syntax oder ein Chrome-Extension-Manifest mit eigener Deskriptorstruktur. Die falsche Formatwahl am Anfang oder eine spätere Migration zwischen Formaten sind mit echten Kosten verbunden.
Dieser Leitfaden behandelt die wichtigsten heute verwendeten JSON-Übersetzungsformate, wie man Übersetzungsdateien in großem Maßstab organisiert, Schlüssel-Namenskonventionen, Pluralisierungsmuster, Validierungs-Tooling und die Migration zwischen JSON und alternativen Formaten wie XLIFF und PO.
TL;DR / Wichtigste Erkenntnisse
- JSON ist das dominante Format für Web-i18n, weil es JavaScript-nativ, menschenlesbar ist und gut mit Versionskontrolle funktioniert — aber es gibt kein einziges "JSON-i18n-Format". Jede wichtige Bibliothek definiert ihre eigenen Konventionen.
- Die häufigsten Varianten sind: flaches Schlüssel-Wert-Format (einfach, aber schwer in großem Maßstab zu warten), verschachtelt/Namespace (organisiert, aber ausführlich), i18next (Namespace mit integrierten Plural-Schlüssel-Suffixen), FormatJS/react-intl (ICU MessageFormat in Werten) und chrome.i18n (Deskriptor-Objekte mit einem
message-Feld und optionalerdescription). - Die Dateiorganisation ist genauso wichtig wie das Format: Das Aufteilen von Übersetzungen nach Namespace oder Feature-Domäne hält Dateien klein, reduziert Merge-Konflikte und ermöglicht Lazy Loading.
- Die Syntax für Pluralisierung und Variableninterpolation variiert je nach Bibliothek — ICU MessageFormat in Werten bietet die portabelste und ausdrucksstärkste Option, erfordert aber eine kompatible Laufzeitumgebung.
- CI-Validierung — das Prüfen auf fehlende Schlüssel, fehlerhaftes JSON und nicht übersetzte Zeichenketten — ist der effektivste Weg, um defekte Übersetzungen von der Produktion fernzuhalten.
Warum JSON für Übersetzungen?
Bevor wir Formate vergleichen, lohnt es sich zu verstehen, warum JSON zum Standard für Web-i18n wurde — und warum diese Wahl nicht immer offensichtlich ist.
Menschenlesbar und diff-freundlich. Eine JSON-Übersetzungsdatei ist ohne Werkzeuge lesbar. Ein Diff in einem Pull Request zeigt genau, welche Zeichenketten geändert, hinzugefügt und entfernt wurden. Vergleichen Sie dies mit XLIFF 2.0, wo dieselbe Änderung in XML-Attributen über mehrere Elemente verteilt ist, oder mit kompilierten Binärformaten, bei denen Diffs unleserlich sind.
JavaScript-nativ. JSON.parse() ist in jede JavaScript-Laufzeitumgebung integriert. Es gibt keine Parsing-Abhängigkeit zu installieren, keinen Format-Adapter zu konfigurieren. Wenn eine Next.js-Anwendung Übersetzungen für den Browser bündelt, sendet sie einfaches JSON — kein Serialisierungs-Overhead, kein benutzerdefinierter Parser.
Einfach programmatisch zu generieren und zu verarbeiten. Jede Sprache hat eine JSON-Bibliothek. Das Generieren von Übersetzungsdateien aus einer Datenbank, einem Tabellenkalkulationsexport oder einer Übersetzungsmanagementsystem-API ist eine direkte JSON-Serialisierungsaufgabe.
Funktioniert gut mit Versionskontrolle. JSON-Dateien sind Text. Sie lassen sich sauber zusammenführen, wenn Änderungen in verschiedenen Schlüsseln vorliegen, sie erzeugen eine lesbare Blame-Historie und funktionieren mit Standard-Diff-Tools.
Alternativen und ihre Kompromisse
| Format | Stärken | Schwächen |
|---|---|---|
| XLIFF 2.0 | Reichhaltige Metadaten, Übersetzer-Notizen, Statusverfolgung, Industriestandard | Ausführliches XML, schlechte Diff-Lesbarkeit, komplexes Tooling |
| PO / Gettext | Reifes Ökosystem, msgid/msgstr-Modell unterstützt Kontext, Pluralformen integriert | Erfordert spezialisierte Parser, weniger verbreitet in JavaScript |
| YAML | Lesbar, unterstützt mehrzeilige Zeichenketten natürlich | Einrückungsempfindlich (fehleranfällig), kein nativer Browser-Parser |
| ARB (Application Resource Bundle) | Flutter/Dart-nativ, unterstützt Metadaten pro Schlüssel | Dart-spezifisches Ökosystem, begrenzte Web-Tooling |
| JSON | Allgegenwärtig, natives JavaScript, tolles Tooling | Keine integrierten Metadaten, Pluralbehandlung variiert je nach Bibliothek |
XLIFF ist die richtige Wahl, wenn Übersetzungen über eine professionelle Übersetzungsagentur mit CAT-Tools laufen. PO ist für Projekte geeignet, die das Gettext-Ökosystem nutzen möchten (Poedit, GNU-Gettext-Dienstprogramme). Für die meisten in React, Vue, Angular oder Svelte erstellten Webanwendungen ist JSON der praktische Standard.
Gängige JSON-Übersetzungsformate
Flaches Schlüssel-Wert-Format
Die einfachste mögliche JSON-Übersetzungsdatei ist ein einstufiges Objekt, bei dem jeder Schlüssel ein Zeichenfolgenbezeichner und jeder Wert die übersetzte Zeichenkette ist.
{
"welcome_message": "Willkommen auf unserer Plattform",
"login_button": "Anmelden",
"logout_button": "Abmelden",
"error_not_found": "Seite nicht gefunden",
"error_server": "Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut."
}
Dieses Format hat keine Lernkurve und funktioniert mit jedem JSON-Parser. Das Problem tritt im großen Maßstab auf: Eine flache Datei mit 500 Schlüsseln für eine große Anwendung wird unnavigierbar. Es gibt keine visuelle Gruppierung, keinen Hinweis darauf, wo eine Zeichenkette verwendet wird, und keine Möglichkeit, eine Teilmenge von Übersetzungen für Lazy Loading zu extrahieren.
Am besten für: Kleine Projekte, Prototypen oder Anwendungen mit weniger als 100 Übersetzungsschlüsseln.
Verschachteltes / Namespace-JSON
Verschachteltes JSON organisiert Schlüssel in einer Hierarchie, die die Struktur der Anwendung widerspiegelt.
{
"auth": {
"login": {
"title": "Bei Ihrem Konto anmelden",
"email_label": "E-Mail-Adresse",
"password_label": "Passwort",
"submit_button": "Anmelden",
"forgot_password": "Passwort vergessen?"
},
"logout": {
"confirm": "Sind Sie sicher, dass Sie sich abmelden möchten?"
}
},
"dashboard": {
"greeting": "Guten Morgen, {{name}}",
"stats": {
"total_users": "Gesamtbenutzer",
"active_sessions": "Aktive Sitzungen"
}
}
}
Bibliotheken wie vue-i18n und angular/localize unterstützen verschachteltes JSON nativ. Auf den Schlüssel wird mit Punktnotation zugegriffen: t('auth.login.title'). Diese Struktur passt natürlich zu Komponentenhierarchien und erleichtert die Identifizierung, wo jede Zeichenkette verwendet wird.
Der Kompromiss ist, dass tief verschachtelte Objekte eine sorgfältigere Schlüsselverwaltung erfordern und lange Zugriffspfade erzeugen können. Die meisten Teams einigen sich auf zwei oder drei Verschachtelungsebenen als praktisches Maximum.
i18next-Format
i18next ist die am weitesten verbreitete i18n-Bibliothek im JavaScript-Ökosystem und hat seine eigenen Konventionen, die auf verschachteltem JSON aufbauen. Am wichtigsten ist sein Plural-Schlüssel-Suffix-System.
{
"common": {
"save": "Speichern",
"cancel": "Abbrechen",
"loading": "Wird geladen..."
},
"items": {
"count_one": "{{count}} Element",
"count_other": "{{count}} Elemente",
"count_zero": "Keine Elemente"
},
"notifications": {
"new_one": "Sie haben {{count}} neue Benachrichtigung",
"new_other": "Sie haben {{count}} neue Benachrichtigungen"
}
}
i18next löst Pluralformen auf, indem es ein Suffix an den Basisschlüssel anhängt. Die Suffixe folgen den CLDR-Pluralregelkategorien: zero, one, two, few, many, other. Für Deutsch gelten nur one und other. Für Arabisch oder Russisch ist der vollständige Satz wichtig.
i18next unterstützt auch Namespacing auf Dateiebene: Jede JSON-Datei ist ein Namespace. Wenn Sie t('common:save') aufrufen, lädt i18next common.json für das aktive Gebietsschema. Dies ermöglicht Namespace-Level-Lazy-Loading in React-Anwendungen mit react-i18next.
{
"title": "Willkommen, {{name}}!",
"description": "Sie sind am {{date, datetime}} beigetreten",
"price": "{{price, currency}}"
}
Die {{value, formatType}}-Syntax löst die Formatierungs-Pipeline von i18next aus, die sich mit der Intl-API für Daten, Zahlen und Währung integriert.
FormatJS / react-intl-Format
FormatJS (das react-intl antreibt) verwendet ICU-MessageFormat-Syntax, die direkt in Zeichenkettenwerte eingebettet ist. Dadurch wird die gesamte Pluralisierungs- und Variablenlogik in die Nachrichtenzeichenkette selbst statt in Schlüsselsuffixe verlagert.
{
"welcome": "Willkommen, {name}!",
"item_count": "{count, plural, =0 {Keine Elemente} one {# Element} other {# Elemente}}",
"last_login": "Letzte Anmeldung: {date, date, medium}",
"account_status": "{gender, select, male {Er ist} female {Sie ist} other {Sie sind}} ein verifiziertes Mitglied.",
"notification_badge": "{count, plural, =0 {} one {({count})} other {({count})}}"
}
ICU MessageFormat ist die ausdrucksstärkste verfügbare Option für komplexe Plural- und Genus-Kongruenzregeln. Das select-Schlüsselwort verarbeitet bedingte Zeichenketten, plural verarbeitet zählungsbasierte Formen und Formattypen (date, number, currency) delegieren an die Intl-API.
Die Schlüssel sind typischerweise flache Zeichenketten, die oft dem Komponentenpfad oder einem semantischen Deskriptor entsprechen. FormatJS bevorzugt beschreibende flache Schlüssel gegenüber tief verschachtelten Strukturen.
Verwendung mit react-intl:
import { useIntl, FormattedMessage } from 'react-intl';
function ItemList({ count }) {
const intl = useIntl();
return (
<p>
<FormattedMessage id="item_count" values={{ count }} />
</p>
);
}
chrome.i18n-Format
Chrome-Erweiterungen verwenden ein spezifisches JSON-Format, das durch die chrome.i18n-API definiert wird. Jeder Schlüssel ist einem Deskriptorobjekt statt einer einfachen Zeichenkette zugeordnet.
{
"extensionName": {
"message": "Meine Erweiterung",
"description": "Der Name der Erweiterung, angezeigt im Chrome Web Store."
},
"welcomeMessage": {
"message": "Hallo, $USER$!",
"description": "Begrüßung beim Öffnen der Erweiterung",
"placeholders": {
"user": {
"content": "$1",
"example": "Alice"
}
}
},
"itemCount": {
"message": "$COUNT$ Elemente ausgewählt",
"placeholders": {
"count": {
"content": "$1",
"example": "3"
}
}
}
}
Das description-Feld wird Endbenutzern nicht angezeigt — es ist Kontext für Übersetzer und den Chrome-Web-Store-Überprüfungsprozess. Platzhalter verwenden eine $PLATZHALTER_NAME$-Konvention mit einem separaten placeholders-Objekt, das den Inhalt und einen Beispielwert definiert.
Dieses Format ist für Chrome-Erweiterungen nicht verhandelbar. Es ist nicht für allgemeine Web-Anwendungs-i18n geeignet.
Dateiorganisationsmuster
Einzelne Datei pro Gebietsschema
Die einfachste Organisation ist eine JSON-Datei pro Gebietsschema, die alle Übersetzungen für die Anwendung enthält.
locales/ en.json fr.json de.json ja.json es.json
Dies funktioniert für kleine Anwendungen, verursacht aber Probleme in großem Maßstab: Dateien wachsen, nicht zusammenhängende Funktionen verursachen Merge-Konflikte in derselben Datei, und Sie können keine Übersetzungen für Abschnitte lazy-loaden, die der Benutzer noch nicht besucht hat.
Namespace-Aufteilung
Das häufigste Muster für mittelgroße und große Anwendungen ist die Aufteilung von Übersetzungen nach Namespace — eine JSON-Datei pro Funktionsbereich und Gebietsschema.
locales/
en/
common.json
auth.json
dashboard.json
settings.json
errors.json
fr/
common.json
auth.json
dashboard.json
settings.json
errors.json
de/
common.json
auth.json
dashboard.json
settings.json
errors.json
Jede Namespace-Datei ist klein und fokussiert. Der common-Namespace enthält Zeichenketten, die in der gesamten Anwendung verwendet werden (Schaltflächenbeschriftungen, Formularfeldbeschriftungen, generische Fehlermeldungen). Feature-Namespaces enthalten Zeichenketten, die spezifisch für dieses Feature sind.
i18next und react-i18next verwenden dieses Muster nativ: t('auth:login.title') lädt auth.json für das aktive Gebietsschema. Next.js-Anwendungen, die next-i18next verwenden, folgen dieser Struktur gemäß Konvention.
Feature-basierte Aufteilung
Für sehr große Anwendungen oder Monorepos, bei denen jedes Paket seine eigenen Übersetzungen besitzt, platziert eine feature-basierte Struktur Übersetzungsdateien neben dem Code, der sie verwendet.
src/
features/
auth/
locales/
en.json
fr.json
components/
LoginForm.tsx
SignupForm.tsx
dashboard/
locales/
en.json
fr.json
components/
DashboardHeader.tsx
checkout/
locales/
en.json
fr.json
Dieses Muster maximiert die Kohäsion: Die Übersetzungsdatei lebt neben der Komponente, die sie verwendet. Das Build-System oder der i18n-Loader führt Namespace-Dateien zur Laufzeit oder zur Build-Zeit zusammen. Der Nachteil ist, dass das Finden aller Übersetzungen für ein bestimmtes Gebietsschema das Durchsuchen des gesamten Quellbaums erfordert, was den Workflow für Übersetzer und Übersetzungsmanagementsysteme erschwert.
Empfehlung: Verwenden Sie Namespace-Aufteilung für die meisten Anwendungen. Verwenden Sie feature-basierte Aufteilung nur, wenn Ihr Team groß genug ist, dass verschiedene Teams verschiedene Features besitzen und Cross-Feature-Merge-Konflikte in Übersetzungsdateien vermeiden müssen.
Vergleichstabelle für Übersetzungsdatei-Formate
| Format | Lesbarkeit | Tooling-Unterstützung | Metadaten-Unterstützung | ICU-Unterstützung | Diff-Freundlichkeit |
|---|---|---|---|---|---|
| JSON (flach) | Hoch | Ausgezeichnet | Keine | Nein (standardmäßig) | Ausgezeichnet |
| JSON (verschachtelt) | Hoch | Ausgezeichnet | Keine | Nein (standardmäßig) | Ausgezeichnet |
| JSON (FormatJS) | Mittel | Gut | Keine | Ja (nativ) | Gut |
| XLIFF 2.0 | Niedrig | Ausgezeichnet (CAT-Tools) | Reich (Status, Notizen, Alt-Übersetzungen) | Ja | Schlecht |
| PO / Gettext | Mittel | Gut (Poedit, Weblate) | Mittel (Kommentare, Kontext) | Teilweise | Mittel |
| YAML | Hoch | Mittel | Keine | Nein | Gut |
| ARB | Hoch | Gut (Flutter) | Metadaten pro Schlüssel | Nein | Gut |
XLIFFs Metadaten-Vorteil ist erheblich, wenn man mit professionellen Übersetzungsagenturen arbeitet: Das Format verfolgt den Übersetzungsstatus (neu, übersetzt, überprüft, final), unterstützt alternative Übersetzungen und ist das native Format für die meisten professionellen CAT-Tools wie Phrase, memoQ und SDL Trados. Wenn Ihr Übersetzungs-Workflow Agenturübergaben beinhaltet, verbessert das Generieren von XLIFF aus Ihrer JSON-Quelle (statt rohes JSON zu senden) die Übersetzerproduktivität und reduziert Fehler.
Schlüssel-Namenskonventionen
Konsistente Schlüsselbenennung ist der Unterschied zwischen einer Übersetzungsdatei, die leicht zu warten ist, und einer, die zur Quelle von Bugs und Verwirrung wird.
Punktnotation vs. Verschachtelung
Flache Schlüssel mit Punkten und echte verschachtelte Objekte repräsentieren beide Hierarchie, verhalten sich aber unterschiedlich. Ein flacher Schlüssel mit Punkten ist eine einzelne Zeichenkette — "auth.login.title". Ein verschachteltes Objekt ist eine echte Objektstruktur mit dem Schlüssel title innerhalb von login innerhalb von auth. Die meisten Bibliotheken unterstützen beides, aber das Mischen der beiden in derselben Datei verursacht Mehrdeutigkeit.
Empfehlung: Verwenden Sie echte Verschachtelung in Ihren JSON-Dateien und Punktnotation nur im Code beim Zugriff auf Schlüssel. Verwenden Sie keine Punkte in Schlüsselnamen innerhalb derselben Verschachtelungsebene.
{
"auth": {
"login": {
"title": "Anmelden"
}
}
}
Im Code als t('auth.login.title') zugegriffen — die Bibliothek übernimmt die Traversierung.
snake_case vs. camelCase
Beide sind verbreitet. snake_case ist in JSON-Dateien lesbarer, weil Wörter visuell nicht verschwimmen. camelCase stimmt mit JavaScript-Konventionen überein und ist in FormatJS-Projekten verbreitet.
{
"submit_button": "Absenden",
"error_message": "Ein Fehler ist aufgetreten"
}
{
"submitButton": "Absenden",
"errorMessage": "Ein Fehler ist aufgetreten"
}
Wählen Sie eine und erzwingen Sie sie mit einem Linter. Inkonsistenz innerhalb eines Projekts ist schlimmer als jede Wahl.
Beschreibend vs. Knapp
Knappe Schlüssel sind kurz, verlieren aber schnell den Kontext:
{
"btn_sub": "Abonnieren",
"btn_cncl": "Abbrechen",
"err_404": "Seite nicht gefunden"
}
Beschreibende Schlüssel kommunizieren den Zweck ohne den Wert zu lesen:
{
"newsletter_subscribe_button": "Abonnieren",
"modal_cancel_button": "Abbrechen",
"error_page_not_found_title": "Seite nicht gefunden"
}
Empfehlung: Verwenden Sie beschreibende Schlüssel, die den UI-Kontext (Komponententyp oder -ort) und den Inhaltstyp (Schaltfläche, Titel, Beschreibung, Platzhalter) enthalten. Dies ermöglicht es zu verstehen, wie ein Schlüssel verwendet wird, ohne den Komponentencode zu lesen.
Hierarchische Gruppierung
Bei der Verwendung von verschachteltem JSON zuerst nach UI-Bereich, dann nach Komponente oder Aktion, dann nach Elementtyp gruppieren:
{
"checkout": {
"cart": {
"title": "Ihr Warenkorb",
"empty_message": "Ihr Warenkorb ist leer",
"item_count_one": "{{count}} Artikel",
"item_count_other": "{{count}} Artikel"
},
"payment": {
"title": "Zahlungsdetails",
"card_number_label": "Kartennummer",
"expiry_label": "Ablaufdatum",
"submit_button": "Jetzt bezahlen"
}
}
}
Plurale und Variablen in JSON verwalten
ICU MessageFormat (FormatJS, vue-i18n, andere)
ICU MessageFormat ist die ausdrucksstärkste und portabelste Syntax für Plurale und Variablen. Es wird nativ von FormatJS unterstützt und kann in vue-i18n und anderen Bibliotheken konfiguriert werden.
{
"file_count": "{count, plural, =0 {Keine Dateien} one {# Datei} other {# Dateien}}",
"upload_progress": "{current} von {total} Dateien werden hochgeladen",
"last_seen": "Zuletzt gesehen {time, date, relative}",
"user_role": "{role, select, admin {Administrator} editor {Redakteur} other {Betrachter}}"
}
Das #-Symbol innerhalb eines Plural-Zweigs wird durch die formatierte Anzahl ersetzt. Das select-Schlüsselwort verzweigt auf einen Zeichenkettenwert statt auf eine Zahl.
i18next-Plural-Suffix-Konvention
i18next löst Plurale auf, indem es ein Suffix an den Schlüssel anhängt. Für Deutsch:
{
"message_count_one": "{{count}} Nachricht",
"message_count_other": "{{count}} Nachrichten",
"message_count_zero": "Keine Nachrichten"
}
Mit t('message_count', { count: 5 }) aufgerufen, wählt i18next message_count_other und interpoliert count. Für Sprachen mit mehr Pluralformen (Russisch hat vier), werden zusätzliche Suffix-Varianten definiert:
{
"file_one": "{{count}} файл",
"file_few": "{{count}} файла",
"file_many": "{{count}} файлов",
"file_other": "{{count}} файлов"
}
Die CLDR-Pluralregelkategorien (zero, one, two, few, many, other) entsprechen den von i18next verwendeten Suffixen.
Variableninterpolation
Jede Bibliothek unterstützt irgendeine Form der Variableninterpolation. Die Syntax variiert:
{
"greeting_i18next": "Hallo, {{name}}!",
"greeting_icu": "Hallo, {name}!",
"greeting_vue": "Hallo, {name}!",
"greeting_angular": "Hallo, {{ name }}!"
}
i18next verwendet standardmäßig doppelte geschweifte Klammern. ICU verwendet einfache geschweifte Klammern. Angulars $localize verwendet ein getaggtes Template-Literal im Code statt einer Laufzeit-Interpolationssyntax im JSON-Wert.
Mischen Sie keine Interpolationssyntaxen im selben Projekt. Wählen Sie die Syntax, die zu Ihrer Bibliothek passt, und erzwingen Sie sie in Ihrer JSON-Schema-Validierung.
Tooling und Validierung
JSON Schema für Übersetzungsdateien
Eine JSON-Schema-Definition ermöglicht es Ihnen, die Struktur von Übersetzungsdateien in CI-Pipelines, Editoren und Pre-Commit-Hooks zu validieren. Hier ist ein minimales Schema für eine flache Schlüssel-Wert-Übersetzungsdatei:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": {
"type": "string"
},
"minProperties": 1
}
Für verschachtelte Dateien wird das Schema rekursiv. Die meisten Teams verwenden eine Kombination aus JSON Schema für Strukturvalidierung und einem dedizierten i18n-Linting-Tool für semantische Prüfungen.
Linting für fehlende Schlüssel
Der häufigste i18n-Bug in der Produktion ist ein fehlender Übersetzungsschlüssel — ein Schlüssel, der auf Englisch vorhanden ist, aber in einer Locale-Datei fehlt. Dies führt zu einem Fallback auf den Schlüsselnamen selbst oder eine leere Zeichenkette, was die UI bricht.
i18next-parser durchsucht Ihren Quellcode nach t('key')-Aufrufen und generiert oder validiert Übersetzungsdateien:
npx i18next-parser --config i18next-parser.config.js
eslint-plugin-i18n-json validiert JSON-Übersetzungsdateien direkt:
npm install --save-dev eslint-plugin-i18n-json
Eine grundlegende ESLint-Konfiguration für die Validierung von Übersetzungsdateien:
{
"plugins": ["i18n-json"],
"rules": {
"i18n-json/valid-json": "error",
"i18n-json/sorted-keys": ["warn", { "order": "asc" }],
"i18n-json/identical-keys": [
"error",
{ "filePath": "src/locales/en.json" }
]
}
}
Die identical-keys-Regel prüft, ob jede Locale-Datei denselben Schlüsselsatz wie die Referenz-Locale-Datei (typischerweise Englisch) enthält. Sie markiert sowohl fehlende Schlüssel als auch zusätzliche Schlüssel, die nicht vorhanden sein sollten.
CI-Prüfungen für Vollständigkeit
Ein CI-Schritt, der Merges blockiert, wenn eine Locale-Datei unvollständig ist, verhindert die Anhäufung von Übersetzungsschulden. Ein einfaches Shell-Skript-Check:
#!/usr/bin/env bash
BASE="src/locales/en.json"
LOCALES=("fr" "de" "ja" "es")
for locale in "${LOCALES[@]}"; do
FILE="src/locales/${locale}.json"
BASE_KEYS=$(jq 'keys | length' "$BASE")
LOCALE_KEYS=$(jq 'keys | length' "$FILE")
if [ "$BASE_KEYS" != "$LOCALE_KEYS" ]; then
echo "FEHLER: ${FILE} hat ${LOCALE_KEYS} Schlüssel, erwartet ${BASE_KEYS}"
exit 1
fi
done
echo "Alle Locale-Dateien sind vollständig."
Für verschachtelte Dateien ist jq-Pfad-Traversierung erforderlich. Plattformen wie Better i18n verwenden JSON als ihr natives Format und synchronisieren Übersetzungen über CLI, was bedeutet, dass die Vollständigkeitsprüfung plattformseitig erzwungen werden kann, bevor Übersetzungen übertragen werden — was den Bedarf an CI-Level-Prüfungen für unvollständige Dateien reduziert.
Editor-Integration
VS-Code-Erweiterungen wie "i18n Ally" bieten Inline-Übersetzungsvorschauen, Hervorhebung fehlender Schlüssel und maschinelle Übersetzungsvorschläge direkt im Editor. Dies verlagert die Validierung nach links — Entwickler sehen fehlende Übersetzungen beim Schreiben von Code statt während CI.
Migration zwischen Formaten
JSON zu XLIFF
XLIFF ist erforderlich, wenn Übersetzungen an eine professionelle Agentur gesendet werden. Die Konvertierung von JSON zu XLIFF 2.0 beinhaltet das Zuordnen von Schlüssel-Wert-Paaren zu <unit>-Elementen mit <segment>-Kindern.
Das Tool i18next-conv behandelt bidirektionale Konvertierung:
npm install -g i18next-conv # JSON zu XLIFF i18next-conv -l en -s locales/en.json -t locales/en.xliff # XLIFF zu JSON i18next-conv -l fr -s locales/fr.xliff -t locales/fr.json
Für FormatJS-Projekte bietet @formatjs/cli XLIFF-Export:
npx formatjs compile-folder --ast src/locales/en.json > compiled/en.json
JSON zu PO
PO (Portable Object) Format wird vom Gettext-Ökosystem verwendet und von Tools wie Poedit und Weblate unterstützt. Das Tool i18next-conv unterstützt auch PO:
# JSON zu PO i18next-conv -l en -s locales/en.json -t locales/en.po # PO zu JSON i18next-conv -l fr -s locales/fr.po -t locales/fr.json
Für vue-i18n-Projekte unterstützt der @intlify/vue-i18n-loader .po-Dateien direkt als Alternative zu JSON, was nützlich ist, wenn Ihr Vue-Projekt Translation Memory mit einer serverseitigen Anwendung teilt, die Gettext verwendet.
Gängige Konvertierungstools
| Tool | Konvertiert | Hinweise |
|---|---|---|
i18next-conv | JSON ↔ PO, JSON ↔ XLIFF, JSON ↔ CSV | Vollständigste für i18next-Format |
@formatjs/cli | FormatJS JSON → XLIFF, extrahierte Nachrichten → Locale-Dateien | Erforderlich für FormatJS/react-intl-Projekte |
gettext-converter | PO ↔ JSON (flach) | Einfach, keine Framework-Annahmen |
xliff-simple-merge | XLIFF zusammenführen und aufteilen | Nützlich für Angular-Projekte mit angular/localize |
| Online XLIFF-Editoren | XLIFF ↔ JSON (über UI) | Phrase, Lokalise und Crowdin bieten alle Import/Export |
Bei der Migration zwischen Formaten die Ausgabe vor dem Übertragen validieren. Automatisierte Konvertierungstools verlieren gelegentlich Kontextzeichenketten, lassen Kommentare fallen oder verarbeiten Pluralformen für Sprachen mit nicht-standardmäßigen Pluralregeln falsch.
FAQ
Welches JSON-Format sollte ich für ein neues React-Projekt verwenden?
Wenn Sie react-i18next verwenden (was die häufigste Wahl ist), beginnen Sie mit Namespace-aufgeteiltem verschachteltem JSON gemäß i18next-Konventionen. Wenn Sie react-intl oder ein FormatJS-basiertes Setup verwenden, nutzen Sie flache Schlüssel mit ICU-MessageFormat-Syntax in Werten. Die Bibliothek, die Sie wählen, bestimmt das Format — wählen Sie zuerst die Bibliothek basierend auf Ihren Projektanforderungen, dann folgen Sie ihren dokumentierten Konventionen.
Sollten meine JSON-Schlüssel die englische Zeichenkette selbst oder ein semantischer Bezeichner sein?
Semantische Bezeichner (wie auth.login.submit_button) sind für die meisten Anwendungen vorzuziehen. Die englische Zeichenkette als Schlüssel zu verwenden (Gettext-Stil: t('Submit')) funktioniert für kleine Projekte, verursacht aber im großen Maßstab Probleme: Sie können nicht zwei verschiedene "Absenden"-Schaltflächen mit unterschiedlichem Kontext im selben Namespace haben, und das Ändern des englischen Textes erfordert die Aktualisierung aller Schlüsselreferenzen im Code.
Wie gehe ich zur Laufzeit mit fehlenden Übersetzungen um, ohne die UI zu beschädigen?
Jede wichtige i18n-Bibliothek fällt auf ein konfiguriertes Standard-Gebietsschema zurück, wenn ein Schlüssel fehlt. Konfigurieren Sie Ihre Bibliothek so, dass sie die englische Locale-Datei als Fallback verwendet, was bedeutet, dass eine fehlende französische Übersetzung die englische Zeichenkette anstelle des Schlüsselnamens anzeigt. Protokollieren Sie fehlende Schlüssel in der Entwicklung (die meisten Bibliotheken unterstützen einen missingKeyHandler-Callback), damit sie beim Testen sichtbar sind.
Ist es sicher, Kommentare in JSON-Übersetzungsdateien zu verwenden?
Standard-JSON unterstützt keine Kommentare. Einige Tools unterstützen JSON5 oder JSONC (JSON mit Kommentaren) als Erweiterung, aber dies bricht die Kompatibilität mit Standard-JSON-Parsern. Wenn Sie Zeichenketten mit Kontext für Übersetzer versehen müssen, verwenden Sie ein separates Beschreibungsfeld auf Schlüsselebene (wie es chrome.i18n tut) oder pflegen Sie eine separate Metadatendatei. Ein einfacherer Ansatz: Verwenden Sie beschreibende Schlüsselnamen, die Kontext ohne Inline-Kommentare kommunizieren.
Wie soll ich Rechts-nach-Links (RTL)-Sprachen in meinen JSON-Dateien handhaben?
Die JSON-Struktur für RTL-Sprachen (Arabisch, Hebräisch, Persisch) ist identisch mit LTR-Sprachen — das Dateiformat ändert sich nicht. RTL-Unterstützung ist ein CSS- und Layout-Anliegen, kein Übersetzungsdatei-Anliegen. Ihre i18n-Bibliothek bietet eine Möglichkeit, die Textrichtung des aktiven Gebietsschemas zu erkennen (typischerweise über die Intl.Locale-API oder ein Locale-Metadatenobjekt), und Ihre Anwendung wendet dir="rtl" auf das Dokument oder die Komponente entsprechend an. Halten Sie RTL-spezifisches CSS in Ihren Stylesheets, nicht in Ihren Übersetzungswerten.
Fazit
JSON-Übersetzungsdateien folgen keinem einzelnen universellen Standard — sie folgen den Konventionen der Bibliothek, die sie liest. Zu verstehen, welches Format Ihre Bibliothek erwartet und warum es so konzipiert wurde, ist nützlicher als die Suche nach einem "richtigen" Ansatz.
Die praktische Empfehlung lautet: Verwenden Sie verschachteltes JSON mit i18next-Konventionen, wenn Sie eine React-, Vue- oder Node.js-Anwendung erstellen und das größte Ökosystem an Tooling und Beispielen möchten. Verwenden Sie ICU MessageFormat in Ihren Werten, wenn Ihre Anwendung komplexe Plurale, Genus-Kongruenz oder reiche Formatierung über viele Gebietsschemas hinweg verarbeiten muss und die Ausdrücke so portabel wie möglich sein sollen. Verwenden Sie flache Schlüssel für kleine Projekte oder schnelle Prototypen, bei denen kognitiver Overhead wichtiger ist als organisatorische Struktur.
Dateiorganisation, Schlüsselbenennung und CI-Validierung sind genauso wichtig wie die Formatwahl. Eine flache Datei mit konsistenter Benennung und automatisierten Vollständigkeitsprüfungen wird einem kleinen Team besser dienen als eine sorgfältig in Namespaces aufgeteilte Struktur ohne Tooling und ohne Durchsetzung.
Übersetzungsschulden häufen sich still an — hier ein fehlender Schlüssel, dort eine veraltete Zeichenkette — bis lokalisierte Benutzer auf defekte UI-Zeichenketten stoßen. Teams, die dieses Ergebnis vermeiden, behandeln Übersetzungsdateien genauso wie jedes andere Code-Artefakt: in Pull Requests überprüft, in CI validiert und mit Blick auf zukünftige Betreuer organisiert.
Referenzen
- i18next documentation: Plurals
- i18next documentation: Interpolation
- FormatJS: ICU Message Syntax
- react-intl documentation
- vue-i18n documentation
- Chrome Extensions: chrome.i18n API
- XLIFF 2.0 specification (OASIS)
- Unicode CLDR Plural Rules
- i18next-conv: Conversion CLI
- eslint-plugin-i18n-json
- i18n Ally VS Code extension
- ICU Message Format reference (Unicode)
Zuletzt aktualisiert: März 2026