Internationalization (i18n) library for CodeIgniter

What it does

Have the language in the URL

  • maestric.com/en/about
  • maestric.com/fr/about

Keep using CodeIgniter Language Class

Example

View

<p>
  <?=lang('about.gender')?>
</p>

English language file

$lang['about.gender'] = "I'm a man";

French language file

$lang['about.gender'] = "Je suis un homme";

Result with maestric.com/en/about

<p>I'm a man</p>

Result with maestric.com/fr/about

<p>Je suis un homme</p>

Installation

  • Put MY_Language.php and MY_Config.php in system/application/libraries

Configuration

  • You must be using pretty URLs (without index.php). With Apache it's usually achieved with mod_rewrite through an .htacess

In config.php

  • $config['base_url'] must correspond to your configuration.
  • $config['index_page'] = ””

In config/routes.php add

// URI like '/en/about' -> use controller 'about'
$route['^fr/(.+)$'] = "$1";
$route['^en/(.+)$'] = "$1";
 
// '/en' and '/fr' URIs -> use default controller
$route['^fr$'] = $route['default_controller'];
$route['^en$'] = $route['default_controller'];

Use

Let's build a bilingual English/French page.

language files

system/application/language/english/about_lang.php

<?php
 
$lang['about.gender'] = "I'm a man";
 
/* End of file about_lang.php */
/* Location: ./system/language/english/about_lang.php */

system/application/language/french/about_lang.php

<?php
 
$lang['about.gender'] = "Je suis un homme";
 
/* End of file about_lang.php */
/* Location: ./system/language/french/about_lang.php */

controller

system/application/controllers/about.php

<?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: ./system/application/controllers/about.php */

view

system/application/views/about.php

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

Test

http://your_base_url/en/about

<p>I'm a man</p>
 
<p><a href="http://mywebsite.com/en/music">Shania Twain</a></p>

http://your_base_url/fr/about

<p>Je suis un homme</p>
 
<p><a href="http://mywebsite.com/fr/music">Shania Twain</a></p>

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.
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');
  • the root page (/) is supposed to be some kind of splash page, without any specific language. This can be changed: see “No splash page” below.

How it works

MY_Config.php contains an override of site_url(): language segment added (when appropriate) to URLs generated with anchor(), form_open()...

Options

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.

In system/application/libraries/MY_Language.php, add admin to the $special array. Now links to admin won't be prefixed by the current language.

site_url('admin');
// http://mywebsite.com/admin

No splash page

In system/application/libraries/MY_Language.php

  • remove ”” from the $special array
  • set $default_uri to something else like home
  • now a request to / will be redirected to en/home, if English is your default language
  • the default language is the first item of the $languages array

Add a new language

  • system/application/libraries/MY_Language.php: add new language to $languages array
// example: German (de)
'de' => 'german',
  • config/routes.php: add new routes
// example: German (de)
$route['^de/(.+)$'] = "$1"; 
$route['^de$'] = $route['default_controller'];
  • create corresponding language folder in system/application/language. For this “German” example, it would be called german.
 

Feedback

This April 15, 2009 update fixes the issues reported before:

- Mark: autoloading of language files wasn't working

- François: language segment was sometimes added to a link when there was already one

- Frank: it wasn't possible to use the library methods in a controller's constructor

Thank you all for your feedback.
Jérôme Jaglale
April 15, 2009
#1
Thanks Jerome, get an error and not sure why, simply replaced the old files with new ones, changed the MY to FW as I had before when all was fine. Fatal error: Call to undefined method FW_Language::init_language() in W:\www\s\system\libraries\Hooks.php on line 205
BS
April 16, 2009
#2
BS, please remove the hook in config/hooks.php, it's not needed anymore.
Jérôme Jaglale
April 16, 2009
#3
When I try to switch to /es/ I get this error: Unable to load the requested language file: language/profiler_lang.php There is no file by that name, and language folder is setup the same as worked with previous version... what did I miss this time? :) thanks a million!
BS
April 16, 2009
#4
Oops, i forgot to mention, this breaks scaffolding links (edit/add/etc), were you aware? I can send you a link to show you what I'm talking about via email rjdjohnston(at)gmail(dot)com if you like.
BS
April 16, 2009
#5
Started a thread on my error from switch from en to es, see here: http://codeigniter.com/forums/viewthread/111938/ Dank je!

April 17, 2009
#6
This April 17, 2009 update fixes the issues reported before:

- BS: scaffolding wasn't working
- Dan: wrong URL generated with form_open(), redirection bugs

Note:
If you've been using a previous version, make sure to remove helpers/MY_url_helper.

Note from Dan:
For people using dx_auth module they will need to edit the config file (system/application/config/dx_auth.php) at line 188 onwards there are some variable definitions e.g. $config['DX_deny_uri'] = '/auth/deny/'; It is best to remove the leading / e.g. $config['DX_deny_uri'] = 'auth/deny/'; otherwise when a user is redirected to the login form the url comes up as http://idm.ts/en//auth/login - this does actually display the right page and doesnt affect it but just to make it look professional!

