CakePHP multilingual static pages

1.2k views Asked by At

I have created a multilingual application in CakePHP 2 I want to include some static content in different languages and I'm having trouble setting up the routing.

I have it working for language/controller/action type routes but if I want to have static content how do I route the PagesController to views in View/Pages/membership.ctp for the default language English and View/fr/Pages/abonnement.ctp for the french translation so that the url will be just /membership or /fr/abonnement? And what is the best way to relate the translations to each other so the language switching links will work and reverse routing will work properly?

I have the following routes already

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

Router::connect('/:language',
                   array('controller' => 'pages', 'action' => 'display', 'home'),
                   array('language' => 'en|fr', 'persist'=>array('language')));

Router::connect('/:language/:controller',
                   array('action' => 'index'),
                   array('language' => 'en|fr', 'persist'=>array('language')));

Router::connect('/:language/:controller/:action/*',
                   array(),
                   array('language' => 'en|fr', 'persist'=>array('language')));

the _setLanguage() method called from AppController's beforeFilter()

protected 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->Cookie->read('lang') && !$this->Session->check('Config.language')) {
      $this->Session->write('Config.language', $this->Cookie->read('lang'));
    }
    //if the user clicked the language URL
    else if ( isset($this->params['language']) && ($this->params['language'] !=  $this->Session->read('Config.language'))) {
        // get the correct language code
        $languageCodeEquivalencies = array(
            'fr'=>'fra',
            'en'=>'eng'
        );
        $languageCode = $this->params['language'];
        if(in_array($languageCode, array_keys($languageCodeEquivalencies))) {
            $languageCode = $languageCodeEquivalencies[$languageCode];
        }
      //then update the value in Session and the one in Cookie
      $this->Session->write('Config.language', $languageCode);
      $this->Cookie->write('lang', $languageCode, false, '20 days');
    }
    //ensure that both I18n and TranslateBehavior access the same language value.
    if ($this->Session->check('Config.language')) {
        Configure::write('Config.language', $this->Session->read('Config.language'));
    }
}

and my language switching links look like this

if($this->Session->read('Config.language') == 'fra'):
    echo $this->Html->link('English', array_merge(array('language'=>'en'), $this->passedArgs));
else:
    echo $this->Html->link('Français', array_merge(array('language'=>'fr'), $this->passedArgs));
endif;
3

There are 3 answers

0
Devin Crossman On BEST ANSWER

Here's what I added to get it working...

Controller/AppController.php

public function beforeFilter() {
  ...
  // render language specific view if it exists
  $locale = Configure::read('Config.language');
  if ($locale && file_exists(APP . 'View' . DS . $locale . DS . $this->viewPath)) {
      // e.g. use /app/View/fra/Pages/tos.ctp instead of /app/View/Pages/tos.ctp
      $this->viewPath = $locale . DS . $this->viewPath;
  }
  ...
}

Config/routes.php

Router::connect('/fr/abonnement', array('language'=>'fr', 'controller' => 'pages', 'action' => 'display', 'membership'));
Router::connect('/en/membership', array('language'=>'en', 'controller' => 'pages', 'action' => 'display', 'membership'));

Which is working fine right now as I have a limited number of static pages and I only need to support two languages. I'm pretty sure manually setting up the routes for each language and static page will become too unwieldy after a decent number of pages. Let me know if you think of a better solution.

0
José Lorenzo Rodríguez On

I have a similar setup. This could be your display function in PagesController:

public function display($page) {
    return $this->render(implode('/', compact($this->request->language, 'page')));
}

That would map to the folder structure you are looking forward to have.

0
Dave On

Might be easiest to just use CakePHP Themes and have a "Theme" for each language. Then just set the theme whenever you're at a place where you know you need to use a static language-specific file.