As we know, CakePHP is prepare to deal with multilingual sites making use of i18n and l10n and its .po files.

We can set a language by default by using the configure statement:

Configure::write('Config.language', 'en');

But if we want to enable the user to change the language on their settings page, for example, we need something else.

Changing language in real time

Well, lets imagine we have a site and we have those lovely language flags at the header. We want to be able to click on our flag and be redirected to the same exact URL in which we were.

How can we accomplish it? Well, first of all, we will make the changes over the session as pointed in CakePHP documentation in order to change the language in real time.

$this->Session->write('Config.language', 'en');

That’s what we are going to do once the user click over the flag, so we will need to define where are we going to redirect the user in that case.

We could place an action in a particular controller or we could better place it in the AppController as it will be called from any controller.

We will call it changeLanguage and it will admit one parameter as the shortcurt of the language we want to change to.

This way, it will look like this: www.mysite.com/changeLanguage/en/

//in AppController.php
public function changeLanguage($lang){
    if(!empty($lang)){
        if($lang == 'du'){
            $this->Session->write('Config.language', 'du');
        }

        else if($lang == 'en'){
            $this->Session->write('Config.language', 'en');
        }

        //in order to redirect the user to the page from which it was called
        $this->redirect($this->referer());
    }
}

And that’s it. We already have a site which allow to change the language in real time.

More improvements

And what if we want to detect the user’s language and set the page on that language?

We could try to read the IP and determine which country the user comes from but, besides being a bit tedious, I don’t personally like the idea. What if I am in USA but I am mexican and I speak spanish? What if I am at holidays in Tokio with my laptop but I only know english?

I have always found much more reasonable, useful and simple, to detect the language of the user’s browser and act accordingly.

We can get the browser language with PHP using the $_SERVER variable:

$_SERVER['HTTP_ACCEPT_LANGUAGE']

That would return us a list of the favorite languages for our browser in order. Something like this:

en-US,en;q=0.8,nl;q=0.6

If we get the first one, we will get the favorite language which is usually the one we want to get:

$browserLanguage = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);

We will make use of this technique the first time the user enters in our page or anytime the language session is not defined. As you can guess, as we want to do it from any section of our site, we will place it in our AppController. And as we want it to be executed at any time, we will do it on the beforeFilter function.

I would recommend creating a protected function and calling it from the beforeFilter:

//in AppController.php
/**
 * Read the browser language and sets the website language to it if available.
 *
 */
protected function _checkBrowserLanguage(){
    if(!$this->Session->check('Config.language')){

        //checking the 1st favorite language of the user's browser
        $browserLanguage = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);

        //available languages
        switch ($browserLanguage){
            case "en":
                $this->Session->write('Config.language', 'en');
                break;
            case "nl":
                $this->Session->write('Config.language', 'du');
                break;
            default:
                $this->Session->write('Config.language', 'en');
        }
    }
}
//in AppController.php
public function beforeFilter() {
    //checking the browsers language when there's no language session
    $this->_checkBrowserLanguage();
}