Thank you for your feedback.
Jérôme Jaglale
April 17, 2009
#7
This April 20, 2009 update fixes a bug: the redirection wasn't working when the language in the URL was wrong.
Jérôme Jaglale
April 20, 2009
#8
Thank you very much for this very useful library! Saved me a ton of work.
Jeroen van der Gulik
May 18, 2009
#9
Thanks a lot, it's excellent !
alyvest
May 20, 2009
#10
I've just modified a line in MY_language.php If the URI doesn't content language information, i'm loading the page asking with the default language. I don't use the default uri anymore Code: header("Location: " . $CFG->site_url($this->lang($this->languages[$this->default_lang()]).'/'.$segment), TRUE, 302);
alyvest
May 20, 2009
#11
is this library work with ocular layout library? thx..
Hammudi
July 15, 2009
#12
Thanks a lot, great work. I discovered small bug in MY_Language: If var $special = array (""); - this array is empty, the function is_special() doesn't work as expected because even empty the URL is treated as special
Martin Rusev
August 6, 2009
#13
Thanks Jérôme, great script! Is there a way I could translate the links too? Example: English url: en/about French url: fr/propos Both URLs routed to the about.php controller where the language strings returned according to the langugae. This would highly increase the search-engine friendlyness of the script. I'm trying to find a solution, but I'm a beginner...
vito
August 15, 2009
#14
Amazing, you saved my life bud!!!
Jorch
August 20, 2009
#15
Just integrated with CI with HMVC, worked fine till now. :)
Mahbubur Rahman
August 24, 2009
#16
Very nice. It's possible to remove the language from the URI ?
Ed
August 25, 2009
#17
Ed: no, the goal here is actually to rely on the language in the URI: so we don't need to set a cookie on the client browser or use the HTTP headers sent by the browser. Also the page will be referenced by search engines in both languages.
Jérôme Jaglale
August 25, 2009
#18
this looks very good... I will try it out merci beaucoup Jerome...
Luca
August 26, 2009
#19
Hi, just to mention that it worked like a charm... indeed saved me hours of work :-) thanks a lot
Luca
August 26, 2009
#20
So i had to drop the HMVC with i18n library. Views in folders don't seem to work easily. Need to change a lot in router to get HMVC+i18n to work. So I'm back without HMVC because i18n was the main need.
Mahbubur Rahman
August 31, 2009
#21
great work man!!
Leandro Gilioli
September 18, 2009
#22
This is great! Really usefull!
demogar
September 18, 2009
#23
very great lib, but I need also HMVC to work, any suggestions? another thing, redirect default language is nice but if you type /controllername/functionname it does not redirect to let's say /en/controllername/functionname
mike
October 17, 2009
#24
This is all fine and dandy, but having to manually write all the routes is not all that useful. Plus, if you are trying to make a multilingual site, you do not want the URIs to be in english:

http://your-base-url/en/about
http://your-base-url/fr/about

It should be like this:
http://your-base-url/en/about
http://your-base-url/fr/a-propos

Ideally this would work by either checking your database to find the uri, or have the system dynamically generate the routing config file.

That's my two cents worth.
Peter Hebert
October 22, 2009
#25
Peter, what do you mean by "having to manually write all the routes"? It's only two routes for each language.

I agree about the localized URLs, that should be an option. I got something working on a project, but it's too much of a hack. I have yet to come with a better solution. Thanks for the feedaback!
Jérôme Jaglale
October 22, 2009
#26
I mean that if you want to call your controller/function by the appropriate name in each language, you would need to write a route for each of them:

ie. if your controller is 'about', and the function is 'men', then you would need two routes if you wanted to call it in english, french, and spanish:

$route['a-propos/hommes'] = "about/men";
$route['acerca/hombres'] = "about/men";

The same would apply for every controller and function.
Peter Hebert
October 27, 2009
#27
Ok, you were already talking about the localization of the URLs..

But you would have to declare them somewhere anyway, routes.php or database, no?

I don't see how you could generate that, especially if you use parameters with the functions: store/buy/chocolat_blanc -> store/buy/white_chocolate

Any ideas?
Jérôme Jaglale
October 27, 2009
#28
Great work, i have a question How can i load a different language from the controller? I have to send an email to the user which has a different preffered language than the admin, how can i load the translation for the user ? Thank you!
Cristian Boboc
November 3, 2009
#29
Automatic configuration for ci_I18n library

//create config/supported_lang.php file
$config [ 'supported_lang'] =
array (
'en' => 'Spanish',
'in' => 'English',
'gl' => 'Galician',
'ca' => 'catalan',
'ja' => 'japanese',
'de' => 'Dutch',
);

//in libraries/MY_Language.php

replace var $languages= array(...)
like this var $languages;

in the class constructor
add
global $CFG;
$this->languages = $CFG->item ( 'supported_lang');

//in config/routes.php
add
global $CFG;

//Load the config file
$CFG->load( 'supported_lang');

