
Tercera parte de la serie en la que tratamos los elementos esenciales a incluir en un plugin profesional. Aunque esté más enfocado en cómo traducir un plugin en WordPress esta información es totalmente válida para la traducción de un tema de WordPress. Vamos a empaparnos un poquito de conocimiento.
Gran parte del contenido de este artículo ha sido extraído y traducido de un lugar u otro de la documentación de WordPress, pero no todo. Y bueno, por qué no decirlo, yo mismo he aprendido un montón preparando este artículo.
Si te interesan los otros artículos de la serie «los elementos esenciales que debe tener un plugin»:
Elementos esenciales para crear un plugin en WordPress
Elementos esenciales para tu plugin II (Seguridad)
Índice de Contenido
Internacionalización
La internacionalización de un tema o plugin es el proceso en el que se facilitan los medios para que se pueda traducir a otro idioma de un modo sencillo. A este proceso también se le suele llamar i18n para poder abreviar tan largo nombre.
Localización
Debemos tener claro que internacionalización no es lo mismo que localización, ya que esta última es la adaptación del tema o plugin (en este caso) a las necesidades lingüísticas de un mercado concreto. Podemos leer este artículo de w3.org en el que se habla sobre las diferencias de ambos términos.
La localización suele abreviarse como l10n.
GNU gettext
Para la traducción de plugins en WordPress se utiliza un grupo de herramientas de internacionalización libres llamado GNU gettext, al igual que para la traducción de temas, claro. Este sistema permite, entre otras cosas, que el ajuste del idioma sea transparente para el usuario, además de que es uno de los estándares más usados.
El framework gettext usa un nivel de traducción por mensaje. Esto quiere decir que cada mensaje (o cadena) está traducido individualmente.
Diferencias entre .po, .pot y .mo, los archivos de localización

El archivo .POT
El archivo, que podríamos decir llamar el esencial para la traducción de todo tema y/o plugin, es el que tiene la extensión .pot. Este archivo contiene un listado de las cadenas de texto utilizadas. Normalmente este es el archivo que debemos enviar a los traductores.
Este archivo suele encontrarse en el directorio de idiomas del tema o plugin. Es decir, una estructura muy usada sería: wp-content/plugins/mi-plugin/languages/mi-plugin.pot. Pero debemos tener en cuenta que muchos plugins, a día de hoy, no usan esta estructura, si no que usan la translation_api, como se explica en el apartado dedicado a la traducción del repositorio, más abajo en este artículo.
Archivo .po o Portable Object
Estos archivos contienen las cadenas de texto originales así como las de la traducción concreta de ese archivo. Este es el archivo que suele recibirse de los traductores.
Si abrimos este archivo con un editor de texto como Visual Studio Code podremos encontrar información acerca de la traducción en el header del mismo, como:
- La última revisión
- La versión MIME
- El idioma
- Si es la última versión estable
- Quién ha sido el traductor o el último traductor
Archivo .mo o Machine Object
El archivo .mo cuenta con el mismo contenido que el de la extensión .po, solo que está en un formato adaptado a la lectura de la máquina. Es decir, son archivos binarios que utilizan las funciones de gettext, una versión compilada de los archivos .po. Esta conversión se realiza mediante la herramienta msgfmt, podemos visitar este enlace si queremos saber más sobre el tema.
Si queremos ver ejemplos de los archivos .po podemos acceder al repositorio de traducciones de WordPress y desde ahí podremos ver todos los detalles de cada traducción, como los autores las fechas, las versiones estables. Al entrar en una traducción, y cuando veamos las dos columnas (original y traducción), abajo a la derecha podremos seleccionar el formato (entre los que encontramos .po y .mo) y hacer clic en exportar para poder descargar el archivo.
Configurando nuestro plugin o tema para que sea compatible con las traducciones
Antes de ponernos a traducir cualquier plugin en WordPress, deberíamos ser conscientes de que cada cadena de texto debe estar configurada de un modo concreto para que, posteriormente, se puedan identificar automáticamente.

