Appendice I. Localizzazione

La localizzazione è una funzionalità di Bash non documentata.

Uno script di shell localizzato visualizza il testo dell'output nella lingua che è stata definita, nel sistema, come locale. Un utente Linux di Berlino, Germania, preferirebbe gli output degli script in tedesco, mentre suo cugino di Berlin, Maryland, li vorrebbe in inglese.

Per creare uno script localizzato, che visualizzi nella lingua dell'utente tutti i messaggi (messaggi d'errore, prompt, ecc,), si usi lo schema descritto nel seguente script.

#!/bin/bash
# localized.sh
#  Script di Stéphane Chazelas,
#+ modificato da Bruno Haible, corretto da Alfredo Pironti.

.gettext.sh

E_CDERROR=65

error()
{
  printf "$@" >&2
  exit $E_CDERROR
}

cd $var || error "`eval_gettext \"Can\'t cd to \\\$var.\"`"
#  È necessaria la tripla barra inversa (escape) davanti a $var
#+ "perché eval_gettext si aspetta una stringa
#+ dove i valori della variabile non sono ancora stati sostituiti."
#    -- secondo Bruno Haible
read -p "`gettext \"Enter the value: \"`" var
#  ...


#  ----------------------------------------------------------------------------
#  Commento di Alfredo Pironti:

#  Lo script è stato modificato in modo da non utilizzare la sintassi
#+ $"..." in favore di "`gettext \"...\"`".
#  Questo è corretto, ma con il nuovo programma localized.sh, i
#+ comandi "bash -D nomefile" e "bash --dump-po-string nomefile"
#+ non produrrebbero alcun risultato
#+ (perché quei comandi cercherebbero solo le stringhe $"...")!
#  Il SOLO modo per estrarre le stringhe dal nuovo file è quello di usare
#+ il programma 'xgettext'. Il programma xgettext, però, presenta dei problemi.

#  Fra gli altri, va notato quest'altro problema di 'xgettext'.
#
# Il comando:
#    gettext -s "I like Bash"
# estrae la stringa correttamente, mentre . . .
#    xgettext -s "I like Bash"
# . . . fallisce!
#  'xgettext' restituisce "-s" perché
#+ il comando estrae semplicemente solo
#+ il primo argomento che incontra dopo la parola 'gettext'.


#  Caratteri di escape:
#
#  Per localizzare una frase come
#     echo -e "Hello\tworld!"
#+ si deve usare
#     echo -e "`gettext \"Hello\\tworld\"`"
#  Il "doppio carattere di escape" prima della `t' è necessario per
#+ consentire a 'gettext' di cercare la stringa: 'Hello\tworld'
#  In questo modo gettext interpreta una `\' letteralmente)
#+ restituendo una stringa del tipo "Bonjour\tmonde",
#+ così che il comando 'echo' possa visualizzare il messaggio correttamente.
#
#  Non si deve usare
#     echo "`gettext -e \"Hello\tworld\"`"
#+ a causa del problema di xgettext spiegato prima.



# Proviamo a localizzare la seguente riga di codice:
#     echo "-h display help and exit"
#
# Come prima soluzione, si potrebbe fare in questo modo:
#     echo "`gettext \"-h display help and exit\"`"
#  Così 'xgettext' funziona correttamente,
#+ mentre il programma 'gettext' avrebbe interpretato "-h" come un'opzione!
#
# Una possibile soluzione sarebbe
#     echo "`gettext -- \"-h display help and exit\"`"
#  Così 'gettext' funziona,
#+ mentre 'xgettext' avrebbe estratto "--", come già spiegato.
#
# Un espediente per localizzare la stringa è
#     echo -e "`gettext \"\\0-h display help and exit\"`"
#  Abbiamo aggiunto un \0 (NULL) all'inizio della frase.
#  In questo modo 'gettext' funziona correttamente, come 'xgettext.'
#  Inoltre, il carattere NULL non modifica il comportamento
#+ del comando 'echo'.
#  ------------------------------------------------------------------------

bash$ bash -D localized.sh
"Can't cd to %s."
"Enter the value: "
Così viene elencato tutto il testo localizzato. (L'opzione -D elenca le stringhe tra doppi apici, precedute da $, senza eseguire lo script.)

bash$ bash --dump-po-strings localized.sh
#: a:6
msgid "Can't cd to %s."
msgstr ""
#: a:7
msgid "Enter the value: "
msgstr ""
L'opzione di Bash --dump-po-strings assomiglia all'opzione -D, ma usa il formato gettext "po".

Nota

Bruno Haible precisa:

A partire da gettext-0.12.2, si raccomanda l'uso di xgettext -o - localized.sh invece di bash --dump-po-strings localized.sh, perché xgettext:

1. interpreta i comandi gettext e eval_gettext (mentre bash --dump-po-strings interpreta solamente la sua deprecata sintassi $"...")

2. può togliere i commenti che il programmatore ha inserito per dare informazioni al traduttore.

Questo codice di shell, quindi, non è più specifico di Bash: funziona allo stesso modo anche con Bash 1.x e altre implementazioni /bin/sh.

Ora è necessario creare un file linguaggio.po, per ogni lingua in cui si vuole vengano tradotti i messaggi degli script, specificando msgstr. Alfredo Pironti ha fornito l'esempio seguente:

fr.po:

#: a:6
msgid "Can't cd to $var."
msgstr "Impossible de se positionner dans le répertoire $var."
#: a:7
msgid "Enter the value: "
msgstr "Entrez la valeur : "

#  Le stringhe vengono fornite per mezzo di variabili, non con la sintassi %s,
#+ come nei programmi in C.
#+ È una funzionalità bellissima se il programmatore ha l'accortezza
#+ di usare nomi di variabili che ne esplicitano il contenuto!

Quindi si esegue msgfmt.

msgfmt -o localized.sh.mo fr.po

Il risultante file localized.sh.mo va collocato nella directory /usr/local/share/locale/fr/LC_MESSAGES e, all'inizio dello script, si inseriscono le righe:

TEXTDOMAINDIR=/usr/local/share/locale
TEXTDOMAIN=localized.sh

Se un utente di un sistema francese dovesse eseguire lo script, otterrebbe i messaggi nella sua lingua.

Nota

Nelle versioni più vecchie di Bash, o in altre shell, la localizzazione richiede l'uso di gettext con l'opzione -s. In questo caso, lo script andrebbe così modificato:

#!/bin/bash
# localized.sh

E_CDERROR=65

error() {
  local format=$1
  shift
  printf "$(gettext -s "$format")" "$@" >&2
  exit $E_CDERROR
}
cd $var || error "Can't cd to %s." "$var"
read -p "$(gettext -s "Enter the value: ")" var
# ...

Le variabili TEXTDOMAIN e TEXTDOMAINDIR devono essere impostate ed esportate. Ciò andrebbe fatto all'interno dello script stesso.

---

Appendice scritta da Stéphane Chazelas, con modifiche suggerite da Alfredo Pironti e da Bruno Haible, manutentore di gettext GNU.