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)
- Extrae cadenas marcadas con las funciones de internacionalización. Herramientas comunes:
- Poedit (interfaz gráfica)
- wp i18n make-pot (paquete @wordpress/i18n CLI)
- Genera el archivo .pot y compílalo en archivos .po (por idioma) y .mo (binario).
- 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
- 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 🙂 |