Cakephp 3 routing with language parameter

Options, such as route element patterns, must be passed via the third argument of Router::connect(), the $options argument.

This route:

$routes->connect(
    '/:language/:controller',
    ['action' => 'index', 'language' => 'ar|de|en|fr'
]);

will catch your /foo/bar URL, it will match foo for the :language element, and bar for the :controller element. Basically the language key in the URL array will be treated as the default value, and it will always be overwritten by the :language element value.

The correct way of defining the route is:

$routes->connect(
    '/:language/:controller',
    ['action' => 'index'],
    ['language' => 'ar|de|en|fr']
);

The other routes need to be adapted accordingly.

See also Cookbook > Routing > Connecting Routes


The best way is using Routing scopes

<?php
$builder = function ($routes) {
    $routes->connect('/:action/*');
};
$scopes = function ($routes) use ($builder) {
    $routes->scope('/questions', ['controller' => 'Questions'], $builder);
    $routes->scope('/answers', ['controller' => 'Answers'], $builder);
};

$languages = ['en', 'es', 'pt'];
foreach ($languages as $lang) {
    Router::scope("/$lang", ['lang' => $lang], $scopes);
}

Router::addUrlFilter(function ($params, $request) {
    if ($request->param('lang')) {
        $params['lang'] = $request->param('lang');
    }
    return $params;
});

Code taken from:

https://github.com/steinkel/cakefest2015/blob/c3403729d7b97015a409c36cf85be9b0cc5c76ef/cakefest/config/routes.php