Una delle caratteristiche che rendono più professionale un sito è la disponibilità di informazioni tradotte in diverse lingue. Spesso i navigatori, specie nel nostro paese, tendono a tralasciare le pagine web che non presentano contenuti nella propria lingua madre. Se vogliamo, quindi, rendere internazionale il nostro sito web ed allargare il bacino d'utenza dobbiamo predisporre le medesime pagine in varie lingue.
Il web server Apache, se opportunamente configurato, può fornire automaticamente al visitatore le pagine nella lingua corretta sollevandolo dalla necessità di effettuare manualmente la scelta. Basandosi sulle informazioni inviate dal browser del visitatore, Apache può stabilire quale sia la lingua da lui preferita ed agire di conseguenza.
Sebbene quest'automatismo renda molto funzionale il nostro sito, non dobbiamo affidarci unicamente ad esso, ma prevedere anche dei link espliciti alle diverse lingue che intendiamo rendere disponibili. Le ragioni sono molteplici, innanzitutto l'utente potrebbe non aver configurato il proprio browser in modo che possa comunicare una preferenza relativa al linguaggio. Questo può accadere o perché; non è in grado di farlo, o perché; non vuole fornire informazioni personali durante la navigazione. Inoltre proviamo ad immaginare di essere all'estero, ad esempio in un internet point, costretti per necessità ad utilizzare un browser in lingua straniera: saremmo obbligati a visualizzare le pagine in una lingua diversa dalla nostra malgrado siano previste pagine in italiano.
Una volta stabilito di predisporre dei link espliciti, per ragioni di usabilità, è meglio che ciascun link sia nella lingua originale: English per l'inglese, Français per il francese e via dicendo.
Negoziazione dei contenuti
Il web server Apache supporta la negoziazione dei contenuti, content negotiation, così come prevista dalle specifiche del protocollo HTTP/1.1. In altri termini possiamo predisporre differenti rappresentazioni di una medesima risorsa, in particolare una pagina web, e poi far sì che Apache fornisca automaticamente al browser quella che meglio si adatta alle sue preferenze. Nel caso specifico prepareremo le nostre pagine in diverse lingue e forniremo al visitatore quella che coincide con le impostazioni del suo browser.
I due sistemi fondamentali di negoziazione dei contenuti sono server-driven negotiation, ovvero negoziazione gestita dal server, e transparent negotiation (RFC2295-2296), negoziazione trasparente. Quest'ultima, più sperimentale e meno consolidata, non verrà presa in considerazione. Il modulo di Apache che si occupa della negoziazione dei contenuti è mod_negotiation, compilato di default.
Il meccanismo di funzionamento si basa su un insieme di intestazioni, le cosiddette Accept Headers, che il browser invia al web server con la richiesta HTTP: Accept, Accept-Language, Accept-Charset, Accept-Encoding. Tali intestazioni permettono di specificare le proprie preferenze in termini di tipo di contenuto, lingua, set di caratteri e codifica nel caso in cui siano disponibili differenti rappresentazioni di una medesima risorsa. Un esempio di richiesta potrebbe essere la seguente:
Accept-Language: it; q=1.0, en; q=0.5
Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6
In questo caso, mediante l'header Accept-Language, viene espressa una preferenza per la lingua italiana con un fattore di qualità (q-value) pari a 1.0 ed una per la lingua inglese con un fattore pari a 0.5. Quindi, sempre nel caso siano previsti diversi linguaggi per la pagina richiesta, verrà cercata e fornita per prima quella in lingua italiana, che ha il valore più alto, poi quella in lingua inglese. Il massimo valore previsto per il q-value è 1.0, se il valore non viene esplicitamente espresso si assume pari al massimo. In altri termini Accept-Language: it ed Accept-Language: it; q=1.0 sono da considerarsi equivalenti.
Nella seconda riga, relativa al tipo di contenuto (media types), viene espressa una preferenza, nell'ordine, per il formato text/html, per un qualsiasi formato che inizia per "text/" (mediante l'uso della wildcard *) ed infine per il formato image/gif.
Come si può notare la specificazione del linguaggio avviene attraverso un tag primario en per l'inglese, fr per il francese, de per il tedesco e così via, che può essere opzionalmente seguito da un tag secondario relativo ad una particolarizzazione del linguaggio. Ad esempio en-gb specifica una preferenza per l'inglese britannico, fr-ch per il francese svizzero.
A questo proposito Apache dalla versione 2.0 adotta un comportamento non esattamente aderente alle specifiche HTTP/1.1, ma più flessibile e più utile al visitatore. Secondo gli standard se nell'header Accept-Language è presente en-gb e non en, una risorsa marcata come en non verrebbe fornita al navigatore. Ciò malgrado sia difficile ritenere che un navigatore che predilige l'inglese britannico non sia in grado di comprendere l'inglese in generale. Apache, invece, implicitamente aggiunge all'elenco il linguaggio principale, en, con un livello di priorità molto basso.
Attenzione, quindi, che se il client invia un header del tipo:
Accept-Language: en-gb;q=1.0, de;0.8
verrà comunque fornito il documento marcato de prima di quello en.
A questo proposito va' sottolineato che le RFC tendono a lasciare al produttore del browser l'onere di assistere l'utente e fargli comprendere la corretta configurazione delle preferenze, cosa che, purtroppo, non si verifica nella realtà dei fatti.
Configuriamo il browser e verifichiamo le preferenze
Per chi utilizza PHP vi è un sistema relativamente semplice per visualizzare gli header Accept inviati dal browser. Basta infatti utilizzare il codice seguente che si limita a stampare alcune variabili predefinite:
<?php
echo "<b>Header Accept:</b> " .$_SERVER["HTTP_ACCEPT"]. "<br />n";
echo "<b>Header Accept-Language:</b> " .$_SERVER["HTTP_ACCEPT_LANGUAGE"]. "<br />n";
echo "<b>Header Accept-Charset:</b> " .$_SERVER["HTTP_ACCEPT_CHARSET"]. "<br />n";
echo "<b>Header Accept-Encoding:</b> " .$_SERVER["HTTP_ACCEPT_ENCODING"]. "<br />n";
?>
Questo sistema può essere utile per verificare cosa effettivamente faccia il browser quando ne impostiamo le preferenze.
Ecco il risultato fornito per l'header Accept-Language dai tre principali browser, Netscape, Internet Explorer ed Opera, senza alcun intervento di configurazione da parte dell'utente. Come si può verificare essi impostano automaticamente all'installazione la lingua relativa alla versione del software:
Netscape 7.1 versione inglese:
Accept-Language: en-us,en;q=0.5
Internet Explorer 6.0 versione italiana:
Accept-Language: it
Opera 7.01 versione inglese:
Accept-Language: en
Per Netscape versione inglese la configurazione della lingua è possibile dal menù Edit voce Preferences e poi Language, per Explorer italiano menù Strumenti voce Opzioni Internet pulsante Lingue, infine per Opera inglese menù File voce Preferences e poi Language. Nessuno dei tre, a dire il vero, offre agli utenti l'assistenza auspicata dall'RFC2616 nella scelta della lingua. Senza l'ausilio del codice sopra riportato non sarebbe possibile, ad esempio, stabilire a priori il risultato di una configurazione in termini di fattore di qualità q-value.
Per fare un esperimento provate ad aggiungere alle preferenze linguistiche del vostro browser Arabo [ar] (Arabic [ar] se in lingua inglese) e portatelo in cima alla lista. Adesso collegatevi alla url http://www.google.com ed osservate il risultato.
Prepariamo le nostre pagine multilingue
A questo punto dobbiamo predisporre le pagine nelle diverse lingue che vogliamo rendere disponibili. Dovremo avere l'accortezza di salvare tali pagine con estensioni del tipo .html.it per l'italiano, .html.en per l'inglese e via dicendo. A titolo di esempio creiamo tre pagine index nelle lingue italiano, francese ed inglese e salviamole in una directory del nostro web server.
index.html.it:
<html>
<head>
<title>Index Italiano</title>
</head>
<body>
<h2>Una pagina in lingua italiana</h2>
</body>
</html>
index.html.fr:
<html>
<head>
<title>Index Français</title>
</head>
<body>
<h2>Une page en français</h2>
</body>
</html>
index.html.en:
<html>
<head>
<title>English Index</title>
</head>
<body>
<h2>An english page</h2>
</body>
</html>
Il risultato che desideriamo ottenere è che, richiamando semplicemente la pagina index.html, venga fornita quella corretta in base alle preferenze linguistiche espresse dal browser. Ovviamente se abbiamo impostato la direttiva DirectoryIndex nel modo seguente:
DirectoryIndex index.html
non sarà necessario specificare il nome del file nella url digitata. Si ricorda che tale direttiva imposta l'elenco di nomi di files che Apache fornisce se viene richiesta genericamente una directory senza specificare un particolare nome di file.
Configuriamo Apache
I moduli interessati nella negoziazione della lingua sono il già citato mod_negotiation, cui si aggiunge mod_mime, entrambi compilati di default. Mod_mime viene utilizzato per associare alcune metainformazioni relative ai files direttamente all'estensione del loro nome, tra queste vi è anche la lingua. Ecco il motivo per cui abbiamo creato le pagine index.html.it, index.html.fr, index.html.en.
Prima di entrare nel merito della configurazione si ricorda brevemente che le direttive del web server Apache si possono applicare a diversi contesti. In particolare possono essere inserite in un qualunque punto del file di configurazione httpd.conf (server config), fra i contenitori o in un file di configurazione per-directory. Nel primo caso il loro effetto sarà globale, riferendosi al web server in generale.
I contenitori, invece, rappresentati da una coppia di tag del tipo <VirtualHost></VirtualHost>, <Directory></Directory>, etc., consentono di stabilire delle limitazioni all'ambito di applicazione di una direttiva.
I file di configurazione per-directory, il cui nome di default è .htaccess, sono file di testo contenenti alcune istruzioni e memorizzati in una specifica directory. Essi vengono analizzati da Apache nel momento in cui viene effettuata una richiesta per un file che si trova nella medesima directory.
Sono di fondamentale importanza per chi, ad esempio, gestisce uno spazio in hosting su un server web unicamente tramite accesso ftp e non ha la possibiltà di accedere al file di configurazione httpd.conf.
Di seguito si descriverà un modo di configurare Apache per ottenere il risultato desiderato, naturalmente sono possibili altre scelte. Innanzitutto si userà l'opzione Multiviews della direttiva Options. Tale direttiva controlla le funzioni del server in un particolare contesto: può essere usata a livello di server config, virtualhost, directory o .htaccess. La sintassi è:
Options + o - opzione
Le opzioni disponibili sono None, All, Indexes, Includes, FollowSymLinks, SymLinksifOwnerMatch, ExecCGI, Multiviews, per una descrizione completa si rimanda alla documentazione ufficiale.
Chiaramente se impostiamo Options su None disabilitiamo tutto, se la impostiamo su All abilitiamo tutte le opzioni ad eccezione di Multiviews. Attenzione che Multiviews deve essere attivata esplicitamente! In sintesi l'effetto dell'opzione Multiviews è questo: se il server riceve una richiesta per http://www.mioserver.it/nome_directory/nome_file ed il file nome_file non esiste, allora effettua una ricerca per tutti i files del tipo nome_file.* e tra questi sceglie quello che meglio si adatta alla richiesta del client.
Supponendo di voler predisporre una particolare directory per l'utilizzo multilingue possiamo cominciare impostando un contenitore <Directory> così:
<Directory "/percorso_della_directory">
DirectoryIndex index.html
Options Multiviews
</Directory>
Altra direttiva importante per i nostri scopi è AddLanguage che ha la seguente sintassi:
AddLanguage MIME-language estensione estensione ....
ad esempio
AddLanguage en .en .english
AddLanguage fr .fr
essa mappa, nel caso particolare, tutti i files con estensione .en ed .english come file in lingua inglese ed i files con estensione .fr in lingua francese. Il file httpd.conf riporta già un elenco di direttive AddLanguage sufficientemente nutrito. Nel caso non bastino o si vogliano variare le estensioni dei files nella mappatura, si interverrà modificando o aggiungendo direttive secondo le proprie esigenze. Anche in questo caso il contesto di utilizzo è server config, virtualhost, directory o file .htaccess.
Una direttiva che può risultare utile in alcune circostanze è DefaultLanguage, con sintassi:
DefaultLanguage MIME-language
ad esempio
DefaultLanguage fr
La direttiva comunica ad Apache che tutti i files senza una specifica estensione di linguaggio (.en, .fr, .it configurate con AddLanguage), devono essere considerati come appartenenti al MIME-language specificato. Questo permette di associare una directory già esistente e non predisposta per la negoziazione della lingua, ad uno specifico linguaggio senza dover rinominare tutti i files. Il contesto in cui può essere usata è server config, virtualhost, directory o file .htaccess.
<Directory "/percorso_della_directory">
DirectoryIndex index.html
Options Multiviews
DefaultLanguage fr
</Directory>
LanguagePriority imposta la precedenza tra le varianti di linguaggio nel caso il client non esprima una preferenza ed invii un header Accept-Language vuoto. A rigore se la lista delle lingue è vuota il browser dovrebbe omettere l'header Accept-Language poichè un Accept-Language senza parametri corrisponde ad un errore nel protocollo. Il contesto in cui è applicabile è sempre server config, virtualhost, directory, .htaccess.
La sintassi è:
LanguagePriority MIME-language MIME-language ......
ad esempio
LanguagePriority it fr de
stabilisce che, in assenza di una preferenza per il linguaggio da parte del browser, prima verrà cercata ed eventualmente fornita la risorsa in lingua italiana, in caso non ci sia si passerà al francese ed infine al tedesco. Tornando al nostro esempio:
<Directory "/percorso_della_directory">
DirectoryIndex index.html
Options Multiviews
LanguagePriority it en da nl et fr de el ja ko no pl pt pt-br ltz ca es sv tw
</Directory>
ForceLanguagePriority è una direttiva introdotta dalla versione 2.0.30, con la seguente sintassi:
ForceLanguagePriority opzione
Le opzioni sono None, Prefer e Fallback.
- None ovviamente disabilita gli effetti della direttiva.
- Prefer utilizza le impostazioni date da LanguagePriority per operare una scelta nel caso il client specifichi lo stesso fattore di qualità per i linguaggi disponibili. Supponendo di avere la seguente configurazione:
LanguagePriority it fr de
ForceLanguagePriority Prefer
e che il browser assegni q=0.5 sia a it che fr, in questo caso il server sceglierà it perché; precede gli altri linguaggi in ordine di priorità
Nel caso della nostra directory:
<Directory "/percorso_della_directory">
DirectoryIndex index.html
Options Multiviews
LanguagePriority it en da nl et fr de el ja ko no pl pt pt-br ltz ca es sv tw
ForceLanguagePriority Prefer
</Directory>
- Fallback, infine, permette al server di fornire comunque una risorsa tra le varianti disponibili anche se le preferenze del browser non coincidono con nessuna di esse. Ad esempio con la seguente configurazione:
LanguagePriority it fr de
ForceLanguagePriority Fallback
se il browser è impostato per richiedere solo en, Accept-Language: en, ma tale variante non risulta disponibile, il server fornirà la prima variante esistente seguendo l'ordine determinato da LanguagePriority.
Senza tale impostazione, seguendo le specifiche del protocollo HTTP, il server risponderebbe con un errore 406, Not Acceptable, e fornirebbe un elenco delle varianti disponibili. Per la nostra directory:
<Directory "/percorso_della_directory">
DirectoryIndex index.html
Options Multiviews
LanguagePriority it en da nl et fr de el ja ko no pl pt pt-br ltz ca es sv tw
ForceLanguagePriority Prefer Fallback
</Directory>
Conclusioni
In questo articolo si sono descritte le direttive fondamentali per la realizzazione di un sito multilingue basato su Multiviews, si è fatto espresso riferimento ad un sito statico, anche se esistono configurazioni che permettono di far cooperare pagine dinamiche (PHP, CGI, etc) con la negoziazione della lingua. Negli esempi fatti si sono utilizzate pagine la cui estensione era del tipo .html.en o .html.it, il discorso non cambierebbe se utilizzassimo le estensioni .en.html o .it.html. Come unica accortezza, nella direttiva DirectoryIndex, dovremmo utilizzare solo il nome del file index ovvero:
DirectoryIndex index
Questa seconda soluzione sembrerebbe inoltre più gradita ai motori di ricerca, in particolare Google. Pare infatti che quest'ultimo indicizzi immediatamente come documenti HTML solo le pagine con specifica estensione htm o html, quindi il file nome_pagina.it.html verrebbe correttamente indicizzato al contrario di nome_pagina.html.it. Ribadisco ancora l'importanza, in termini di usabilità, di predisporre comunque dei link espliciti e comprensibili alle diverse lingue rese disponibili sul nostro sito.
Consiglio infine di fare qualche esperimento modificando le impostazioni della lingua dei vari browser, verificando gli headers Accept mediante il codice sopra riportato ed analizzandone il comportamento a seconda delle direttive impostate.