In CakePHP 2.x it was pretty cumbersome to get the language across all pages into the URL. With CakePHP 3 it is just awesome and easy. You can now create persistent URL parameters.

This is basically all you need for the most basic implementation inside your config/routes.php. The code is mostly the same as in the previous link to the persistent URL parameters page but I’ve added the default language so  that it is always present. If you don’t want a default language to be always present just remove the elseif part. Notice that you’ll have to add routes into the /:language/* scope to inject it.

If you now want to change the URL to something else by a simple click on a flag for example you can use a simple link like this to change it:

If you don’t want the language to be part of the URL but still detect the language somehow you can use the LocaleSelector dispatcher filter that will get it from the client. This is straight taken from the CakePHP book:

By using the LocaleSelectorFilter in your application, CakePHP will automatically set the locale based on the current user:


  • Pingback: CakePHP 3.0 i18n – language inside the UR...()

  • Mahdi El Masaoudi

    Thats not working because when you have an url like /fr/myroute . CakePHP generate an error of missing controller FrController.php . Do you have a solution for this secondry effect ?

    • burzum

      We’re running 30 domains with 18 languages with this solution and using the two character language prefix as well and it works just fine. Your routing is already not working because it doesn’t even get your language right.

  • Hi Burzum. This works perfectly, thank you. But this leads me to a new question, how do you handle this with custom prefix (i.e. to get: ?

    • burzum

      I never tried it with a prefix, we have no direct admin section but a complete backend application for our editors. User content is edited via a one-click session override and switch-back to the original editor account if they have to work with user permissions or their data. In theory just add /:language/:prefix/* to the route. I would have to try it myself but it’s just a matter of getting the route right.