lunes, 13 de junio de 2011

¿Manejo de varios lenguajes en una Página web utilizando CodeIgniter?

El framework CodeIgniter permite el uso de varias librerias que nos facilitan el trabajo, una de esas librerias son las de lenguaje(language); podemos utilizar librerias para poder manejar diferentes lenguajes desde la URL o URI, como prefieran llamar a la dirección web.

Con esta librería el lenguaje que se mostrará en la página se debe especificar en la URI, por ejemplo:
Aqui vamos a mostrar dichas librerias, para CodeIgniter 2.x
Si necesitas la versión para CodeIgniter 1.7.X visita la siguiente página.

 http://maestric.com/en/doc/php/codeigniter_i18n
Aqui también podrás encontrar mayor ayuda para el manejo de

1) Deben de ir a su archivo de configuración y ver el prefijo que tenemos, en im caso lo tengo como "Base", otro pueden tenerlo como "MY_".

      $config['subclass_prefix'] = 'Base';

2) En la carpeta application/Core/ creamos el archivo BaseConfig o MY_Config y copiamos el siguiente código.

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class BaseConfig extends CI_Config {
    function site_url($uri = '')
    {
        if (is_array($uri))
        {
            $uri = implode('/', $uri);
        }

        if (function_exists('get_instance'))
        {
            $CI =& get_instance();
            $uri = $CI->lang->localized($uri);
            $uri = substr($uri, 2);
        }

        return parent::site_url($uri);
    }

}
// END BaseConfig Class

/* End of file BaseConfig.php */
/* Location: ./system/application/Core/BaseConfig.php */


3) En la carpeta application/Core/ creamos el archivo BaseLang y copiamos el siguiente código.

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class BaseLang extends CI_Lang {
    /**************************************************
     configuration
    ***************************************************/
    // languages
    var $languages = array(
        'en' => 'english',
        'es' => 'spanish',
    );
    // Se especifiacn los controllers "especiales" que no necesitan el idioma en la URI
    var $special = array (
        ""
    );
    // Se coloca el controller al que se redireccionará si no se coloca lenguaje en la URI
    var $default_uri = '';
    /**************************************************/

    function BaseLang()
    {
        parent::__construct();
        global $CFG;
        global $URI;
        global $RTR;
        $segment = $URI->segment(1);
        if (isset($this->languages[$segment]))    // URI con lenguaje ok
        {
            $language = $this->languages[$segment];
            $CFG->set_item('language', $language);
        }
        else if($this->is_special($segment)) // URI especial -> no redirecciona
        {
            return;
        }
        else    // URI sin lenguaje -> redirecciona a la default_uri
        {
            // se pone el lenguaje por defecto
            $CFG->set_item('language', $this->languages[$this->default_lang()]);
            // redirecciona
            header("Location: " . $CFG->site_url($this->localized($this->default_uri)), TRUE, 302);
            exit;
        }
    }

    // retorna el lenguaje actual
    // ejemplo: retorna 'en' si el languaje en CI config es 'english'
    function lang()
    {
        global $CFG;
        $language = $CFG->item('language');
        $lang = array_search($language, $this->languages);
        if ($lang)
        {
            return $lang;
        }
        return NULL;    // esto no debe pasar
    }

    function is_special($uri)
    {
        $exploded = explode('/', $uri);
        if (in_array($exploded[0], $this->special))
        {
            return TRUE;
        }
        if(isset($this->languages[$uri]))
        {
            return TRUE;
        }
        return FALSE;
    }
    /*
    function switch_uri($lang)
    {
        $CI =& get_instance();
        $uri = $CI->uri->uri_string();
        if ($uri != "")
        {
            $exploded = explode('/', $uri);
            if($exploded[1] == $this->lang())
            {
                $exploded[1] = $lang;
            }
            $uri = implode('/',$exploded);
        }
        return $uri;
    }
    */
    function switch_uri($lang)
    {
        $CI =& get_instance();
        $uri = $CI->uri->uri_string();
        if ($uri != "")
        {
            $exploded = explode('/', $uri);
            // Si tenemos una URI con un idioma --> es/controller/metodo
            if($exploded[0] == $this->lang())
            $exploded[0] = $lang;
            // Si tenemos una URI sin un idioma --> /controller/metodo
            // "Lenguaje por defecto"
            else if (strlen($exploded[0]) != 2)
            $exploded[0] = $lang . "/" . $exploded[0];
            $uri = implode('/',$exploded);
        }
        return $uri;
    }
    // Hay un segmento de lenguaje en esta $uri?
    function has_language($uri)
    {
        $first_segment = NULL;
        $exploded = explode('/', $uri);
        if(isset($exploded[0]))
        {
            if($exploded[0] != '')
            {
                $first_segment = $exploded[0];
            }
            else if(isset($exploded[1]) && $exploded[1] != '')
            {
                $first_segment = $exploded[1];
            }
        }
        if($first_segment != NULL)
        {
            return isset($this->languages[$first_segment]);
        }
        return FALSE;
    }

    // Lenguaje por defecto: primer elemento de $this->languages
    function default_lang()
    {
        foreach ($this->languages as $lang => $language)
        {
            return $lang;
        }
    }
    // agrega un segmento lenguaje a la $uri (si es apropiado)
    function localized($uri)
    {
        if($this->has_language($uri)
                || $this->is_special($uri)
                || preg_match('/(.+)\.[a-zA-Z0-9]{2,4}$/', $uri))
        {
            // no necesitamos un segmento lenguaje en la URI por que:
            // - ya hay un segmento lenguaje
            // - es una uri especial (colocala en $special)
            // - es un link a un archivo
        }
        else
        {
            $uri = $this->lang() . '/' . $uri;
        }
        return $this->lang() . '/' . $uri;
    }
}
// END BaseLang Class
/* End of file BaseLang.php */
/* Location: ./system/application/Core/BaseLang.php */

