Strings zur Übersetzung aus Gutenberg-Blöcken extrahieren

Während der Entwicklung meiner ersten komplexeren Blöcke bin ich in verschiedene Probleme gelaufen. Eines davon war das Extrahieren meiner Strings für Übersetzungen. In meinem vorherigen Beitrag habe ich beschrieben, wie man solche Strings aus PHP-Dateien extrahieren kann. Diese Methoden funktionieren grundsätzlich auch für JavaScript-Dateien, da sie „die gleichen Funktionen“ verwenden, bzw. Funktionen mit einem gleichlautenden Alias.

Strings in einem Gutenberg-Block übersetzen

Schauen wir uns zuerst einmal an wie Strings in einem Block übersetzt werden. Dieses Beispiel stammt aus dem Create a Block Tutorial und zeigt die „Edit“ Komponente:

import { TextControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
 
export default function Edit( { attributes, className, setAttributes } ) {
    return (
        <div className={ className }>
            <TextControl
                label={ __( 'Message', 'gutenpride' ) }
                value={ attributes.message }
                onChange={ ( val ) => setAttributes( { message: val } ) }
            />
        </div>
    );
}

Die __ Funktion wird von der @wordpress/i18n Komponente importiert. Diese Code funktioniert problemlos, um den String in Zeile 8 zu übersetzen. Es schlägt nur fehl, wenn man versucht den String in eine PO-Datei zu exportieren.

Kompilierte JavaScript-Datei

Aber wieso funktioniert das das Beispiel nicht, wenn man versucht die Strings zu extrahieren? Wenn man mit Komponenten wie diesen arbeitet, dann verteilt man den JavaScript Code in der Regel auf mehrere Dateien. Diese importiert dann man dann in eine Haupt-Datei und kompiliert diese in eine einzelne Datei, die an den Browser ausgeliefert wird. Hierzu verwendet man zum Beispiel @wordpress/scripts, das auch im Kapitel the JavaScript Build Setup beschrieben wird. Dieses Skript erstellt dann eine Datei build/index.js und die Strings aus dem Beispiel sehen dann wie folgt aus:

// ...
/* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n");
// ...
function Edit(_ref) {
  var attributes = _ref.attributes,
      className = _ref.className,
      setAttributes = _ref.setAttributes;
  return Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])("div", {
    className: className
  }, Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__["TextControl"], {
    label: Object(_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__["__"])('Message', 'block-i18n'),
    value: attributes.message,
    onChange: function onChange(val) {
      return setAttributes({
        message: val
      });
    }
  }));
}

In Zeile 11 finden wir wieder die Strings. Allerdings sind sie nicht direkt von der __ Funktion umschlossen. Stattdessen wurden beim Kompilieren sehr merkwürdige Funktionsnamen generiert, die beim Import durch Webpack entstanden sind. Da diese Syntax dem wp i18n make-pot Kommande oder der X-Poedit-KeywordsList in Poedit bekannt ist, können sie beim Parsen nicht gefunden werden.

Lösung: Eine andere Syntax beim Importieren von Komponenten verwenden

Es gibt eine sehr einfache Lösung für das Problem. Man kann Komponenten auf verschiedene Weisen importieren. Wir ersetzen den Import der i18n Funktion in Zeile 2 einfach durch diesen „Import“:

const { __ } = wp.i18n;

Als Ergebnis erhalten wir dann die folgende kompilierte JavaScript-Datei, welche wieder direkt die __ Funktion verwendet (in Zeile 10), die der Parser dann wieder erkennt:

// ...
var __ = wp.i18n.__;
function Edit(_ref) {
  var attributes = _ref.attributes,
      className = _ref.className,
      setAttributes = _ref.setAttributes;
  return Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])("div", {
    className: className
  }, Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__["TextControl"], {
    label: __('Message', 'block-i18n'),
    value: attributes.message,
    onChange: function onChange(val) {
      return setAttributes({
        message: val
      });
    }
  }));
}

Interessanterweise hat es auch dann funktioniert, wenn ich den import entfernt und nicht ersetzt habe. Eventuell wurde die __ Funktion bereits durch eine andere Komponente importiert und war deshalb verfügbar. Ich würde dennoch empfehlen alle externen Komponenten und Funktionen, die ihr in eurem Code verwenden auch explizit zu importieren. Auf die gleiche Weise könnte man übrigens auch die erste Zeile umschreiben:

const { TextControl } = wp.components;

Andere Tutorials verwenden immer diese Methode um Komponenten von WordPress/Gutenberg zu importieren und ich würde euch auch entfernen, es immer so zu tun. Ich hatte bisher damit noch keine Probleme und die resultierende JavaScript-Datei war sogar ein wenig kleiner.

Fazit

Das Übersetzen von String in Gutenberg-Blöcken (oder ähnlichem JavaScript-Code für WordPress) ist wirklich sehr einfach und man kann die gleichen Funktionen verwenden, die man auch von PHP her kennt. Wenn man aber die Imports „falsch“ machen, wird das Extrahieren von Strings mit Poedit nicht funktionieren.

Da es aber Plugins gibt, die dennoch Imports auf diese Weise machen und dennoch funktionsfähige Übersetzungen habe, gibt es vielleicht doch einen Weg. Wenn ihr vielleicht wisst, wie diese Plugins es machen, würde ich mich sehr freuen, wenn ihr es mir vielleicht in einem Kommentar erklärt.

Veröffentlicht von

Bernhard ist fest angestellter Webentwickler, entwickelt in seiner Freizeit Plugins, schreibt in seinem Blog über WordPress und andere Themen, treibt sich gerne bei den WP Meetups in Berlin und Potsdam herum und läuft nach Feierabend den ein oder anderen Halbmarathon.

3 Kommentare » Schreibe einen Kommentar

    • Ich beobachte das auch noch sehr interessiert. Aktuell habe ich beide Varianten im Einsatz, einmal mit den Metadaten in einer eigenen JSON-Datei und einmal in einer normalen JavaScript-Datei. Noch habe ich für mich keinen Favoriten identifiziert.

      • Vorteil ist, dass die block.json auch von PHP gelesen werden kann d.h. man spart sich die ganzen Attribute doppelte in JavaScript und PHP zu registrieren. Finde ich schon sehr sinnvoll aber leider mit der Einschränkung aktuell, dass keine Übersetzung möglich ist.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert