Skip to content

CodeIgniter 2.1 internationalization i18n

Derek Jones edited this page Jul 4, 2012 · 25 revisions

Category:Internationalization Category:Core::Language Category:Libraries::Internationalization Category:Libraries::Language

[b]Internationalization (i18n) for CodeIgniter 2.x[/b] is small modification to: [url]http://maestric.com/doc/php/codeigniter_i18n[/url] to work with CodeIgniter 2.1. [h2]Credits:[/h2] Original Author: [b]Jérôme Jaglale[/b]. Original Post (and instructions): [url]http://maestric.com/doc/php/codeigniter_i18n[/url]. Modifications by [b]Yeb Reitsma[/b] [i]Placeholders substitution in language strings[/i]: [b][url=http://codeigniter.com/member/40637]alvil[/url][/b] (original wiki page: [url]http://codeigniter.com/wiki/Placeholders_substitution_in_language_strings/[/url]) [h2]What it does:[/h2] Use [url=http://codeigniter.com/user_guide/libraries/language.html]CodeIgniter's Language Class[/url] through the language in the URI: [pre]http://example.com/en/welcome http://example.com/es/welcome[/pre] with the possibility to add placeholders ("%s") inside your language strings, to make it more dinamic. [h2]Installation and configuration:[/h2] [h3]1. Use pretty URLs (without index.php)[/h3] a) With Apache it's usually achieved with [b]mod_rewrite[/b] through an .htaccess. (See [url=http://codeigniter.com/user_guide/general/urls.html]CodeIgniter User Guide for URLs[/url] for more information about this)

b) In [b].application/config/config.php[/b] set to blank [pre]$config['index_page'] = ””[/pre]

[h3]2. Create [b]application/core/MY_Lang.php[/b]:[/h3]

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

// Originaly CodeIgniter i18n library by Jérôme Jaglale
// http://maestric.com/en/doc/php/codeigniter_i18n
// modification by Yeb Reitsma

/*
in case you use it with the HMVC modular extension
uncomment this and remove the other lines
load the MX_Loader class */

//require APPPATH."third_party/MX/Lang.php";

//class MY_Lang extends MX_Lang {
 
class MY_Lang extends CI_Lang {


    /**************************************************
     configuration
    ***************************************************/
   
    // languages
    private $languages = array(
        'en' => 'english',
        'de' => 'german',
        'fr' => 'french',
        'nl' => 'dutch'
    );
   
    // special URIs (not localized)
    private $special = array (
        "admin"
    );
    
    // where to redirect if no language in URI
    private $uri;
    private $default_uri;
    private $lang_code;
   
    /**************************************************/
    
    
    function MY_Lang()
    {
        parent::__construct();
        
        global $CFG;
        global $URI;
        global $RTR;
        
        $this->uri = $URI->uri_string();
        $this->default_uri = $RTR->default_controller;
        
        $uri_segment = $this->get_uri_lang($this->uri);
        $this->lang_code = $uri_segment['lang'] ;
        
        $url_ok = false;
        if ((!empty($this->lang_code)) && (array_key_exists($this->lang_code, $this->languages)))
        {
            $language = $this->languages[$this->lang_code];
            $CFG->set_item('language', $language);
            $url_ok = true;
        }
        
     if ((!$url_ok) && (!$this->is_special($uri_segment['parts'][0]))) // special URI -> no redirect
     {
      // set default language
      $CFG->set_item('language', $this->languages[$this->default_lang()]);
      
      $uri = (!empty($this->uri)) ? $this->uri: $this->default_uri;
          $uri = ($uri[0] != '/') ? '/'.$uri : $uri;
      $new_url = $CFG->config['base_url'].$this->default_lang().$uri;
      
      header("Location: " . $new_url, TRUE, 302);
      exit;
     }
    }

    
    
    // get current language
    // ex: return 'en' if language in CI config is 'english' 
    function lang()
    {
        global $CFG;        
        $language = $CFG->item('language');
        
        $lang = array_search($language, $this->languages);
        if ($lang)
        {
            return $lang;
        }
        
        return NULL;    // this should not happen
    }
    
    
    function is_special($lang_code)
    {
        if ((!empty($lang_code)) && (in_array($lang_code, $this->special)))
            return TRUE;
        else
            return FALSE;
    }
   
   
    function switch_uri($lang)
     {
         if ((!empty($this->uri)) && (array_key_exists($lang, $this->languages)))
         {

          if ($uri_segment = $this->get_uri_lang($this->uri))
          {
           $uri_segment['parts'][0] = $lang;
           $uri = implode('/',$uri_segment['parts']);
          }
          else
          {
           $uri = $lang.'/'.$this->uri;
          }
         }

         return $uri;
     }
    
 //check if the language exists
 //when true returns an array with lang abbreviation + rest
    function get_uri_lang($uri = '')
    {
     if (!empty($uri))
     {
      $uri = ($uri[0] == '/') ? substr($uri, 1): $uri;
      
      $uri_expl = explode('/', $uri, 2);
      $uri_segment['lang'] = NULL;
      $uri_segment['parts'] = $uri_expl;  
      
      if (array_key_exists($uri_expl[0], $this->languages))
      {
       $uri_segment['lang'] = $uri_expl[0];
      }
      return $uri_segment;
     }
     else
      return FALSE;
    }

    
    // default language: first element of $this->languages
     function default_lang()
 {
  $browser_lang = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? strtok(strip_tags($_SERVER['HTTP_ACCEPT_LANGUAGE']), ',') : '';
  $browser_lang = substr($browser_lang, 0,2);
  return (array_key_exists($browser_lang, $this->languages)) ? $browser_lang: 'en';
 }
    
    
    // add language segment to $uri (if appropriate)
    function localized($uri)
    {
     if (!empty($uri))
     {
      $uri_segment = $this->get_uri_lang($uri);
      if (!$uri_segment['lang'])
      {

       if ((!$this->is_special($uri_segment['parts'][0])) && (!preg_match('/(.+)\.[a-zA-Z0-9]{2,4}$/', $uri)))
       {
                 $uri = $this->lang() . '/' . $uri;
                }
            }
     }
        return $uri;
    }
} 

