Introduzione
Il problema dell'internazionalizzazione di un'applicazione è ben noto. Un'applicazione può essere fruita da utenti di diversi paesi. Ciò significa che deve adattarsi alle preferenze in termini di lingua, e non solo, degli utenti che la utilizzano. Paesi diversi e lingue diverse non significano solamente la diversa traduzione di un testo o di una label, ma anche la gestione di numerosi altri aspetti quali la rappresentazione delle date, delle valute se non addirittura la modalità di visualizzazione stessa. Basti pensare a quelle lingue nelle quali il verso della scrittura è da destra a sinistra, da cui consegue la necessità di ribaltare l'interfaccia dell'applicazione come davanti ad uno specchio. Il linguaggio Java come è noto mette a disposizione gli strumenti per affrontare questo problema. In Java l'insieme delle preferenze legate ad un paese e ad una lingua viene chiamato locale. Internazionalizzare un'applicazione significa predisporla a operare con molteplici locale. Localizzarla significa modificarla per uno specifico locale. Nei paragrafi seguenti vedremo come agire per localizzare la nostra applicazione JSF.
Locale e ResourceBundle
Nelle pagine di MokaByte si è parlato molte volte degli strumenti che Java mette a disposizione per l'internazionalizzazione delle applicazioni [6], alla quale ci si riferisce nel linguaggio degli sviluppatori con la sigla i18n, ottenuta dalla prima e l'ultima lettera della parola con in mezzo il numero delle lettere comprese tra queste. Java mette a disposizione la classe java.util.Locale che rappresenta un Paese e una lingua e la classe astratta java.util.ResourceBundle che consente di definire delle risorse contenenti le informazioni utili a localizzare un'applicazione. Un resource bundle contiene informazioni nella forma chiave/valore dove la chiave identifica uno specifico elemento localizzato e può essere implementato mediante una classe o un file di testo. Nella pratica a un resource bundle è quasi sempre associato un file di testo di tipo .properties. Un locale è rappresentato da un codice composto da due parti: una individua il Paese e una individua la lingua. Ad esempio il codice enGB rappresenta l'inglese e la Gran Bretagna mentre il codice enUS rappresente l'inglese e gli USA. La lingua è obbligatoria mentre il codice del paese è opzionale. Tipicamente un resource bundle è implementato mediante un file properties specifico per ogni locale. Nell'applicazione saranno quindi definiti un file properties di default e file properties aggiuntivi per ciascuna combinazione di paese e lingua per la quale la nostra applicazione necessita di essere localizzata. Quindi, ad esempio, avremo un file LocalizationResources.properties contenente i valori di default per tutte le stringhe localizzate dell'applicazione ed un file LocalizationResourcesfrFR.properties per la versione francese delle stesse. L'header della richiesta HTTP contiene l'informazione sul locale in uso da parte del browser dell'utente; questa informazione consente all'applicazione di presentare all'utente un'interfaccia opportunamente localizzata. Ovviamente in un'applicazione non è detto che tutte le lingue siano supportate. In tal caso viene preso in considerazione il resource bundle di default. Internazionalizzare un'applicazione quindi significa predisporre un'applicazione a supportare molteplici locale . Localizzare significa modificare l'applicazione per uno specifico locale.
Localizzazione delle stringhe statiche dell'interfaccia
Come ogni framework anche JSF offre strumenti per internazionalizzare e localizzare un'applicazione. Nella discussione si farà riferimento alla localizzazione di stringhe statiche di testo, quali le label presenti nelle pagine, e dei messaggi di errore generati dal framework.
Per poter utilizzare nella propria applicazione delle stringhe di testo localizzato, come prima cosa bisogna definire quali siano i locale supportati. Come intuibile questa definizione va inserita nel file di configurazione di JSF faces-config.xml. Ecco la sezione che definisce i locale supportati:
<application> <locale-config> <default-locale>it_IT</default-locale> <supported-locale>en_US</supported-locale> </locale-config> <message-bundle>it.mokabyte.jsf.LocalizationResources</message-bundle> </application>
I file conterranno nella forma chiave = valore tutte le stringhe che è necessario localizzare. Le chiavi saranno sempre le stesse e i valori cambieranno ovviamente da locale a locale. Un file di questo tipo conterrà ad esempio delle righe come le seguenti nella versione italiana: label.benvenuto=Benvenuto label.button=Invia
label.benvenuto=Welcome label.button=Submit
<f:loadBundle basename="it.mokabyte.jsf.LocalizationResources" var="bundle"/>
<h:outputText value="#{bundle[\'label.welcome\']}" />
FacesContext context = FacesContext.getCurrentInstance();
Locale currentLocale = context.getViewRoot().getLocale();
String bundleName = context.getApplication().getMessageBundle();
ResourceBundle bundle = ResourceBundle.getBundle(bundleName, currentLocale);
String valore = bundle.getString(chiave);
