title: Localized routing in CakePHP: How to redirect to default language
body: <p>Since 2012, <a href="http://colorblindprogramming.com/multiple-languages-in-a-cakephp-2-application-in-5-steps" rel="noreferrer">this post</a> appears to be the most definitive resource on how to do localized routes in CakePHP (code copied below).</p>
  
  <p>It works great, with one exception: it doesn't redirect requests that are missing the language prefix. For example, <a href="http://example.com" rel="noreferrer">http://example.com</a> will show the same content as <a href="http://example.com/eng" rel="noreferrer">http://example.com/eng</a> (if English is the default language). And similarly, if it's not the homepage: <a href="http://example.com/foo/bar/" rel="noreferrer">http://example.com/foo/bar/</a> => <a href="http://example.com/eng/foo/bar" rel="noreferrer">http://example.com/eng/foo/bar</a>. There is some mention of this problem in the comments, but no conclusive solution, which is what I'm looking for.</p>
  
  <p>Code.</p>
  
  <pre><code>// Step 1: app/Config/routes.php
  Router::connect('/:language/:controller/:action/*',
                    array(),
                    array('language' =&gt; 'eng|fra'));
  
  Router::connect('/:language/:controller',
                    array('action' =&gt; 'index'),
                    array('language' =&gt; 'eng|fra'));  
  
  Router::connect('/:language',
                    array('controller' =&gt; 'welcome', 'action' =&gt; 'index'),
                    array('language' =&gt; 'eng|fra'));
  
  //Step 2: app/Config/core.php
  Configure::write('Config.language', 'eng');
  
  //Step 3: create app/View/Helper/MyHtmlHelper.php
  App::uses('HtmlHelper', 'View/Helper');
  class MyHtmlHelper extends HtmlHelper {
      public function url($url = null, $full = false) {
          if(!isset($url['language']) &amp;&amp; isset($this-&gt;params['language'])) {
            $url['language'] = $this-&gt;params['language'];
          }
          return parent::url($url, $full);
     }
  }
  
  //Step 4: app/Controller/AppController.php
  class AppController extends Controller {
      public $components = array('Cookie','Session');
      //set an alias for the newly created helper: Html&lt;-&gt;MyHtml
      public $helpers = array('Html' =&gt; array('className' =&gt; 'MyHtml'));
  
      public function beforeFilter() {
            $this-&gt;_setLanguage();
          }
  
      private function _setLanguage() {
      //if the cookie was previously set, and Config.language has not been set
      //write the Config.language with the value from the Cookie
          if ($this-&gt;Cookie-&gt;read('lang') &amp;&amp; !$this-&gt;Session-&gt;check('Config.language')) {
              $this-&gt;Session-&gt;write('Config.language', $this-&gt;Cookie-&gt;read('lang'));
          } 
          //if the user clicked the language URL 
          else if (   isset($this-&gt;params['language']) &amp;&amp; 
          ($this-&gt;params['language'] !=  $this-&gt;Session-&gt;read('Config.language'))
                  ) {
              //then update the value in Session and the one in Cookie
              $this-&gt;Session-&gt;write('Config.language', $this-&gt;params['language']);
              $this-&gt;Cookie-&gt;write('lang', $this-&gt;params['language'], false, '20 days');
          }
      }
  
      //override redirect
      public function redirect( $url, $status = NULL, $exit = true ) {
          if (!isset($url['language']) &amp;&amp; $this-&gt;Session-&gt;check('Config.language')) {
              $url['language'] = $this-&gt;Session-&gt;read('Config.language');
          }
          parent::redirect($url,$status,$exit);
      }
  }
  
  //add the links to the languages:
  //Step 5: app/View/...
  echo $this-&gt;Html-&gt;link('English', array('language'=&gt;'eng')); 
  echo $this-&gt;Html-&gt;link('Français', array('language'=&gt;'fra')); 
  </code></pre>
  
  <p><strong>UPDATE 1</strong></p>
  
  <p>I tried the suggestion by user221931, but it doesn't seem to work. Here is what I added to my routes:</p>
  
  <pre><code>/* Add default language param */
  Router::redirect('/:controller/:action/*', 
                      array('language' =&gt; 'fra'), 
                      array('persist' =&gt; false) );
  Router::redirect('/:controller/', 
                      array('language' =&gt; 'fra'), 
                      array('persist' =&gt; false) );
  Router::redirect('/', 
                      array('controller'=&gt;'pages', 'action'=&gt;'display', 'language' =&gt; 'fra', 'home'), 
                      array('persist' =&gt; false) );
  </code></pre>
  
  <p>It seems to have no effect. The following URLs are <em>not</em> redirected: http:example.com/, <a href="http://example.com/controller/" rel="noreferrer">http://example.com/controller/</a>, <a href="http://example.com/controller/action/" rel="noreferrer">http://example.com/controller/action/</a></p>
  
  <p><strong>UPDATE 2</strong>
  As requested, here is my <em>complete</em> routes file:</p>
  
  <pre><code>&lt;?php
  /**
   * Routes configuration
   *
   * In this file, you set up routes to your controllers and their actions.
   * Routes are very important mechanism that allows you to freely connect
   * different URLs to chosen controllers and their actions (functions).
   *
   * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
   * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
   *
   * Licensed under The MIT License
   * For full copyright and license information, please see the LICENSE.txt
   * Redistributions of files must retain the above copyright notice.
   *
   * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
   * @link          http://cakephp.org CakePHP(tm) Project
   * @package       app.Config
   * @since         CakePHP(tm) v 0.2.9
   * @license       http://www.opensource.org/licenses/mit-license.php MIT License
   */
  
  #http://book.cakephp.org/2.0/en/views/json-and-xml-views.html
  Router::parseExtensions('json');
  
  /**
   * Here, we are connecting '/' (base path) to controller called 'Pages',
   * its action called 'display', and we pass a param to select the view file
   * to use (in this case, /app/View/Pages/home.ctp)...
   */
      Router::connect('/', array('controller' =&gt; 'pages', 'action' =&gt; 'display', 'home'));
  /**
   * ...and connect the rest of 'Pages' controller's URLs.
   */
      Router::connect('/pages/*', array('controller' =&gt; 'pages', 'action' =&gt; 'display'));
  
  
  /**
   * LOCALIZED URLs
   * See: http://colorblindprogramming.com/multiple-languages-in-a-cakephp-2-application-in-5-steps
   */
  Router::connect('/:language/:controller/:action/*',
                         array(),
                         array('language' =&gt; 'eng|fra'));
  
  Router::connect('/:language/:controller',
                     array('action' =&gt; 'index'),
                     array('language' =&gt; 'eng|fra')); 
  
  Router::connect('/:language',
                     array('controller' =&gt; 'pages', 'action' =&gt; 'display', 'home'),
                     array('language' =&gt; 'eng|fra'));
  
  # prevent routing conflicts with plugins...
  # http://www.omaroid.com/cakephp-locale-language-routing/
  // make an array of loaded plugins
  $loaded = CakePlugin::loaded();
  array_walk($loaded, function(&amp;$item,$key){
      $item = Inflector::underscore($item);
  });
  $loaded = implode('|', $loaded);
  
  Router::connect('/:language/:plugin/:controller/:action/*', 
                      array(), 
                      array('language' =&gt; 'eng|fra','plugin' =&gt; "($loaded)"));
  
  /* HIDE /index */
  //Router::connect('/:controller/', array('action'=&gt;'index') );
  Router::connect('/:language/:controller/', array('action'=&gt;'index') );
  
  /**
   * Load all plugin routes. See the CakePlugin documentation on
   * how to customize the loading of plugin routes.
   */
      CakePlugin::routes();
  
  /**
   * Load the CakePHP default routes. Only remove this if you do not want to use
   * the built-in default routes.
   */
      require CAKE . 'Config' . DS . 'routes.php';
  </code></pre>