Development

Documentation/fr_FR/book/1.2/13-I18n-and-L10n

You must first sign up to be able to contribute.

Version 6 (modified by Elianel, 9 years ago)
--

Cette page fait partie de la traduction en français de la documentation de Symfony. Il s'agit d'une version traduite qui peut comporter des erreurs. La seule version officielle est la version en anglais.

  • Traduction : PAVEL Aurélien
  • Date de traduction : 18 Décembre 2008
  • Date de dernière modification : 18 Décembre 2008

Chapitre 13 - I18n et L10n

Si vous avez déjà développé une application dont l'interface est en plusieurs langues, vous savez combien les traductions, la localisation des différents contenus peuvent rapidement tourner au cauchemard. Symfony gère tous ces aspects nativement.

Les développeurs font souvent référence au terme internationalisation par le raccourci i18n (vous pouvez comptez le nombre de lettres pour en comprendre la raison). De même ils font référence à la localisation par son raccourci l10n. Internationalisation et localisation couvrent deux aspects différents pour un site multilingues.

Une application multilingues contient plusieurs versions du même contenu dans différentes langues ou format. Par exemple, un webmail fournit les mêmes fonctionnalités dans plusieurs langues, seul l'interface change.

Une application localisée affiche des informations différentes suivant le pays de l'internaute. Par exemple, pour un portail d'actualités, quelqu'un habitant aux États-unis vera les dernières nouvelles américaines, alors que quelqu'un habitant en France vera les dernières nouvelles françaises. Une application localisée présente une interface dans la langue de celui qui la regarde mais peut aussi présenter un contenu spécifique.

Pour résumé, une application internationalisée et localisée doit gérer :

  • la traduction des textes (interface, images, et contentu)
  • les différents formats et notations (dates, nombres, monnaie, etc)
  • les contenus localisés (plusieurs versions d'un objet en fonction du pays)

Ce chapitre va nous montrer la façon dont symfony gère tous ces aspects et comment on peut l'utiliser pour créer des applications internationalisées et localisées.

Culture de l'utilisateur

Toutes les fonctionalités d'internationalisation de symfony sont basées sur une variable de session utilisateur appelé culture. La culture est la combinaison de la langue et du pays de l'utilisateur. Elle détermine la façon dont sont affichées les textes et les informations dépendant de la culture. La culture est une variable de session, elle est donc conservée de pages en pages.

Configurer la culture par défaut

Par défaut, la culture d'un nouveau visiteur est default_culture. Vous pouvez changer cette valeur dans le fichier de configuration i18n.yml, comme montré sur le Listing 13-1.

Listing 13-1 - Positionner la culture par défaut, dans myapp/config/i18n.yml

all: 
  default_culture:     fr_FR

NOTE Pendant la phase de développement, ne soyez pas surpris si un changement de la culture dans le fichier i18n.yml ne change pas la culture dans le navigateur. Cette persistance est dû au fait que la culture est présente dans la session utilisateur. Si vous voulez que votre changement soit effectif, supprimer le cookie de session ou redémarrez votre navigateur.

Garder à l'esprit que la langue et le pays sont nécessaires, vous pouvez avoir des traductions françaises différentes pour des français, des belges ou des québécois et de même vous pouvez avoir des traductions espagnoles différentes pour des espagnols ou des méxicains. Le langage est codé sur deux caractères, en accord avec la norme ISO 639-1 (par exemple fr pour français). Le pays est codé sur deux caractères en majuscules en accord avec la norme ISO 3166-1 (par exemple FR pour des français de France).

Changer la culture d'un utilisateur

Vous pouvez changer la culture d'un utilisateur - par exemple si l'utilisateur décide de passer de la version en anglais à la version en français. -, ou par exemple quand un utilisateur se connecte et que l'on veut utiliser la langue de son navigateur. Pour faciliter ces changements, la classe sfUser fournit des accesseurs à la culture de l'utilisateur. Le listing 13-2 montre comment utiliser ces méthodes dans une action.

Listing 13-2 - Setting and Retrieving the Culture in an Action [php] // Culture setter $this->getUser()->setCulture('en_US');

// Culture getter
$culture = $this->getUser()->getCulture();
 => en_US

SIDEBAR Gestion de la culture dans l'URL

Quand vous utilisez la localisation et l'internationalisation dans symfony, vos pages ont des versions différentes pour une même URL. Cela vous empêche de mettre en cache vos pages et cela empêche un robot d'indexer vos pages de manière correcte.

La solution est d'ajouter la culture dans toutes vos URL. Ainsi toutes les pages traduites ont des URL différentes. Pour faire cela, il suffit d'ajouter le paramètre :sf_culture dans toutes les règles du fichier routing.yml de votre application.

page: 
  url: /:sf_culture/:page 
  requirements: { sf_culture: (?:fr|en|de) } 
  params: ... 

article: 
  url: /:sf_culture/:year/:month/:day/:slug 
  requirements: { sf_culture: (?:fr|en|de) } 
  params: ...

Pour éviter d'ajouter manuellement le paramètre sf_culture à chaque utilisation de la fonction link_to(), symfony ajoute automatiquement la culture aux paramètres des routes pas défaut. Le mécanisme fonctionne dans l'autre sens : symfony change automatiquement la culture de l'utilisateur si le paramètre sf_culture est trouvé dans l'URL.

Determiner la culture automatiquement

Dans de nombreuses applications, la culture est définie à la première requête, en se basant sur les préférences du navigateur. Les utilisateurs peuvent définir une liste de langues acceptées dans leur navigateur. Ces informations sont envoyées au serveur à chaque requête, dans l'entête HTTP Accept-Language. Dans symfony, vous pouvez récupérer ces informations à travers l'objet sfRequest. Par exemple, pour récupérer la liste des langues acceptées, dans une action, faîtes ceci :

 [php]
 $languages = $this->getRequest()->getLanguages();

Les entêtes HTTP sont en fait une chaîne de caractères mais symfony analyse automatiquement cette chaîne et la transforme en tableau. Ainsi la langue préférée de l'utilisateur est accessible par $languages[0] dans l'exemple précédent.

Ainsi on peut positionner de manière automatique la culture de l'utilisateur dans l'application en se basant sur la langue préférée de son navigateur. On peut faire cela sur la page d'accueil ou au moyen d'un filtre dans toutes les pages. Mais comme votre site ne support surement qu'un nombre limité de langues, il est préférable d'utiliser la fonction getPreferredCulture(). Cela renvoie la langue la plus probable en comparant les langues préférées et les langues supportées.

 [php]
 $language = $request->getPreferredCulture(array('en', 'fr')); // le site est disponible en Anglais et Français

Si il n'y a pas de correspondance, la fonction renvoie le première langue supporté ( en dans l'exemple précédent).

