viernes, 17 de mayo de 2013

CodeIgniter 2: Implementar mecanismo de idiomas para tus aplicaciones PHP

CodeIgniter 2 trae su propio sistema de regionalización de idiomas, pero francamente me parece poco práctico, pues se basa en crear arreglos asociativos con las diferentes cadenas de traducción, el problema de esta técnica es que se requiere consultar constantemente el archivo de configuración para ver el nombre de la llave del arreglo y poder obtener la cadena, en cambio, sugiero usar un sistema más parecido al que usa Magento, que traduce la cadena en función de la cadena misma, y utiliza un sencillo sistema de archivos separados por comas y en pares.

Así que los pasos para implementar un sistema de regionalización de idiomas son:

Paso 1.

Crear en la carpeta application/language/, los diferentes códigos de idiomas, en mi caso, utilzaré en_US/ y es_MX/

Paso 2.

Nuestra base siempre va a ser el inglés de estados unidos, así que vamos a crear en la carpeta en_US un archivo llamado core_general.csv

Paso 3.

Es importante señalar que uno puede organizar los archivos de idiomas según su ámbito, por ejemplo, podemos crear uno llamado core_exceptions.cvs, otro para core_database.csv, otro para sales.csv, otro para checkout.csv, otro crm.csv, etc.

Paso 4.

La técnica es usar los archivos separados por comas en pares: tal como se muestra el ejemplo, recordemos que la base es el idioma inglés de E.U., en este ejemplo te muestro los dos archivos, el que colocaremos en la carpeta en_US/ y el que colocaremos en la carpeta es_MX/, con esto ya se va comprendiendo más la lógica:

en_US/core_general.csv

"ERP","ERP"
"MRP","MRP"
"CRM","CRM"
"FRM","FRM"
"HRM","HRM"
"SCM","SCM"
"Enterprise Resource Planning","Enterprise Resource Planning"
"Material Resource Planning","Material Resource Planning"
"Customer Relationship Management","Customer Relationship Management"
"Financial Resource Management","Financial Resource Management"
"Human Resource Management","Human Resource Management"
"Supply Chain Management","Supply Chain Management"
"Inbox","Inbox"
"Personal","Personal"
"Important","Important"
"Pending","Pending"
"Archived","Archived"
"archived","archived"
"Schedule","Schedule"
"Calendar","Calendar"
"Notes","Notes"
"Groups","Groups"
"Messages","Messages"
"Create/Join Groups","Create/Join Groups"
"Go!","Go!"
"Search...","Search..."
"Edit Profile","Edit Profile"
"View Profile","View Profile"
"View All","View All"
"Logout","Logout"
"Login","Login"
"",""
"",""
"",""
"",""
"",""
"",""

es_MX/core_general.csv

"ERP","PRE"
"MRP","PRM"
"CRM","GAC"
"FRM","GRF"
"HRM","GRH"
"SCM","GCS"
"Enterprise Resource Planning","Planificación de recursos empresariales"
"Material Resource Planning","Planificación de recursos materiales"
"Customer Relationship Management","Gestión de atención al cliente"
"Financial Resource Management","Gestión de recursos financieros"
"Human Resource Management","Gestión de recursos humanos"
"Supply Chain Management","Gestión de la cadena de suministro"
"Inbox","Bandeja de entrada"
"Personal","Personal"
"Important","Importante"
"Pending","Pendiente"
"Archived","Archivados"
"archived","archivados"
"Schedule","Agenda"
"Calendar","Calendario"
"Notes","Notas"
"Groups","Grupos"
"Messages","Mensajes"
"Create/Join Groups","Crear/Unir grupos"
"Go!","Ir..."
"Search...","Buscar..."
"Edit Profile","Modificar perfil"
"View Profile","Ver perfil"
"View All","Ver todo"
"Logout","Desconectar"
"Login","Conectar"
"",""
"",""
"",""
"",""
"",""
"",""

Paso 5.

Ahora, vamos a crear un helper, llamado translate_helper.php y lo vamos a colocar en la carpeta application/helpers/

<?php

/**
 * Regresa una cadena con la traducción especificada.
 * Si se especifica $code, se regresa la cadena en ese idioma, 
 * si no se envía el parámetro opcional $code, entonces la 
 * cadena es regresada en el idioma especificado en el archivo 
 * config.php de CI.
 * 
 * @param string $texto La cadena a traducir
 * @param string $archivo El archivo de traducción, por default, el core_general.csv
 * @param string $codigo El código idioma_región, pe: es_MX
 * @return string
 */
