MokaByte
Numero 12 - Ottobre 1997
|
|||
|
|
||
Michele Sciabarrà |
Come rendere le proprie applicazioni non solo portabili ma anche comprensibili in tutto il mondo. | ||
Ogni cosa
esposta su Internet è visibile in tutto il mondo. L'inglese è
considerata la lingua di Internet, infatti moltissime pagine sono scritte
in inglese. Comunque non è vero che tutti conoscono l'inglese. In
realtà esistono delle aree di Internet caratterizzate da una ben
precisa identità culturale e linguistica. per Per esempio, navigando
nei siti italiani si trova molto materiale in italiano, anche se non sono
pochi i siti che adottano un approccio multilingue: "click here for English
Version of this page".
La realtà
è che, se si vuole veramente seguire un approccio internazionale,
occorre saper portare la montagna a Maometto e tradurre il proprio messaggio
nella lingua del destinatario. Questo discorso vale per le pagine Web che
per applicazioni e soprattutto applet Java. A differenza del software pacchettizzato
tradizionale, in cui le versioni in più lingue seguivano dopo la
versione nella lingua del produttore, quando si espone una applet su Internet
questa deve essere immediatamente e contemporaneamente utilizzabile in
più lingue. Per fortuna la API 1.1. di Java ci aiuta a risolvere
questo problema.
Panoramica
L'internazionalizzazione
di una applicazione consiste nel mostrare menù, bottoni, messaggi
di errore e altri elementi testuali (ed eventualmente grafici) in varie
lingue. Meglio ancora, all'avvio una applicazione deve consentire la scelta
tra più lingue.
Con qualche manovra di codice era possibile ottenere questi risultati col JDK 1.0, che non aveva un esplicito supporto all'internazionalizzazione. Comunque ci si scontrava con una serie di limitazioni. Il JDK 1.1 invece supporta estesamente l'internazionalizzazione e consente di risolvere facilmente problemi che prima erano abbastanza ardui, come la rappresentazione di date ed ore secondo le varie convenzioni locali. In particolare:
Locale
La classe java.util.Locale
viene utilizzata come parametro per la selezione delle risorse da utilizzare.
Questa classe rappresenta una zona dal punto di vista sia linguistico che
geografico. Una zona viene infatti individuata sia per lingua che per area
geografica. Sebbene spesso in una area geografica si parla solo una lingua,
questo non è sempre vero. In tutta Italia si parla solo l'italiano
(senza voler considerare in questo caso i dialetti), ma in per esempio
in Svizzera si parla correntemente sia l'italiano che il tedesco. Il locale
non serve solo ad identificare la lingua, ma anche altre informazioni come
la valuta o la rappresentazione di data e ora.
Quindi, anche data una lingua, sono possibili due diversi locale, determinati dall'area geografica. Il locale dell'Italia sarà specificato da una stringa it_IT (lingua, area geografica), la Svizzera italiana con it_CH e la Svizzera tedesca con de_CH. Java usa degli standard internazionali per identificare lingue e aree geografiche. Per la precisione per le lingue si utilizza lo standard ISO Language Code, mentre per le aree geografiche si utilizza lo standard ISO Country Code. Il primo identifica una lingua con due lettere minuscole mentre il secondo utilizza due lettere maiuscole per identificare la regione. La stringa composta dai due codici separati da una sottolineatura si utilizza spesso in nomi di classi di risorse. L'instanza della classe Locale desiderata si ottiene passando al costruttore come parametro le due stringhe Language e Country code. Per esempio per l'Italia, si può creare il locale con new Locale("it", "IT"). Molti Locale sono sicuramente più usati di altri: per questi ultimi sono disponibili delle costanti (oggetti static final) facilmente accessibili: per esempio Locale.ITALIAN, Locale.US o persino Locale.CANAD_FRENCH . Non sono previsti comunque casi particolari più limitati come quello della Svizzera tedesca.
Bisogna tenere
ben presente che le istanze della classe Locale hanno il solo scopo di
indentificare una area linguistico-geografica e di servire come parametro
per identificare le informazioni di una certa zona. Di per sé, comunque,
non contengono alcuna informazine specifica. Le informazioni specifiche
vengono invece memorizzate in classi come le istanze di ResourceBundle.
Risorse
Per riuscire
a internazionalizzare facilmente una interfaccia grafica, occorre riuscire
concentrare tutte le informazioni che possono variare da una lingua all'altra
in file con un formato facilmente modificabili. La traduzione infatti spesso
viene fatta da personale che non è necessariamente un programmatore
in grado di modificare del codice.
Grazie all'uso delle risorse, per aggiungere una nuova lingua ad una applicazione basta tradurre alcuni file e aggiungerli all'applicazione. Attraverso appositi meccanismi che vedremo, le nuove risorse verranno automaticamente utilizzate qualora si imposti adeguatamente il Locale corrente dell'applicazione.
Ovviamente occorre scrivere l'applicazione in modo che faccia uso esplicito delle risorse. Per esempio consideriamo una applet che deve essere internazionalizzata. All'avvio questa può presentare dei bottoni che consentono di scegliere la lingua da utilizzare nell'applicazione: per esempio Italiano, Inglese e Francese. Premendo uno di questi tasti impostiamo una variabile, locale di tipo Locale. Quando il costruttore dell'interfaccia imposta testi, numeri ed eventualmente immagini, deve prima caricare le risorse utilizzando il locale come parametro. In questo modo le stringhe che compariranno a video proverranno dalle risorse per la lingua opportuna. Questo non basta, ma il resto lo vedremo più avanti. Adesso concentriamoci sulla gestione di risorse.
La classe principale per la gestione delle risorse è java.util.ResourceBundle. Questa classe è astratta e non può essere istanziata. Si utilizzano invece le classi concrete java.util.ListResourceBundle (che definisce le risorse utilizzando delle costanti espresse in codice Java) o java.util.PropertyResourceBundle (che consente di specificare le risorse utilizzando dei file di proprietà). Una altra interessante possibilità è estendere direttamente la classe ResourceBundle per definire una sorgente di risorse ad hoc, per esempio prelevandole da un database.
Consideriamo per prima ListResourceBundle. Per utilizzarla è necessario estenderla con una classe il cui nome termina con la stringa _<lingua>_<area>, e definire il metodo public Object[][] getContens(), il quale deve ritornare un array di array. Ogni elemento dell'array deve essere un array il cui primo elemento deve essere una stringa e il secondo un oggetto qualsiasi (solitamente una stringa anche esso). Per esempio per le risorse per l'italiano occorre creare una classe
class Res_it_IT extends ListResourceBundle {
public Object[][] getContents(){
return contents; }
static final Object[][] contents = {{ "m_file", "File" },{ "m_open", "Apri"
} }
}
In realtà non occorre specificare completamente lingua e regione, sarebbe potuto bastare nel nostro caso chiamare la classe semplicemente Res_it : la risorsa verrebbe utilizzata ogni volta che viene richiesta la lingua italiana, indipendentemente dalla regione. In questo caso per la Svizzera italiana, in mancanza di una classe più specifica (che si dovrebbe chiamare Res_it_CH), verrebbe scelta la risorsa Res_it. È anche possibile definire una risorsa di default, il cui nome non deve avere specificatori di regioni. Solitamente questa scelta viene riservata alle classi in inglese per gli Stati Uniti, che viene spesso considerata la scelta di default.
Le risorse devono essere compilate adeguatamente, ottenendo un file .class per ogni risorsa. A questo punto utilizzando
ResourceBundle res = ResourceBundle.getBundle("Res", locale);
si caricano le risorse. La selezione della classe opportuna viene svolta da ResourceBundle in base al locale. A questo punto si possono utilizzare le risorse per esempio nella costruzione di un MenuItem , scrivendo
item = new MenuItem(res.getString("m_open"));
Se il locale corrente è l'italiano (ed sono disponibili le risorse per l'italiano), si otterrà "Apri" come voce di menù. Notare l'utilizzo di una stringa "neutrale" (nel nostro caso m_open) per identificare la risorsa, specificata in inglese ma solo come convenzione interna di codifica. Ovviamente le risorse devono essere esplicitamente utilizzate nella costruzione di menù, nei messaggi e in altri elementi testuali e grafici delle GUI per ottenere l'internazionalizzazione. Per aggiungere una nuova lingua è sufficiente aggiungere una nuova classe con il nome opportuno, e impostare correttamente il locale corrente (solitamente all'avvio dell'applicazione).
Una altra via di personalizzare le risorse è l'uso di un file di proprietà che consente di memorizzare risorse di tipo stringa in un file del formato di un file standard di proprietà. La cosa interessante è che quando si cerca una risorsa, se non viene trovato un file .class , viene cercato un file .properties con un nome appropriato. Per esempio, per personalizzare in inglese il nostro programma, quando viene richiesto un locale en , se è presente un file Res_en.properties con questo contenuto:
m_file=File
m_open=Open
allora questo file verrà usato al posto di un file Res_en.class per le risorse per l'applicazione. Le
Numeri
e lettere
Il package java.text
contiene numerose classi che servono a gestire la formattazione di
dati numerici e testuali secondo le varie convenzioni locali. Al solito
è necessario utilizzare un oggetto istanza della classe Locale come
parametro per stabilire la formattazione da applicare. Consideriamo innanzitutto
il caso di data e ora.
Tramite
import java.text.*;
DateFormat df = DateFormat.getDateInstance(locale);
si ottiene una
instanza localizzata del formattatore di date, che ci consente sia di stampare
e ottenere informazioni sulla data (df.format, df.getCalendar , df.getTimeZone,
eccetera) che di analizzare una stringa che esprime la data nel formato
locale (df.parse). Queste funzioni sono in grado di tenere conto
delle differenze tra i diversi usi locali. Per esempio in Italia (e in
Europa) 9/7/68 indica il 9 luglio 1968, mentre negli Stati Uniti indica
il 7 settembre 1968! Analogamente NumberFormat è in grado
di fornire informazioni sulle consuetudini locali relative ai formati numerici.
Tramite
NumberFormat nf = NumberFormat.getInstance(locale);
per i numeri in genere, oppure
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
per la valuta si gestiscono la scansione (nf.parse) e la formattazione (nf.format) dei numeri utilizzando le convenzioni locali, che generalmente riguardano il carattere utilizzato per identificare la valuta, separare la virgola o i decimali. Per esempio (differenze di valore di cambio a parte) ciò che in Italia si scriverebbe Lit.1.234,56 (con il punto separatore di migliaia e la virgola come separatore di decimali), negli USA è $ 1,234.56 (virgole e punto sono scambiate, e la valuta è diversa).
Infine accenniamo i problemi di ordinamento alfabetico e di comparazione di stringhe che non sono affatto semplici. La classe Collator fornisce un metodo di comparazione , compare, e lo strenght per impostare l'esattezza della comparazione. Per intenderci, normalmente quando si fanno delle ricerche in un file di testo si può selezionare tra la ricerca esatto (che tiene conto di maiuscole e minuscole) e una più rilassata (e più utile) che ignora le differenze tra maiuscolo e minuscolo. La classe Collator fornisce 4 livelli di comparazione: IDENTICAL, PRIMARY, SECONDARY e TERTIARY , il cui significato varia a seconda del locale. Per esempio in italiano, "e" ed "e" sono identiche, "e" ed "è" hanno una differenza secondaria, mentre "e" ed "E" hanno una differenza terziaria. Impostando la strength a terziaria vengono ignorate le differenze tra minuscolo e maiuscolo, mentre impostandola a secondaria vengono ignorare le differenze di accento.
Michele
Sciabarrà è consulente informatico e scrittore
tecnico specializzato in sistemi e applicazioni Internet Intranet.
Si occupa di consulenza, amministrazione e sviluppo software per ambienti di rete e siti web. Può essere contattato presso l'indirizzo sciabarra@infomedia.it |
|
||
|
||
MokaByte ricerca
nuovi collaboratori
|
||
|