Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 10-02-2011 16:38:38

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

[Tutoriel] Traductions routes

Bonjour,

Cela fait maintenant plusieurs jours que je me bat contre Zend pour faire marcher correctement la traduction des routes. La plupart des tutoriaux sur Internet ne contenant qu'une partie de ce que je voulais faire, j'ai mis un peu les mains dans le cambouis, et je vous propose le code ici, j'en suis sûr que ça en aidera certains.

Tout d'abord l'objectif : je souhaitais pouvoir tout traduire, des URL, du texte, Zend_Navigation... Les url devaient avoir la forme www.monsite.com/language/... Si aucune langue n'est spécifiée à l'accueil : www.monsite.com, le système doit choisir la langue du navigateur (par exemple français), et si la langue n'est pas supportée, revenir sur une langue de base (anglais dans mon cas).

Les routes devaient être traduites automatiquement, tout comme l'utilisation de Zend_Navigation.

La première chose à faire attention est de disposer de deux objets Zend_Translate différents. La raison est que la traduciton des routes ne fonctionne pas tout à fait. Ainsi "about" se traduirait normalement "a propos", sauf que dans le cas des routes il faudra le traduire par "a-propos" pour qu'il y ait la correspondance entre la traduction et le nom de l'action.

Bootstrap

Au niveau du bootstrap, rien à déclarer.

Fichier de configuration

La, il y a un peu plus. On va tout d'abord ajouter la ligne pour créer une locale (avec comme valeur par défaut : en) - (j'utilise YAML comme fichiers de configuration, pensez à le changer si vous utilisez les fichiers .ini) :

Code:

locale:
  default = en;

ainsi qu'une ressource translate :

Code:

translate:
      adapter: gettext
      content: APPLICATION_PATH/configs/lang
      disableNotices: true
      scan: filename

Les routes personnalisées :

Code:

router:
      routes:
        languageRoute:
          type: Zend_Controller_Router_Route
          route: :lang/
          reqs:
            lang: ^(en|fr)
          defaults:
            module: default
            controller: index
            action: index
        controllerRoute:
          type: Zend_Controller_Router_Route
          route: :lang/:@controller/*
          defaults:
            module: default
            action: index
        controllerActionRoute:
          type: Zend_Controller_Router_Route
          route: :lang/:@controller/:@action/*
          defaults:
            module: default
        moduleControllerActionRoute:
          type: Zend_Controller_Router_Route
          route: :lang/:@module/:@controller/:@action/*

Dans mon cas, mes fichiers de traduction sont stockés dans le dossier configs/lang, et la recherche se fait par le nom de fichier (j'ai donc un fichier fr.po et en.po).


J'ajoute également un plugin au front controller :

Code:

frontController:
      plugins:
        LangSelector: Zund_Controller_Plugin_LangSelector

Plugin

Le plugin fait l'intégralité du boulot. Le principal soucis que j'ai rencontré, c'est que la fonction routeStartup est trop tôt, tandis que la fonction routeShutdown est trop tard (elle est appelée après que la requête ait été décomposé), et donc la traduction ne se fait pas.

L'idée, c'était donc de définir la locale et de l'attribuer aux différents éléments utilisant la traduction (mes deux Zend_Translate et Zend_Navigation) directement dans le routeStartup.

Voici donc la fonction routeStartup :

Code:

public function routeStartup(Zend_Controller_Request_Abstract $request)
        {
            $locale = Zend_Registry::get('Zend_Locale');
            $translate = Zend_Registry::get('Zend_Translate');

            if (substr($request->getRequestUri(), 0, -1) == $request->getBaseUrl())
            {
                if ($translate->isAvailable($locale->getLanguage()))
                    $request->setParam('lang', $locale->getLanguage());
                else
                    $request->setParam('lang', 'en');
            }
            else
            {
                $lang = substr($request->getRequestUri(), 1, 2);

                if ($translate->isAvailable($lang))
                    $request->setParam('lang', $lang);
                else
                    $request->setParam('lang', 'en');
            }

            // Make the lang parameter global so we don't have to specify it every time
            Zend_Controller_Front::getInstance()->getRouter()->setGlobalParam('lang', $request->getParam('lang'));

            // We change the locale if it is different from the valid language selected
            if ($request->getParam('lang') !== $locale->getLanguage())
                $locale->setLocale($request->getParam('lang'));

            // And init a lot of stuff !
            $this->_initGenericTranslator();
            $this->_initRouteTranslator();
            $this->_initNavigation();
        }

On rentre dans le premier if lorsque l'utilisateur n'a pas donné de paramètre lang (que dans la page d'accueil, après dans les autres pages, si on ne spécifie pas de locale dans l'url cela renvoie une erreur 404).

On récupère la locale (qui a été calculée automatiquement par Zend), et si cette langue est disponible, on rajoute le paramètre "lang" à la requête, autrement on ajoute la langue par défaut.

Sinon, c'est qu'une langue a été donnée. On la récupère avec un substr sur l'URI, et pareil, on vérifie si elle est valide.

La ligne suivante permet de donner ce paramètre à la route de manière globale. Cela permet d'éviter de spécifier l'attribut lang lorsque l'on créé des url.

La condition en dessous est utile dans le cas ou la locale calculée automatiquement et la langue trouvée ne correspondent pas. Par exemple, si un espagnol tombe sur la page, sa locale ('es_ES') sera différente de la langue ('en'), il faut donc remplacer sa locale par ('en'), ce qui est logique puisque la locale est utilisée également dans les autres composants comme Zend_Date, ce serait pas très logique de voir une date formatée pour un espagnol alors que le reste du site est en anglais ^^.

Les trois appels à la fin de la fonction sont définis ainsi :

Code:

/**
         * Init the generic translator
         *
         * @return void
         */
        protected function _initGenericTranslator()
        {
            Zend_Registry::get('Zend_Translate')->setLocale(Zend_Registry::get('Zend_Locale'));
        }

        /**
         * Init the route translator
         *
         * @return void
         */
        protected function _initRouteTranslator()
        {            
            $routeTranslator = new Zend_Translate(array('adapter' => 'csv',
                                                        'content' => APPLICATION_PATH . '/configs/lang/routes/',
                                                        'disableNotices' => true,
                                                        'scan' => Zend_Translate::LOCALE_FILENAME));

            Zend_Controller_Router_Route::setDefaultTranslator($routeTranslator);
        }

        /**
         * Init the navigation
         *
         * @return void
         */
        protected function _initNavigation()
        {
            $view = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('View');

            $config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml', 'nav');
            $navigation = new Zend_Navigation($config);

            $view->navigation($navigation)
                 ->setTranslator(Zend_Registry::get('Zend_Translate'));
        }