function __($texto, $archivo = 'core_general', $codigo = NULL)
{
    $texto_str = (string) $texto;

    # validar si la cadena viene vacía
    if ('' == $texto_str) {
        return '';
    }

    # quitar espacios a la cadena
    $texto_ok = trim($texto);

    # inicializar locale por si no se encuentra la cadena a traducir
    $text_locale = $texto_ok;

    # validar código de idiomas
    if (!is_string($codigo)) {
        $codigo = config_item('locale_default');
    } else {
        $valid_code = array_search($codigo, config_item('locale_list'));

        # si el código locale no está en la lista de paquetes de idioma disponibles,
        # entonces, tomar el default.
        if (FALSE === $valid_code) {
            $codigo = config_item('locale_default');
        }
    }

    $archivo = PATH_RAIZ . URL_ROOT_FOLDER . APPPATH . DIR_LANG . $codigo . '/' . $archivo . '.csv';

    try {
        $handle = @fopen($archivo, 'rb');
    } catch (Exception $e) {
        return $text_locale;
    }
    
    if (FALSE !== $handle) {
        while (FALSE !== ($data = fgetcsv($handle, 1000, ','))) {
            if ($texto_ok == $data[0]) {
                $text_locale = $data[1];
                break;
            }
        }
        fclose($handle);
    }

    return $text_locale;
}

/*  EOF  */

Paso 6.

Ahora necesitamos crear unas constantes, así que editamos el archivo application/config/constants.php y declaramos las siguientes constantes:

define('PATH_RAIZ', $_SERVER['DOCUMENT_ROOT'] . '/');
define('URL_ROOT_FOLDER', ''); // si tu aplicación corre desde un(os) subdirectorio(s), ponerlo aquí por ejemplo: define('URL_ROOT_FOLDER', 'misubfolder/');
define('DIR_LANG', 'language/');

Paso 7.

Editamos el archivo application/config/autoload.php y agregamos el nuevo helper (translate) a la lista, en mi ejemplo se vería así:

$autoload['helper'] = array('url', 'form', 'directory', 'file', 'html', 'date', 'cookie', 'translate');

Paso 8.

En el mismo archivo autoload.php debemos colocar en una sección llamada "Auto-load config files", lo siguiente:

/*
| -------------------------------------------------------------------
|  Auto-load Config files
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['config'] = array('config1', 'config2');
|
| NOTE: This item is intended for use ONLY if you have created custom
| config files.  Otherwise, leave it blank.
|
*/

$autoload['config'] = array('locale');

Paso 9.

Ahora debemos crear el archivo de configuración locale.php en la carpeta application/config/ y colocamos el siguiente contenido:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

$config['locale_default'] = 'es_MX';

//$config['locale_list'] = array('en_US', 'en_GB', 'es_ES', 'es_AR', 'es_CL', 'es_MX', 'es_UY', 'es_VE', 'fr_FR', 'pt_BR');

# idiomas disponibles, en mi caso, solamente manejaré éstos dos:
$config['locale_list'] = array('en_US', 'es_MX');

/* EOF */

Paso 10.

Listo, ahora ya estamos preparados para usar nuestro archivo de traducciones en cualquier tipo de script: vista, controlador, modelo, helpers, librerías, etc., aquí un ejemplo para usarlo en una vista:

<ul>
    <li class="admin-username"><?php echo $username; ?></li>
    <li><a href="#"><?php echo __('Edit Profile'); ?></a></li>
    <li><a href="#"><?php echo __('View Profile'); ?></a><a href="#"><i class="icon-lock"></i><?php echo __('Logout'); ?

></a></li>
    <li class="active"><a href="#messages" class="icon-inbox" title="<?php echo __('Messages'); ?>"></a></li>
    <li><a href="#schedule" class="icon-calendar" title="<?php echo __('Schedule'); ?>"></a></li>
    <li><a href="#groups" class="icon-group" title="<?php echo __('Groups'); ?>"></a></li>
</ul>

11. Por último, las variantes para este helper, serían por ejemplo:

__('String to translate', 'sales'); // usar el archivo sales.csv
__('String to translate', 'sales', 'fr_FR'); // usar el archivo sales.csv y además forzar a usar el idioma francés de Francia.

Espero que le sea de utilidad.

No hay comentarios:

Publicar un comentario

Datos personales

Mi foto
Podrás encontrar códigos recursos y artículos sobre PHP, JavaScript, jQuery, MooTools, Ajax, CSS, HTML, UML, RUP, AUP, XP (eXtreme Programming), Six-Sigma, CMMI, FrameWorks, Zend Framework, Magento, CodeIgniter, CakePHP, Joomla 1.5, Doctrine, Active Record, ORM, POO, MVC, MySql, PostgreSql. Este espacio está destinado a ayudar y compartir un poco de lo mucho que he recibido de la comunidad en la Red.