Como cargar textdomain en plugins y temas con PHP en WordPress

Contents

Introducción

Este artículo explica con todo detalle cómo cargar el textdomain en plugins y temas de WordPress usando PHP. Cubre conceptos clave, convenciones de nombres, funciones principales, ejemplos completos de código listos para usar, creación y ubicación de archivos de traducción (.pot, .po, .mo), buenas prácticas y errores comunes. Los ejemplos de código están listados en bloques preparados para resaltado sintáctico.

Conceptos clave

  • Textdomain: Identificador único que asocia las cadenas traducibles de un plugin o tema con sus archivos de traducción (.mo/.po). Normalmente coincide con el slug del plugin o tema.
  • Locales y .mo/.po/.pot: El .pot es la plantilla, .po contiene las traducciones editables y .mo es la versión compilada que carga WordPress.
  • WP_LANG_DIR: Carpeta global de traducciones de WordPress (normalmente wp-content/languages). WordPress puede cargar traducciones desde allí antes que desde el propio plugin/tema.
  • Funciones de localización: __(), _e(), _n(), _x(), esc_html__(), esc_attr__(), etc. Son las funciones que marcan cadenas para traducción y recuperan las traducciones en tiempo de ejecución.

Convenciones y cabeceras (headers)

Para que WordPress o herramientas de traducción detecten correctamente el textdomain de un plugin, incluye cabeceras en el archivo principal del plugin. Ejemplo de cabecera mínima:


Text Domain debe coincidir con el nombre del archivo .pot/.po/.mo (sin sufijos de idioma). Domain Path es la ruta relativa dentro del plugin donde estarán las traducciones, por ejemplo /languages.

Funciones principales para cargar textdomain

  • load_plugin_textdomain( domain, deprecated, plugin_rel_path ) — carga traducciones desde el directorio del plugin. plugin_rel_path suele ser dirname( plugin_basename( __FILE__ ) ) . /languages.
  • load_theme_textdomain( domain, path ) — carga traducciones para temas. path habitualmente es get_template_directory() . /languages o get_stylesheet_directory() para child themes.
  • load_textdomain( domain, mofile ) — carga directamente un archivo .mo específico se usa para cargar ficheros en ubicaciones personalizadas (por ejemplo en WP_LANG_DIR).
  • is_textdomain_loaded( domain ) — función interna útil para comprobaciones (no tan usada por desarrolladores).

Cargar textdomain en plugins: patrón recomendado

La estrategia recomendada es intentar primero cargar un archivo .mo desde WP_LANG_DIR (carpeta global), y si no existe, cargar desde la carpeta languages del plugin. Esto permite que WordPress centralice traducciones (por ejemplo las del repositorio de WordPress) y mantiene copias locales dentro del plugin como respaldo.

Ejemplo: carga segura de traducciones en un plugin

= 5.0
    mofile_global = WP_LANG_DIR . /plugins/ . domain . - . locale . .mo

    if ( file_exists( mofile_global ) ) {
        load_textdomain( domain, mofile_global )
        return
    }

    // 2) Cargar traducciones desde la carpeta /languages/ del plugin
    load_plugin_textdomain(
        domain,
        false,
        dirname( plugin_basename( __FILE__ ) ) . /languages/
    )
}
add_action( init, mpe_load_textdomain )

Explicación rápida: determine_locale() obtiene el locale activo WP carga primero las traducciones globales si existen. Si no, load_plugin_textdomain carga desde la carpeta del plugin.

Ejemplo práctico completo de un plugin mínimo

 . esc_html__( Hola, este texto es traducible., mi-plugin-ejemplo ) . 

} add_action( wp_footer, mpe_init_function )

Cargar textdomain en temas

En temas, la función típica es load_theme_textdomain y debe invocarse en el hook after_setup_theme para que el tema principal tenga sus traducciones listas antes de renderizar plantillas.


Si es un tema hijo y quieres cargar traducciones del child theme usa get_stylesheet_directory() en lugar de get_template_directory().

Usar las funciones de internacionalización en el código

Estas son las funciones más usadas para marcar y obtener cadenas traducidas:

  • __() — devuelve la cadena traducida. Útil cuando necesitas la cadena en variables o concatenaciones.
  • _e() — imprime la cadena traducida (echo).
  • _n() — para plurales: acepta singular, plural y número.
  • _x() y _ex() — similar a __() y _e(), pero con contexto para distinguir homónimos.
  • esc_html__(), esc_attr__() — combinan traducción con escape apropiado.
// Ejemplos
saludo = __( Hola Mundo, mi-plugin-ejemplo )
_e( Texto que se imprime, mi-plugin-ejemplo )

printf(
    / translators: %s = nombre de usuario /
    esc_html__( Bienvenido %s, mi-plugin-ejemplo ),
    esc_html( username )
)

// Plurales
contador = 3
printf(
    _n( %s elemento, %s elementos, contador, mi-plugin-ejemplo ),
    number_format_i18n( contador )
)

Creación y ubicación de archivos de traducción (.pot/.po/.mo)

  1. Extrae cadenas marcadas con las funciones de internacionalización. Herramientas comunes:
    • Poedit (interfaz gráfica)
    • wp i18n make-pot (paquete @wordpress/i18n CLI)
  2. Genera el archivo .pot y compílalo en archivos .po (por idioma) y .mo (binario).
  3. Ubica los archivos:
    • Para distribuir con el plugin: /wp-content/plugins/mi-plugin/languages/mi-plugin-ejemplo-es_ES.mo
    • Para unifica en WordPress: wp-content/languages/plugins/mi-plugin-ejemplo-es_ES.mo
  4. Asegúrate de que los nombres de los archivos sigan la convención: {textdomain}-{locale}.mo (por ejemplo mi-plugin-ejemplo-es_ES.mo).

Compatibilidad con el sistema de traducciones de WordPress.org

Si tu plugin o tema está en el repositorio de WordPress.org, las traducciones se gestionan en translate.wordpress.org y WordPress las descarga automáticamente. Requisitos:

  • Tener el Text Domain definido correctamente en la cabecera.
  • Si quieres archivos locales como fallback, mantener /languages/ dentro del plugin/tema.
  • En muchos casos ya no es necesario llamar manualmente a load_plugin_textdomain para que WordPress.org cargue traducciones, pero mantener la llamada no causa problemas y es buena práctica para entornos offline o instalaciones sin traducciones centralizadas.

Buenas prácticas y errores comunes

  • Usa un único textdomain consistente: evita variantes con guiones/underscores diferentes. El textdomain debe coincidir con el slug del plugin o tema.
  • Establece Domain Path: añade Domain Path en la cabecera si las traducciones están en una carpeta distinta a /languages/.
  • Prioriza WP_LANG_DIR: permite que las traducciones centralizadas del sitio sobrescriban las locales del plugin si fuera necesario.
  • Carga antes de imprimir cadenas: asegura que load_plugin_textdomain o load_theme_textdomain se ejecuten antes de que se rendericen textos traducibles (por eso init/after_setup_theme son buenos hooks).
  • Escapa tras la traducción: usa esc_html__(), esc_attr__() o esc_html( __( ... ) ) según corresponda.
  • No traduzcas cadenas dinámicas mal construidas: evita concatenar fragmentos que dificulten la traducción usa printf() con comentarios para traductores.
  • Comprueba paths y permisos: si las traducciones no cargan, revisa las rutas y permisos de archivos .mo.
  • Idioma y locales: en instalaciones multisite o con filtros personalizados puede ser necesario usar determine_locale() para obtener el locale correcto.

Soluciones a problemas frecuentes

  • Si las traducciones no aparecen, comprueba que el Text Domain en la cabecera coincide exactamente con el usado en las funciones de traducción.
  • Verifica que el nombre del archivo .mo sea {textdomain}-{locale}.mo y esté en la ruta esperada (por ejemplo /languages/ o wp-content/languages/plugins/).
  • Activa WP_DEBUG y revisa errores de carga de archivos o rutas incorrectas.
  • Para pruebas locales, borra la caché de objetos y transients a veces WordPress cachea información de idiomas.

Recursos útiles

Conclusión

Seguir las prácticas descritas garantiza que las cadenas de tu plugin o tema se traduzcan correctamente y que las traducciones se carguen desde la ubicación más adecuada (WP_LANG_DIR o carpeta local). Usa load_textdomain para cargas puntuales desde ubicaciones personalizadas, load_plugin_textdomain para la carga típica de plugins y load_theme_textdomain en after_setup_theme para temas. Mantén el textdomain constante, genera archivos .pot/.po/.mo correctamente y emplea las funciones de internacionalización apropiadas para facilitar el trabajo de los traductores y la correcta visualización en diferentes idiomas.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *