Tłumaczenie dodatkowych bloków Gutenberg
Gato AI Translations for Polylang może tłumaczyć posty oparte na blokach.
Plugin zawiera obsługę wielu bloków od razu po instalacji. W przypadku wszystkiego poza tym — własnych niestandardowych bloków lub bloków z wtyczek innych firm, które nie zawierają pliku wpml-config.xml — możesz rozszerzyć obsługę za pomocą hooków PHP.
Tłumaczenie ciągów tekstowych
Aby zarejestrować dodatkowe atrybuty nadające się do tłumaczenia dla bloku, użyj filtra gatompl:gutenberg_block_type_translatable_attribute_regexes.
Dlaczego wyrażenia regularne?
Blok Gutenberg jest zapisywany w post_content jako komentarz HTML zawierający atrybuty JSON bloku, a następnie wyrenderowany HTML bloku, na przykład:
<!-- wp:my-plugin/my-block {"title":"Hello"} -->
<div class="wp-block-my-plugin-my-block">Hello</div>
<!-- /wp:my-plugin/my-block -->Tłumaczenie bloku oznacza znalezienie konkretnego podciągu do przetłumaczenia wewnątrz tego znacznika, zastąpienie go tłumaczeniem i pozostawienie wszystkiego innego bez zmian (nazwa bloku, inne atrybuty, struktura HTML, otaczające bloki). Wyrażenia regularne pozwalają pluginowi dokładnie wskazać, który podciąg zastąpić: tekst przed i po wartości jest przechwytywany w grupach, a sama wartość jest częścią, która zostaje zamieniona.
Standardowe atrybuty tekstowe (przechowywane w JSON bloku)
Jeśli właściwość jest zwykłym ciągiem tekstowym przechowywanym w atrybutach JSON bloku, przekaż true, a plugin użyje swojego domyślnego wyrażenia regularnego.
Na przykład, aby przetłumaczyć atrybuty daysLabel, hoursLabel, minutesLabel i secondsLabel bloku kadence/countdown — którego znacznik wygląda tak:
<!-- 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 -->…zarejestruj atrybuty w następujący sposób:
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;
}
);Wartość true jest wewnętrznie rozwijana do tego domyślnego wyrażenia regularnego:
#(<!-- wp:%3$s \{.*?\"%2$s\":\")%1$s(\".*?\}/?-->)#…gdzie symbole zastępcze to:
%1$s→ wartość atrybutu%2$s→ nazwa atrybutu%3$s→ nazwa bloku
Dla atrybutu daysLabel w kadence/countdown symbole zastępcze są podstawiane następująco: %3$s → kadence/countdown, %2$s → daysLabel, %1$s → Days, dając wynik:
#(<!-- wp:kadence/countdown \{.*?\"daysLabel\":\")Days(\".*?\}/?-->)#Zastępowane jest tylko Days; nazwa bloku, inne atrybuty i komentarz zamykający są zachowane przez grupy przechwytywania.
Postać wyrażenia regularnego wygląda następująco:
#(wszystko przed)wartość atrybutu(wszystko po)#Ciągi tekstowe przechowywane wewnątrz HTML bloku
Jeśli wartość nie jest przechowywana w atrybutach JSON, lecz wewnątrz wyrenderowanego HTML, dostarcz własne wyrażenie regularne. Możesz użyć %s (zamiast %1$s) w miejscu wartości atrybutu, a nazwę bloku i atrybutu zakodować bezpośrednio w wyrażeniu regularnym.
Przykład — tłumaczenie atrybutu content bloku generateblocks/text. Jego znacznik wygląda następująco — zauważ, że Hello world nie znajduje się w JSON, lecz między wyrenderowanymi tagami:
<!-- wp:generateblocks/text {"uniqueId":"abc123","tagName":"p"} -->
<p class="gb-text">Hello world</p>
<!-- /wp:generateblocks/text -->Domyślne wyrażenie regularne nigdy nie znalazłoby tego podciągu, dlatego dostarczasz własne:
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;
}
);Gdy ta sama wartość pojawia się w wielu miejscach
Jeśli ten sam atrybut pojawia się zarówno w atrybutach JSON jak i w HTML (lub w dwóch różnych miejscach), przekaż tablicę wyrażeń regularnych — każde z nich musi zostać uruchomione, aby wszystkie kopie ciągu zostały przetłumaczone.
Na przykład w bloku generateblocks/media atrybuty alt i title są przechowywane zarówno wewnątrz htmlAttributes w JSON, jak i jako atrybuty HTML na wyrenderowanym znaczniku <img>:
<!-- 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 -->Dwa wyrażenia regularne na atrybut — jedno celujące w JSON, drugie w <img> — zapewniają, że obie kopie pozostają zsynchronizowane po tłumaczeniu:
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;
}
);Jeśli wartość atrybutu jest obiektem JSON, możesz celować w konkretną właściwość podrzędną, używając . (kropki) w nazwie atrybutu, jak pokazano powyżej z htmlAttributes.alt i htmlAttributes.title w generateblocks/media.
Wyłączanie tłumaczenia automatycznie tłumaczonego atrybutu
Przekazanie false lub null usuwa tłumaczenie atrybutu, który plugin w innym przypadku przetłumaczyłby automatycznie. Jest to przydatne na przykład, aby wykluczyć konkretny atrybut tekstowy z automatycznego tłumaczenia w blokach tylko PHP lub dla bloków importowanych z wpml-config.xml, których zadeklarowanych atrybutów nie chcesz tłumaczyć:
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;
}
);Tłumaczenie odwołań do encji
Odwołania do encji (identyfikator posta/mediów/terminu/menu przechowywany w atrybucie bloku) mogą być przemapowane na odpowiadającą im encję w języku docelowym w czasie tłumaczenia. Użyj jednego z poniższych filtrów w zależności od rodzaju odwołania:
| Rodzaj odwołania | Filtr |
|---|---|
| Custom posts i media | gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes |
| Terminy taksonomii | gatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes |
| Menu po ID | gatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes |
| Menu po slug | gatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes |
Każdy filtr otrzymuje tę samą strukturę co filtr atrybutów nadających się do tłumaczenia (true dla domyślnego wyrażenia regularnego, ciąg lub tablica dla niestandardowych wyrażeń regularnych).
Na przykład blok woocommerce/single-product przechowuje powiązany produkt jako numeryczny productId:
<!-- wp:woocommerce/single-product {"productId":42} /-->Gdy post jest tłumaczony, to 42 (produkt w języku źródłowym) musi zostać przemapowane na jego odpowiednik w języku docelowym (powiedzmy 87). Oznacz productId jako odwołanie do custom posta, aby plugin przechwycił i zamienił identyfikator w czasie tłumaczenia:
add_filter(
'gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes',
static function (array $regexes): array {
$regexes['woocommerce/single-product'] = [
'productId' => true,
// …lub niestandardowe wyrażenie regularne, jeśli `productId` nie jest przechowywany w standardowym formacie JSON:
// 'productId' => '#(<!-- wp:woocommerce/single-product \{.*?\"productId\":)%s([,\}].*? /?-->)#',
];
return $regexes;
}
);Używaj tego samego wzorca dla innych rodzajów odwołań. Każdy rodzaj wygląda tak samo w znaczniku bloku — numeryczny identyfikator lub slug osadzony w JSON — różnica polega na tym, jak plugin rozwiązuje go w języku docelowym:
<!-- 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;
}
);Odkrywanie nazw atrybutów
Najszybszym sposobem na znalezienie nazw atrybutów i sposobu ich przechowywania jest uruchomienie zapytania GraphQL Translate custom posts i sprawdzenie pola odpowiedzi blockFlattenedDataItems dla danego bloku.
Zapoznaj się z przewodnikiem Pobieranie danych page buildera do tłumaczenia, aby dowiedzieć się, jak uruchomić to zapytanie i odczytać jego wyniki.
Obejście bloków, których atrybuty wymagają przetworzenia
Powyższe hooki zakładają, że wartość atrybutu udostępniana przez blockFlattenedDataItems jest już wartością do przetłumaczenia (skalar lub tablica).
Jeśli wartość jest opakowana — na przykład atrybut przechowuje <li>Some text</li>, a Ty chcesz przetłumaczyć tylko Some text — musisz najpierw ją wyodrębnić za pomocą filtra gatompl:gutenberg_block_flattened_data_item_attributes.
Blok generateblocks/image jest przykładem z rzeczywistego życia: jego atrybuty alt i title nie są udostępniane jako samodzielne atrybuty, lecz znajdują się wewnątrz HTML innerContent i muszą być wyodrębnione za pomocą wyrażenia regularnego.
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
);Gdy alt i title istnieją już w obiekcie atrybutów, hooki oparte na wyrażeniach regularnych opisane powyżej mogą je wskazywać jak każdy inny atrybut.
Gdzie znaleźć przykłady
Własne integracje pluginu są dobrymi odwołaniami z rzeczywistego życia. Zapoznaj się z tymi plikami wewnątrz zainstalowanego pluginu:
- Wyrażenia regularne atrybutów bloku:
wp-content/plugins/gato-ai-translations-for-polylang/src/Constants/BlockTypeAttributeValues.php - Wstępne przetwarzanie atrybutów bloku:
wp-content/plugins/gato-ai-translations-for-polylang/src/ConditionalOnContext/LicenseIsActive/Hooks/CoreBlockFlattenedDataItemAttributesHookSet.php