Erweitern
ErweiternZusätzliche Gutenberg-Blöcke übersetzen

Zusätzliche Gutenberg-Blöcke übersetzen

Gato AI Translations for Polylang kann blockbasierte Beiträge übersetzen.

Das Plugin enthält Unterstützung für viele Blöcke direkt nach der Installation. Für alles darüber hinaus — eigene benutzerdefinierte Blöcke oder Blöcke von Drittanbieter-Plugins, die keine wpml-config.xml mitbringen — kannst du die Unterstützung über PHP-Hooks erweitern.

Strings übersetzen

Um zusätzliche übersetzbare Attribute für einen Block zu registrieren, verwende den Filter gatompl:gutenberg_block_type_translatable_attribute_regexes.

Warum reguläre Ausdrücke?

Ein Gutenberg-Block wird in post_content als HTML-Kommentar gespeichert, der die JSON-Attribute des Blocks enthält, gefolgt vom gerenderten HTML des Blocks, zum Beispiel:

<!-- wp:my-plugin/my-block {"title":"Hello"} -->
<div class="wp-block-my-plugin-my-block">Hello</div>
<!-- /wp:my-plugin/my-block -->

Einen Block zu übersetzen bedeutet, die genaue Teilzeichenkette zu finden, die innerhalb dieses Markups übersetzt werden soll, sie durch ihre Übersetzung zu ersetzen und alles andere unverändert zu lassen (Blockname, andere Attribute, HTML-Struktur, umgebende Blöcke). Reguläre Ausdrücke sind das Mittel, mit dem das Plugin genau bestimmt, welche Teilzeichenkette ersetzt werden soll: Der Text vor und nach dem Wert wird in Gruppen erfasst, und der Wert selbst ist der Teil, der ausgetauscht wird.

Standard-String-Attribute (im JSON des Blocks gespeichert)

Wenn die Eigenschaft ein normaler String ist, der in den JSON-Attributen des Blocks gespeichert wird, übergib true und das Plugin verwendet seinen Standard-Regulärausdruck.

Um zum Beispiel die Attribute daysLabel, hoursLabel, minutesLabel und secondsLabel des Blocks kadence/countdown zu übersetzen — dessen Markup so aussieht:

<!-- wp:kadence/countdown {"uniqueID":"_abc123","date":"2026-12-31 00:00:00","daysLabel":"Days","hoursLabel":"Hours","minutesLabel":"Minutes","secondsLabel":"Seconds"} -->
<div class="wp-block-kadence-countdown">…</div>
<!-- /wp:kadence/countdown -->

…registriere die Attribute so:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        $regexes['kadence/countdown'] = [
            'daysLabel'    => true,
            'hoursLabel'   => true,
            'minutesLabel' => true,
            'secondsLabel' => true,
        ];
        return $regexes;
    }
);

Der Wert true wird intern zu diesem Standard-Regulärausdruck erweitert:

#(<!-- wp:%3$s \{.*?\"%2$s\":\")%1$s(\".*?\}/?-->)#

…wobei die Platzhalter folgendes bedeuten:

  1. %1$s → der Attributwert
  2. %2$s → der Attributname
  3. %3$s → der Blockname

Für das Attribut daysLabel auf kadence/countdown werden die Platzhalter wie folgt ersetzt: %3$skadence/countdown, %2$sdaysLabel, %1$sDays, was ergibt:

#(<!-- wp:kadence/countdown \{.*?\"daysLabel\":\")Days(\".*?\}/?-->)#

Nur Days wird ersetzt; der Blockname, die anderen Attribute und der schließende Kommentar werden durch die Erfassungsgruppen bewahrt.

Die Form des regulären Ausdrucks lautet:

#(alles davor)Attributwert(alles danach)#

Im HTML des Blocks gespeicherte Strings

Wenn der Wert nicht in den JSON-Attributen, sondern im gerenderten HTML gespeichert ist, stelle deinen eigenen regulären Ausdruck bereit. Du kannst %s (anstelle von %1$s) verwenden, wo der Attributwert steht, und den Block- sowie den Attributnamen direkt im regulären Ausdruck kodieren.

Beispiel — Übersetzen des Attributs content des Blocks generateblocks/text. Sein Markup sieht so aus — beachte, dass Hello world nicht im JSON steht, sondern zwischen den gerenderten Tags:

<!-- wp:generateblocks/text {"uniqueId":"abc123","tagName":"p"} -->
<p class="gb-text">Hello world</p>
<!-- /wp:generateblocks/text -->

