WordPress JSON-Übersetzung: JavaScript im Block-Editor übersetzen

Sie haben Ihr Plugin übersetzt. Die PHP-Strings werden perfekt in den Admin-Einstellungen, den Frontend-Templates und den E-Mail-Benachrichtigungen angezeigt – alles lokalisiert. Dann öffnen Sie den Block-Editor, und jedes Label in Ihrem benutzerdefinierten Gutenberg-Block ist hartnäckig, ja spöttisch auf Englisch. Der Button „Add Item“, die Überschriften des Inspektorbereichs, der Platzhaltertext. Ihre .mo-Datei ist geladen. Warum werden diese Strings dann nicht übersetzt?
Weil seit WordPress 5.0 und dem Aufkommen von Gutenberg JavaScript-Strings überhaupt nicht aus Ihrer .mo-Datei stammen. Sie benötigen eine völlig separate, pro Skript generierte WordPress JSON-Übersetzungsdatei – und wenn Sie diese nicht generieren, bleibt Ihr Block-Editor auf Englisch, egal wie vollständig Ihre .po-Datei ist. Dies ist eine der häufigsten und verwirrendsten Lokalisierungslücken in der modernen WordPress-Entwicklung. Dieser Leitfaden erklärt genau, warum dies geschieht, wie das JSON-Übersetzungssystem funktioniert, die MD5-gehashten Dateinamen, die alle verwirren, und die vollständige Toolchain zur Behebung des Problems.
Warum Ihre Block-Editor-Strings auf Englisch bleiben
Kurze Antwort: PHP und JavaScript verwenden in WordPress zwei völlig unterschiedliche Übersetzungs-Bereitstellungssysteme, und Ihre .mo-Datei speist nur das PHP-System.
Zwei Übersetzungssysteme, ein Plugin
Wenn WordPress load_plugin_textdomain() ausführt, liest es Ihre kompilierte .mo-Datei in den PHP-Speicher ein. Jeder Aufruf von __(), _e() und _x() in Ihrem PHP-Code sucht dort seine Übersetzung. Dies funktioniert, weil PHP serverseitig rendert – die .mo-Daten sind direkt im selben Prozess verfügbar.
JavaScript ist anders. Ihr Block-Code läuft im Browser, lange nachdem PHP seine Arbeit beendet hat. Er kann nicht auf eine serverseitige .mo-Datei zugreifen. Stattdessen erwartet das @wordpress/i18n-Paket – das JS-Äquivalent von Gettext, das __(), _x() und sprintf() für Ihre Skripte bereitstellt – dass Übersetzungen als JSON-Payload geliefert werden, die an das spezifische Skript angehängt ist, das sie benötigt.
Was mit einem unübersetzten JS-String passiert
Ein Block mit Strings wie diesem:
import { __ } from '@wordpress/i18n';
registerBlockType( 'myplugin/feature-box', {
title: __( 'Feature Box', 'myplugin' ),
edit: () => {
return <Button>{ __( 'Add Item', 'myplugin' ) }</Button>;
},
} );
wird „Feature Box“ oder „Add Item“ niemals in Ihrer .mo-Datei finden, da der Browser niemals .mo-Dateien liest. Diese Strings müssen als JSON ankommen, verknüpft mit diesem genauen Skript-Handle. Wenn Sie das nicht eingerichtet haben, geben die JS __()-Aufrufe einfach das ursprüngliche Englisch zurück – lautlos und ohne Fehlermeldung in der Konsole.
Verknüpfen von JSON-Übersetzungen mit wp_set_script_translations()
Die Brücke zwischen Ihrem Skript und seinen JSON-Übersetzungen ist eine einzelne PHP-Funktion: wp_set_script_translations(). Die Antwort auf die Frage „Woher weiß WordPress, welche JSON-Datei zu welchem Skript gehört?“ lautet: Sie sagen es ihm, indem Sie das Skript registrieren und dann dessen Textdomain und den Ordner deklarieren, in dem die JSON-Datei liegt.
Registrieren des Skripts und seines Übersetzungsordners
add_action( 'init', function () {
wp_register_script(
'myplugin-editor',
plugins_url( 'build/index.js', __FILE__ ),
array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
'1.0.0'
);
// Tell WordPress where this script's JSON translations live
wp_set_script_translations(
'myplugin-editor', // the registered script handle
'myplugin', // text domain
plugin_dir_path( __FILE__ ) . 'languages'
);
} );
Wenn der Editor myplugin-editor lädt, weiß WordPress nun, dass es im Ordner languages/ nach einer JSON-Datei suchen muss, die diesem Skript und der aktuellen Sprache des Benutzers entspricht. Findet es eine, injiziert es die Übersetzungen, bevor Ihr Skript ausgeführt wird, und die JS __()-Aufrufe werden korrekt aufgelöst. Der von Ihnen übergebene Handle muss exakt mit einem registrierten Skript übereinstimmen – ein nicht übereinstimmender oder fehlender Handle ist der zweithäufigste Grund, warum Übersetzungen stillschweigend fehlschlagen.
Der MD5-gehashte Dateiname, den niemand erwartet
Hier ist das Detail, das fast jeden aus der Bahn wirft. Die JSON-Datei, nach der WordPress sucht, ist nicht ordentlich benannt wie myplugin-fr_FR.json. Sie wird mit einem MD5-Hash des Quellpfads des Skripts benannt:
Entschlüsseln des Dateinamenmusters
myplugin-fr_FR-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.json
Das Muster ist {textdomain}-{locale}-{md5}.json, wobei der Hash der MD5-Wert des relativen Pfads zur Skriptdatei (zum Beispiel build/index.js) ist, wie registriert. WordPress berechnet diesen Hash zur Laufzeit, um die richtige JSON-Datei für das richtige Skript zu finden. Wenn Sie Ihre Datei manuell benennen, wird WordPress sie nicht finden, und Sie werden schwören, das System sei kaputt, obwohl es nur nach einem anderen Dateinamen sucht.
Sie berechnen den Hash nicht selbst. Der WP-CLI i18n-Befehl erledigt das für Sie, weshalb Sie unbedingt die Tools verwenden sollten, anstatt diese Dateien manuell zu erstellen. Das Verständnis, dass der Hash existiert, erspart Ihnen jedoch Stunden, wenn eine JSON-Datei in languages/ vorhanden ist, aber dennoch ignoriert wird – es ist fast immer eine Nichtübereinstimmung des Dateinamen-Hashs, weil sich der Skriptpfad geändert hat.
Der vollständige Workflow: make-pot zu make-json
Die gute Nachricht ist, dass Sie Ihre Übersetzungen in denselben .po-Dateien beibehalten, die Sie bereits verwenden. Die JSON-Datei ist ein abgeleitetes Artefakt, das am Ende generiert wird. Die Antwort auf die Frage „Muss ich JS-Strings separat pflegen?“ lautet nein – sie leben in derselben .pot/.po-Datei wie Ihre PHP-Strings, und ein zusätzlicher Befehl trennt die JS-Strings in JSON auf.
Die Vier-Befehl-Pipeline
Hier ist die vollständige Pipeline:
# 1. Extract ALL translatable strings (PHP and JS) into one template
wp i18n make-pot . languages/myplugin.pot
# 2. Translate languages/myplugin-fr_FR.po as usual (Poedit, AI, etc.)
# 3. Compile the .mo for PHP strings (server-side, as always)
wp i18n make-mo languages/
# 4. Generate the MD5-hashed JSON files for JS strings
wp i18n make-json languages/ --no-purge
Der make-pot-Befehl aus Schritt 1 ist intelligent genug, um sowohl Ihre .php-Dateien als auch Ihre .js/.jsx-Quellcodedateien zu scannen, sodass eine einzige .po-Datei pro Sprache alles enthält. Der make-json-Befehl aus Schritt 4 liest jede übersetzte .po-Datei, findet die Einträge, die aus JavaScript-Dateien stammen, und schreibt eine korrekt gehashte JSON-Datei pro Skript aus. Das --no-purge-Flag behält die JS-Strings auch in Ihrer .po-Datei, sodass ein späteres make-mo sie nicht verliert – ohne dieses Flag entfernt make-json JS-Einträge aus der .po-Datei, was Leute überrascht, die die Befehle in der falschen Reihenfolge ausführen.
Eine generierte JSON-Datei sieht aus wie ein Übersetzungsset im Jed-Format:
{
"translation-revision-date": "2026-06-12 10:00+0000",
"generator": "WP-CLI/2.x",
"domain": "messages",
"locale_data": {
"messages": {
"": { "domain": "messages", "lang": "fr_FR" },
"Feature Box": [ "Bloc fonctionnalité" ],
"Add Item": [ "Ajouter un élément" ]
}
}
}
WordPress liest locale_data und speist es in @wordpress/i18n ein, bevor Ihr Skript ausgeführt wird. Nun gibt __( 'Add Item', 'myplugin' ) im Browser Ajouter un élément zurück, und Ihr Block-Editor ist endlich lokalisiert.
Wie sich dies von i18next JSON unterscheidet
Beide Systeme verwenden JSON, beide zielen auf JavaScript ab, und diese oberflächliche Ähnlichkeit führt zu echter Verwirrung. Sie sind nicht austauschbar. WordPress Block-Editor-JSON ist eine Gettext-abgeleitete, MD5-gehashte, pro-Skript-Payload, die von @wordpress/i18n konsumiert wird. i18next JSON ist eine flache oder verschachtelte Schlüssel-Wert-Datei, die von react-i18next oder next-intl konsumiert wird, mit ihrer eigenen {{interpolation}}-Syntax und Plural-Schlüsselkonventionen.
Wenn Sie mit reinem React oder Next.js außerhalb von WordPress arbeiten, möchten Sie den i18next-Ansatz, den wir unter i18next JSON in React und Next.js übersetzen behandeln. Innerhalb von WordPress möchten Sie den oben beschriebenen make-json-Workflow. Sie zu verwechseln – zum Beispiel das manuelle Schreiben von flachem JSON im i18next-Stil und die Erwartung, dass wp_set_script_translations() es lädt – wird einfach nicht funktionieren, weil WordPress nach dem gehashten Jed-Format sucht, nicht nach beliebigen Schlüssel-Wert-Paaren.
Eine Quelle, jedes benötigte Format
Die Zerbrechlichkeit bei all dem liegt im Übersetzungsschritt in der Mitte. Ihre .po-Datei speist sowohl die .mo (PHP) als auch die JSON (JavaScript), sodass eine einzige fehlerhafte Übersetzung – ein verstümmeltes %s, ein kaputter <strong>-Tag, eine umbenannte Pluralform – beide Ausgaben gleichzeitig vergiftet. Und weil JS-Strings asynchron im Browser geladen werden, äußert sich ein struktureller Fehler dort oft als leeres Label oder als harter Absturz anstatt als eleganter Fallback.
Ein Upload, PHP und JavaScript abgedeckt
Hier verdient eine Übersetzungs-Pipeline, die die Gettext-Struktur versteht, ihren Platz. SimplePoTranslate nimmt eine Quell-.po- oder .pot-Datei und erzeugt saubere, übersetzte Ausgabe in mehreren Formaten aus einem einzigen Upload – .po, .mo, .json, .php und .xliff –, sodass Sie keine separaten Tools für Ihre PHP- und JavaScript-Schichten zusammenfügen müssen. Sein Syntax Locking hält %s, %1$s, {count} und Inline-HTML an Ort und Stelle, was bei Block-Editor-Strings doppelt wichtig ist, da ein fehlerhafter Platzhalter das gesamte Editor-Panel zum Absturz bringen kann. Wir gehen tiefer auf das Modell „eine Quelle, viele Ausgaben“ in eine Datei rein, fünf Formate raus ein.
Sie führen immer noch make-json aus, um die gehashten Dateien zu erstellen, die WordPress erwartet – dieser Schritt ist WordPress-spezifisch und bleibt in Ihrem Build. Aber die Übersetzung selbst, der Teil, der am ehesten Ihre JS-Strings beschädigt, wird von einer kontextsensitiven Engine anstelle eines Suchen-und-Ersetzen-Skripts gehandhabt.
Fazit
Der Grund, warum Ihr Block-Editor auf Englisch bleibt, ist strukturell, kein Fehler: Die WordPress JSON-Übersetzung ist ein separates Bereitstellungssystem von der .mo-Datei, das speziell entwickelt wurde, weil Browser keine serverseitigen Gettext-Daten lesen können. Sobald Sie verstehen, dass JavaScript-Strings pro Skript generiertes, MD5-gehashtes JSON benötigen, das von wp i18n make-json erstellt und mit wp_set_script_translations() verknüpft wird, ist die Behebung mechanisch. Bewahren Sie Ihre Strings in einer .po-Datei auf, kompilieren Sie die .mo für PHP und führen Sie make-json für JS aus.
Machen Sie den Übersetzungsschritt richtig, und beide Ausgaben stimmen. Machen Sie ihn falsch, und Sie debuggen einen Nachmittag lang leere Editor-Panels.
Bereit, Ihre WordPress JSON- und PHP-Strings aus einer sauberen Quelle zu übersetzen? Testen Sie SimplePoTranslate kostenlos – keine Kreditkarte erforderlich. Die kostenlose Stufe übersetzt echte
.po- und.pot-Dateien mit platzhalter-sicherem Syntax Locking, sodass Ihre Block-Editor-Strings korrekt ausgeliefert werden.