// END MY_Lang Class

/* End of file MY_Lang.php */
/* Location: ./application/core/MY_Lang.php */

Add your languages to the "$language" array. [b]The first language will be the default language[/b].

[h4]Special URIs:[/h4] A special URI is not prefixed by a language. The root URI (/) is by default a special URI.

You might need other special URIs, like for an "admin" section, which would be in just one language.

Add "admin" to the "$special" array.

Now, links to "admin" won't be prefixed by the current language.

[h3]3. Create [b]application/core/MY_Config.php[/b]:[/h3]

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

// Originaly CodeIgniter i18n library by Jérôme Jaglale
// http://maestric.com/en/doc/php/codeigniter_i18n
//modification by Yeb Reitsma

/* 
in case you use it with the HMVC modular extention
uncomment this and remove the other lines
load the MX_Loader class */
//require APPPATH."third_party/MX/Config.php";

//class MY_Config extends MX_Config {
 

class MY_Config 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);            
        }

        return parent::site_url($uri);
    }
        
}

// END MY_Config Class

/* End of file MY_Config.php */
/* Location: ./application/core/MY_Config.php */ 

[h3]4. Replace original Language helper[/h3] In case you are going to use [b]placeholders[/b] (add dynamic variables to your language strings), you'll need to modify the language helper in order to substitute each placeholder ("%s") with its correspondent value.

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

 function lang($line, $id = '')
 {
  $CI =& get_instance();
  $line = $CI->lang->line($line);
  
  $args = func_get_args();
  
  if(is_array($args)) array_shift($args);
  
  if(is_array($args) && count($args))
  {
      foreach($args as $arg)
      {
          $line = str_replace_first('%s', $arg, $line);
      }
  }

  if ($id != '')
  {
   $line = '<label for="'.$id.'">'.$line."</label>";
  }
  
  return $line;
 }

 function str_replace_first($search_for, $replace_with, $in)
 {
     $pos = strpos($in, $search_for);
     if($pos === false)
     {
         return $in;
     }
     else
     {
         return substr($in, 0, $pos) . $replace_with . substr($in, $pos + strlen($search_for), strlen($in));
     }
 }

/* End of file MY_language_helper.php */
/* Location: ./application/helpers/MY_language_helper */

[h3]5. Add routes[/h3] Add these lines to [b]./application/config/routes.php[/b]:

// URI like '/en/about' -> use controller 'about'
$route['^(en|de|fr|nl)/(.+)$'] = "$2";

// '/en', '/de', '/fr' and '/nl' URIs -> use default controller
$route['^(en|de|fr|nl)$'] = $route['default_controller'];

where [b]en|de|fr|nl[/b] are the same languages as in your "MY_Lang"'s "$languages" array.

[h3]6. Creating languages files[/h3] As explained in [url=http://codeigniter.com/user_guide/libraries/language.html]CodeIgniter's Language Class user guide[/url]. Read this carefully to learn how to load, store and write language files.

You can add [b]placeholders[/b] inside your strings. For instance, if you like to add the "username" to a string, you can by writing this lang string:

$lang['welcome'] = "Welcome, %s.";

See [b]8. Create View[/b] for further reference.

[h3]7. Create Controller[/h3]

&lt;?php
class About extends Controller {
 
 function index()
 {
  // you might want to just autoload these two helpers
  $this->load->helper('language');
  $this->load->helper('url');
 
  // load language file
  $this->lang->load('about');
 
 
  $this->load->view('about');
 }
}
 
/* End of file about.php */
/* Location: ./application/controllers/about.php */

[h3]8. Create View[/h3] To fetch a lang line or add an anchor:

<p>&lt;?=lang('about.gender')?&gt;</p>
 
<p>&lt;?=anchor('music','Shania Twain')?&gt;</p>

Read [url=http://codeigniter.com/user_guide/helpers/language_helper.html]CodeIgniter's Language Helper user guide[/url] to learn more on how to fetch language lines.

In case you use placeholders inside your language strings, you can use them like this:

<p>&lt;?php $username = "John Doe";
echo lang('welcome', $username)?&gt;</p>

This should appear like: ```php Welcome, John Doe.




That's all. Try it, it should work!

[h2]Notes[/h2]
- You might need to [b]translate some of CodeIgniter's language files[/b] in system/language. Example: if you're using the “Form Validation” library for French pages, translate system/language/form_validation_lang.php to system/application/language/french/form_validation_lang.php.

- Links to internal pages are prefixed by the current language, but links to files are not:
```php
site_url('about/my_work');
// http://mywebsite.com/en/about/my_work

site_url('css/styles.css');
// http://mywebsite.com/css/styles.css
  • Get the current language:
$this->lang->lang();
// en
  • Switch to another language:
anchor($this->lang->switch_uri('fr'),'Display current page in French');

[h2]Further information and useful modifications[/h2]

  • [url=http://codeigniter.com/forums/viewthread/197965/#930928]Avoid Spider Bots problems with "$_SERVER['HTTP_ACCEPT_LANGUAGE']"[/url]

[h2]Disclaimer[/h2] It works on a scratch installation of CodeIgniter 2.0.3, on MAPM 2.0.3 (localhost) in Mac OS X 10.7.2 (2011-10-23)

Clone this wiki locally