En fait, dans ces fonctions, on se contente surtout d'attribuer la nouvelle locale aux différents éléments qui l'utilise.


Bref, avec tout ça mis en place, les labels de la navigation, les URL, les mots... tout sera correctement traduit (pour peu que vous remplissiez les différents fichiers de traduction), éivdemment.

J'avoue que c'est presque un petit peu magique de voir comment tout fonctionne wink.

Hors ligne

 

#2 11-02-2011 10:46:20

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: [Tutoriel] Traductions routes

J'ai un peu simplifié le code (en bougeant certaines parties qui avaient plus leur place dans le bootstrap). En tout cas la documentation sur ce point est assez peu précise. J'ai vu notamment que, pour ceux qui souhaitent localiser SANS PASSER de paramètre de langue dans l'URL, peuvent la transmettre au routeur en donnant une variable nommée "@locale". Celle-ci sera automatiquement récupérée par le routeur et sera utilisée comme locale de traduction.

Voici le code (le plugin ne contient maintenant que le code de sélection de la langue) :

Code:

class Zund_Controller_Plugin_LangSelector extends Zend_Controller_Plugin_Abstract
    {
        /**
         * Set a valid language if there isn't one (default : 'en')
         *
         * @param Zend_Controller_Request_Abstract $request
         * @return void
         */
        public function routeStartup(Zend_Controller_Request_Abstract $request)
        {
            $locale = Zend_Registry::get('Zend_Locale');
            $translate = Zend_Registry::get('Zend_Translate');

            if (substr($request->getRequestUri(), 0, -1) == $request->getBaseUrl())
            {
                if ($translate->isAvailable($locale->getLanguage()))
                    $request->setParam('lang', $locale->getLanguage());
                else
                    $request->setParam('lang', 'en');
            }
            else
            {
                $lang = strtok($request->getRequestUri(), '/');
                
                if ($translate->isAvailable($lang))
                    $request->setParam('lang', $lang);
                else
                    $request->setParam('lang', 'en');
            }

            if ($locale !== $request->getParam('lang'))
                $locale->setLocale($request->getParam('lang'));

            Zend_Controller_Front::getInstance()->getRouter()->setGlobalParam('lang', $locale->getLanguage());
            Zend_Controller_Router_Route::getDefaultTranslator()->setLocale($locale);
            $translate->setLocale($locale);
        }
    }

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages