Recent posts
Recent comments
- In i18n routes with CakePHP 1.3
- pierre_martin wrote: Hi everyone and thank you for the feedbacks! Since this article was published, we improved...
- In i18n routes with CakePHP 1.3
- Mateusz Mucha wrote: Thank you!
- In i18n routes with CakePHP 1.3
- Piotr wrote: Wow! That's great and usefull. Ways easier than with old methods. I added some code to update...
- In i18n routes with CakePHP 1.3
- Lee wrote: Once you set $url['lang'] when empty is doesn't update $this-params with the default...
- In CakePHP Migrations plugin: easily version and deploy whole applications
- Remigijus wrote: When I am trying to run 'migration generate' for first time, my migration file 'up' has value...
Categories
There are no categories to display
i18n routes with CakePHP 1.3
Written on Thu, Aug 5th 2010, 10:00 in Uncategorized
Internationalizing a CakePHP application can be tricky when it comes to deal with i18n urls. We will see in this article how the Custom route classes introduced by CakePHP 1.3 could be used to add the current language to your urls in a few lines of code.
EDIT: This proof of concept has now been improved and a better version of the code below can be found in CakeDC's I18n plugin on Github
Requirements
This article will not go too deep in internationalizing an application as many resources already exist about it. We suppose the following:
- Your application defines the current language on given the language code passed in the url
- The available languages are configured via Configure::write('Config.languages', array('eng', 'fre', 'deu'));
- You use the CakePHP array syntax for defining urls:
- $this->Html->link('link', array('controller' => 'posts', 'action' => 'view', $post['Post']['id']));
- $this->redirect(array('controller' => 'posts', 'action' => 'index'));
- Router::url(array('controller' => 'posts', 'action' => 'index'), true);
Custom routes were already introduced by Mark Story on his blog, so we will not do it again here... before continuing be sure you have read "Using custom Route classes in CakePHP"
Show me some code!
I18nRoute
As I said (or not), routes are probably the best place for customizing your urls and add information in them... much more better at least than overriding the Helper::url() method in an AppHelper class!
Custom routes introduced a way to customize how routes are processed in a very easy and powerful way (i.e ~20 lines of code). It is a bit like wrapping the Router class in CakePHP 1.2, a good example of this was the CroogoRouter.
First, we are going to create an I18nRoute class extending CakeRoute in the "/libs/routes/i18n_route.php" file. Here is its code:
<?php
class I18nRoute extends CakeRoute {
/**
* Constructor for a Route
* Add a regex condition on the lang param to be sure it matches the available langs
*
* @param string $template Template string with parameter placeholders
* @param array $defaults Array of defaults for the route.
* @param string $params Array of parameters and additional options for the Route
* @return void
* @access public
*/
public function __construct($template, $defaults = array(), $options = array()) {
$options = array_merge((array)$options, array(
'lang' => join('|', Configure::read('Config.languages'))
));
parent::__construct($template, $defaults, $options);
}
/**
* Attempt to match a url array. If the url matches the route parameters + settings, then
* return a generated string url. If the url doesn't match the route parameters false will be returned.
* This method handles the reverse routing or conversion of url arrays into string urls.
*
* @param array $url An array of parameters to check matching with.
* @return mixed Either a string url for the parameters if they match or false.
* @access public
*/
public function match($url) {
if (empty($url['lang'])) {
$url['lang'] = Configure::read('Config.language');
}
return parent::match($url);
}
}
The most important part of the code is in the "match()" method. We just add the current language to the url "lang" named param if it was not set. The constructor was also overriden to add a regex pattern for the "lang" param. Thus, only lang prefixes defined in your list of available languages will be parsed by the route.
Define your routes
It is now time to use this custom route in your application. Here is how the default route for pages could be defined in "/config/routes.php":
App::import('Lib', 'routes/I18nRoute');
Router::connect('/:lang/pages/*', array('controller' => 'pages', 'action' => 'display'), array('routeClass' => 'I18nRoute'));
- import the library file containing the custom route
- add a ":lang" param in where you want the language code appear in the url
- tell the Router you want to use this custom class (third param)
Link from everywhere!
Now you won't have to worry about the language code transmitted in your urls... every generated link will contain the current language code. If you want to switch the language (for instance switching to the French version of your application), you will just have to add the "lang" param to the url array.
Here are some examples of urls which would be generated on the "/eng/posts/index" page:
$this->Html->link(__('French', true), array_merge($this->passedArgs, array('lang' => 'fre'))); // /fre/posts/index
$this->Html->link('link', array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); // /eng/posts/view/2
Disclaimer
This code is experimental and the article shows you how to use CustomRoutes to implement this basic feature. Many improvements could be added to fit your needs (no language code for the default application lang, short languages code...)
Even if the tests we made were successful, we have not used this code in production yet so there may be "real word" use cases that are not handled correctly with this solution... if you find one, please tell us in the comments!

What is OpenID?
OpenID is a new open standard that lets you sign in to web sites with a single URL that you own. This URL can be your homepage or blog, or it can be provided to you by a web site you use. In either case, you only have to sign in once to your OpenID provider and so you only need to maintain a single password.Learn more.
How is CakeDC using OpenID?
You can use your OpenID identity when posting comments on the site. When you see a form field with
entering your OpenID identity is sufficient to allow your post. We also accept Google or Yahoo! identities. Simply use either "google.com" or "yahoo.com" and our OpenID library will locate your information from the appropriate source.
Comments:
Add New Comment
Redirect
Reply | Lee | posted on 13/8/10
-
Reply | Piotr | posted on 1/9/10
Just what I needed
Reply | Mateusz Mucha | posted on 9/9/10
Update
Reply | pierre_martin | posted on 17/9/10