Der Standard-Regulärausdruck würde diese Teilzeichenkette niemals finden, daher stellst du deinen eigenen bereit:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        $regexes['generateblocks/text'] = [
            'content' => '#(<!-- wp:generateblocks/text [^>]*?-->\n?<[a-z0-9]+ ?[^>]*?>)%s(</[a-z0-9]+>\n?<!-- /wp:generateblocks/text -->)#',
        ];
        return $regexes;
    }
);

Wenn derselbe Wert an mehreren Stellen vorkommt

Wenn dasselbe Attribut sowohl in den JSON-Attributen als auch im HTML vorkommt (oder an zwei verschiedenen Stellen), übergib ein Array von regulären Ausdrücken — jeder muss ausgelöst werden, damit jede Kopie des Strings übersetzt wird.

Beim Block generateblocks/media zum Beispiel sind alt und title sowohl innerhalb von htmlAttributes im JSON als auch als HTML-Attribute am gerenderten <img> gespeichert:

<!-- wp:generateblocks/media {"mediaId":42,"htmlAttributes":{"alt":"Cat sitting","title":"My cat"}} -->
<figure class="gb-media"><img src="…" alt="Cat sitting" title="My cat"></figure>
<!-- /wp:generateblocks/media -->

Zwei reguläre Ausdrücke pro Attribut — einer für das JSON, einer für das <img> — stellen sicher, dass beide Kopien nach der Übersetzung synchron bleiben:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        $regexes['generateblocks/media'] = [
            'htmlAttributes.alt' => [
                '#(<!-- wp:generateblocks/media \{.*?\"htmlAttributes\":\{.*?\"alt\":\")%s(\".*?\}.*?\} -->)#',
                '#(<!-- wp:generateblocks/media [^>]*?-->\n?.*<img [^>]*alt=\")%s(\"[^>]*?>.*\n?<!-- /wp:generateblocks/media -->)#',
            ],
            'htmlAttributes.title' => [
                '#(<!-- wp:generateblocks/media \{.*?\"htmlAttributes\":\{.*?\"title\":\")%s(\".*?\}.*?\} -->)#',
                '#(<!-- wp:generateblocks/media [^>]*?-->\n?.*<img [^>]*title=\")%s(\"[^>]*?>.*\n?<!-- /wp:generateblocks/media -->)#',
            ],
        ];
        return $regexes;
    }
);

Wenn der Attributwert ein JSON-Objekt ist, kannst du eine bestimmte Untereigenschaft ansprechen, indem du einen . (Punkt) im Attributnamen verwendest, wie oben mit htmlAttributes.alt und htmlAttributes.title auf generateblocks/media gezeigt.

Übersetzung für ein automatisch übersetztes Attribut deaktivieren

Das Übergeben von false oder null entfernt die Übersetzung für ein Attribut, das das Plugin andernfalls automatisch übersetzen würde. Das ist nützlich, um beispielsweise ein bestimmtes String-Attribut von der automatischen Übersetzung in reinen PHP-Blöcken auszuschließen, oder für Blöcke, die aus einer wpml-config.xml importiert wurden, deren deklarierte Attribute du nicht übersetzen möchtest:

add_filter(
    'gatompl:gutenberg_block_type_translatable_attribute_regexes',
    static function (array $regexes): array {
        // Disable translation of the `header` attribute on the
        // `my-plugin/duplicate-alert` block (either form works)
        unset($regexes['my-plugin/duplicate-alert']['header']);
        $regexes['my-plugin/duplicate-alert']['implications'] = false;
        return $regexes;
    }
);

Entitätsreferenzen übersetzen

Entitätsreferenzen (eine Beitrags-/Medien-/Term-/Menü-ID, die in einem Block-Attribut gespeichert ist) können bei der Übersetzung der entsprechenden Entität in der Zielsprache neu zugeordnet werden. Verwende einen der folgenden Filter, je nach Art der Referenz:

ReferenzartFilter
Custom Posts und Mediengatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes
Taxonomiebegriffegatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes
Menüs nach IDgatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes
Menüs nach Sluggatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes

Jeder Filter erhält dieselbe Struktur wie der Filter für übersetzbare Attribute (true für den Standard-Regulärausdruck, ein String oder Array für benutzerdefinierte Ausdrücke).

Der Block woocommerce/single-product zum Beispiel speichert das verknüpfte Produkt als numerische productId:

<!-- wp:woocommerce/single-product {"productId":42} /-->

Wenn der Beitrag übersetzt wird, muss diese 42 (das Produkt in der Ausgangssprache) dem entsprechenden Gegenstück in der Zielsprache (z. B. 87) neu zugeordnet werden. Markiere productId als Custom-Post-Referenz, damit das Plugin die ID bei der Übersetzung erfasst und ersetzt:

