Date de première publication : 2012/05/21
Objectif et contexte
L'objectif de cet exercice est de compléter le petit jeu de devinette d'un nombre en introduisant l'internationalisation
Traductions et configuration
S'il existe plusieurs techniques pour le faire, nous allons "internationaliser" le site en proposant les traductions en ressource, dans des "bundles". Une seule différence notable avec les ressources classiques : elles ne se trouvent pas dans le répertoire habituel.
Fichiers contenant les traductions
- (M) New file > other > Properties file
- Nom : src/java/.../messages (le nom que vous voulez mais le répertoire est important)
# commentaire : fichier clé=valeur
phrase.bienvenue=Bonjour, je pense à un nombre entre 1 \
et 100. Pouvez-vous le deviner ?
phrase.petit=est trop petit !
phrase.grand=est trop grand.
phrase.fin=Bravo, vous avez trouvé ! On rejoue ?
bouton = Tester
Sauvegarder le fichier sous messages_en.properties
et ouvrir ce nouveau fichier. Il apparait alors une interface comparative assez sympa pour traduire les éléments que l'on a retenu.
phrase.bienvenue=Hello, I chose a number between 1 \
and 100. Can you find it ?
phrase.petit=is to small
phrase.grand=is too big
phrase.fin=Congrats, you found it ! Do we play again ?
bouton=Test
Configuration
Il faut maintenant configurer l'application pour utiliser ces fichiers de traduction. Pour cela, il faut créer un fichier faces-config.xml
. la méthode la plus rapide, hormis le copier-coller, est de passer par l'assistant :
- (M) New file > JavaServer Faces > JSF Faces configuration
- Nom : faces-config
C'est un fichier bien pratique qui peut également contenir les flux entre les pages (création graphique) mais revenons à la traduction et ajoutons cela :
<application>
<resource-bundle>
<base-name>messages</base-name>
<var>bundle</var>
</resource-bundle>
<locale-config>
<default-locale>fr</default-locale>
<supported-locale>en</supported-locale>
</locale-config>
</application>
<base-name>
est le nom du fichier sans extension avec le chemin relatif par rapport au répertoire src/java
Traduire
Le bouton
On va tout d'abord proposer la traduction pour le bouton :
<h:commandButton value ="#{bundle.bouton}"
action="#{loicBean.comparer()}" />
L'affichage de la langue dépend des préférences de votre navigateur, ce qui peut donc se changer pour tester. Par exemple, sous Firefox, cela se fait par là :
(M) Tools > Options > (O) Content > Languages > (B) Choose
C'est chouette, non ?
Si vous n'avez pas le courage de configurer votre navigateur, on peut également changer la langue de manière statique. Le tutoriel Java EE 6 propose utiliser la balise <fmt:setLocale value="fr">
de l'espace de nommage xmlns:fmt="http://java.sun.com/jstl/fmt"
. Cette partie de la bibilothèque JSTL n'est pas compatible avec Facelets. En revanche, on peut changer la locale avec :
<f:view locale="fr_FR" />
La phrase
On va maintenant passer à la traduction de la phrase. Il faut tout d'abord accéder au "bundle", ce que fait le code suivant :
ResourceBundle bundle = ResourceBundle.getBundle("messages",
FacesContext.getCurrentInstance().getViewRoot().getLocale());
Il faut donner le nom du fichier avec son chemin (basename) et non pas la variable définie dans le fichier de configuration. Le bundle ne contient que les chaines traduites pour la locale donnée.
Pour obtenir une traduction, il faut alors interroger le bundle :
phrase = bundle.getString("phrase.bienvenue");
Nous devons résoudre une difficulté supplémentaire avec notre application qui vient du fait que l'on s'est limité à une seule page pour tout afficher. Il faut maintenant prendre en compte que la phrase qui change en fonction du contexte, change également lors d'un changement de locale.
Je propose de changer la signification de l'attribut phrase
du bean managé et d'adapter le getter qui est appelé lors d'une instruction comme celle-ci (oui, c'est bien le getter qui est appelé et non l'attribut directement) :
<h:outputText value="#{loicBean.phrase}" escape="false" />
Je propose de place dans phrase
une des clés du fichier de traduction et on délègue à getPhrase()
la traduction dans la bonne locale.
Changer la langue d'affichage par l'utilisateur
Pour changer la langue de notre application, nous allons afficher deux petits drapeaux ( et ) représentant les langues disponibles. Les images sont évidemment à copier dans le répertoire des ressources. Ces drapeaux seront des liens vers le changement de locale. On impose alors la locale dans le document avec <h:view>
Du côté du fichier xhtml, il faut créer un nouveau formulaire et mettre ce genre de chose :
<h:commandLink action="#{loicBean.setLocale('FR')}">
<h:graphicImage library="images" name="fr.gif" alt="Français" />
</h:commandLink>
Bien entendu, cela suppose que l'on ajoute une nouvelle méthode au bean qui change la locale. Vous savez le faire, vous avez été capable de récupérer la locale ! On peut également modifier l'attribut lang
de la balise html
pour donner la langue.
public String setLocale(String lang) {
locale = new Locale(lang);
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
return "index";
}
Est-ce que vous avez remarqué que même les messages d'erreur à la validation par exemple sont également traduits ?
La dernière chose que je vous propose est de modifer les balises <h:commandLink>
que l'on vient d'ajouter pour n'afficher que la langue qui n'est pas utilisée avec l'attribut rendered
et EL.
<h:commandLink action="#{loicBean.setLocale('EN')}"
rendered='#{loicBean.locale ne "en"}'>
Et voilà, c'en est fini pour cet exercice/tuto !
Si ce que l'on a fait dans cette dernière partie ne vous plait pas, voilà une alternative au choix de la langue avec une boîte de sélection et un listener.
Éléments de correction
Si vous êtes bloqués, je préfère que vous me demandiez de vous aider.
Si vous voulez comparer avec ce que vous avez fait, voilà des éléments de correction :
Vous êtes sûr ? C'est ici