Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Internazionalizzazione in JSF2 con PrimeFaces

Link copiato negli appunti

L'obiettivo di questo articolo è mostrare l'implementazione delle funzionalità di internazionalizzazione all'interno di una applicazione web scritta con JSF 2. Come esempio faremo riferimento all'articolo introduttivo su primefaces 2.2.1, estendendo le funzionalità del progetto di esempio: vogliamo realizzare una semplice soluzione che permetta all'utente di scegliere in quale lingua visualizzare il sito (tra quelle disponibili), senza la necessità di alcuna impostazione a livello di browser.

Configurazione

Vediamo preliminarmente tutto quello che occorre configurare,a livello di progetto web, per poter istruire il framework alla visualizzazione delle pagine in differenti lingue. Configuriamo il file faces-config.xml aggiungendo il seguente tag di configurazione del message bundle:

<application>
	<locale-config>
		<default-locale>it</default-locale>
  		<supported-locale>it</supported-locale>
  		<supported-locale>en</supported-locale>
  	</locale-config>
  	<resource-bundle>
  		<base-name>prime.messages</base-name>
  		<var>msgs</var>
  	</resource-bundle>
</application>

Con questa informazione stiamo sostanzialmente dicendo che intendiamo supportare due lingue(italiano e inglese con italiano lingua di default), che la variabile che utilizzeremo all'interno delle pagine per riferirci ai messaggi è definita con l'alias msgs e che i nostri file di properties risiedono nel package prime con i seguenti nomi:

messages_en.properties
messages_it.properties

Si tratta di semplici file di testo. In ogni riga di un file di properties è presente una coppia nel formato chiave=valore. La chiave è la stringa che ci permette di recuperare il testo(label di un campo,messaggio di errore...) il valore è il testo che visualizzeremo identificato dalla chiave. Editiamo i nostri file con i messaggi di cui abbiamo bisogno. Inseriamo i seguenti messaggi:

in messages_it.properties

label_name=Nome
label_surname=Cognome
label_phone=Telefono
[...]

in messages_en.properties

label_name=Name
label_surname=Surname
label_phone=Phone
[...]

Tutte queste stringhe di testo che abbiamo definito, ci serviranno per le intestazioni della tabella, per il form di inserimento/aggiornamento di un contatto e per la visualizzazione dei messaggi.

Aggiunta di management bean per la scelta della lingua

L'applicativo deve permettere all'utente di cambiare la lingua in qualsiasi momento, lo stato relativo alla scelta viene mantenuto in sessione attraverso una variabile denominata currentLocale, questo per far in modo che la scelta sia mantenuta quando l'utente si sposta da una pagina ad un'altra cambiando quindi la view JSF. Per la gestione del passaggio da una lingua ad un'altra, realizziamo un managed bean completamente dedicato a questa operazione :

public class LanguageBean {
	public LanguageBean() {
		if (getSessionMap().get("currentLocale") == null) {
			Locale locale = FacesContext.getCurrentInstance().getViewRoot()	.getLocale();
			getSessionMap().put("currentLocale", locale);
			setViewRootLocale(locale);
		} else {
			setViewRootLocale((Locale) getSessionMap().get("currentLocale"));
		}
	}
	public void englishAction(ActionEvent event) {
		setViewRootLocale(Locale.ENGLISH);
		getSessionMap().put("currentLocale", Locale.ENGLISH);
	}
	[...]
}

(visualizza il sorgente completo)

Il managed bean deve essere dichiarato nel faces-config.xml nel seguente modo:

<managed-bean>
	<managed-bean-name>languageBean</managed-bean-name>
	<managed-bean-class>prime.sample.LanguageBean</managed-bean-class>
	<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

La classe importata, prime.sample.utils.Messages, contiene alcuni metodi statici che facilitano il recupero della session map di JSF (getSessionMap()) e l'impostazione della lingua di internazionalizzazione (setViewRootLocale()). Presenteremo il codice di questa classe tra breve, concentriamoci per il momento sulla classe appena scritta. L'attivazione del managed bean avviene grazie al metodo getInitilizeLanguage(), invocato attraverso un campo hidden della pagina come vedremo successivamente. Il costruttore del managed bean viene eseguito e controlla se in sessione è presente un oggetto java.util.Locale che rappresenta la scelta dell'utente. Se il controllo ha esito positivo l'oggetto locale recuperato viene utilizzato per impostare il locale da utilizzare per la visualizzazione della pagina, altrimenti viene impostato il locale di default. I metodi englishAction e italianAction realizzano il passaggio da una lingua all'altra come vedremo più in dettaglio nel proseguo dell'articolo. La classe Messages è invece la seguente:

