Publi

Creando un plugin epara WordPress: localizar el plugin e insertar traducciones (cuarta parte)

simterm
Estoy haciendo un pequeño tutorial de cómo me lo he montado para crear un plugin de WordPress: simterm. Podéis echar un vistazo al plugin desde la página anterior, y probarlo si queréis 🙂

Esta es la cuarta parte, enfocada a la localización de plugins. Podéis acceder desde aquí a:

  • Primera parte. Introducción y conceptos básicos de plugins de WordPress y algunas manías personales.
  • Segunda parte. Enfocada a la pantalla de configuración de nuestro plugin.
  • Tercera parte. Enfocada a la inclusión de recursos CSS y JS y a los shortcodes.

El proceso de localización (l10n) de WordPress está basado en los principios de gettext. Si quieres, puedes ver otros posts de traducciones con gettext aquí: Traducciones Gettext para nuestros proyectos en PHP y 5 consejos para internacionalizar nuestros programas con gettext en PHP). De todas formas, WordPress tiene sus propias herramientas, parecidas, pero propias.

El proceso de localización de un plugin

La localización se basa en archivos .po y .mo que podemos editar con poedit (ver los posts enlazados un poco más arriba). En estos ficheros habrá una asociación entre el mensaje en un idioma neutral (yo suelo utilizarlo en inglés) y los mismos mensajes en un idioma de destino. Esto nos facilitará la vida a la hora de crear el código, puesto que sólo tenemos que escribir en un idioma, olvidándonos de establecer convenciones, ni crear variables específicas ni nada, sólo añadiendo una función. Lo más importante que tenemos que tener en cuenta es el dominio de las traducciones. Este dominio será algo así como nuestro módulo (plugin, tema, parte en la que utilizamos la traducción), y luego el idioma, en mi caso es_ES (que será español-España, como también tendremos es_MX (para español Mexico), es_AR (español Argentina), etc.

Para ordenar un poco nuestros archivos, dentro del directorio o carpeta del plugin crearemos otro directorio llamado langs/ (o languages/, l10n/, etc), el objetivo de esto es separar los archivos de nuestro plugin de las traducciones. Los archivos de las traducciones, si por ejemplo nuestro dominio (que podemos darle el mismo nombre que al plugin), se llama myplugin, los archivos de traducción se llamarían:

Para español España
langs/myplugin-es_ES.po
langs/myplugin-es_ES.mo
Para francés de Francia
langs/myplugin-fr_FR.po
langs/myplugin-fr_FR.mo
Para chino de Singapur
langs/myplugin-zh_SG.po
langs/myplugin-zh_SG.mo

Algo muy bueno que tiene este sistema es que si alguien quiere traducir el plugin, no tiene por qué saber PHP, ni tiene que pelearse con los archivos del plugin. Sólo tiene que generar los archivos .po y .mo

Lo que tenemos que hacer en el código

En nuestro plugin, tenemos que decir de alguna forma que es traducible, y decirle el dominio de traducciones del que hemos hablado antes. Además, en WordPress hay que decírselo dos veces (tiene su lógica).

La primera vez que hay que hablarle a WordPress sobre traducciones es para que cuando un plugin no esté instalado, sepa de dónde sacar sus mensajes. Sobre todo para la descripción del plugin, para que ésta pueda escribirse en el idioma que debe, que esto queda muy bien. Para ello tenemos que escribir esto en el archivo principal de nuestro plugin (donde están las cabeceras), fijémonos sólo en Text Domain y Domain Path:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
/**
 * Plugin Name: SimTerm
 * Plugin URI:  http://gaspar.totaki.com/en/php-project/simterm/
 * Description: Simulates terminal input/output for tutorials
 * Version: 0.1.0
 * Author: Gaspar Fernández
 * Author URI: https://poesiabinaria.net/
 * License: GPL3
 * Text Domain: simterm
 * Domain Path: /languages/
 */

Text Domain especifica el dominio, y se llama casi igual que el plugin, pero todo en minúsculas. Podría tener el nombre que quisiéramos, pero debe ser único para todo WordPress si no queremos que éste se confunda buscando las traducciones.
Domain Path especifica el directorio dentro del plugin donde están los archivos de traducciones.

La segunda vez que le hablamos a WordPress sobre traducciones, debe ser nada más cargado el plugin, escribiendo algo como esto:

1
2
<?php
  load_plugin_textdomain( 'simterm', false, dirname( plugin_basename( __FILE__ ) ).'/languages/' );

Con esta línea hacemos que se cargue el dominio de traducciones, en la ruta especificada para nuestro plugin, cuando éste ya está cargado. Es decir, esto es lo más importante.

Aunque el dominio puede que no siempre nos interese cargarlo. Si nuestro plugin, sólo es accesible desde administración (o los mensajes traducibles los escribe en la zona de administración podemos cargarlo de la siguiente forma:

1
2
3
4
5
6
7
<?php
add_action( 'admin_init', 'load_textdomain' );

function load_textdomain()
{
  load_plugin_textdomain( 'simterm', FALSE, dirname( plugin_basename( __FILE__ ) ).'/languages/' );
}

Por lo que sólo se cargará cuando se inicialice la zona de administración. Si, por ejemplo en add_action() sólo ponemos ‘init’, se cargará siempre.

Cuando quiero que un texto se traduzca…

Tenemos que escribir algo más que el propio texto. WordPress utiliza entre otros, la función __() que tiene dos argumentos. El primero es el texto a traducir, y el segundo el dominio. Por lo que cada cosa que queramos traducir quedaría:

1
2
<?php
echo __('Plugin options', 'simterm');

Y se representará en el idioma del WordPress en que se ejecute (si dicho idioma está disponible en nuestro plugin), o en el idioma original (si el idioma no se encuentra).

Encontramos varias funciones de WordPress para representar traducciones, además de __() que presenta una traducción simple, es decir, un texto en un idioma original por un texto traducido. Tenemos:

  • _e($texto, $dominio) : que es lo mismo que echo __($texto, $dominio);
  • _n($singular, $plural, $numero, $dominio) : presentará una traducción en función de $numero ya sea 1 o superior, para especificar plurales.
  • _x($texto, $contexto, $dominio) : Selecciona la mejor traducción en función del contexto, porque una misma palabra puede significar varias cosas y eso hace las traducciones muy duras.
  • Hay muchoss más, incluso existen esc_html__(), esc_html_x() para devolver cadenas escapadas, y mucho más.

Cuando queremos traducir un texto con variables dentro…

Un texto con variables puede ser. “Tu IP real es: xxx.xxx.xxx.xxx” por lo que, dentro del mensaje traducido debemos escribir algo que de paso a la variable. Esto lo podemos hacer con sprintf() de la siguiente forma:

1
2
<?php
echo sprintf(__('Tu IP real es %s', 'dominio'), $ip);

El problema aquí viene cuando hay varias variables. Como “Tu IP real es xxx.xxx.xxx.xxx y conectas desde: España”, en algunos idiomas puede tener más sentido decir: “Conectas desde España con esta IP: xxx.xxx.xxx.xxx” y con el uso habitual de sprintf podemos tener un problema, ya que depende de la posición donde se encuentre la variable. Aunque podríamos hacer lo siguiente:

1
2
<?php
echo sprintf(__('Tu IP real es %s$2 y conectas desde: %s$1', 'dominio'), $pais, $ip);

Es recomendable, si utilizamos programas que automáticamente recorran los textos traducibles (como poedit) hacer una llamada a __($texto, $dominio) siendo $texto la descripción de nuestro plugin, tal y como aparece en el comentario principal. Así el programa nos detectará la traducción.

Una pequeña advertencia

Si en tu plugin, vas a poner URLs, como URL de donación, de la página de tu plugin, tu e-mail (no es recomendable, pero quién sabe), nombre de la licencia, tu nombre, etc. Utiliza variables para ello y no las incluyas en la traducción. Puede que un traductor a un idioma extraño del que no tengas ni idea cambie algún dato.

Hasta aquí una breve introducción…

Si queréis más documentación, podéis visitar la página de internacionalización de WordPress.

También podría interesarte....

Leave a Reply