CAUTION L'entete HTTP Accept-Language n'est pas une information très fiable car les utilisateur ne savent que rarement ou modifier ce paramètre dans leur navigateur. La plupart du temps, la langue préféré du navigateur est la langue de sont interface, or ils ne sont pas traduit dans toutes les langues. Si vous décidez de définir automatiquement la culture en fonction de la langue préféré du navigateur, assurez vous de fournir un moyen pour l'utilisateur puisse choisir une autre langue.

Standards et Formats

Les fonctionnement interne d'une application web ne dépendent pas d'une culture en particulier. Les bases de données, par exemple, utilisent un standard international pour stocker les dates, nombres et autres. Lorsque qu'une donnée est envoyé ou récupéré pas l'utilisateur, une conversion doit être faite. Un utilisateur de comprendrais pas un timestamps et il préfére redéfinir la langue maternelle en tant que Français plutôt que French. Vous aurez donc besoin d'une assistance pour faire la conversion automatiquement, basé sur la culture.

Écrire les données dans la culture de l'utilisateur

Une fois que la culture est défini, les helpers en dépendant aurons automatiquement la bonne sortie. Par exemple, l'helpers format_number() affiche automatiquement un nombre dans un format familier a l'utilisateur en fonction de sa culture, comme montré dans l'exemple 13-3 :

Listing 13-3 - Displaying a Number for the User's Culture

 [php]
 <?php use_helper('Number') ?>

 <?php $sf_user->setCulture('en_US') ?>
 <?php echo format_number(12000.10) ?>
  => '12,000.10'

 <?php $sf_user->setCulture('fr_FR') ?>
 <?php echo format_number(12000.10) ?>
  => '12 000,10'

Vous n'avez pas besoin de precicer la culture aux helpers, ils vont elles même regarder dans l'objet session courant. Le listing 13-4 liste les helpers qui prennent en compte la culture de l'utilisateur pour leur affichage.

Listing 13-4 - Culture-Dependent Helpers

 [php]
 <?php use_helper('Date') ?>

 <?php echo format_date(time()) ?>
  => '9/14/06'

 <?php echo format_datetime(time()) ?>
  => 'September 14, 2006 6:11:07 PM CEST'

 <?php use_helper('Number') ?>

 <?php echo format_number(12000.10) ?>
  => '12,000.10'

 <?php echo format_currency(1350, 'USD') ?>
  => '$1,350.00'

 <?php use_helper('I18N') ?>

 <?php echo format_country('US') ?>
  => 'United States'

 <?php format_language('en') ?>
  => 'English'

 <?php use_helper('Form') ?>

 <?php echo input_date_tag('birth_date', mktime(0, 0, 0, 9, 14, 2006)) ?>
  => input type="text" name="birth_date" id="birth_date" value="9/14/06" size="11" />

 <?php echo select_country_tag('country', 'US') ?>
  => <select name="country" id="country"><option value="AF">Afghanistan</option>
       ...
       <option value="GB">United Kingdom</option>
       <option value="US" selected="selected">United States</option>
       <option value="UM">United States Minor Outlying Islands</option>
       <option value="UY">Uruguay</option>
       ...
     </select>

