Blog de Norore
Geek en perdition dans un monde qui va trop vite

Codes en vrac : internationalisation sous Symfony

10 May 2018 - Norore
Une bulle de BD avec beaucoup de noms de langues en anglais.

Dans le cadre de mon travail, l’interface de l’application que je développe sera essentiellement utilisée par des francophones. Cependant, certains utilisateurs étant étrangers, il leur sera également proposé une traduction en anglais pour l’interface. Comme j’ai eu parfois des difficultés à comprendre comment résoudre certains points précis de la documentation, probablement dû au fait que je manquais d’exemple concret et d’une meilleure appréhension de l’internationalisation au sein du framework, je profite de mon blog pour mettre des portions de code que j’ai mis en place. Je présenterai succinctement le code, le but n’étant pas ici d’apprendre à développer sous Symfony, mais bien d’avoir du code clé-en-main pour se lancer plus facilement !

Activer l’internationalisation

Depuis la racine du projet Symfony, là où se trouvent le fichier composer.json et les répertoires app/, src/ et vendor/, il faut modifier le fichier app/config/config.yml :

# app/config/config.yml
parameters:
    locale: 'fr'
    app.locales: fr|en

framework:
    translator: { fallbacks: ['%locale%'] }
    default_locale: '%locale%'
  • parameters initialise les paramètres de l’application Symfony :
    • locale indique la langue locale utilisée par défaut par l’application ;
    • app.locales indique la liste des langues disponibles pour l’application.
  • framework définit les paramètres du framework :
    • translator initialise le moteur de traduction de Symfony en lui indiquant d’utiliser locale en fallback ;
    • default_locale définit la langue locale à utiliser par défaut, ici le français.

Traduction des pages

Les fichiers de traduction

Les fichiers de traduction peuvent être au format XLIF (XML), YAML ou PHP. Symfony recommande le format XLIF.

<!-- app/Resources/translations/messages.fr.xlf -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="fr" target-language="fr" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="titre.application">
                <source>titre.application</source>
                <target>Le titre de ma super application !</target>
            </trans-unit>
            <trans-unit id="titre.fiche.etudiant">
                <source>titre.fiche.etudiant</source>
                <target><![CDATA[Fiche de l'étudiant %prenom% %nom%]]></target>
            </trans-unit>
        </body>
    </file>
</xliff>

Il y a plusieurs types de fichiers possibles à créer :

  • messages.fr.xlf pour définir les différents messages affichés sur l’interface web ;
  • validator.fr.xlf pour définir les messages d’erreur lors de la soumission de formulaire.

Les fichiers de traductions peuvent être placés dans les répertoires suivants :

  • translations/
  • app/Resources/translations/
  • src/MonBundle/Resources/translations/
  • src/Resources/MonBundle/translations/

Pour pouvoir envoyer des résultats de variables aux traductions, il faut définir la traduction dans <![CDATA[]]>. Par convention, je définis les variables qui seront modifiées en les entourant de %.

Application dans le template

Pour traduire directement dans le template Twig, au niveau du code HTML :

<!-- src/MonBundle/Resources/view/index.html.twig -->
<h1>{{ 'titre.application'|trans }}</h1>
<h2>{{ 'titre.fiche.etudiant'|trans({'%nom%': etudiant.nom, '%prenom%': etudiant.prenom}) }}</h2>

Pour la traduction, on utilise simplement le filtre trans du moteur de template Twig. Pour envoyer les variables au moteur de traduction, on ajoute un tableau associatif (array) au filtre trans, avec pour clé la ou les variable(s) définie(s) dans le fichier de traduction, et en valeur son résultat attendu.

Pour afficher la traduction sur la page HTML après l’avoir mise à jour, côté client, avec JavaScript, il faut d’abord initialiser la variable souhaitée, et traduite, dans le template Twig :

<!-- src/MonBundle/Resources/view/formulaire_nouvel_etudiant.html.twig -->
{% set label_nom = 'label.etudiant.nom'|trans %}
{% set label_prenom = 'label.etudiant.prenom'|trans %}

<script type="text/javascript">
    document.getElementById('label_nom').src = '{{ label_nom }}';
    document.getElementById('label_prenom').src = '{{ label_prenom }}';
</script>

Application dans le formulaire

Pour appliquer la traduction dans un formulaire, il suffit de l’indiquer au niveau du label, par exemple :

# src/MonBundle/Form/NouvelEtudiantType.php
$builder->add('nom', null, [
                'label' => 'label.etudiant.nom',
            ])
        ->add('prenom', null, [
                'label' => 'label.etudiant.prenom',
            ])

Application dans le contrôleur

Si on a besoin d’afficher du texte depuis le contrôleur, comme créer un fichier PDF par exemple, il faut faire comme indiqué ci-dessous :

# src/MonBundle/Controller/EtudiantsController.php
$translator = $this->get('translator');
$translator->trans('titre.table.etudiants.nom', array(), 'messages', 'en');
$translator->trans('texte.table.etudiants.nom', array('%nom%' => $nom_etudiant), 'messages', 'en');

La fonction trans() attend 4 arguments :

  • la variable textuelle à utiliser ;
  • le tableau associatif associé à la variable ;
  • le fichier de traduction à utiliser, ici messages.langue.xlf ;
  • la langue à utiliser, ici l’anglais.

Pour en savoir plus :https://symfony.com/doc/current/components/translation/usage.html

Pouvoir modifier la langue de la page consultée

En voulant améliorer l’interface de mon application, je voulais pouvoir proposer à l’utilisateur de changer la langue de la page consultée sans qu’il soit pour autant obligé de repasser par la page d’accueil. Voici une portion de code, combinant le moteur de template Twig et le service Request :

<!-- app/Resources/view/base.html.twig -->
<a href="{{ path(
                 app.request.get('_route'),
                 app.request.get('_route_params')|merge({'_locale': 'en'})) 
}}">{{ 'texte.lien.changer.langue'|trans }}</a>

Comment ça marche ? Tout d’abord on indique à Twig que l’on veut accéder au service Request de l’application, via app.request, puis nous lui indiquons les clés à utiliser :

  • app.request.get(‘_route’) renvoie la route définie dans ‘_route’ ;
  • app.request.get(‘_route_params’) renvoie les paramètres de la route définis dans ‘_route_params’ ;
  • merge({‘_locale’: ‘en’}) écrase le paramètre de la variable ‘_locale’ définie par la requête en écrivant ‘en’ (anglais) à la place de ‘fr’ (français).

Et comme je veux construire le lien qui renvoie la page traduite en anglais, je précise à Twig de construire le chemin avec path.

Pfiou, ça commence à faire pas mal de petits bouts de code, et encore, je ne gère pas la pluralisation comme il le faudrait, je n’ai pas encore eu le temps de faire ça proprement pour l’instant :-) ! Peut-être que j’en parlerai dans un autre billet quand j’aurai eu le temps de m’y mettre ?


Source de l’image d’accroche : une bulle de BD avec beaucoup de noms de langues en anglais. Image par ryantbarnettusu, sous licence CC0 sur Pixabay