Estender
EstenderTraduzir blocos Gutenberg adicionais

Traduzir blocos Gutenberg adicionais

Gato AI Translations for Polylang pode traduzir posts baseados em blocos.

O plugin vem com suporte para muitos blocos por padrão. Para tudo além disso — seus próprios blocos personalizados, ou blocos de plugins de terceiros que não incluem um wpml-config.xml — você pode estender o suporte via hooks PHP.

Traduzir strings

Para registrar atributos traduzíveis adicionais para um bloco, use o filtro gatompl:gutenberg_block_type_translatable_attribute_regexes.

Por que expressões regulares?

Um bloco Gutenberg é persistido em post_content como um comentário HTML que carrega os atributos JSON do bloco, seguido pelo HTML renderizado do bloco, por exemplo:

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

Traduzir um bloco significa encontrar a substring específica a traduzir dentro desse markup, substituí-la pela sua tradução e deixar todo o resto intocado (nome do bloco, outros atributos, estrutura HTML, blocos ao redor). As expressões regulares são a forma como o plugin identifica exatamente qual substring substituir: o texto antes e depois do valor é capturado em grupos, e o próprio valor é a parte que é trocada.

Atributos de string padrão (armazenados no JSON do bloco)

Se a propriedade é uma string normal armazenada nos atributos JSON do bloco, passe true e o plugin usará sua expressão regular padrão.

Por exemplo, para traduzir os atributos daysLabel, hoursLabel, minutesLabel e secondsLabel do bloco kadence/countdown — cujo markup se parece com este:

<!-- 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 -->

…registre os atributos assim:

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;
    }
);

O valor true é expandido internamente para esta expressão regular padrão:

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

…onde os marcadores são:

  1. %1$s → o valor do atributo
  2. %2$s → o nome do atributo
  3. %3$s → o nome do bloco

Para o atributo daysLabel em kadence/countdown, os marcadores são substituídos assim: %3$skadence/countdown, %2$sdaysLabel, %1$sDays, produzindo:

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

Apenas Days é substituído; o nome do bloco, os outros atributos e o comentário de fechamento são preservados pelos grupos de captura.

A forma da expressão regular é:

#(tudo antes)valor do atributo(tudo depois)#

Strings armazenadas no HTML do bloco

Se o valor não está armazenado nos atributos JSON, mas dentro do HTML renderizado, forneça sua própria expressão regular. Você pode usar %s (em vez de %1$s) onde vai o valor do atributo, e ter o nome do bloco e o nome do atributo codificados diretamente na expressão regular.

Exemplo — traduzir o atributo content do bloco generateblocks/text. Seu markup se parece com este — note que Hello world não está no JSON, ele fica entre as tags renderizadas:

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

A expressão regular padrão nunca encontraria essa substring, então você fornece a sua própria:

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;
    }
);

Quando o mesmo valor aparece em múltiplos lugares

Se o mesmo atributo aparece tanto nos atributos JSON quanto no HTML (ou em dois lugares diferentes), passe um array de expressões regulares — cada uma precisa ser acionada para que cada cópia da string seja traduzida.

Por exemplo, no bloco generateblocks/media, alt e title são armazenados tanto dentro de htmlAttributes no JSON quanto como atributos HTML no <img> renderizado:

<!-- 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 -->

Duas expressões regulares por atributo — uma mirando o JSON, outra mirando o <img> — garantem que ambas as cópias permaneçam sincronizadas após a tradução:

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;
    }
);

Se o valor do atributo é um objeto JSON, você pode mirar uma sub-propriedade específica usando um . (ponto) no nome do atributo, como mostrado acima com htmlAttributes.alt e htmlAttributes.title em generateblocks/media.

Desativar a tradução de um atributo traduzido automaticamente

Passar false ou null remove a tradução de um atributo que o plugin de outra forma traduziria automaticamente. Isso é útil, por exemplo, para excluir um atributo de string específico da tradução automática em blocos somente PHP, ou para blocos importados de um wpml-config.xml cujos atributos declarados você não quer traduzir:

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;
    }
);

Traduzir referências a entidades

Referências a entidades (um ID de post/mídia/termo/menu armazenado em um atributo de bloco) podem ser remapeadas para a entidade correspondente no idioma de destino no momento da tradução. Use um dos seguintes filtros dependendo do tipo de referência:

Tipo de referênciaFiltro
Custom posts e mídiagatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes
Termos de taxonomiagatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes
Menus por IDgatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes
Menus por sluggatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes

Cada filtro recebe a mesma estrutura que o filtro de atributos traduzíveis (true para a expressão regular padrão, uma string ou array para expressões regulares personalizadas).

Por exemplo, o bloco woocommerce/single-product armazena o produto vinculado como um productId numérico:

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

Quando o post é traduzido, esse 42 (o produto no idioma de origem) precisa ser remapeado para seu equivalente no idioma de destino (digamos 87). Marque productId como uma referência de custom post para que o plugin capture e troque o ID no momento da tradução:

add_filter(
    'gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes',
    static function (array $regexes): array {
        $regexes['woocommerce/single-product'] = [
            'productId' => true,
            // …ou uma expressão regular personalizada se `productId` não estiver armazenado no formato JSON padrão:
            // 'productId' => '#(<!-- wp:woocommerce/single-product \{.*?\"productId\":)%s([,\}].*? /?-->)#',
        ];
        return $regexes;
    }
);

Use o mesmo padrão para os outros tipos de referência. Cada tipo tem o mesmo aspecto no markup do bloco — um ID numérico ou um slug embutido no JSON — o que difere é como o plugin o resolve no idioma de destino:

<!-- 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;
    }
);

Descobrindo os nomes dos atributos

A maneira mais rápida de encontrar os nomes dos atributos e como eles são armazenados é executar a query GraphQL Translate custom posts e examinar o campo de resposta blockFlattenedDataItems para o bloco em questão.

Consulte o guia Recuperando dados do page builder para traduzir para saber como executar essa query e ler seu resultado.

Contornando blocos cujos atributos precisam de processamento

Os hooks acima pressupõem que o valor do atributo exposto via blockFlattenedDataItemsé o valor a traduzir (um escalar ou array).

Se o valor está encapsulado — por exemplo, o atributo armazena <li>Some text</li> e você quer que apenas Some text seja traduzido — você precisa extraí-lo primeiro via o filtro gatompl:gutenberg_block_flattened_data_item_attributes.

O bloco generateblocks/image é um exemplo real: seus atributos alt e title não são expostos como atributos independentes, eles ficam dentro do HTML de innerContent e precisam ser extraídos com uma expressão regular.

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
);

Uma vez que alt e title existam no objeto de atributos, os hooks baseados em expressões regulares acima podem mirá-los como qualquer outro atributo.

Onde encontrar exemplos

As próprias integrações do plugin são boas referências reais. Explore estes arquivos dentro do plugin que você instalou:

  • Expressões regulares de atributos de bloco: wp-content/plugins/gato-ai-translations-for-polylang/src/Constants/BlockTypeAttributeValues.php
  • Pré-processamento de atributos de bloco: wp-content/plugins/gato-ai-translations-for-polylang/src/ConditionalOnContext/LicenseIsActive/Hooks/CoreBlockFlattenedDataItemAttributesHookSet.php