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

Internazionalizzazione e localizzazione con WindowBuilder

Funzionalità per l'nternazionalizzazione e la localizzazione in WindowBuilder
Funzionalità per l'nternazionalizzazione e la localizzazione in WindowBuilder
Link copiato negli appunti

Internazionalizzazione e localizzazione

Con il termine internazionalizzazione intendiamo il processo di predisposizione di una applicazione al supporto di diverse lingue (spesso abbreviato in "i18n"). Con il termine localizzazione ("L10n") si intende il complementare processo di adattamento dell'applicazione a una specifica regione o lingua, ottenuto mediante traduzione del testo e aggiunta/modifica di un locale, un set di parametri che definisce lingua e posizione dell'utente, eventualmente corredato da altri valori.

Tipicamente in Java il processo di traduzione è affidato a file di <>property basati sul linguaggio dell'utente. A runtime avviene il processo di individuazione del corrispondente file di property, riconosciuto sulla base di un locale, di norma associato al linguaggio configurato nel sistema operativo dell'utente.

WindowBuilder offre il supporto per esternalizzare le stringhe, utile per supportare diverse lingue, permettendo di cambiare rapidamente le impostazioni per verificare la formattazione dell'interfaccia con ogni lingua. In questa lezione forniremo un esempio di realizzazione di un semplice form multilingua, estendendolo in modo da supportare la scelta della lingua a runtime.

Il passo base consiste nella creazione del form. Come già visto in precedenza, utilizziamo il wizard per generare un nuovo JFrame ("Application Window"), per poi popolarlo come di seguito (nel progetto allegato alla guida è la classe languageGUI.Form):

Figura 1. L'interfaccia grafica d'esempio e il pulsante Externalize strings
Pulsante Externalize strings

Lo scheletro del form è basato su due pannelli. il primo contenente due label e due aree di testo, il secondo contenente due pulsanti. Al pulsante di destra associamo un evento basato su click del mouse, ne stabiliremo il comportamento in un secondo momento.

Una volta disegnata l'interfaccia, può cominciare il processo di esternalizzazione. Nell'immagine precedente un cerchio rosso evidenzia il pulsante "Externalize strings". Premuto, si aprirà una finestra che ci consentirà di scegliere quali stringhe esternalizzare, ossia predisporre per il processo di traduzione. Nell’immagine seguente vediamo che stiamo per esternalizzare il testo relativo alle due label e ai due pulsanti.

Figura 2. Scelta delle stringhe da esternalizzare
Scelta delle stringhe da esternalizzare

Il processo di esternalizzazione si basa su bundle, risorse quali i file di properties contenenti le stringhe di testo corrispondenti per ogni lingua. WindowBuilder si occuperà di crearli per noi per ogni nuova lingua che decideremo di supportare. Occorre quindi predisporre tale mapping, cosa che faremo tramite la sezione "Existing sources".

Premendo sul pulsante "New…" potremo scegliere tra diverse modalità di associazione tra campi e stringhe. Nel nostro caso esse saranno:

  1. "Classic Eclipse message class": permette di creare un nuovo bundle di accesso o di selezionarne uno esistente, consentendo di specificare nome e percorso del file;
  2. "Direct ResourceBundle usage": richiede solo di specificare nome e posizione del bundle;
  3. ResourceBundle in field": oltre a nome e posizione del bundle, consente anche di specificare il nome dell’istanza del bundle.

Scelte le stringhe da esternalizzare e scelta la modalità accesso (nel nostro caso "Classic Eclipse message class"), sarà possibile esternalizzarle tramite il pulsante "Externalize".

Ciò porterà alla creazione di una classe (Messages.java) incaricata di gestire i file di properties, e di un file di properties (messages.properties), contenente tante properties quante sono le stringhe da esternalizzare. In pratica si è creato il file di properties di default e la classe che provvederà al caricamento a runtime del file di properties più adatto fra quelli disponibili.

Ciò significa che se nel processo di traduzione si è previsto il locale coincidente con il locale dell'utente del form, il form verrà visualizzato con i valori caratteristici dell'utente, viceversa si ricorrerà ai valori presenti nel file di default. Vedremo inoltre che il pulsante "Externalize strings" ha cambiato forma e riporta una stringa "default". Premendovi sopra, si aprirà una finestra che ci consentirà di aggiungere il supporto a nuove lingue (ognuna associata a un locale).

La voce default, associata al file messages.properties, è utile per fornire le stringhe per tutte le lingue non previste, dovrebbe pertanto essere basata su una lingua di larga diffusione (non a caso il relativo locale è basato, come vedremo, su UK).

Nel nostro esempio aggiungiamo il supporto per l'Italiano e provvediamo a modificare i campi come indicato di seguito (nell'esempio allegato è previsto anche il supporto per il Francese):

