Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Internationalisation de pages JSF

Liaison aux données dans vos formulaires JSF Définition d'un template pour vos facelets



Accès rapide :
Introduction
Activation de l'internationalisation dans votre application JSF
Définir des traductions par localisation
Injection des chaînes internationalisées dans la facelet
Changer les préférences de votre navigateur en termes de localisation
Formater vos données en fonction de la localisation
Formater vos valeurs numériques
Formater vos dates

Introduction

L'internationalisation d'un site web et de ses pages consiste en l'ajout de code permettant son affichage dans de multiples langues et en tenant compte de la localisation géographique de son utilisateur. Effectivement, on n'affiche pas de la même manière des données numériques, des dates ou des monnaies en fonction que l'on soit localisé dans un pays ou dans un autre.

le mot anglais « Internationalization » est complexe à écrire car constitué de 20 lettres. Les informaticiens préfèrent souvent utiliser le raccourci « i18n ». Les lettres i et n correspondent bien entendu à la première et à la dernière lettre du mot et 18 remplace les 18 lettres comprises entre le i et le n. De même, on utilise aussi souvent le terme « l10n » en lieu et place du mot anglais « Localization ».
Truc de Geek ;-)

Le Java SE propose déjà un certain nombre de possibilité en termes d'i18n : ces possibilités sont principalement localisées dans les packages java.util et java.text. JSF complète ces mécanismes avec des solutions adaptées à la mise en oeuvre de vos facelets.

Activation de l'internationalisation dans votre application JSF

La première étape consiste à activer l'internationalisation au sein du fichier de configuration JSF : le fichier WEB-INF/faces-config.xml. On doit notamment y lister l'ensemble de langues (voir des localisations) supportées par l'application ainsi que la configuration par défaut. Voici un exemple de code permettant l'activation du support de langues dans le fichier de configuration JSF (bloc <locale-config>).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                        http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
    version="2.3">

    <navigation-rule>
        <from-view-id>/login.xhtml</from-view-id>
        <navigation-case>
            <from-outcome>success</from-outcome>
            <to-view-id>/viewArticle.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>  

    <application>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>fr</supported-locale>
            <supported-locale>en</supported-locale>
        </locale-config>
    </application>

</faces-config>
Activation du support de langues dans le fichier de configuration JSF

