• 10 heures
  • Facile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 03/09/2019

Gérez les messages et l'internationalisation

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Au niveau des messages et plus généralement de tous les textes affichés dans une application, il est courant :

  • d'avoir le même message à plusieurs endroits ou dans différentes pages,

  • de ne pas avoir le contenu définitif des messages pendant le développement.

Afin éviter d'avoir à repasser dans toutes les JSP et les actions pour apporter les modifications nécessaires en cas de changement de ces messages, il est une bonne pratique d'utiliser des Resource Bundles avec des fichiers properties. De plus, cela facilite également l'internationalisation de l'application.

Dans ce chapitre, je vais vous montrer comment Struts se base sur cette pratique pour gérer les messages et la simplicité de mise en place de l'internationalisation d'une application Struts !

Externaliser les messages dans des fichiers properties

Dans Struts, la gestion des Resource Bundles est déjà implémentée.

L'utilisation d'un message se fait grâce aux méthodes getText(...), aux tags text ou ì18n, à l'attribut key de la plupart des tags Struts.

La recherche des messages se fait dans l'ordre suivant :

  1. Fichier properties au nom et dans le package de la classe de l'action <actionClassPackage>/<ActionClass>.properties

  2. Fichier properties au nom et dans le package d'une des interfaces de la classe de l'action /.properties (recherché pour chaque interface et sous-interface implémentée par la classe de l'action).

  3. Fichier properties au nom et dans le package d'une des classes de la hiérarchie d'héritage de la classe de l'action BaseClass.properties (dans l'ordre d'héritage, jusqu'à Object).

  4. Si la classe de l'action implémente l'interface ModelDriven, la recherche suit le même principe qu'à partir du point n°1 mais avec la classe de l'object model.

  5. Fichier package.properties dans le package de la classe de l'action ou un package parent.

  6. Fichiers properties de resource global (définis via la propriété de configuration Struts struts.custom.i18n.resources).

Ici je vais créer un fichier properties de resource global.

Créer un fichier de resource global

Je commence par créer le fichier src/main/resources/messages.properties :

## Accueil
home.welcome=Bienvenue sur l''application Ticket

## Liens de navigation
nav.listProjet=Liste des projets

## Erreurs
error.title=Une erreur s''est produite
error.project.missing.id=Vous devez indiquer un id de projet.
error.project.notfound=Projet non trouv\u00e9 (ID = {0}).

error.user.missing.id=Vous devez indiquer un id d''utilisateur.
error.user.notfound=Utilisateur non trouv\u00e9 (ID = {0}).

Je déclare ensuite ce fichier en tant que fichier de ressource global pour les messages dans le fichier struts.properties

# Resource Bundles
struts.custom.i18n.resources=messages

Utiliser les messages des Resource Bundles dans les JSP

Vous avez plusieurs moyens d'utiliser les messages des Resource Bundles dans les JSP.

Dans le fichier src/main/webapp/jsp/index.jsp j'utilise par exemple le tag <s:text> :

...
<body>
    <h2><s:text name="home.welcome" /></h2>

    <s:a action="projet_list">
        <s:text name="nav.listProjet" />
    </s:a>
</body>
...

Utiliser les messages des Resource Bundles dans les actions

Si votre classe d'action hérite de la classe ActionSupport de Struts, celle-ci met à disposition des méthodes getText afin d'accéder aux messages des Resource Bundles.

/**
 * Action affichant les détails d'un {@link Projet}
 * @return success / error
 */
public String doDetail() {
    if (id == null) {
        this.addActionError(getText("error.project.missing.id"));
    } else {
        try {
            projet = WebappHelper.getManagerFactory().getProjetManager().getProjet(id);
        } catch (NotFoundException pE) {
            this.addActionError(getText("error.project.notfound", Collections.singletonList(id)));
        }
    }

    return (this.hasErrors()) ? ActionSupport.ERROR : ActionSupport.SUCCESS;
}

Formater les nombres, dates...

Comme je vous le disais juste avant, Struts permet d'utiliser MessageFormat.

Prenons un exemple : je veux ajouter sur la page d'erreur, la date et l'heure où l'action a levé une erreur.

Dans le fichier src/main/resources/messages.properties, j'ajoute le message error.metadata :

error.metadata=Erreur g\u00e9n\u00e9r\u00e9e le {0,date,dd/MM/yyyy} \u00e0 {0,time,HH:mm:ss}.

Pour générer un message du genre « Erreur générée le 31/12/2017 à 23:59:59. »

Dans le fichier src/main/webapp/jsp/error.jsp, j'ajoute 2 éléments :

  • L'instanciation, via le tag <s:bean>, d'un objet java.util.Date pour obtenir la date courante. Cette instance est placée sur la value stack avec le nom now.

  • J'affiche le message error.metadata (tag <s:text>) en lui passant en paramètre le bean now (via le tag <s:param>).

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE html>
<html>
<head>
    <%@ include file="_include/head.jsp"%>
</head>

<body>
    <h2><s:text name="error.title" /></h2>

    <s:actionerror />

    <s:bean name="java.util.Date" var="now" />
    <s:text name="error.metadata">
        <s:param value="now" />
    </s:text>
