Seit WordPress 5.0 können auch in JavaScript Übersetzungsfunktionen genutzt werden. Beim Bau von Gutenberg-Blöcken sind die sehr nützlich, allerdings gibt es ein paar Hürden bei der Übersetzung, wenn das Plugin mit dem Block nicht im offiziellen WordPress.org-Verzeichnis liegt. Hier zeige ich, wie Übersetzungen für Blöcke angelegt werden können.

Voraussetzungen

Neben einem Plugin, in dem wir JS-Strings übersetzen möchten, brauchen wir WP-CLI 2.2.0 oder neuer. Falls ihr das Tool noch nicht installiert habt, findet ihr auf der Installing-Seite des WP-CLI-Handbuchs verschiedene Möglichkeiten dafür.

Zudem müssen für die Strings im JS die seit WordPress 5.0 vorhandenen JS-Übersetzungsfunktionen genutzt werden, die genauso funktionieren wie die PHP-Funktionen – __() wird vermutlich meist ausreichen.

Diese Funktionen sind Teil des wp-18n-Skripts, das ihr eurem Block-Skript bei der Registrierung als Abhängigkeit mitgeben müsst. Außerdem muss das Skript früh genug registriert werden, enqueue_block_editor_assets ist zu spät.

Wir nutzen den init-Hook, und damit kann das beispielsweise so aussehen:

add_action( 'init', function() {
	wp_register_script(
		'krautpress-block-editor-script',
		plugins_url( 'assets/js/editor.blocks.js', __FILE__ ),
		[ 'wp-blocks', 'wp-element', 'wp-edit-post', 'wp-i18n' ]
	);
} );
Code-Sprache: PHP (php)

Einbinden werden wir das Skript dann so:

add_action( 'enqueue_block_editor_assets', function() {
	wp_enqueue_script( 'krautpress-block-editor-script' );
} );
Code-Sprache: JavaScript (javascript)

Wenn wir direkt im init-Part wp_enqueue_script() nutzen würden, würde das Skript überall geladen werden, auch im Frontend.

Übersetzungsdateien erstellen und laden

Wir haben jetzt alle Vorbereitungen getroffen und können an das Erstellen der Übersetzungsdateien gehen.

PO-Datei erstellen

Zunächst erstellen wir eine PO-Datei über das folgende WP-CLI-Kommando, das ihr in dem Verzeichnis eures Plugins ausführen müsst:

wp i18n make-pot ./ languages/<textdomain>-<lang>.poCode-Sprache: HTML, XML (xml)

<textdomain> ersetzt ihr dabei durch die Textdomain des Plugins, <lang> durch den Sprachcode, also beispielsweise de_DE. Danach könnt ihr die Strings in einem Programm wie Poedit oder mit Loco Translate übersetzen.

PO-Übersetzungen in JSON-Dateien konvertieren

Im Anschluss müssen die übersetzten Strings in das JED-1.x-Format (JSON) gebracht werden, wofür erneut WP-CLI zum Einsatz kommt:

wp i18n make-json languages/<textdomain>-<lang>.po --no-purge --pretty-printCode-Sprache: HTML, XML (xml)

Auch hier ersetzten wir die Platzhalter wieder entsprechend, sodass wir als Parameter an das Kommando den relativen Pfad zur übersetzten PO-Datei übergeben. Mit --no-purge geben wir an, dass die extrahierten Strings nicht aus der PO-Datei gelöscht werden sollen, und wir möchten das JSON schön formatiert (--pretty-print).

Der Befehl erstellt pro JavaScript-Datei eine JSON-Datei im languages-Verzeichnis, die nach dem Schema <textdomain>-<lang>-<hash>.json benannt ist. <hash> ist der md5()-Hash des Dateinamens der JS-Datei. Es kann aber durchaus sein (bei meinem Setup die Regel), dass dieser Wert nicht passt, weil es sich dabei um die Source-Datei handelt, nicht die kompilierte Datei, die letztlich von WordPress geladen wird.

