Introduzione
Uno
degli aspetti che maggiormente contribuisce al successo di un software
è legato alla sua semplicità d’uso, sia in termini di installazione
che nell’utilizzo vero e proprio. Per quanto concerne l’uso del servizio
da parte dell’utente finale, l’utilizzo di Cartolina.java risulta piuttosto
intuitivo in quanto simile a “prodotti concorrenti”, ovvero ad altri servizi
di e-card che l’utente può aver utilizzato in passato. Anche qualora
l’utente non avesse mai inviato cartoline elettroniche l’interazione non
dovrebbe costituire un grosso problema, in quanto le azioni che l’utente
deve svolgere sono analoghe a quelle che una persona compie inviando una
cartolina reale: si sceglie un’immagine, si immettono nome e indirizzo
di mittente e destinatario, si scrive un breve messaggio e si invia.
Per
quanto concerne la facilità di installazione intervengono altri
problemi. Il principale è costituito dal fatto che per far funzionare
una servlet è necessario che il server internet sul quale si intende
far girare l’applicazione supporti la tecnologia, attraverso un’estensione
del demone http o attraverso un’applicazione indipendente. Questo prerequisito
risulta tuttora piuttosto limitante, in quanto i service providers che
supportano l’utilizzo delle servlet sono tuttora una minoranza, e presuppone
che l’amministratore di sistema abbia una buona familiarità sia
con il sistema operativo sottostante (linux o NT) che con l’ambiente java.
Un amministratore capace di far convivere linux, apache, jserv e jdk 1.2
(tanto per citare l’ambiente che io utilizzo) non dovrebbe spaventarsi
di fronte all’ipotesi di metter mano ad alcune righe di codice java e ricompliare
la classe in questione.
D’altro
canto è comunque buona norma adottare, nei limiti del possibile,
soluzioni che richiedano il minimo intervento da parte dell’utilizzatore,
soprattutto qualora non si intenda distribuire il codice sorgente.
Uno
dei punti di forza di java è la sua idipendenza di piattaforma:
una stessa applicazione gira, a parità di macchina virtuale, su
sistemi diversi. Cartolina.java può essere compilata su Windows
98 (il pc del mio ufficio) ed il file Cartolina.class gira perfettamente
su Red Hat 6.2 (il mio server). I problemi sorgono nel momento in cui la
servlet deve leggere o scrivere dei file, in quanto i nomi di percorso
su macchine diverse - anche con lo stesso s.o. - probabilmente non coincidono.
La
soluzione più pratica consiste nel separare le variabili specifiche
per ogni macchina dal codice della classe: l’applicazione andrà
a leggere su di un file esterno i valori in questione. In questo modo sarà
sufficiente mettere mano al file di testo senza dover ricompilare il programma.
Per
far fronte a questa esigenza java mette a disposizione la classe ResourceBundle,
finalizzata proprio a gestire in maniera efficace un file di risorse esterno
da parte di una classe java.
Potete
trovare un ottimo esempio dell’utilizzo di ResourceBundle in Stylepad,
una delle applicazioni distribuite assieme al jdk (si trova in %javahome%/demo/jfc/Stylepad/).
Le prime righe della classe Stylepad si occupano proprio di costruire l’oggetto
ResourceBundle:
private
static ResourceBundle resources;
static {
try {
resources =
ResourceBundle.getBundle("resources.Stylepad",
Locale.getDefault());
}
catch (MissingResourceException mre) {
System.err.println("Stylepad.properties not found");
System.exit(0);
}
}
L’oggetto
resources viene creato attraverso l’invocazione del metodo static ResourceBundle.getBundle
che, come possiamo notare, prevede due parametri. Il primo parametro si
riferisce al nome del file in questione: la funzione getBundle cercherà
un file chiamato Stylepad.properties nella sottodirectory resources (per
una spiegazione più dettagliata si veda
http://java.sun.com/products/jdk/1.1/docs/api/java.util.ResourceBundle.html).
Il
secondo parametro richiesto è un oggetto di tipo Locale. Ci soffermeremo
su questo aspetto nel prossimo paragrafo, dedicato al supporto multilingue
della servlet. Per ora soffermiamoci su come Cartolina.java utilizza ResourceBundle
per definire le variabili d’ambiente.
Locale lingua = Locale.getDefault();
try {
resources = ResourceBundle.getBundle("CustomCard", lingua);
serverdirpath = resources.getString("serverdirpath");
serverlogpath = resources.getString("serverlogpath");
imageURL = resources.getString("imageURL");
URLpath = resources.getString("URLpath");
smtpserver = resources.getString("smtpserver");
countfilename = serverlogpath + "customcount.log";
logname = serverlogpath + "customlog.log";
}
catch
(MissingResourceException mre) {
System.err.println(mre);
}
Questo
codice, inserito nella funzione init, permette alla servlet di acquisire
il percorso assoluto dove dovrà cercare o salvare i file. L’applicazione
si aspetta di trovare un file denominato CustomCard.properties che definisce
le variabili in questione. Se andiamo a leggere il file CustomCard.properties
troveremo fra l’altro le seguenti righe:
#
the path on your server where generated cards are stored
serverdirpath
= /home/httpd/html/files/customcards/
#
the path on your server where you want to save the logs
serverlogpath
= /home/pippo/lavoro/
#
the url were images are linked
imageURL=http://www.miosito.it/cartoline/
#
the url where generated cards are linked
URLpath=http://www.miosito.it/files/customcards/
smtpserver=mail.mioserver.it
Queste
variabili sono appropriate per funzionare sul server. Se voglio testare
l’applicazione in locale sul mio PC (ad esempio usando jswdk) le variabili
d’ambiente saranno le seguenti:
serverdirpath=C:\\Programmi\\java12\\jswdk\\examples\\cartoline\\
serverlogpath=C:\\Programmi\\java12\\jswdk\\examples\\cartoline\\
imageURL=http://127.0.0.1:8080/examples/cartoline/
URLpath=http://127.0.0.1:8080/examples/cartoline/
smtpserver=mail.mioprovider.it
Ricapitolando:
io creo due versioni diverse del file CustomCard.properties: una da salvare
sul server, una da mantenere in locale. Il sistema cercherà il file
nella stessa directory della applicazione. Qualora volessi salvare il file
nella sottodirectory pippo l’invocazione della classe da parte del metodo
getBundle dovrà avvenire utilizzando la notazione getBundle (“pippo.CustomCard”,
lingua). In questo modo io posso compilare la classe sul mio pc locale
e questa funzionerà allo stesso modo sia su windows 98 e jswdk che
su linux e apache jmod. Chiunque voglia usare la servlet dovrà adattare
soltanto il file CustomCard.properties, in base alle impostazioni del proprio
sistema. Facciamo incidentalmente notare che, poiché la servlet
invia un messaggio di posta elettronica di notifica, dovrà utilizzare
un server smtp. La variabile smtpserver=mail.mioprovider.it è deputata
proprio ad identificare un server cui il sistema può accedere.
Localizzazione:
creare una servlet multilingue
Ritorniamo
alla funzione ResourceBundle.getBundle. Il secondo argomento consiste in
un oggetto di tipo Locale.
La
classe Locale è finalizzata ad identificare una regione geografica
o culturale. In pratica la classe viene utilizzata per localizzare un’applicazione,
ovvero per tradurre un’applicazione in differenti lingue. Se scrivo un
programma per un mercato internazionale, è necessario che io predisponga
delle versioni diverse per ognuna delle aree linguistiche dove prevedo
che il prodotto venga utilizzato. In maniera del tutto simile a quella
delle variabili di ambiente appena viste, la soluzione più elegante
consiste nel separare il codice del programma da tutti gli aspetti di interfaccia
connotati linguisticamente, quali le voci dei menu, dei dialoghi e così
via. Prima dell’avvento di internet la necessità di tradurre un’applicazione
in differenti lingue era circoscritta ad aziende di grandi o medie dimensioni,
ma con il diffondersi del web e la possibilità di distribuire i
propri lavori on line il problema della localizzazione diventa centrale.
La soluzione più semplice consiste nello scrivere tutto direttamente
in inglese, la lingua di riferimento per la rete. L’approccio più
elegante ed efficace, per chi usa java, è quello di usare le due
classi ResourceBundle e Locale.
Se
si considera che una servlet è per definizione un’applicazione che
gira su internet ecco che la necessità di creare una interfaccia
multilingue potrebbe risultare addirittura comune: personalmente ho scritto
Cartolina.java per pubblicizzare il sito di un albergo, ed è dunque
auspicabile che il servizio venga utilizzato da utenti italiani, tedeschi,
inglesi.
Il
primo passo da compiere per avere una cartolina virtuale multilingue è
creare un file CustomCard.properties per ognuna delle lingue supportate,
per esempio italiano ed inglese.
La
classe ResourceBundle prevede che i file che identificano le risorse vengano
salvati attraverso una precisa notazione: “nomerisorsa_lingua_paese.properties”.
Ad
esempio CustomCard_en_US.properties identifica l’inglese statunitense,
CustomCard_en_uk.properties quello britannico.
In
realtà è possibile specificare con ancora maggior dettaglio
la localizzazione, definendo una “variante” linguistica: per approfondimenti
si consiglia di far riferimento alla documentazione concernente la classe
Locale.
E’
possibile usare un file che specifichi la lingua ma non il paese (CustomCard_en.properties).
Questa
risorsa verrà utilizzata qualora non esista un file specifico per
il paese, o non si ritenga opportuno specificare versioni diverse per i
diversi paesi.
Nel
nostro esempio, se intendiamo realizzare una versione delle cartoline in
italiano ed una in inglese, dovremo creare i file CustomCard_it.properties
e CustomCard_en.properties. Nei due file sono state inserite tutte le frasi
che la servlet usa per interagire con il mittente, per inviare l’e-mail
al destinatario e per generare la cartolina. Alcune righe di esempio chiariranno
il concetto:
in
CustomCard_it.properties troveremo, fra l’altro, le seguenti righe.
warning=Attenzione,
parametri mancanti! tutti i campi devono essere compilati
imageField=l'immagine
della cartolina
sendernamefield=inserisci
il tuo nome
sendermailfield=la
tua e-mail
receivernamefield=il
nome del destinatario
receivermailfield=l'e-mail
del destinatario
textfield=il
testo della cartolina
In
CustomCard_en.properties le corrispondenti righe sono:
warning=Warning,
some fields are empty. you have to fill all the fields
imageField=the
image of the e-card
sendernamefield=your
name (or nick)
sendermailfield=your
e-mail
receivernamefield=the
name (nick) of your friend
receivermailfield=the
e-mail of your friend
textfield=the
text of the e-card
Queste
variabili si riferiscono alla descrizione dei campi della form che l’utente
utilizza per mandare la cartolina. Per conoscere la lingua dell’utente,
si utilizza la variabile “Accept-Language” che il browser invia al server
tramite http, attraverso il metodo request.getHeader("Accept-Language");
Poiché
abbiamo creato soltanto 2 versioni linguistiche delle nostre properties,
dovremo adottare una soluzione di compromesso:
String
language = request.getHeader("Accept-Language");
if (language == null) {
lingua = Locale.ENGLISH;
return;
}
if (language.equalsIgnoreCase ("en")) {
lingua = Locale.ENGLISH;
return;
}
if (language.equalsIgnoreCase ("it")) {
lingua = Locale.ITALIAN;
return;
}
lingua = Locale.ENGLISH;
}
In
queste righe di codice si interroga la variabile “Accept-Language”. Se
l’utente è italiano si utilizza il locale italiano, in tutti gli
altri casi si risponde in inglese (lingua internazionale). Qualora approntassimo
un file CustomCard_de.properties, basterebbe aggiungere tre righe di codice
per permettere alla servlet di utilizzare la versione tedesca:
if (language.equalsIgnoreCase ("de")) {
lingua = Locale.GERMAN;
return;
}
Infine
si interroga il file di proprietà selezionato per ricavarne le frasi
da utilizzare nell’interfaccia:
warning = resources.getString("warning");
imageField = resources.getString("imageField");
sendernamefield = resources.getString("sendernamefield");
sendermailfield = resources.getString("sendermailfield");
receivernamefield = resources.getString("receivernamefield");
receivermailfield = resources.getString("receivermailfield");
Nel
visualizzare la form verranno utilizzate le variabili così ottenute,
generando una pagina di volta in volta in italiano, o in inglese, o in
tedesco:
out.println("<tr><td>" + sendernamefield + "</td>");
out.println("<td><input name=\"nomemitt\" type=\"text\" value=\"\"></td></tr>");
out.println("<tr><td>" + sendermailfield +"</td>");
out.println("<td><input name=\"mailmitt\" type=\"text\" value=\"\"></td></tr>");
out.println("<tr><td>" + receivernamefield + "</td>");
out.println("<td><input name=\"nomedest\" type=\"text\" value=\"\"></td></tr>");
out.println("<tr><td>" + receivermailfield + "</td>");
out.println("<td><input name=\"maildest\" type=\"text\" value=\"\"></td></tr>");
Come
vediamo, nel generare il codice html della form vengono utilizzate le variabili
acquisite dai file di risorsa.
Cartoline internazionali
Ne
“Il computer invisibile” Donald Norman afferma che una tecnologia, per
essere efficace e di facile usabilità, dovrebbe essere invisibile
all’utente, e funzionare senza che questi se ne accorga. La strategia di
localizzazione descritta in queste righe funziona proprio in questo modo:
l’utente chiede un servizio, inconsapevole che il proprio browser comunica
al server le sue preferenze linguistiche. Il server elabora la pagina richiesta,
in maniera congruente con le informazioni che dispone, e la presenta all’utente.
Questi non sa, o non sospetta, che esistano differenti versioni della stessa
pagina: la tecnologia è dunque efficace ma invisibile. Il problema
linguistico emerge soltanto nel momento in cui un utente italiano invia,
ad esempio, una cartolina ad un amico inglese. Poiché l’applicazione
da noi sviluppata tiene conto soltanto della lingua del mittente, i (pochi)
elementi linguistici della cartolina saranno in italiano. Per risolvere
questo problema si dovrebbe ricorrere all’uso di un database: la servlet
salva le informazioni sotto forma di record, evita di creare una versione
statica della cartolina ma la genera dinamicamente nel momento in cui viene
letta. In questo modo può “tradurre” l’interfaccia nella lingua
del destinatario. Una simile strategia risulta sproporzionata per le esigenze
di una cartolina virtuale, ma risulterebbe utilissima in siti come e-bay,
dove persone di differenti paesi vendono e comperano i propri beni. In
questo caso il server potrebbe tradurre non soltanto l’interfaccia linguistica
ma anche la valuta: posso comperare in lire un portatile usato che uno
statunitense vende in dollari, sperando che l’euro, nel frattempo, non
precipiti! :-(.
Conclusioni
Siamo
abituati ad apprezzare java come linguaggio multipiattaforma. Attraverso
un accorto utilizzo dei package che java ci mette a disposizione, possiamo
creare, senza grosse difficoltà, applicazioni multilingue: la stessa
applicazione può girare su macchine diverse ed essere fruita da
utenti di differenti estrazioni linguistiche.
Bibliografia
The
java tutorial: Intenationalization
Donald
Norman: The Invisible Computer
Stefano
Bussolon, laureato in psicologia sperimentale. Partecipa, nella veste di
"cultore della materia", all'attività didattica dei corsi di Intelligenza
Artificiale e di Ergonomia della Facoltà di Psicologia di Padova.
Per il corso di Ergonomia ha condotto un seminario sull’usabilità
del www. Fa parte del laboratorio di realtà virtuale del dipartimento
di Psicologia Generale di Padova. E-mail: bussolon@psy.unipd.it
|