PTC

¿No aparecen las traducciones de su plugin de WordPress? Solucione la falta de traducciones

¿Faltan traducciones después de una ejecución de PTC? Cuatro comprobaciones permiten encontrar casi cualquier causa. Compruebe si la cadena llegó a PTC, si el nombre del archivo .mo coincide con lo que WordPress espera y si el text domain es coherente en todo su código. Esta guía le llevará por cada comprobación en el orden en que debe ejecutarlas.

El mismo orden de diagnóstico funciona tanto si ha traducido con PTC (Private Translation Cloud), GlotPress o cualquier otra herramienta basada en gettext. Los modos de fallo son inherentes al flujo de trabajo de i18n de WordPress, no a un traductor en particular.

Confirme que la cadena llegó a PTC

La primera pregunta es si la cadena está en su proyecto de PTC. Si una cadena no se extrajo en su archivo .pot, PTC nunca la vio. El archivo .po no tiene traducción para ella. El plugin en ejecución muestra el idioma de origen como alternativa.

Cómo comprobarlo:

  1. Abra la cadena afectada en el plugin en ejecución y copie su texto exacto.
  2. Vaya a su panel de control de PTC, abra la pestaña Translations y busque la cadena.
  3. Si no está allí, PTC nunca la recibió.

A continuación se presentan las causas comunes.

Causa 1: la cadena falta en su archivo POT

wp i18n make-pot solo extrae cadenas dentro de las funciones de i18n reconocidas. Esto significa __(), _e(), _n(), _x() y las variantes con escape, con el text domain correcto. Las cadenas dentro de un dominio incorrecto se omiten. Las cadenas hardcoded fuera de una función de i18n se omiten.

Vuelva a ejecutar la extracción y verifique que la cadena esté ahora en el .pot:

wp i18n make-pot . languages/my-plugin.pot --domain=my-plugin
grep "Save Changes" languages/my-plugin.pot

Si grep devuelve la cadena con un msgid, la extracción funciona. Vuelva a subir el nuevo .pot a PTC y vuelva a traducir. Si grep no devuelve nada, la cadena está hardcoded y no está envuelta en __(). Ese es su error. Envuelva la cadena y vuelva a extraer.

Causa 2: el texto no está envuelto en una función gettext

Cada cadena traducible en su código necesita un envoltorio. Use __(), esc_html__(), _e(), _n() o _x() con el text domain correcto:

__( 'Hello, world!', 'your-plugin' );

Causa 3: las cadenas de JavaScript no se marcaron como traducibles

Si su plugin incluye texto traducible en JavaScript:

  1. En el panel de control de PTC, vaya a Settings > Monitored Files.
  2. Edite el archivo de recursos correspondiente y active “Is this a WordPress project with localizable JavaScript?”

Esto le indica a PTC que escanee los archivos JavaScript en busca de cadenas traducibles. PTC regenera las traducciones y abre un nuevo merge request con los archivos actualizados.

A continuación, asegúrese de que WordPress sepa dónde cargar los archivos de traducción .json que produjo PTC. Llame a wp_set_script_translations() con la ruta correcta:

// For plugins
wp_set_script_translations(
    'script-handle',
    'text-domain',
    plugin_dir_path( __FILE__ ) . 'languages'
);

// For themes
wp_set_script_translations(
    'script-handle',
    'text-domain',
    get_template_directory() . '/languages'
);

Esto le indica a WordPress que cargue los archivos .json desde la carpeta de su plugin o tema.

Confirme que WordPress está cargando su archivo .mo

Si la cadena está en PTC y el archivo .mo existe en el directorio languages/ de su plugin, pero el plugin renderizado sigue mostrándose en inglés, WordPress no está cargando el .mo.

Diagnóstico 1: ¿está configurado correctamente el locale del sitio? Vaya a Ajustes > Generales > Idioma del sitio en wp-admin y confirme que coincide con su idioma de destino. Por ejemplo, configúrelo en “Español” para probar el español. Si el sitio está en inglés, su .mo en español nunca se cargará. Esto no es un error.

