Introduzione
Nei precedenti articoli abbiamo esaminato l'architettura di
Struts e abbiamo descritto gli elementi fondamentali del framework
e come questo implementi il pattern MVC. Con questo articolo
iniziamo a descrivere alcune problematiche tipiche di una
web application e come queste possano essere risolte con Struts.
Iniziamo con il tema dell'internazionalizzazione di una applicazione
, molto importante per chi si trova a dover progettare applicazioni
che devono essere fruite in diverse lingue ed in diverse località
geografiche.
Internazionalizzazione
e Java
Internazionalizzare un'applicazione significa predisporla
a supportare lingue diverse e regioni geografiche diverse
senza dover intervenire con modifiche all'architettura.
Le specifiche standard riguardanti l'internazionalizzazione
enunciano che un'applicazione internazionalizzata deve rispondere
ai seguenti requisiti:
- Lingue
diverse devono essere supportate senza modifiche al codice
- Testi
e immagini devono essere memorizzati esternamente al codice
- Date,
numeri , valute devono essere correttamente formattate in
base alle regole della regione geografica nella quale l'applicazione
è eseguita
- Sono
supportati caratteri non standard
- L'applicazione
si adatta rapidamente a supportare una nuova lingua o una
nuova regione
Il
problema non è di poco conto poiché gli elementi
che sono affetti da cambiamenti al variare della lingua e/o
della regione sono molteplici all'interno di una applicazione.
Spesso l'errore è di focalizzarsi solo sul primo punto
che è il più evidente; si pensa infatti che
internazionalizzare un'applicazione significhi rendere l'applicazione
multilingua in quanto è immediato pensare alle label
presenti nelle interfacce grafiche come unico elemento critico.
In realtà anche date, numeri , valute sono elementi
che variano al variare della lingua e del paese e quindi sono
da tenere in conto. E' sicuramente molto importante sapere
in fase di progettazione dell'applicazione che l'applicazione
deve essere internazionalizzata poiché un intervento
a posteriori sarebbe sicuramente estremamente oneroso.
Internazionalizzare una applicazione quindi dal punto di vista
tecnico si traduce nello scrivere del codice che si comporti
correttamente qualora la lingua o il paese cambino ma senza
che sia necessario apportare modifiche allo stesso. E' ovvio
che tutta una serie di risorse dell'applicazione saranno diverse
a seconda della lingua. La label 'benvenuto' nella pagina
iniziale dell'applicazione visitata da un utente di lingua
italiana dovrà apparire come 'welcome' per un utente
di lingua inglese. Per far si che un'applicazione internazionalizzata
abbia un comportamento simile è necessario localizzarla.
Il processo di adattare un'applicazione internazionalizzata
ad una specifica lingua e regione si definisce quindi localizzazione.
Per la localizzazione di una applicazione predisposta all'internazionalizzazione
Java fornisce una serie di classi che consentono una gestione
del problema estremamente flessibile ed elegante.
La localizzazione si basa sull'utilizzo di due classi fondamentali:
java.util.Locale e java.util.ResourceBundle, e su una serie
di altre classi che fanno riferimento a queste.
La classe java.util.Locale è quella che consente all'applicazione
di conoscere in quale lingua e in quale paese viene eseguita.
E' un identificatore per ogni combinazione di lingua e regione
geografica, una istanza di questa classe identifica una combinazione
language/country. Per istanziare un oggetto della classe Locale
bisogna passare al costruttore un identificativo della lingua
e della regione. Ad esempio il locale che identifica la lingua
italiano e la regione Italia va costruito nel seguente modo:
Locale
locale = new Locale("it", "IT").
Le classi del linguaggio che cambiano il proprio comportamento
in funzione del locale corrente si dicono locale-sensitive.
Rientrano ad esempio. in questa categoria le classi per la
formattazione delle date e degli importi che vengono utilizzate
nella scrittura di una applicazione internazionalizzata. Mediante
queste classi è possibile scrivere codice che ha comportamento
diverso in base al locale corrente e che quindi è predisposto
ad essere eseguito per lingue diverse e in paesi diversi.
La classe java.util.ResourceBundle è invece un contenitore
di oggetti cosiddetti locale-specific ovvero oggetti che assumono
valori differenti in base al locale. Ad esempio una risorsa
locale-specific è sicuramente la stringa che rappresenta
una label di una interfaccia grafica; l'applicazione internazionalizzata
reperirà la stringa dal ResourceBundle specifico per
il locale corrente e quindi sarà predisposta al cambiamento
della lingua o della regione. In realtà la classe java.util.ResourceBundle
è una classe astratta. Una implementazione concreta
è la java.util.PropertyResourceBundle che gestisce
le risorse specifiche per un dato locale memorizzandole in
file di properties. I file di properties sono file di testo
contenenti un elenco di coppie chiave/valore, dove la chiave
è un identificativo associato ad una determinata stringa
e valore è la stringa stessa per quel determinato locale.
I
componenti di Struts per la gestione dell'internazionalizzazione
Struts fornisce supporto all'internazionalizzazione essenzialmente
per ciò che riguarda il reperimento di testo e immagini
localizzate. Per gli altri aspetti, quali formattazione di
date, importi etc. bisogna fare ricorso alle classi Java standard
per le quali rimandiamo alla documentazione ufficiale presente
sul sito della Sun (http://java.sun.com).
Struts gestisce l'internazionalizzazione fornendo gli strumenti
per reperire risorse localizzate da opportuni resource bundle
in base al locale corrente.
In una web-application, e quindi anche in quelle costruite
con Struts, è possibile reperire l'informazione relativa
al locale dell'utente mediante il metodo public java.util.Locale
getLocale() dell'oggetto HttpServletRequest.
Infatti l'informazione del locale utilizzato dall'utente è
inviata al container in ogni request; Struts come default
memorizza questa informazione nella sessione, ma è
possibile variare questo comportamento impostando il valore
dell'attributo locale del tag <controller
/> nello
struts-config.xml. Il valore di default è false.
Con l'informazione del locale presente in sessione l'applicazione
è quindi in grado di reperire dal resource bundle appropriato
la risorsa localizzata.
Per
la gestione dei resource bundle in Struts viene usata la classe
org.apache.struts.util.MessageResources che segue la stessa
logica della java.util.ResourceBundle arricchendola con alcune
funzioni di utilità.
Anche la classe org.apache.struts.util.MessageResources è
una classe astratta, e la sua concreta implementazione è
fornita dalla classe org.apache.struts.util.PropertyMessageResources
che consente di leggere stringhe localizzate alle quali è
associata una chiave reperendole da file di properties, esattamente
come fa la java.util.PropertyResourceBundle.
Il primo elemento da definire quindi per localizzare una applicazione
Struts sono proprio i resource bundle ovvero i file di properties
contenenti la lista in formato nome/valore di tutte le label
dell'applicazione. Esisterà un file di properties per
la lingua di default della propria applicazione chiamato ad
esempio ApplicationResources.properties
Che avrà una serie di elementi del tipo :
...
button.aggiorna=Aggiorna
button.conferma=Conferma
button.elimina=Elimina
button.inserisci=Inserisci
button.salva=Salva
...
Dovranno poi essere definiti tanti altri altri file di properties
per tutte le combinazioni lingua/regione per le quali si vuole
che l'applicazione sie predisposta. Ad
esempio
ApplicationResource_en_En.properties
per inglese/regnoUnito
ApplicationResource_en_US.properties per inlese/Stati Uniti
ApplicationResources_fr_FR.properties per francese/Francia
e
così via. Il file ApplicationResource_en_En.properties
sarà ad esempio del tipo :
...
button.aggiorna=Update
button.conferma=Confirm
button.elimina=Delete
button.inserisci=Insert
button.modifica=Modifica
button.salva=Save
...
...
Nello
struts-config.xml va indicato qual è il resource bundle
utilizzato dall'applicazione con il tag
<message-resources parameter="it.prova.ApplicationResources"/>
indicando il nome radice della famiglia di resource bundle
che si riferiscono alle stesse risorse localizzate.
I file di properties così definiti vanno quindi installati
nella cartella /WEB-INF/classes dell'applicazione rispettando
la struttura di package dichiarata nella definizione precedente.
La
lettura dei resource bundle in Struts
I file di properties vengono letti allo start-up dell'applicazione,
e usati per valorizzare istanze della classe org.apache.struts.util.PropertyMessageResources
memorizzate poi nel ServletContext. E' quindi possibile accedere
ai resource bundle dalle Action, dagli ActionForm o dalle
pagine JSP.
Nelle Action il reperimento può essere fatto utilizzando
i metodi della classe org.apache.struts.util.MessageResources
come nell'esempio seguente relativo ad una Action:
...
//acquisizione del locale corrente mediante il metodo
//getLocale(HttpServletRequest request)
//della classe org.apache.struts.action.Action che restiuisce
il locale corrente //dell'utente
Locale locale = this.getLocale(request);
//
acquisizione del MessageResources
MessageResources messages = servlet.getResources();
// acquisizione della stringa localizzata corrispondente al
locale corrente e
// alla chiave memorizzata nel parametro key
String value = messages.getMessage(locale,key);
oppure
più frequentemente mediante i costruttori delle classi
ActionMessages e ActionErrors utilizzate nella gestione dei
messaggi di errore, che ricevono come parametro la chiave
della label da reperire e acquisiscono in automatico dal resource
bundle del locale corrente il valore della label stessa localizzata.
Un esempio è il metodo validate di una ActionForm nel
quale viene utilizzata la classe ActionError per rappresentare
un messaggio di errore il cui valore localizzato viene reperito
passando al costruttore la chiave corrispondente.
public
ActionErrors validate(ActionMapping mapping,HttpServletRequest
request) {
ActionErrors errors = new ActionErrors();
if ((username == null) || (username.length() < 1))
errors.add ("username",new ActionError("errore.username.obbligatorio"));
if ((password == null) || (password.length() < 1))
errors.add("password",new ActionError("errore.password.obbligatoria"));
return errors;
}
Per
reperire le stringhe localizzate nelle pagine JSP si utilizza
invece un custom-tag della libreria struts-bean, precisamente
il tag <bean:message>.
L'utilizzo è banale , basta fornire come attributo
la chiave corrispondente alla label che si vuole acquisire
come nell'esempio seguente:
<bean:message
key="label.username" />
In questo modo è molto semplice scrivere pagine JSP
nelle quali non sono presenti label direttamente scritte nel
codice , e quindi utilizzare lo stesso sorgente della pagina
per visualizzare informazioni in lingue differenti.
Conclusioni
In questo articolo abbiamo esaminato gli strumenti che Struts
ci mette a disposizione per l'internazionalizzazione e di
una applicazione. Utilizzando queste funzionalità è
veramente molto semplice scrivere una applicazione nella quale
tutte le stringhe sono esterne al codice e indipendente al
variare del locale. Va ancora ribadito che Struts risolve
solo una parte delle esigenze di un applicazione con supporto
all'internazionalizzazione. La scrittura di codice per la
corretta formattazione di date e importi al variare di lingua
e paese va fatta mediante le classi standard del linguaggio
Java e non è risolta da componenti specifici di Struts.
Bibliografia
[1] Chuck Cavaness - "Programming Jakarta Struts",
O'Reilly, 2003
[2] James Goodwill, Richard Hightower - Professional Jakarta
Struts" - Wrox 2004
Alfredo Larotonda, laureato in
Ingegneria Elettronica, lavora da diversi anni nel settore
IT. Dal 1999 si occupa di Java ed in particolare dello sviluppo
di applicazioni web J2EE. Dopo diverse esperienze di disegno
e sviluppo ora si occupa in particolare di aspetti architetturali
per progetti rivolti al mercato finanziario ed industriale.
E' Web Component Developer certificato SUN per la piattaforma
J2EE e Programmer per la piattaforma Java.
|