Extender
ExtenderTraducir bloques de Gutenberg adicionales

Traducir bloques de Gutenberg adicionales

Gato AI Translations for Polylang puede traducir entradas basadas en bloques.

El plugin trae soporte para muchos bloques de serie. Para cualquier otro caso —tus propios bloques personalizados o bloques de plugins de terceros que no incluyan un wpml-config.xml— puedes ampliar el soporte mediante hooks de PHP.

Traducir cadenas

Para registrar atributos traducibles adicionales para un bloque, utiliza el filtro gatompl:gutenberg_block_type_translatable_attribute_regexes.

¿Por qué expresiones regulares?

Un bloque de Gutenberg se persiste en post_content como un comentario HTML que contiene los atributos JSON del bloque, seguido del HTML renderizado del bloque. Por ejemplo:

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

Traducir un bloque significa encontrar la subcadena concreta a traducir dentro de ese marcado, sustituirla por su traducción y dejar todo lo demás intacto (nombre del bloque, otros atributos, estructura HTML, bloques contiguos). Las expresiones regulares son la forma en la que el plugin localiza exactamente qué subcadena reemplazar: el texto anterior y posterior al valor se captura en grupos, y el propio valor es la parte que se sustituye.

Atributos de cadena estándar (almacenados en el JSON del bloque)

Si la propiedad es una cadena normal almacenada en los atributos JSON del bloque, pasa true y el plugin utilizará su regex por defecto.

Por ejemplo, para traducir los atributos daysLabel, hoursLabel, minutesLabel y secondsLabel del bloque kadence/countdown —cuyo marcado tiene este aspecto—:

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

…registra los atributos así:

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

El valor true se expande internamente a esta expresión regular por defecto:

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

…donde los marcadores son:

  1. %1$s → el valor del atributo
  2. %2$s → el nombre del atributo
  3. %3$s → el nombre del bloque

Para el atributo daysLabel en kadence/countdown, los marcadores se sustituyen como %3$skadence/countdown, %2$sdaysLabel, %1$sDays, produciendo:

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

Solo se reemplaza Days; el nombre del bloque, los demás atributos y el comentario de cierre se preservan gracias a los grupos de captura.

La forma de la expresión regular es:

#(todo lo anterior)valor del atributo(todo lo posterior)#

Cadenas almacenadas dentro del HTML del bloque

Si el valor no está almacenado en los atributos JSON sino dentro del HTML renderizado, proporciona tu propia expresión regular. Puedes utilizar %s (en lugar de %1$s) en el lugar del valor del atributo, y tener el nombre del bloque y del atributo escritos directamente en la expresión.

Ejemplo: traducir el atributo content del bloque generateblocks/text. Su marcado tiene este aspecto —fíjate en que Hello world no está dentro del JSON, sino entre las etiquetas renderizadas—:

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

La expresión regular por defecto nunca encontraría esa subcadena, así que aportas la tuya:

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

Cuando el mismo valor aparece en varios sitios

Si el mismo atributo aparece tanto en los atributos JSON como en el HTML (o en dos sitios diferentes), pasa un array de expresiones regulares: cada una debe dispararse para que cada copia de la cadena sea traducida.

Por ejemplo, en el bloque generateblocks/media, alt y title se almacenan tanto dentro de htmlAttributes en el JSON como en forma de atributos HTML en el <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 -->

Dos expresiones regulares por atributo —una dirigida al JSON, otra al <img>— garantizan que ambas copias queden sincronizadas tras la traducción:

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

Si el valor del atributo es un objeto JSON, puedes apuntar a una sub-propiedad concreta utilizando un . (punto) en el nombre del atributo, como se muestra arriba con htmlAttributes.alt y htmlAttributes.title en generateblocks/media.

Desactivar la traducción para un atributo traducido automáticamente

Pasar false o null elimina la traducción de un atributo que el plugin traduciría automáticamente en otro caso. Esto es útil, por ejemplo, para excluir de la traducción automática a un atributo de cadena concreto en bloques solo de PHP, o para bloques traídos desde un wpml-config.xml cuyos atributos declarados no quieres que se traduzcan:

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

Traducir referencias a entidades

Las referencias a entidades (un ID de entrada/multimedia/término/menú almacenado en un atributo de un bloque) pueden reasignarse a la entidad correspondiente en el idioma de destino en el momento de la traducción. Utiliza uno de los siguientes filtros según el tipo de referencia:

Tipo de referenciaFiltro
Custom posts y multimediagatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes
Términos de taxonomíagatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes
Menús por IDgatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes
Menús por sluggatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes

Cada filtro recibe la misma estructura que el filtro de atributos traducibles (true para la expresión regular por defecto, una cadena o array para expresiones personalizadas).

Por ejemplo, el bloque woocommerce/single-product almacena el producto vinculado como un productId numérico:

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

Cuando se traduce la entrada, ese 42 (el producto en el idioma de origen) necesita reasignarse a su equivalente en el idioma de destino (por ejemplo, 87). Marca productId como referencia a custom post para que el plugin capture e intercambie el ID en el momento de la traducción:

add_filter(
    'gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes',
    static function (array $regexes): array {
        $regexes['woocommerce/single-product'] = [
            'productId' => true,
            // …o una expresión regular personalizada si `productId` no se almacena en la forma JSON estándar:
            // 'productId' => '#(<!-- wp:woocommerce/single-product \{.*?\"productId\":)%s([,\}].*? /?-->)#',
        ];
        return $regexes;
    }
);

Utiliza el mismo patrón para los demás tipos de referencia. Todos tienen el mismo aspecto en el marcado del bloque —un ID numérico o un slug incrustado en el JSON— y lo que cambia es cómo el plugin lo resuelve al 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;
    }
);

Descubrir los nombres de los atributos

La forma más rápida de averiguar los nombres de los atributos y cómo se almacenan es ejecutar la consulta GraphQL Translate custom posts y mirar el campo de respuesta blockFlattenedDataItems para el bloque en cuestión.

Consulta la guía Obtener datos del page builder a traducir para saber cómo ejecutar esa consulta y leer su salida.

Trabajar con bloques cuyos atributos requieren procesamiento

Los hooks anteriores asumen que el valor del atributo expuesto en blockFlattenedDataItems ya es el valor a traducir (un escalar o un array).

Si el valor está envuelto —por ejemplo, el atributo almacena <li>Some text</li> y solo quieres que se traduzca Some text— necesitas extraerlo previamente mediante el filtro gatompl:gutenberg_block_flattened_data_item_attributes.

El bloque generateblocks/image es un ejemplo real: sus atributos alt y title no están expuestos como atributos independientes, sino que viven dentro del HTML de innerContent y hay que extraerlos con una expresión 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
);

Una vez que alt y title existen en el objeto de atributos, los hooks basados en expresiones regulares anteriores pueden apuntar a ellos como a cualquier otro atributo.

Dónde encontrar ejemplos

Las propias integraciones del plugin son buenas referencias del mundo real. Explora estos ficheros dentro del plugin que has instalado:

  • Expresiones regulares de atributos de bloque: wp-content/plugins/gato-ai-translations-for-polylang/src/Constants/BlockTypeAttributeValues.php
  • Preprocesamiento de atributos de bloque: wp-content/plugins/gato-ai-translations-for-polylang/src/ConditionalOnContext/LicenseIsActive/Hooks/CoreBlockFlattenedDataItemAttributesHookSet.php