El Text Domain
Ya sea que queramos internacionalizar (qué complicadito el nombre) un plugin o tema, deberemos tener muy en cuenta el text-domain. Esto es un pequeño texto que se incluye en el archivo principal del plugin en el style.css del tema.
Es muy importante que no usemos variables cuando queramos representar nuestro Text Domain.
El Domain Path
En el caso de los plugins (O sea, que esto no se usaría en un tema) también es necesario especificar el Domain Path, y al igual que el Text Domain, es un texto que se añadiría en el header del archivo principal de nuestro plugin. Este texto especifica el lugar donde se encuentran las traducciones.
Las cadenas básicas o ‘Basic strings’
Las cadenas básicas devuelven la traducción del argumento y no contienen placeholders o plurales (se explica más adelante). Se presentan del siguiente modo:
__( 'Texto en idioma original', 'text-domain' );
Si lo que queremos es hacer un echo de esta cadena en nuestro código podríamos hacerlo tan fácil que así:
_e( 'Texto en idioma original', 'text-domain' );

Variables
Si queremos representar un texto de forma variable no podremos usar las cadenas básicas. Por ejemplo, si queremos hacer algo así:
echo 'Tu ciudad es $city.'
La solución la encontramos en el uso de placeholders en conjunto con la función printf. Este sería el modo correcto de su uso:
printf(
/* translators: %s: Nombre de la ciudad */
__( 'Tu ciudad es %s.', 'text-domain' ),
$city
);
Como podemos ver hay un pequeño comentario que facilita el trabajo a los traductores.
Si se tiene más de un placeholder se recomienda el formateo del mismo mediante sprintf. Su correcto uso sería:
sprintf(
/* translators: 1: Nombre de la ciudad 2: código ZIP */
__( 'Tu ciudad es %1$s, y tu código ZIP %2$s.', 'text-domain' ),
$city,
$zipcode
);
Plurales
Si contamos con un texto que varía dependiendo de otros valores variables y que sea singular o plural depende del caso, entonces deberíamos usar la función _n(). Esta función acepta 4 argumentos:
- La forma singular de la cadena de texto
- La forma plural de la misma
- El número de objetos que determinarán si es plural o singular
- Y nuestro famoso text-domain
Un buen ejemplo es el que se presenta en la documentación. El titular del campo de comentarios variaría dependiendo de la cantidad de comentarios que existan. Entonces podríamos hacer lo siguiente:
printf(
_n(
'%s comentario',
'%s comentarios',
get_comments_number(),
'text-domain'
),
number_format_i18n( get_comments_number() )
);
Traducción dependiendo del contexto
Hay veces en las que un mismo término puede usarse o no dependiendo del contexto. Es entonces cuando deberíamos usar las funciones _x()
y _ex()
. La última se usaría si queremos hacer un echo. A diferencia de __()
y _e()
se incluye un segundo argumento, el contexto. Os presento el ejemplo que se presenta en la documentación en inglés, que coloca como contexto si es nombre o verbo:
_ex( 'Post', 'noun', 'my-plugin' );
_ex( 'Post', 'verb', 'my-plugin' );
Creando los archivos de traducción para WordPress
Para comenzar deberíamos empezar por el archivo .pot, que como hemos explicado anteriormente, es el que entregaremos a los/as traductores/as. Pero antes de este paso es muy importante configurar nuestro plugin o tema como hemos explicado más arriba. Para crear los archivos encontramos los siguientes métodos:
Mediante WP-CLI
WP-CLI es la interfaz de línea de comandos para WordPress. Si la tenemos instalada podremos crear un archivo .pot con un simple comando:
$ wp i18n make-pot . languages/miplugin.pot
Aquí podemos leer más sobre el tema.
Grunt
Grunt es un programa en JavaScript para correr tareas que se puede instalar vía NPM. Cuenta con un paquete para localización en WordPress llamado grunt-wp-i18n que escaneará tu plugin o tema encontrando las cadenas y compilando un archivo .pot.