Diagnóstico 2: ¿se está ejecutando realmente load_plugin_textdomain()? Añada una línea de depuración temporal:

add_action( 'init', function() {
    $loaded = load_plugin_textdomain(
        'my-plugin',
        false,
        dirname( plugin_basename( __FILE__ ) ) . '/languages'
    );
    error_log( 'my-plugin textdomain loaded: ' . var_export( $loaded, true ) );
} );

Recargue una página y compruebe su registro de errores de PHP. loaded: true significa que WordPress encontró y cargó un archivo .mo para el locale actual. loaded: false significa que no lo hizo. La causa suele ser una discrepancia en el nombre del archivo (consulte la siguiente sección) o una ruta de directorio incorrecta.

Diagnóstico 3: ¿es correcto el momento del hook? load_plugin_textdomain() debe ejecutarse en el hook init. Ese es el hook canónico para que las traducciones se apliquen a las cadenas que se muestran durante el procesamiento normal de la solicitud.

Diagnóstico 4: ¿están las traducciones de la comunidad anulando sus archivos incluidos? Por defecto, WordPress prioriza los archivos de traducción almacenados en /wp-content/languages/. Si su plugin o tema tiene traducciones proporcionadas por la comunidad en WordPress.org, esos archivos pueden anular los archivos .mo incluidos en su proyecto. Para evitar esto, use el filtro load_textdomain_mofile para forzar la carga de la ruta de su archivo incluido antes de que WordPress compruebe el directorio global. Los proyectos con múltiples text domains (un plugin que incrusta otro plugin) necesitan que cada dominio se cargue por separado. Cada dominio necesita su propia llamada a load_plugin_textdomain() o load_theme_textdomain().

Asegúrese de que el nombre del archivo MO coincida con el patrón de búsqueda de WordPress

La búsqueda de archivos .mo de WordPress sigue una convención de nomenclatura estricta. Con un solo carácter de diferencia, WordPress vuelve silenciosamente al inglés.

La convención depende de dónde coloque el archivo:

Ubicación Patrón Ejemplo
/languages/ del plugin {text-domain}-{locale}.mo my-plugin-de_DE.mo
/languages/ del tema {locale}.mo de_DE.mo
Dir global (/wp-content/languages/...) {text-domain}-{locale}.mo my-theme-de_DE.mo

Algunos ejemplos prácticos:

  • my-plugin-es_ES.mo para español (España)
  • my-plugin-fr_FR.mo para francés (Francia)
  • my-plugin-pt_BR.mo para portugués (Brasil)
  • my-plugin-zh_CN.mo para chino simplificado
  • my-plugin-ja.mo para japonés (algunos locales no tienen sufijo de región)

Errores comunes:

  • Prefijo de text-domain incorrecto. Si la cabecera Text Domain de su plugin es my-plugin pero el .mo se llama myplugin-es_ES.mo (sin guion), WordPress no lo encontrará. El prefijo debe coincidir exactamente con el valor de Text Domain.
  • Código de locale incorrecto. es.mo en lugar de es_ES.mo. WordPress utiliza códigos de locale regionales. es_ES, es_MX y es_AR son archivos diferentes. Un código de idioma básico solo funciona cuando no existe un archivo regional.
  • Guion frente a guion bajo. Los códigos de locale utilizan el guion bajo (es_ES), nunca el guion (es-ES). Esto confunde a los desarrolladores que copian los códigos de locale de las cabeceras Accept-Language del navegador o de fuentes BCP 47, donde el guion es el estándar.
  • Directorio incorrecto. La cabecera Domain Path debe apuntar al directorio que contiene sus archivos .mo. Si Domain Path es /languages y sus archivos .mo están en /lang/, WordPress no los encontrará.

Compruébelo listando los archivos que PTC produjo frente al locale que su sitio está utilizando:

ls plugins/my-plugin/languages/
# my-plugin-es_ES.mo
# my-plugin-es_ES.po
# my-plugin-fr_FR.mo
# my-plugin-fr_FR.po

Si los nombres parecen correctos pero las traducciones siguen sin cargarse, ejecute el diagnóstico de load_plugin_textdomain() anterior para confirmar que WordPress está encontrando el directorio.

Compruebe que su text domain sea coherente en todo su código

Este es el asesino silencioso. Cada llamada a __(), _e(), _n(), _x() en su código pasa un text domain como último argumento. Si incluso una sola llamada pasa el dominio incorrecto, esa cadena específica no se traducirá. Todas las demás cadenas del plugin funcionarán bien.

// Correct - matches the plugin's Text Domain
$correct = __( 'Save Changes', 'my-plugin' );

// Wrong - text domain typo; this string is never translated
$wrong = __( 'Save Changes', 'myplugin' );  // missing hyphen

// Wrong - copy-pasted from another plugin
$wrong = __( 'Save Changes', 'other-plugin' );

// Wrong - WordPress core domain; works for core strings but not yours
$wrong = __( 'Save Changes', 'default' );

Encuentre incoherencias buscando en su código base:

grep -rE "__\(|_e\(|_n\(|_x\(" --include="*.php" .

Observe el último argumento de cada coincidencia. Todos deberían ser el text domain de su plugin. Si encuentra erratas o errores de copiar y pegar, corríjalos y vuelva a ejecutar wp i18n make-pot para actualizar el .pot.

Para el código JavaScript que utiliza @wordpress/i18n, se aplica la misma regla. wp_set_script_translations() en PHP también debe pasar el dominio correspondiente:

wp_set_script_translations( 'my-plugin-editor', 'my-plugin', '...' );
//                                                ^^^^^^^^^^^
//                                                Must match the JS calls

Detecte los mismos problemas antes de lanzarlos con AI Visual QA

El ciclo de diagnóstico anterior es reactivo. Falta una traducción y tiene que buscar la causa. AI Visual QA de PTC detecta los mismos problemas antes de que se publiquen. Inspecciona el plugin renderizado en cada idioma de destino después de cada actualización de traducción e informa de lo que falta o está mal.

Para una cadena en inglés hardcoded fuera de __() (Causa 1 anterior), AI Visual QA ve la cadena sin traducir en el plugin renderizado. PTC genera un prompt listo para pegar en Cursor o Claude Code para envolver la cadena en __(). Para una discrepancia de text domain (la comprobación de la sección anterior), detecta la cadena sin traducir cuando otras cadenas en la misma pantalla sí están traducidas, e informa de la incoherencia.

Si aún no ha activado AI Visual QA, consulte el tutorial de temas y plugins de WordPress para la configuración.

Cuando las cuatro comprobaciones pasan y las traducciones siguen faltando

Si ha ejecutado las cuatro comprobaciones y las traducciones siguen sin aparecer, envíe un correo electrónico al soporte de PTC con:

  • El text domain de su plugin.
  • Uno de los nombres de archivo .mo (por ejemplo, my-plugin-es_ES.mo).
  • Una captura de pantalla del panel de control de PTC que muestre la cadena afectada con su traducción.
  • La configuración del idioma del sitio desde Ajustes > Generales.

La mayoría de los casos de “traducción faltante” se reducen a una de las causas anteriores. Los casos extremos (versiones específicas de WordPress, resolución de locale en MultiSite, conflicto con otro plugin de i18n) a veces necesitan una segunda revisión.

Mantenga las futuras versiones sincronizadas con la traducción continua

Una vez que sus traducciones se carguen correctamente, configure el flujo de trabajo de traducción continua para que las futuras versiones se mantengan sincronizadas con sus traducciones, de forma automática, en cada push a main.