MokaByte Numero 12 - Ottobre 1997
Foto
 
Internazionalizzazione 
 
di
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

La differenza principale è che le prime sono necessarie quando si deve specificare delle risorse in formato non testuale.
 

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 rivista web su Java

MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it