Poedit
Poedit es un editor de listas de texto Gettext que podemos instalar en nuestro dispositivo Windows, Linux o Mac. Es libre, sorprendentemente intuitivo y la versión gratuita puede cumplir con nuestras necesidades.
Aunque nunca he probado este método para la creación de archivos .pot, en la documentación de WordPress se asegura que es posible.
Plugin Loco translate
Para crear el archivo .pot a través de este plugin tan solo tendremos que instalarlo desde el repositorio de WordPress, como cualquier otro plugin, y activarlo. Luego podremos acceder al plugin haciendo clic en el menú derecho del panel de control, lo solemos encontrar casi al final del todo.
Para crear el archivo .pot tendremos que seleccionar la sección plugins o temas (dependiendo de lo que queramos traducir), seleccionar el elemento concreto y hacer clic en crear plantilla. Voilá, ya tenemos nuestro archivo .pot creado automáticamente.
Traduciendo el tema o plugin de WordPress
Para traducir un tema o un plugin de WordPress necesitamos tener el archivo .po. Y encontramos varias opciones:
Traducción manual
Oye, todo hay que decirlo, y hay a quien le gusta la interfaz de su editor de texto. Quizá es un poco más laborioso pero funciona al 100%. Así que sí, puedes abrir tu archivo .po y editarlo manualmente con tu editor de texto. Cada cadena de texto a traducir quedaría algo que así:
#: direccion/hasta/mi/archivo/miplugin.php:256
msgid "El loco de la colina"
msgstr "The hill’s fool"
Como podemos ver, primero se presenta la localización del archivo, así como la línea donde se encuentra la cadena. Y se continúa con la cadena en el idioma original y la traducción.
La aplicación Poedit
Una vez que contamos con el archivo .pot podremos acceder a Poedit y seguir los siguientes pasos:
- Clic en Archivo
- Clic en “Nueva desde archivo POT/PO…”
- Seleccionamos el archivo .pot que queremos traducir y convertir a .po
- Seleccionamos el idioma al que queremos traducirlo
- Y voilá, tenemos una interfaz en la que encontraremos las cadenas a traducir, el texto en el idioma original y el campo donde podremos incluir la cadena traducida

El plugin Loco translate
Sí, con el plugin Loco Translate también podemos traducir nuestro plugin o tema de WordPress:
- Una vez hayamos creado el archivo .pot como hemos explicado más arriba accedemos a la plantilla que hemos creado
- Encontraremos entonces una interfaz muy similar a la de Poedit
Traducción desde el repositorio de WordPress
Si nuestro plugin está en el repositorio de WordPress podremos publicar los archivos de las traducciones en el repositorio para no tener que cargarlos en el mismo plugin. Esto supondría un plugin más ligero en cuanto a archivos, pero también tendríamos que tener en cuenta la llamada a un servidor externo, cada uno debe valorar lo que mejor le convenga.
A día de hoy es muy probable que las traducciones se obtengan mediante la función translations_api(), la cual hace una llamada a wordpress.org para obtener los archivos necesarios para la traducción.
WordPress Translations API
Un buen ejemplo para ilustrar lo mencionado anteriormente es Contact Form 7, que anteriormente incluía los archivos de localización bajo la carpeta contact-form-7/languages, pero si accedemos ahora encontraremos un readme.txt en el que se especifica que las traducciones han sido movidas a la página concreta de wordpress.org. Y si vamos un poco más allá encontraremos bajo contact-form-7/includes/l10n.php la llamada a la API del siguiente modo:
$api = translations_api( 'plugins', array(
'slug' => 'contact-form-7',
'version' => WPCF7_VERSION,
) );
Seguridad al traducir nuestro plugin o tema en WordPress
Es muy importante que escapemos las cadenas que se vayan a mostrar en el front. De hecho ya contamos con funcionalidades que automáticamente lo hacen. Entonces deberíamos:
- Usar
esc_html_()
en lugar de_e()
- Usar
printf(exc_html__())
en lugar de_e()
cuando sea conveniente
Archivos .mo
Si contamos con un equipo de traducción y nos entrega el archivo .mo, siempre es mejor que nos entregue el .po y que lo compilemos nosotros para evitar posibles errores o incluso código malicioso.
Compilando nuestro archivo .po para nuestra traducción en WordPress
Es verdad que si estamos usando Poedit para las traducciones nos entregaría un archivo .mo compilado. El problema de usar este archivo es que se sobreescribiran los encabezados, por lo que siempre es mejor hacerlo a través de la línea de comandos:
msgfmt -cv -o /path/to/output.mo /path/to/input.po