Adding a prefix to every URL in CakePHP

What's the cleanest way to add a prefix to every URL in CakePHP, like a language parameter?

http://example.com/en/controller/action
http://example.com/ru/admin/controller/action

It needs to work with "real" prefixes like admin, and ideally the bare URL /controller/action could be redirected to /DEFAULT-LANGUAGE/controller/action.

It's working in a retro-fitted application for me now, but it was kind of a hack, and I need to include the language parameter by hand in most links, which is not good.

So the question is twofold:

  • What's the best way to structure Routes, so the language parameter is implicitly included by default without having to be specified for each newly defined Route?
    • Router::connect('/:controller/:action/*', ...) should implicitly include the prefix.
    • The parameter should be available in $this->params['lang'] or somewhere similar to be evaluated in AppController::beforeFilter().
  • How to get Router::url() to automatically include the prefix in the URL, if not explicitly specified?
    • Router::url(array('controller' => 'foo', 'action' => 'bar')) should return /en/foo/bar
    • Since Controller::redirect(), Form::create() or even Router::url() directly need to have the same behavior, overriding every single function is not really an option. Html::image() for instance should produce a prefix-less URL though.


The following methods seem to call Router::url.

  • Controller::redirect
  • Controller::flash
  • Dispatcher::__extractParams via Object::requestAction
  • Helper::url
  • JsHelper::load_
  • JsHelper::redirect_
  • View::uuid, but only for a hash generation

Out of those it seems the Controller and Helper methods would need to be overridden, I could live without the JsHelper. My idea would be to write a general function in AppController or maybe just in bootstrap.php to handle the parameter insertion. The overridden Controller and Helper methods would use this function, as would I if I wanted to manually call Router::url. Would this be sufficient?