Manual de WordPress: Internacionalizar un plugin
Dado que WordPress se usa a escala internacional es altamente recomendable internacionalizar nuestro plugin, es decir, prepararlo para que los textos se muestren en diferentes idiomas.
Recursos
- Ayuda de WordPress: i18n for WordPress Developers
- Ayuda del GNU: GNU gettext utilities
- Download código fuente del plugin "Hello World 2.0": helloworld-2.0.tar.gz
Previamente tendremos que establecer las locale editando wp-config.php:
define ('WPLANG', 'es_ES');
WordPress usa para i18n (internationalization, 18 letras entre la i y la n) la librería gettext (GNU internationalization utilities). Lo más práctico es hacer el plugin en inglés y prepararlo para su traducción utilizando las funciones __() y _e(), añadiendo como argumento el text domain, el identificador que permite a WordPress distinguir qué traducción utilizar de las disponibles. Lo más recomendable es utilizar como text domain el nombre del directorio del plugin, en nuestro caso helloworld. Marcaremos en nuestro código las cadenas traducibles de esta manera:
- función __(): en las cadenas, en vez de...
<?php echo "<h2>Blog Options</h2>"; ?>
... usaremos:
<?php echo "<h2>".__('Blog Options', 'helloworld')."</h2>"; ?>
- función _e(): si usamos echo, en vez de...
<?php echo "We deleted spams"; ?>
... usaremos:
<?php _e("We deleted spams", "helloworld"); ?>
Vamos a añadir soporte para idiomas en el plugin "Hello World 1.0"
obteniendo de esa manera la versión "Hello World 2.0".
A los dos archivos que formaban el plugin:
- helloworld.php
- readme.txt
ubicados en el directorio:
wp-content/plugins/helloworld/
añadiremos tres más:
- helloworld.pot
- helloworld-es_ES.po
- helloworld-es_ES.mo
ubicados en este caso en el directorio:
wp-content/plugins/helloworld/lang/
Comenzaremos editando el archivo helloworld.php de "Hello World 1.0" y marcando con __() o _e() las cadenas traducibles...
<?php // registrar la funcion que se ejecuta al activar el plugin register_activation_hook(__FILE__, 'helloworld_activate'); // funcion que se ejecuta al activar el plugin function helloworld_activate() { // crear la tabla del plugin e insertar dos registros global $wpdb; $table_name= $wpdb->prefix."helloworld"; $sql = "CREATE TABLE $table_name ( `id` mediumint( 9 ) NOT NULL auto_increment, `type` tinytext NOT NULL, `saludo` tinytext NOT NULL, PRIMARY KEY (`id`) )"; $wpdb->query($sql); $sql = "INSERT INTO $table_name (`id`, `type`, `saludo`) VALUES (1, 'default', 'Hello World')"; $wpdb->query($sql); $sql = "INSERT INTO $table_name (`id`, `type`, `saludo`) VALUES (2, 'custom', 'Hola Mundo')"; $wpdb->query($sql); // añadir la option del plugin add_option('helloworld_saludo_type', 'default'); } // registrar la funcion que se ejecuta al desactivar el plugin register_deactivation_hook(__FILE__, 'helloworld_deactivate'); // funcion que se ejecuta al desactivar el plugin function helloworld_deactivate() { // borrar la tabla del plugin global $wpdb; $table_name = $wpdb->prefix."helloworld"; $sql = "DROP TABLE $table_name"; $wpdb->query($sql); // borrar la option del plugin delete_option('helloworld_saludo_type'); } // crear un item en el panel de administracion add_action('admin_menu', 'helloworld_menu'); // crear la pagina de opciones del plugin function helloworld_menu() { add_options_page('Hello World plugin options', 'Hello World', 8, basename(__FILE__), 'helloworld_options'); } // funcion que muestra la pagina de opciones del plugin function helloworld_options() { // comprobar si la peticion procede del form global $wpdb; $table_name = $wpdb->prefix."helloworld"; if (isset($_POST['saludo_custom_new']) && !empty($_POST['saludo_custom_new'])) { $sql = "UPDATE $table_name SET saludo ='{$_POST['saludo_custom_new']}' WHERE type='custom'"; $wpdb->query($sql); } if (isset($_POST['saludo_type'])) { update_option('helloworld_saludo_type', $_POST['saludo_type']); } // mostrar la pagina de opciones $saludo_default = $wpdb->get_var("SELECT saludo FROM $table_name WHERE type='default'" ); $saludo_custom = $wpdb->get_var("SELECT saludo FROM $table_name WHERE type='custom'" ); $saludo_type = get_option('helloworld_saludo_type'); if ($saludo_type == "default") { $checked_default = "checked"; $checked_custom = ""; } else { $checked_default = ""; $checked_custom = "checked"; } echo "<div class='wrap'>\n"; echo "<h2>Hello World plugin options</h2>\n"; echo "<form method='post' action=''>\n"; echo "Display:<br />\n"; echo "<input type='radio' name='saludo_type' value='default' ".$checked_default." /> Message default (<b>".$saludo_default."</b>)<br />\n"; echo "<input type='radio' name='saludo_type' value='custom' ".$checked_custom." /> Message custom (<b>".$saludo_custom."</b>)<br />\n"; echo "New Message custom: <input type='text' name='saludo_custom_new' /><br />\n"; echo "<input type='submit' name='update' value='Update' />\n"; echo "</form>\n"; echo "</div>\n"; } // funcion del plugin para usar en PHP, devuelve un string function helloworld() { // recuperar el saludo global $wpdb; $table_name = $wpdb->prefix."helloworld"; $saludo_type = get_option('helloworld_saludo_type'); $saludo = $wpdb->get_var("SELECT saludo FROM $table_name WHERE type='$saludo_type'" ); // output del plugin return "<p>".$saludo."</p>\n"; } // registrar la funcion que se ejecuta al llamar al shortcode add_shortcode('helloworld', 'helloworld_shortcode'); // shortcode del plugin para usar en los post function helloworld_shortcode($atts) { // el valor devuelto por return se inserta en el post en lugar // del shortcode. No se debe usar echo sino return return helloworld(); } ?>
... obteniendo:
<?php // registrar la funcion que se ejecuta al activar el plugin register_activation_hook(__FILE__, 'helloworld_activate'); // funcion que se ejecuta al activar el plugin function helloworld_activate() { // crear la tabla del plugin e insertar dos registros global $wpdb; $table_name= $wpdb->prefix."helloworld"; $sql = "CREATE TABLE $table_name ( `id` mediumint( 9 ) NOT NULL auto_increment, `type` tinytext NOT NULL, `saludo` tinytext NOT NULL, PRIMARY KEY (`id`) )"; $wpdb->query($sql); $sql = "INSERT INTO $table_name (`id`, `type`, `saludo`) VALUES (1, 'default', 'Hello World')"; $wpdb->query($sql); $sql = "INSERT INTO $table_name (`id`, `type`, `saludo`) VALUES (2, 'custom', 'Hola Mundo')"; $wpdb->query($sql); // añadir la option del plugin add_option('helloworld_saludo_type', 'default'); } // registrar la funcion que se ejecuta al desactivar el plugin register_deactivation_hook(__FILE__, 'helloworld_deactivate'); // funcion que se ejecuta al desactivar el plugin function helloworld_deactivate() { // borrar la tabla del plugin global $wpdb; $table_name = $wpdb->prefix."helloworld"; $sql = "DROP TABLE $table_name"; $wpdb->query($sql); // borrar la option del plugin delete_option('helloworld_saludo_type'); } // crear un item en el panel de administracion add_action('admin_menu', 'helloworld_menu'); // crear la pagina de opciones del plugin function helloworld_menu() { add_options_page(__('Hello World plugin options', 'helloworld'), 'Hello World', 8, basename(__FILE__), 'helloworld_options'); } // funcion que muestra la pagina de opciones del plugin function helloworld_options() { // comprobar si la peticion procede del form global $wpdb; $table_name = $wpdb->prefix."helloworld"; if (isset($_POST['saludo_custom_new']) && !empty($_POST['saludo_custom_new'])) { $sql = "UPDATE $table_name SET saludo ='{$_POST['saludo_custom_new']}' WHERE type='custom'"; $wpdb->query($sql); } if (isset($_POST['saludo_type'])) { update_option('helloworld_saludo_type', $_POST['saludo_type']); } // mostrar la pagina de opciones $saludo_default = $wpdb->get_var("SELECT saludo FROM $table_name WHERE type='default'" ); $saludo_custom = $wpdb->get_var("SELECT saludo FROM $table_name WHERE type='custom'" ); $saludo_type = get_option('helloworld_saludo_type'); if ($saludo_type == "default") { $checked_default = "checked"; $checked_custom = ""; } else { $checked_default = ""; $checked_custom = "checked"; } echo "<div class='wrap'>\n"; echo "<h2>".__('Hello World plugin options', 'helloworld')."</h2>\n"; echo "<form method='post' action=''>\n"; echo __('Display', 'helloworld').":<br />\n"; echo "<input type='radio' name='saludo_type' value='default' ".$checked_default." /> ".__('Message default', 'helloworld')." (<b>".$saludo_default."</b>)<br />\n"; echo "<input type='radio' name='saludo_type' value='custom' ".$checked_custom." /> ".__('Message custom', 'helloworld')." (<b>".$saludo_custom."</b>)<br />\n"; echo __('New', 'helloworld')." ".__('Message custom', 'helloworld').": <input type='text' name='saludo_custom_new' /><br />\n"; echo "<input type='submit' name='update' value='".__('Update', 'helloworld')."' />\n"; echo "</form>\n"; echo "</div>\n"; } // funcion del plugin para usar en PHP, devuelve un string function helloworld() { // recuperar el saludo global $wpdb; $table_name = $wpdb->prefix."helloworld"; $saludo_type = get_option('helloworld_saludo_type'); $saludo = $wpdb->get_var("SELECT saludo FROM $table_name WHERE type='$saludo_type'" ); // output del plugin return "<p>".$saludo."</p>\n"; } // registrar la funcion que se ejecuta al llamar al shortcode add_shortcode('helloworld', 'helloworld_shortcode'); // shortcode del plugin para usar en los post function helloworld_shortcode($atts) { // el valor devuelto por return se inserta en el post en lugar // del shortcode. No se debe usar echo sino return return helloworld(); } ?>
Además, añadiremos en helloworld.php una sección en la que se carga el idioma i18n:
- Cargar el idioma i18n
<?php // ejecutar una funcion una vez que WordPress ha cargado add_action('init', 'helloworld_textdomain'); // funcion para cargar el idioma i18n function helloworld_textdomain() { $dir = basename(dirname(__FILE__))."/lang"; load_plugin_textdomain( 'helloworld', 'wp-content/plugins/'.$dir, $dir); } ?>
Una vez que hayamos marcado en nuestro código fuente con __() o _e() las cadenas traducibles utilizaremos el comando xgettext (una herramienta de la librería gettext) para extraer las cadenas originales y generar el archivo POT (PO Template, extensión .pot), la plantilla de traducción. Para generar el archivo POT (helloworld.pot) haremos:
$ xgettext --keyword=__ --keyword=_e --language=PHP --from-code=UTF-8 --output=helloworld.pot helloworld.php
El contenido de helloworld.pot será:
msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-09-01 20:05+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <email@ADDRESS>\n" "Language-Team: LANGUAGE <[email protected]>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: helloworld.php:74 helloworld.php:101 msgid "Hello World plugin options" msgstr "" #: helloworld.php:103 msgid "Display" msgstr "" #: helloworld.php:104 msgid "Message default" msgstr "" #: helloworld.php:105 helloworld.php:106 msgid "Message custom" msgstr "" #: helloworld.php:106 msgid "New" msgstr "" #: helloworld.php:107 msgid "Update" msgstr ""
El charset lo tenemos que establecer manualmente. Para ello reemplazaremos la línea...
"Content-Type: text/plain; charset=CHARSET\n"
... por:
"Content-Type: text/plain; charset=UTF-8\n"
Cada traductor se encargará de editar la plantilla POT (helloworld.pot) y traducir las secciones msgstr a su idioma, obteniendo el archivo PO (Portable Object, extensión .po), en este caso traducido al español (helloworld-es_ES.po):
msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-31 07:02+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <email@ADDRESS>\n" "Language-Team: LANGUAGE <[email protected]>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: helloworld.php:74 helloworld.php:101 msgid "Hello World plugin options" msgstr "Opciones del plugin Hello World" #: helloworld.php:103 msgid "Display" msgstr "Mostrar" #: helloworld.php:104 msgid "Message default" msgstr "Saludo por defecto" #: helloworld.php:105 helloworld.php:106 msgid "Message custom" msgstr "Saludo personalizado" #: helloworld.php:106 msgid "New" msgstr "Nuevo" #: helloworld.php:107 msgid "Update" msgstr "Guardar"
Una vez que disponemos del archivo PO tenemos que generar el archivo MO (Machine Object, extensión .mo), la traducción en formato binario, un formato más adecuado para una rápida extracción de las cadenas traducidas. Para generar el archivo MO (helloworld-es_ES.mo) haremos:
$ msgfmt helloworld-es_ES.po -o helloworld-es_ES.mo
Para cargar la traducción incluiremos en nuestro código lo siguiente:
<?php $dir = basename(dirname(__FILE__))."/lang"; load_plugin_textdomain( 'helloworld', 'wp-content/plugins/'.$dir, $dir); ?>
Ésta será la página de opciones del plugin en inglés (en_US)...
... y ésta traducida al español (es_ES):
Deja un comentario