Dynamically change CakePHP language January 30, 2014


or how to control the locale of a CakePHP 2.x application by a parameter in the URL

Preamble

When I made the previous version of this website, I encountered a problem to which i found no satisfactory solution online: how to easily change the language of a CakePHP application. The framework's documentation itself doesn't help much, saying only:

There are several ways to do this, it can be by using language specific subdomains (en.example.com, fra.example.com, etc.), or using a prefix to the URL such as is done with this application. You may also wish to glean the information from the browser’s user-agent, among other things.

This is all well and good, but how to actually do it? And more importantly, how to do it in an elegant way, without polluting the entire application? Although Dorin Moise has managed to do something that works, the comments under his post suggest that a better solution is possible. In addition, the code managing the language change is mixed with AppController. When there is no satisfactory solution, the only thing left is to create one yourself! I invite you to check my complete solution on GitHub. The rest of this post will detail how to integrate the solution.

Installation Details

The heart of the module is located in the component LanguageComponent. To start, you must add the file in the Component folder in this location:

app/Controller/Component/LanguageComponent.php

Then, include the class in the application controller. In its definition, give the LanguageComponent the list of languages ​​supported by your application. Note that the array key can be anything you choose. However, note that this is the value that will be used to recognize the language parameter in the URL. For the associated value, you must use an ISO 639-2 locale code. Here is an example:

app/Controller/AppController.php

public $components = array(
    'Language' => array(
        'supportedLanguages' => array(
            'en' => 'eng',
            'fr' => 'fra'
            ),
        )
);

Once the component included in the project, make sure that the links with language parameters are properly managed by the application. First, to ensure that the language is part of all the links in your application, you must redefine two functions:

app/Controller/AppController.php

public function redirect($url, $status = NULL, $exit = true)
{
    if (is_array($url) && !isset($url['language']))
    {
        $url['language'] = $this->Language->getLanguage();
    }

    parent::redirect($url, $status, $exit);
}

app/View/Helper/AppHelper.php

public function url($url = null, $full = false)
{
    if(is_array($url) && !isset($url['language']))
    {
        $url['language'] = $_SESSION['Config']['languageCode'];
    }

    return parent::url($url, $full);
}

Now that the user is always redirected to a page that contains the language in the URL, you must define this language parameter in your application's routes. This will require to modify the routes.php file like this:

app/Config/routes.php

//user-defined language codes here, must be same ones used for the LanguageComponent
$languageCodes = array('language' => 'en|fr');

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/:language', array('controller' => 'pages', 'action' => 'display', 'home'), $languageCodes);

Router::connect('/:language/pages/*', array('controller' => 'pages', 'action' => 'display'), $languageCodes);

//default cakePHP routing, with language codes
Router::connect('/:language/:controller/:action/*', array(), $languageCodes);
Router::connect('/:language/:controller', array('action' => 'index'), $languageCodes);

For safety, add a default locale for your application by defining it in core.php:

app/Config/core.php

/**
 * Application default locale
 * Must use an ISO 639-2 locale code
 */
Configure::write('Config.language', 'eng');

For everything to work automatically, there are two more changes to do to the application controller. The first changes the locale of your application using this language parameter in the URL. The second gives you access to the current language of your application in all your views. Here they are:

app/Controller/AppController.php

public function beforeFilter()
{
    $this->Language->set($this->params['language']);
}

function beforeRender()
{
    $this->set('language', $this->Language->getLanguage()); //to access the language code from any view
}

And voilà! The current language code is available in all your pages using the variable $language. To add a language-changing link to your pages, just add the language option in the options array $options = array() of a link created by HtmlHelper::link. For example:

echo $this->Html->link('Français', array('language'=>'fr'));

CakePHP Internationalization PHP
Last updated on October 14, 2018

— Etienne Lamoureux