public class Messages {
	public static String getMessage(String id, Locale locale) {
		ResourceBundle bundle = getResourceBundle(locale);
		return bundle.getString(id);
	}
	public static ResourceBundle getResourceBundle(Locale locale) {
		FacesContext context = FacesContext.getCurrentInstance();
		context.getViewRoot().setLocale(locale);
		ResourceBundle bundle = context.getApplication().getResourceBundle(context, "msgs");
		return bundle;
	}
	public static Map getSessionMap() {
		return FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
	}
	public static void setViewRootLocale(Locale locale) {
		FacesContext context = FacesContext.getCurrentInstance();
		context.getViewRoot().setLocale(locale);
		getSessionMap().put("currentLocale", locale);
	}
	[...]
}

(visualizza il sorgente completo)

Aggiunta dell'internazionalizzazione alla classe ContactsBean

Come detto precedentemente questa classe ci permette di recuperare rapidamente un messaggio e di impostare il Locale, e quindi la lingua, per la pagina da visualizzare, si tratta essenzialmente di una classe di utility. La classe ContactsBean dell'articolo introduttivo su PrimeFaces, vede i metodi per la stampa dei messaggi modificati in modo tale che il messaggio da stampare venga selezionato in base al Locale corrente scelto dall'utente. Ad esempio il metodo showGrowlInsMessage:

private void showGrowlInsMessage() {
	FacesContext context = FacesContext.getCurrentInstance();
	Locale currentLocale = (Locale) getSessionMap().get("currentLocale");
	context.addMessage(null,
			new FacesMessage(
					getMessage("label_success", currentLocale),
					getMessage("insert_message", currentLocale)
			)
	);
}
[...]

(visualizza il sorgente completo)

chiaramente è necessaria la seguente importazione

import static prime.sample.utils.Messages.*;

per poter utilizzare il metodo getMessage() che attraverso l'id del messaggio ed il locale corrente è in grado di restituire la stringa di testo nella lingua attualmente scelta dall'utente. Dal punto di vista del codice queste sono tutte le aggiunte e modifiche necessarie. Occorre soltanto inserire nelle pagine dell'applicativo il tag che invoca l'inizializzazione della lingua ed un paio di link, magari con due eleganti bandierine, per il passaggio da una lingua all'altra. Prima di mostrare queste modifiche, diamo un'occhiata a qualche schermata che mostra graficamente il nostro obiettivo:

Figura 1. selezione della lingua nei casi italiano ed inglese
confronto tra le view italiana ed inglese
visualizza lo screenshot della view in italiano

visualizza lo screenshot della view in inglese

Quando facciamo click sua una bandierina, la vedremo lampeggiare grazie ad un effetto molto carino di primefaces, ciò che invece accade lato server è l'invocazione del metodo

public void englishAction(ActionEvent event) {
	setViewRootLocale(Locale.ENGLISH);
	getSessionMap().put("currentLocale", Locale.ENGLISH);
}

per la bandierina inglese, mentre

public void italianAction(ActionEvent event) {
	setViewRootLocale(Locale.ITALIAN);
	getSessionMap().put("currentLocale", Locale.ITALIAN);
}

per la bandierina italiana.

Internazionalizzazione per le View JSF

Prendendo come esempio le view di inserimento dei nuovi contatti, vogliamo ottenere a seguito di una selezione della lingua un risultato simile a questo:

Figura 2. dettaglio del confronto tra view in italiano e in inglese
scelta della lingua
visualizza lo screenshot della view in italiano

visualizza lo screenshot della view in inglese

La pagina viene ricaricata ma per la view viene impostato il Locale configurato tramite questi metodi. Vediamo come viene modificata la pagina dataTable.xhtml per realizzare quanto visto:

<h:form>
	<p:dialog widgetVar="newDialog" header="#{msgs.label_insert_contact}"
		width="430" height="220" modal="true">
		<p:outputPanel id="newDisplay">
			<h:panelGrid columns="2">
				<h:outputLabel value="#{msgs.label_name}" />
				<p:inputText value="#{contactsBean.contact.nome}"></p:inputText>
				<h:outputLabel value="#{msgs.label_surname}" />
				<p:inputText value="#{contactsBean.contact.cognome}"></p:inputText>
				<h:outputLabel value="#{msgs.label_phone}" />
				<p:inputText value="#{contactsBean.contact.telefono}"></p:inputText>
				<h:outputLabel value="#{msgs.label_job}" />
				<p:inputText value="#{contactsBean.contact.professione}"></p:inputText>
			</h:panelGrid>
			<p:commandButton value="#{msgs.label_save}" ajax="true"
				actionListener="#{contactsBean.salva}" update="tbl"
				onclick="newDialog.close()">
			</p:commandButton>
		</p:outputPanel>
	</p:dialog>
</h:form>

(visualizza il sorgente completo)

in grassetto è evidenziata la nuova parte che gestisce il cambio di lingua. Il tag hidden

<h:inputHidden value="#{languageBean.initilizeLanguage}" />

inizializza il managed bean LanguageBean di gestione della lingua, l'invocazione del metodo getInitializeLanguage(), come detto, provoca l'esecuzione del costruttore che a sua volta imposta il locale di default. Successivamente attraverso il click sul link

<h:commandLink actionListener="#{languageBean.englishAction}">
	<p:graphicImage value="/images/english.png"
		style="border:#{sessionScope.currentLocale=='en'?'2px solid':'none'}">
	<p:effect type="pulsate" event="load"
		rendered="#{sessionScope.currentLocale=='en'}" />
	</p:graphicImage>
</h:commandLink>

viene eseguito il metodo englishAction di LanguageBean, l'effetto è quello di impostare il Locale sulla lingua inglese, la pagina viene ricaricata e la vista setta il suo locale su quello da noi impostato. Infine grazie al p:effect vedremo un elegante lampeggio della bandierina inglese.Il link

<h:commandLink actionListener="#{languageBean.italianAction}">
	   <p:graphicImage value="/images/italy.png"
	    	style="border:#{sessionScope.currentLocale=='it'?'2px solid':'none'}">
	   <p:effect type="pulsate" event="load"
			rendered="#{sessionScope.currentLocale=='it'}" />
	  </p:graphicImage>
</h:commandLink>

avvia l'esecuzione del metodo italianAction, questo metodo svolge lo stesso lavoro di englishAction ma imposta chiaramete il Locale sulla lingua italiana. Solito ricaricamento della pagina, la vista viene impostata sul Locale italiano, ed è questa volta la bandierina italiana a lampeggiare. L'ultima modifica effettuata riguarda i riferimenti alle labels che abbiamo pazientemente scritto nei nostri file di properties, ad esse ci riferiamo all'interno delle pagine nel seguente modo:

#{msgs.[chiave]}

dove msgs è la variabile che abbiamo definito nel faces-config e [chiave] è la particolare chiave che intendiamo visualizzare sulla pagina, un esempio:

attraverso la viariabile msgs e la chiave label_phone, visualizziamo sulla pagina la label del telefono nella lingua italiana o inglese a seconda del Locale corrente. Come ulteriore modifica è stato aggiunto un pulsante che permette la navigazione verso un'altra pagina contenente un carosello che permette lo scorrimento dei contatti. La pagina è presente nel codice allegato (carouselContacts.xhtml) ed è molto semplice, ma permette di testare come lo stato scelto dall'utente riguardo alla lingua, venga mantenuto passando attraverso le varie pagine dell'applicativo.

<h:outputLabel value="#{msgs.label_phone}" />

Conclusioni

Abbiamo visto come l'utilizzo congiunto di JSF 2 e PrimeFaces permetta di realizzare in modo relativamente semplice moderne applicazioni J2EE. In questo articolo abbiamo trattato un argomento interessante:l'internazionalizzazione. Abbiamo fornito una soluzione personale al problema della scelta di una lingua di visualizzazione a discrezione dell'utente. Proseguiremo oltre,espandendo la nostra demo di PrimeFaces, vedendo, come attraverso JSF2, sia possibile realizzare validatori semplici e multipli per le nostre form di interfaccia.

Ti consigliamo anche