//browser language
$browser_lang = strtolower (substr ($_SERVER ["HTTP_ACCEPT_LANGUAGE"], 0.2));
//if supported
if(array_key_exists($browser_lang,$CFG->item('supported_lang')))
{
$CFG->set_item('language', $CFG->item($browser_lang,'supported_lang'));
}

$route['default_controller'] = "my_default_controller";
$route['scaffolding_trigger'] = "";
//
foreach($CFG->item('supported_lang') as $lang => $value)
{
$route["^$lang/(.+)$"] = "$1";

$route["^$lang\$"] = $route['default_controller'];

}

I want them to be useful
Jérôme Jaglale thank for their fantastic
library and sorry for my English
tolo
November 3, 2009
#30
Cristian, you could use the second parameter:
$this->lang->load('about', 'fr');
Jérôme Jaglale
November 3, 2009
#31
Great work. I am doing this small assignment and got familiar with CodeIgniter just for that. The aim of the assignment is i18n. I am using the form_validation library for my assignment and I need to have localized error messages for the library. If I create a lang file under application/languages/french/form_validation_lang.php how can I dynamically load it in the controller? Will your library do this? Thanks!
chamila
December 31, 2009
#32
Yes, your helper sure helps!! Thanks again for the great work. :)
chamila
December 31, 2009
#33
This is great !! Is this library working with HMVC library?
James
January 2, 2010
#34
@alyvest: I think the better solution would be header("Location: " . $CFG->site_url($this->lang($this->languages[$this->default_lang()]).$URI->uri_string()), TRUE, 302); If no language is provided
Solutionvibes.com
January 9, 2010
#35
hi this one is one of my favorites CI library i have one question is if i have default language is English and i dont want to use en in url and when i want to change language then i want lang name in url fr default maestric.com/about localized maestric.com/fr/about
umefarooq
January 12, 2010
#36
umefarooq, it's probably possible with a bit of customization: just one route for the fr (routes.php), no redirect if there's isn't any language in the URL and don't add the language segment if it's English (MY_Language.php).
Jérôme Jaglale
January 12, 2010
#37
Hey Jérôme, thanks for the library, it's pretty wicked! Definitely saved me some time :) I am stuck with a little problem tho and was wondering if u can help me out. I'm trying to reroute some URIs to the same controller as such: /collection/2010 /collection/2009 etc should all reroute to the 'collection' class and pass the 'function' (2009 or 2010) as a variable. I've tried adding a simple route rule to the routes.php but haven't found a way to do so correctly... you got any ideas?!
Lennart Thiel
January 16, 2010
#38
Hello, I tried to implement your script, but i get this error: Fatal error: Call to a member function localized() on a non-object in [app]\application\libraries\MY_Config.php on line 19 . Can you please explain what might be wrong? Thanks and great job ;)
Dever
January 17, 2010
#39
Hi your library is no more working with modular separation here is the link http://codeigniter.com/forums/viewthread/121820/ so what's the solution for it.
webmasterdubai
February 3, 2010
#40
Hi I have made some changes in your MY_Config.php file regarding special URI. I was working on it I have created admin panel which is my special URI but the form URI alway's getting lang segment in it. I have made some changes in site_url function may be will help all this library users
function site_url($uri = '')
 {
            
  if (is_array($uri))
  {
   $uri = implode('/', $uri);
  }
  
  if (function_exists('get_instance'))  
  {
   $CI =& get_instance();
                        $segment =  $CI->uri->segment(1);
                        if(!$CI->lang->is_special($segment))
   $uri = $CI->lang->localized($uri);   
  }

  return parent::site_url($uri);
 }
It will not localize form for special URI
webmasterdubai
February 3, 2010
#41
here again modified site_url function
function site_url($uri = '')
 {
            
  if (is_array($uri))
  {
   $uri = implode('/', $uri);
  }
  
  if (function_exists('get_instance'))  
  {
   $CI =& get_instance();

                        $segment =  $CI->uri->segment(1);

                        if(!in_array($segment, $CI->lang->special))
   $uri = $CI->lang->localized($uri);
                        
  }

  return parent::site_url($uri);
 }
webmasterdubai
February 4, 2010
#42
Him Jerome!

I'm testing this on my local machine and I want to be able to change the language on my home page. I have this code:

&lt;?php echo anchor($this->lang->switch_uri('en'), 'EN'); ?&gt;
&lt;?php echo anchor($this->lang->switch_uri('ro'), 'RO'); ?&gt;

When I press any of the two links, the language remains the same... the default RO...

Can you help me with that?
Thanks!
Constantin
February 10, 2010
#43
Hi again!
I got this working by adding

else
{
$uri = $lang;
}

in the 'switch_uri' function.

Thanks again for this really useful!
Constantin
February 10, 2010
#44
* Thanks again for this really useful! :)
Constantin
February 10, 2010
#45
** Thanks again for this really useful feature!

I wonder what's with this hurry... :)
Constantin
February 10, 2010
#46
how can we get active language using this library.
webmasterdubai
March 1, 2010
#47