add_filter(
    'gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes',
    static function (array $regexes): array {
        $regexes['woocommerce/single-product'] = [
            'productId' => true,
            // …oder ein benutzerdefinierter Regulärausdruck, wenn `productId` nicht in der Standard-JSON-Form gespeichert ist:
            // 'productId' => '#(<!-- wp:woocommerce/single-product \{.*?\"productId\":)%s([,\}].*? /?-->)#',
        ];
        return $regexes;
    }
);

Verwende dasselbe Muster für die anderen Referenzarten. Jede Art sieht im Block-Markup gleich aus — eine numerische ID oder ein Slug, der im JSON eingebettet ist — was sich unterscheidet, ist die Art und Weise, wie das Plugin es in der Zielsprache auflöst:

<!-- wp:my-plugin/related-category {"categoryId":17} /-->
<!-- wp:my-plugin/menu-picker {"menuId":5} /-->
<!-- wp:my-plugin/menu-picker {"menuSlug":"main-nav"} /-->
// Taxonomy term reference
add_filter(
    'gatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes',
    static function (array $regexes): array {
        $regexes['my-plugin/related-category'] = [
            'categoryId' => true,
        ];
        return $regexes;
    }
);
 
// Menu reference by ID
add_filter(
    'gatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes',
    static function (array $regexes): array {
        $regexes['my-plugin/menu-picker'] = [
            'menuId' => true,
        ];
        return $regexes;
    }
);
 
// Menu reference by slug
add_filter(
    'gatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes',
    static function (array $regexes): array {
        $regexes['my-plugin/menu-picker'] = [
            'menuSlug' => true,
        ];
        return $regexes;
    }
);

Attributnamen herausfinden

Der schnellste Weg, die Attributnamen und ihre Speicherart zu finden, ist es, die GraphQL-Query Translate custom posts auszuführen und das Antwortfeld blockFlattenedDataItems für den betreffenden Block zu untersuchen.

Lies die Anleitung Page-Builder-Daten zum Übersetzen abrufen, um zu erfahren, wie du diese Query ausführst und ihre Ausgabe liest.

Blöcke umgehen, deren Attribute verarbeitet werden müssen

Die obigen Hooks gehen davon aus, dass der über blockFlattenedDataItems bereitgestellte Attributwert bereits der zu übersetzende Wert ist (ein Skalar oder ein Array).

Wenn der Wert eingebettet ist — zum Beispiel speichert das Attribut <li>Some text</li> und du möchtest nur Some text übersetzen — musst du ihn zuerst über den Filter gatompl:gutenberg_block_flattened_data_item_attributes extrahieren.

Der Block generateblocks/image ist ein reales Beispiel: Seine Attribute alt und title sind nicht als eigenständige Attribute verfügbar, sie befinden sich im HTML von innerContent und müssen mit einem regulären Ausdruck extrahiert werden.

add_filter(
    'gatompl:gutenberg_block_flattened_data_item_attributes',
    static function (?\stdClass $attributes, string $blockTypeName, \stdClass $blockDataItem): ?\stdClass {
        if ($attributes === null || $blockTypeName !== 'generateblocks/image') {
            return $attributes;
        }
 
        $innerContent = $blockDataItem->innerContent ?? null;
        if (!is_array($innerContent) || !isset($innerContent[0]) || !is_string($innerContent[0])) {
            return $attributes;
        }
        $html = $innerContent[0];
 
        if (preg_match('#<img [^>]*alt="([^"]*)"[^>]*?>#', $html, $matches) === 1 && $matches[1] !== '') {
            $attributes->alt = $matches[1];
        }
        if (preg_match('#<img [^>]*title="([^"]*)"[^>]*?>#', $html, $matches) === 1 && $matches[1] !== '') {
            $attributes->title = $matches[1];
        }
        return $attributes;
    },
    10,
    3
);

Sobald alt und title im Attributobjekt vorhanden sind, können die oben genannten regulärausdrucksbasierten Hooks sie wie jedes andere Attribut ansprechen.

Wo du Beispiele findest

Die eigenen Integrationen des Plugins sind gute praxisnahe Referenzen. Erkunde diese Dateien im installierten Plugin:

  • Reguläre Ausdrücke für Block-Attribute: wp-content/plugins/gato-ai-translations-for-polylang/src/Constants/BlockTypeAttributeValues.php
  • Vorverarbeitung von Block-Attributen: wp-content/plugins/gato-ai-translations-for-polylang/src/ConditionalOnContext/LicenseIsActive/Hooks/CoreBlockFlattenedDataItemAttributesHookSet.php