Vous noterez que le <default-locale> est configuré sur en : cela correspond à la localisation à utiliser par défaut (ici l'anglais) si le navigateur utilisé demande une langue non supportée par l'application.

Ces différents codes sont constitués d'une ou de deux parties : la langue souhaitée (première partie en minuscule) et le pays considéré (seconde partie en majuscules, mais qui reste facultative). Ces codifications sont standardisées ISO : ISO-639 pour le code langue et ISO-3166 pour le code pays. Pour comprendre le besoin de ces deux informations, gardez à l'esprit que pour parler de couleur en Angleterre (en-GB) on utilise le mot colour alors qu'on utilise plutôt color en Amérique (en-US). Or, dans les deux pays, on parle anglais.

pour nous, les choses resterons simples et nous exploiterons juste le code langue et non pas le code pays.

Définir des traductions par localisation

L'étape suivante consiste à définir des fichiers contenant les traductions des chaînes de caractères sur site. Il y aura au moins un fichier par langue. Ces fichiers sont au format .properties : chaque ligne est une association type clé = valeur. Vous pouvez ajouter des commentaires dans ces fichiers et ils devront commencer par un caractère #.

A titre d'exemple, nous chercherons à internationaliser la page de connexion à notre site de vente en ligne (facelet login.xhtml). Voici un exemple d'un fichier pour la langue française.

# Ce fichier contient les chaînes de caractères de l'écran login en français.

title=Ecran de connexion

loginLabel=Identifiant : 
loginValidatorMessage=C'est votre email

passwordLabel=Mot de passe:
passwordValidatorMessage=Votre mot de passe doit contenir entre 3 à 12 caractères

connectLabel=Se connecter
cancelLabel=Annuler 

Et voici celui en langue anglaise.

# This file contains strings for the english login screen

title=Login screen

loginLabel=Login: 
loginValidatorMessage=It's your mail

passwordLabel=Password:
passwordValidatorMessage=3 to 12 characters are required

connectLabel=Connect 
cancelLabel=Cancel

Ces fichiers devront être accessible à partir du CLASSPATH : je vous propose donc de les placer directement dans le dossier src du projet et comme il ne s'agit pas de fichier de code source, ils seront recopiés tels quels dans le dossier classes de votre WAR.

Notez que ces fichiers possèdent une même base de nom : c'est cette base qui nous permettra de lier notre facelet à l'un de ces fichiers, en fonction de la langue retenue.

Injection des chaînes internationalisées dans la facelet

Il est maintenant temps de modifier le code de notre facelet afin :

Voici un exemple de ce que pourrait donner votre facelet login.xhtml, une fois modifiée.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
<!DOCTYPE html>
<html xmlns:f="http://xmlns.jcp.org/jsf/core" 
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <f:view>
        <head>
            <title>#{bundle.title}</title>
            <link rel='stylesheet' type='text/css' href='../styles.css' />
            <f:loadBundle basename="login" var="bundle" />
        </head>
        <body>
            <h1>#{bundle.title}</h1>
                    
            <h:form id="form">
                #{bundle.loginLabel} 
                <h:inputText id="login" value="#{loginBean.login}"
                             validatorMessage="#{bundle.loginValidatorMessage}" /> &#160;
                <h:message for="login" styleClass="errorBlock" />
                <br/>
                
                #{bundle.passwordLabel}
                <h:inputSecret id="password" value="#{loginBean.password}" 
                               validatorMessage="#{bundle.passwordValidatorMessage}" /> &#160;
                <h:message for="password" styleClass="errorBlock" />
                <br/><br/>
                
                <h:commandButton action="#{loginBean.returnAction}" value="#{bundle.connectLabel}" />
                <h:commandButton value="#{bundle.cancelLabel}" immediate="true" />
            </h:form>
        </body>
    </f:view>
</html>
Injection des chaînes internationalisées dans la facelet

Comme vous le constatez, le bundle (le sac de ressources) chargé en ligne 8 est basé sur le préfixe login et son nom est bundle. On peut ensuite utiliser ce nom de bundle comme conteneur de chaînes de caractères dans le moteur d'expressions EL : le nom de chaque chaîne correspond, bien entendu, à celui spécifié dans le fichier de ressources. Et encore une fois, ces noms sont sensibles à la casse.

personnellement, j'ai un bug d'affichage dans Eclipse qui me dit que mes fichiers de ressources (login_fr.properties et login_en.properties) ne sont pas accessibles à partir du CLASSPATH, comme en atteste la capture d'écran ci-dessous. Je pense que c'est effectivement un bug et si vous déployez malgré l'avertissement l'application dans votre serveur d'applications, vous constaterez que tout fonctionne parfaitement.
Eclipse: Resource bundle login cannot be found on classpath

Changer les préférences de votre navigateur en termes de localisation

Il nous faut maintenant vérifier que la page Web se présente bien dans la langue demandée. Pour ce faire, je vous propose d'obtenir les préférences de votre navigateur et d'y trouver l'écran de configuration de la langue souhaitée. La capture d'écran ci-dessous a été réalisée avec Chrome et je vous laisse vous adapter si vous utilisez un autre navigateur.

Changement de la langue souhaitée dans les préférences de votre navigateur

Normalement vous devriez pouvoir monter ou descendre une préférence de langue, en sachant que la plus haute est celle demandée tant que possible. Les deux captures d'écran ci-dessous vous montre la même page, soit en anglais, soit en français.

Ecran de connexion affiché en français. Ecran de connexion affiché en anglais.

Formater vos données en fonction de la localisation

Outre les chaînes de caractères, il est possible de formater vos données numériques, vos dates... en fonction de la localisation demandée par le navigateur de l'utilisateur. Cela se fait au niveau du code Java. Pour retrouver la localisation demandée par le navigateur, utilisez les lignes de code suivantes.

 1 
 2 
FacesContext context = FacesContext.getCurrentInstance();
Locale loc = context.getViewRoot().getLocale();
Récupération de la localisation demandée par le navigateur
il est aussi possible que vous ayez récupéré l'instance de type FacesContext par injection de dépendance CDI. Voici un exemple de code adapté à cette situation.
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
public class ABackingBean implements Serializable {

    @Inject
    private FacesContext context;            
    
    public void aMethod() {
        Locale loc = context.getViewRoot().getLocale();
        // Do something.
    }
}
Récupération de la localisation demandée par le navigateur

Formater vos valeurs numériques

Pour formater des données numériques, nous allons utiliser la classe java.text.NumberFormat : en fait, cette classe est fournie par le Java SE. Pour en obtenir une instance, on passe par une méthode de fabrique à laquelle on passe l'instance de Locale à utiliser.

 1 
 2 
 3 
 4 
 5 
Locale loc = context.getViewRoot().getLocale();
NumberFormat formatter = NumberFormat.getCurrencyInstance( loc ); 

double price = 1_000_000.926;
String strPrice = formatter.format( price );
Exemple d'utilisation de la classe NumberFormat

En fonction de la localisation, strPrice pourra valoir $1,000,000.93 (en_US), 1 000 000,93 € (fr_FR),...

Comme vous l'avez constaté, l'exemple précédent demande un formateur adapté à la gestion des monnaies. Il existe d'autres méthodes de fabriques :

Formater vos dates

C'est à peu près la même technique pour formater vos dates : la classe java.text.DateFormat expose diverses méthodes de fabrique en fonction que vous souhaitiez formater la date, le temps ou les deux parties.

Notez aussi que vous devrez passer une information complémentaire à la méthode de fabrique pour indiquer si vous vous souhaitez un affichage long (DateFormat.LONG), moyen (DateFormat.MEDIUM) ou cours (DateFormat.SHORT). Voici un exemple d'utilisation.

 1 
 2 
 3 
Locale loc = context.getViewRoot().getLocale();
DateFormat formatter = DateFormat.getDateInstance( DateFormat.SHORT, loc ); 
String strDate = formatter.format( new Date() );
Exemple d'utilisation de la classe DateFormat


Liaison aux données dans vos formulaires JSF Définition d'un template pour vos facelets