</body>
</html>

L'internationalisation

Comme tous les messages sont désormais externalisés dans des Resource Bundles, l'internationalisation (i18n) de l'application ne devrait pas être techniquement compliquée...

C'est pas faux ! Struts vous permet de gérer facilement l'internationalisation (i18n) grâce à un interceptor : le I18nInterceptor.

L'interceptor I18nInterceptor

Vous ne savez pas encore ce que sont réellement les interceptors (nous verrons cela dans la deuxième partie de ce cours) mais si vous vous rappelez du schéma général du premier chapitre, vous voyez que les interceptors sont un peu comme les Filters d'une application web JEE.

Schéma général
Fonctionnement général de Struts

La requête HTTP passe à travers une pile d'interceptors avant d'arriver sur la classe d'action. Sachez simplement que le I18nInterceptor fait partie de la pile d'interceptors par défaut de Struts (nous verrons aussi cela dans la deuxième partie de ce cours).

Le rôle du I18nInterceptor est de configurer le contexte Struts de la requête avec la bonne locale (langue/pays de l'utilisateur).

Le fonctionnement est assez simple :

  • Si un paramètre spécifique (request_only_locale) est passé dans la requête indiquant d'utiliser une certaine locale uniquement pour cette requête, alors celle-ci est utilisée.

  • Si un paramètre spécifique (request_locale) est passé dans la requête indiquant d'utiliser une certaine locale, alors celle-ci est utilisée et cette configuration est cette configuration est sauvegardée (soit en session, soit via un cookie).

  • Si aucun paramètre n'est passé :

    • si la configuration de la locale a déjà été sauvegardée c'est celle-ci qui sera utilisée ;

    • sinon, par défaut, la locale utilisée est celle envoyée par le navigateur de l'utilisateur.

Configurer les messages dans les différentes locales

Afin de gérer plusieurs locales, il suffit de créer les mêmes fichiers properties que précédemment mais en suffixant le nom du fichier par _ et le code de la locale.

Par exemple :

🗁 src/main/resources
├── 🗎 messages.properties     (par défaut)
├── 🗎 messages_en.properties  (locale english)
└── 🗎 messages_fr.properties  (locale french)

Dans cet exemple voici l'ordre des fichiers dans lesquels sont recherchés les messages

Locale

Ordre de priorité des fichiers

en

messages_en.propertiesmessages.properties

fr

messages_fr.propertiesmessages.properties

autre locale

messages.properties

Dans le cadre de mon application, je vais considérer que la langue par défaut est le Français. Cette locale sera dont gérer via le fichier messages.properties. Je veux également gérer la langue anglaise. Je crée donc le fichier src/main/resources/messages_en.properties :

## Accueil
home.welcome=Welcome on Ticket

## Liens de navigation
nav.listProjet=Project List

## Erreurs
error.title=An error occured
error.metadata=Error generate on {0,date,MM/dd/yyyy} - {0,time,HH:mm:ss}.
error.project.missing.id=Missing project id.
error.project.notfound=Project not found (ID = {0}).
error.user.missing.id=Missing user id.
error.user.notfound=User not found (ID = {0}).

Permettre à l'utilisateur de choisir sa langue

Le choix par l'utilisateur de la locale à utiliser peut se faire au niveau de la configuration du navigateur. Bien que cela soit pratique car configuré de manière globale pour tous les sites que va parcourir l'utilisateur, il peut être judicieux de proposer à l'utilisateur de choisir la langue qu'il veut utiliser dans votre application directement sur une page de l'application.

Pour cela, je vous ai dit que le I18nInterceptor scrutait des paramètres spécifiques. C'est ce que je vais utiliser pour ajouter le choix de la langue de l'application sur la page d'accueil.

Je modifie donc le fichier src/main/webapp/jsp/index.jsp afin d'ajouter 2 liens : un pour passer en Anglais l'autre pour passer en Français. Ces liens pointent vers l'action index et passent en paramètre la locale désirée via le paramètre spécifique request_locale.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE html>
<html>
<head>
    <%@ include file="_include/head.jsp"%>
</head>

<body>
    <h2><s:text name="home.welcome" /></h2>

    <nav>
        <s:a action="projet_list">
            <s:text name="nav.listProjet" />
        </s:a>
    </nav>

    <footer>
        <s:a action="index">
            <s:param name="request_locale">en</s:param>
            [English]
        </s:a>
        <s:a action="index">
            <s:param name="request_locale">fr</s:param>
            [Français]
        </s:a>
    </footer>
</body>
</html>

Et voilà, maintenant, lorsque l'utilisateur cliquera sur l'un des 2 liens, cela configurera la locale qu'il désire pour l'application et cette configuration sera conservée tout au long de sa session.

Conclusion

Dans ce chapitre, vous avez pu voir comment l'externalisation, la centralisation et l'internationalisation des messages est simple à gérer dans une application Struts.

Si vous voulez approfondir un peu ce sujet, voici quelques liens vers la documentation du framework :

Dans le prochain chapitre, je vous montrerai comment interroger l'utilisateur et gérer des formulaires avec Struts.

Exemple de certificat de réussite
Exemple de certificat de réussite