Figura 3. Le voci tradotte per ogni Locale supportato
Le voci tradotte per ogni Locale supportato

Modificati i campi e premuto su "OK", verrà generato un nuovo file di properties (messages_it.properties) contenente le stesse propeties del file già esistente ma con i valori tradotti per la lingua italiana. Da notare che invece la classe Messages non presenterà modifiche. Inoltre, premendo sulla parte destra del pulsante "Externalize strings" si aprià un menu a tendina che ci darà la possibile di scegliere tra "default" e "Italiano", consentendoci di verificare il layout del form per le diverse lingue supportate, verificando ad esempio che le stringhe siano correttamente contenute nei campi. Di seguito affianchiamo il form visualizzato in Italiano con quello di default.

Figura 4. La stessa interfaccia al variare della lingua
Stessa interfaccia al variare della lingua

Provando ad eseguire il main associato alla classe, nel nostro caso il locale dovrebbe essere inizialmente impostato sul valore "ITALY", per cui dovremmo vedere visualizzata la finestra direttamente con la lingua italiana. Premendo il pulsante del cambio lingua non dovrebbe succedere niente, a meno di non aver leggermente modificato la classe Messages per estenderne il comportamento e il form, come fatto nell'esempio allegato alla guida.

Abbiamo visto infatti che la classe Messages non fa altro che riconoscere il locale associato al sistema utilizzato dall'utente, a meno che non sia modificata come quella del progetto associato alla guida. La classe creata automaticamente dispone di un metodo getString che carica la properties desiderata. Ma di fatto il caricamento del bundle avviene una tantum all'avvio, caricamento che avviene in base alle impostazioni del sistema, per tramite della classe java.util.Locale. Anche variando a runtime il contenuto del locale per mezzo di un eventuale pulsante, la classe continuerebbe a restituire i valori dello stesso file di properties.

Volendo personalizzarne questo comportamento si può richiedere di ricaricare il bundle a ogni invocazione, variando il bundle in base al locale aggiornato. Questa modifica può essere fatta direttamente sul metodo precedente, o in alternativa creando un nuovo metodo getUpdatedString, come fatto di seguito.

public static String getUpdatedString(String key) {
	try {
		ResourceBundle bundle = loadBundle();
		return bundle.getString(key);
	} catch (MissingResourceException e) {
		return "!" + key + "!";
	}
}

Con piccole modifiche, siamo quindi in grado di cambiare a runtime la lingua visualizzata. A questo punto apportiamo qualche modifica alla classe dell'interfaccia. In primo luogo rendiamo final le label e i pulsanti, quindi implementiamo il comportamento del pulsante di destra, nel seguente modo:

btnNewButton_1.addMouseListener(new MouseAdapter() {
	@Override
	public void mouseClicked(MouseEvent arg0) {
		Locale currentLocale = Locale.getDefault();
		Locale finalLocale = null;
		if(currentLocale.equals(Locale.ITALY)){
			finalLocale = Locale.UK;
			}
		else{
			finalLocale = Locale.ITALY;
		}
		Locale.setDefault(finalLocale);
		lblNewLabel_1.setText(Messages.getUpdatedString("Form.lblNewLabel_1.text"));
		lblNewLabel.setText(Messages.getUpdatedString("Form.lblNewLabel.text"));
                btnNewButton.setText(Messages.getUpdatedString("Form.btnNewButton.text_1"));
                btnNewButton_1.setText(Messages.getUpdatedString("Form.btnNewButton_1.text"));
		contentPane.updateUI();
	}
});

In pratica non si fa altro che verificare il locale impostato e se è settato su "ITALY" viene modificato su UK e viceversa. Successivamente vengono aggiornati i valori dei campi utilizzando il metodo getUpdatedString, che come abbiamo visto tiene conto del locale corrente. Con l'"updateUI" viene aggiornata l'interfaccia, e il cambio di lingua a runtime è completo.

Rilanciando il main e premendo il pulsante di cambio lingua, come effetto dovremmo ottenere la modifica del locale su UK e aggiornamento delle stringhe esternalizzate, che verranno ricaricate in Inglese. Il comportamento standard prevede che se il locale impostato non è tra quelli previsti, semplicemente verrà utilizzata la risorsa default.

Il comportamento descritto è estremamente semplice. Questo è un esempio introduttivo, si possono aggiungere altre lingue, sostituire il pulsante con un JRadioButton con il quale selezionare la lingua tra quelle a disposizione, realizzare finestre più complesse, comunque WindowBuilder semplifica il processo di design e test rapido di interfacce multilingua. Inoltre, è possibile apportare modifiche senza che queste rendano inutilizzabile l'editor visuale.

Ti consigliamo anche