4) Después de tener esos archivos listos, en nuestra vista podemos copiar el siguiente código para hacer el cambió de lengiaje.

 if ($this->lang->lang() == "en"){
           echo anchor ($this->lang->switch_uri ('es'), 'Ver la Página en Español');}
else{
          echo anchor($this->lang->switch_uri('en'), 'Display current page in English');}
Por último es bueno saber que utilizando el url_helper podemos utilizar anchor para crear links, de esta manera no tenemos que colocar el idioma en los enlaces. por ejemplo podemos utilizar.

anchor('controller/metodo', 'Este es un link')
en lugar de poner, los siguentes enlaces: Estos enlaces no funcionarían bien.

anchor('en/controller/metodo', 'Este es un link')
<a href="controler/metodo">Este es un link</a>
y el idioma que tome será el que a sido activado anteriormente.

www.example.com/en/controller/metodo

3 comentarios:

  1. Hola: Gracias por tu post. Estoy tratando de implementarlo en un nuevo proyecto en CodeIgniter 2.0.2, pero no acaba de funcionar.

    Te copio el error por si me puedes ayudar:
    atal error: Call to undefined method CI_Lang::CI_Lang() in C:\xampp\htdocs\dominio.com\application\core\MY_Lang.php on line 33

    Gracias.-

    ResponderEliminar
  2. Una pregunta más:
    En la estructura de carpetas de codeIgner 2.0.2 no existe "./system/application/Core/BaseConfig.php".

    Cuando tu dices ... "En la carpeta application/Core/ creamos el archivo..." ¿te refieres a system/application?
    Gracias.-

    ResponderEliminar
  3. Hola Gamez, creo saber cual es el problema.

    En C:\xampp\htdocs\dominio.com\application\core\MY_Lang.php tienes que ver el constructor, en la version que trabajo es "parent::__construct();" pero en la 2.0.2 no se, posiblemente tendrías que cambiarlo.

    Los archivos que van en la carpeta "core" tienes que crearlos y ponerles el nombre con el prefijo "Base" o con "MY_". por el primer error q me mandaste veo que estas trabajando con "MY_".

    Por ultimo, cuando yo dije la carpeta application/core, puede ser también system/application/core ya que la carpeta "application" puedes sacarla de "system" y no hay ningun problema, espero haber ayudado, en todo caso te recominedo que vuelvas a leer los pasos 1 y 2. Si aún asi no puedes, no dudes en escribirme, me encantaría ayudarte.

    ResponderEliminar