Statt des Hashes kann aber noch das Handle des Skripts angegeben werden, das bei wp_register_script() als erster Parameter genutzt wird – in unserem Fall krautpress-block-editor-script. Damit müsste die Datei für die deutsche Übersetzung bei der Textdomain krautpress-block dann so heißen: krautpress-block-de_DE-krautpress-block-editor-script.json.

Gegebenenfalls mehrere JSON-Dateien zusammenführen

Wenn der Block aus mehreren Source-Dateien besteht, die in eine Datei kompiliert werden, müssen die Strings aus diesen Dateien in einer JSON-Datei zusammengeführt werden. Wenn wir zum Beispiel die folgenden beiden Dateien haben:

{
  "translation-revision-date": "+0000",
  "generator":                 "GlotPress/2.3.0-alpha",
  "domain":                    "messages",
  "locale_data":               {
    "messages": {
      "": {
        "domain":       "messages",
        "plural-forms": "n != 1",
        "lang":         "de_DE"
      },
      "Block name": [
        "Blockname"
      ],
    }
  }
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
{
  "translation-revision-date": "+0000",
  "generator":                 "GlotPress/2.3.0-alpha",
  "domain":                    "messages",
  "locale_data":               {
    "messages": {
      "": {
        "domain":       "messages",
        "plural-forms": "n != 1",
        "lang":         "de_DE"
      },
      "Field description": [
        "Feldbeschreibung"
      ],
    }
  }
}
Code-Sprache: JSON / JSON mit Kommentaren (json)

Müssten wir sie in einer Datei zusammenführen, die so aussieht:

{
  "translation-revision-date": "+0000",
  "generator":                 "GlotPress/2.3.0-alpha",
  "domain":                    "messages",
  "locale_data":               {
    "messages": {
      "": {
        "domain":       "messages",
        "plural-forms": "n != 1",
        "lang":         "de_DE"
      },
      "Block name": [
        "Blockname"
      ],
      "Field description": [
        "Feldbeschreibung"
      ],
    }
  }
}
Code-Sprache: JSON / JSON mit Kommentaren (json)

Jetzt sind beide Strings innerhalb des messages-Objekts enthalten.

Übersetzungen laden

Zum Laden der JS-Übersetzungen gibt es die Funktion wp_set_script_translations():

add_action( 'init', function() {
    wp_set_script_translations( '<handle>', '<textdomain>', plugin_dir_path( __FILE__ ) . 'languages' );
} );
Code-Sprache: JSON / JSON mit Kommentaren (json)

Als Parameter erwartet sie

  1. das Handle des Skripts, für das die Übersetzungen sind, das wäre bei uns krautpress-block-editor-script.
  2. die Textdomain, bei uns krautpress-block.
  3. den absoluten Pfad zu den Übersetzungen.

Fazit

Das ist im Vergleich zu wp_localize_script(), womit übersetzbare Strings aus PHP in JavaScript integriert werden können, natürlich recht aufwendig. Einfach ist es, wenn das Plugin bei WordPress.org liegt, weil da die ganze Magie im Hintergrund abläuft und sich für die Übersetzenden nichts ändert.

Vorteil der neuen Vorgehensweise ist beispielsweise, dass sich auch Singular-/Plural-Übersetzungen in JS jetzt elegant über _n() lösen lassen.

Laut Website arbeiten zum Beispiel die Loco-Translate-Macher daran, auch die Erstellung von den JSON-Dateien zu unterstützen, aber mit GlotPress als WordPress-Plugin in Verbindung mit Traduttore von required gibt es vielleicht jetzt schon einen relativ bequemen Weg. Ich bin momentan noch bei der Einrichtung, aber wenn alles klappt, wird es hier darüber etwas zu lesen geben 🙃

Danke an Matze Kittsteiner, der die notwendigen Schritte bei seinem ersten Verwenden festgehalten und mir zur Verfügung gestellt hat 🙂