L'helper de date accepte un paramètre pour forcer un affichage ne dépendant pas de la culture, mais vous ne devriez pas l'utiliser si votre application est internationalisé.

Recevoir des données depuis un champs localisé

Si il est nécessaire de montrer les information en fonction de la culture de l'utilisateur, de même que pour les récupérer, vous devez, le plus possible pousser vos utilisateurs a rentrer des données internationalisées. De cette façon vous évitez de d'essayer de trouver commnent convertir les données avec différents formats et des localisation incertaines. Par exemple, qui penserais a inséré une somme avec une virgule dans un champs ?

Vous pouvez encadrer le format des entrées de l'utilisateur en cachant les données actuel (comme avec select_coutry_tag()) ou en séparant les différents morceaux d'un données complexe en plusieurs petit données.

Pour les dates par contre ce n'est pas souvent possible. Les utilisateurs sont habitué a les écrire dans le format de leur culture, et vous devez être capable de convertir de tel données dans un format interne (et international). C'est ici que la classe sfI18N s'applique. Le listing 13-5 montre comment utiliser cette classe.

Listing 13-5 - Getting a Date from a Localized Format in an Action

 [php]
 $date= $request->getParameter('birth_date');
 $user_culture = $this->getUser()->getCulture();

 // Récupérer un timestamp
 $timestamp = $this->getContext()->getI18N()->getTimestampForCulture($date, $user_culture);

 // Récupérer une date structuré
 list($d, $m, $y) = $this->getContext()->getI18N()->getDateForCulture($date, $user_culture);

Information dans la base de donnée

Une application localisé offre un contenu différent suivant le culture de l'utilisateur. Par exemple, un magasin en ligne peut vendre ses produit au même prix a travers le monde, mais fournir une description localisé pour chaque pays. Cela signifie que la base de donnée doit pouvoir stocker différente version d'une même information, pour cela vous devez concevoir votre schéma d'une façon particulière et utiliser la culture chaque fois que vous voulez une information localisé.

Création du schéma localisé

Chaque table contenant des données a localisé doit être découpé en deux parties : une table qui ne contient pas de colonne i18n et une autre qui ne contient que les donnée localisé. Ces deux table sont liées par une relation un-a-plusieurs. Cette configuration nous permet d'ajouter d'autre langues sans changer le model. Prenons comme exemple une table product.

Listing 13-6 - Sample Schema for i18n Data, in config/schema.yml

 [YML]
 my_connection:
   my_product:
     _attributes: { phpName: Product, isI18N: true, i18nTable: my_product_i18n }
     id:          { type: integer, required: true, primaryKey: true, autoincrement: true }
     price:       { type: float }

   my_product_i18n:
     _attributes: { phpName: ProductI18n }
     id:          { type: integer, required: true, primaryKey: true, foreignTable: my_product, foreignReference: id }
     culture:     { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true }
     name:        { type: varchar, size: 50 }

Remarquez les attributs isI18N et i18nTable dans la première table et la colonne culture dans la seconde. Ce sont des amélioration Propel spécifique a symfony.

Les automatisme de symfony le rende plus rapide a écrire. Si la table qui contient les données internationalisé a le même nom que la table principale avec le suffix _i18n et qu'elles sont associé au travers d'une colonne nommé id, vous pouvez omettre les colonne id et culture dans la table i18n ainsi que les attributs spécifique de la table principale, symfony va les déduire. Cela signifie que symfony verra le schéma du Listing 13-7 de la même façon que celui du Listing 13-6.

Listing 13-7 - Sample Schema for i18n Data, Short Version, in config/schema.yml

 [YML]
 my_connection:
   my_product:
     _attributes: { phpName: Product }
     id:
     price:       float
   my_product_i18n:
     _attributes: { phpName: ProductI18n }
     name:        varchar(50)

Utiliser les objets i18n généré

Une fois que les objets correspondant au model ont été construit (n'oubliez pas d'appeler la tache propel:build-model apres chaque modification du fichier shema.yml), vous pouvez utiliser votre classe Product avec support de l'internationalisation comme si il n'y avait qu'une seule table, comme le montre le Listing 13-8.

Listing 13-8 - Dealing with i18n Objects

 [php]
 $product = ProductPeer::retrieveByPk(1);
 $product->setName('Nom du produit'); // Par défaut la culture est celle de l'utilisateur
 $product->save();

 echo $product->getName();
  => 'Nom du produit'

 $product->setName('Product name', 'en'); // change la valeur de la culture pour 'en'
 $product->save();

 echo $product->getName('en');
  => 'Product name'