Skip to content

CodeIgniter 2.1 internationalization i18n

Derek Jones edited this page Jul 5, 2012 · 21 revisions

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

Internationalization (i18n) for CodeIgniter 2.x is small modification to: http://maestric.com/doc/php/codeigniter_i18n to work with CodeIgniter 2.1.

Credits:

Original Author: Jérôme Jaglale. Original Post (and instructions): http://maestric.com/doc/php/codeigniter_i18n. Modifications by Yeb Reitsma Placeholders substitution in language strings: alvil (original wiki page: http://codeigniter.com/wiki/Placeholders_substitution_in_language_strings/)

What it does:

Use CodeIgniter's Language Class 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.

Installation and configuration:

1. Use pretty URLs (without index.php)

a) With Apache it's usually achieved with mod_rewrite through an .htaccess. (See CodeIgniter User Guide for URLs for more information about this)

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

2. Create application/core/MY_Lang.php:

<?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. The first language will be the default language.

Special URIs:

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.

3. Create application/core/MY_Config.php:

<?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 */ 

4. Replace original Language helper

In case you are going to use placeholders (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 */

5. Add routes

Add these lines to ./application/config/routes.php:

// 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 en|de|fr|nl are the same languages as in your "MY_Lang"'s "$languages" array.

6. Creating languages files

As explained in CodeIgniter's Language Class user guide. Read this carefully to learn how to load, store and write language files.

You can add placeholders 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 8. Create View for further reference.

7. Create Controller

&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 */

8. Create View

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 CodeIgniter's Language Helper user guide 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!

## Notes

- You might need to **translate some of CodeIgniter's language files** 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');

Further information and useful modifications

Disclaimer

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