[precedente] Free Sofware - Copertina - Creare CD [successivo]

Articoli


OPEN

Uso del locale

Un modo per rendere un programma più user-friendly è quello di usare messaggi nella lingua dell'utente. Per implementare questa possibiltà ci sono vari metodi. Si potrebbe scrivere una versione del programma per ogni lingua, anche se ciò implica un una crescita del sorgente ed una difficile manutenzione dello stesso (se si apporta una modifica, bisogna farlo per tutte le lingue).

Un altro metodo è quello di avere il programma e il file dei messaggi separati. Per esempio se scrivo un programma in inglese, una persona italina deve solo modificare il file dei messaggi, senza modificare il sorgente, in questo modo anche se non conosce si il linguaggio in cui è scritto il programma può avere i messaggi nella propria lingua o anche se si vuole nel proprio dialetto.

La GLIBC2 ha due differenti modi per implementare ciò, catgets (X/Open standard) ed gettext (Uniforum, definito da SUN); anche se nessuno di questi due modi è uno standard POSIX. Il catgets proviene da decisioni industriali e non ``ragionate''. Bisogna anche dire che il catgets ha avuto molte versioni, e quindi ci sono anche delle incompatibiltà. Diciamo che la GNU usa, almeno per i pacchetti che ho visto io, il gettext Uniforum (che dal punto di vista del programmatore è piu semplice, almeno per me).

Per poter decidere in quale lingua vogliamo vedere visualizzati i messaggi (e non solo) del sistema si sono delle variabili di ambiente:

Queste variabili possono essere modificate con il comando:
LC_MESSAGES=it;export  LC_MESSAGES (per bash)
setenv LC_MESSAGES it (per [t]csh).

Vediamo più da vicino queste implemenatazioni.

Catgets Standard

Le funzioni definite in questo standard sono: catopen(), catgets(), catclose(). La prima serve per aprire il file dove sono definiti i messaggi, catgets serve per accedere ai messaggi aperti precedentemente, mentre l'ultima chiude il file.  Vediamo  l'header di queste funzioni, come creare un file di messaggi e un esempio esemplicativo.

nl_catd catopen ( const char *cat_name, int flag)
char * catgets (nl_catd catalog_desc, int set, int message, const char *string)
int catclose(nl_catd catalog_desc)

La variabile cat_name è il nome del file che contiene i messaggi, il quale viene cercato nelle directory specificate da NLSPATH, il quale ha il seguente formato:
prefix/share/locale/%L/%N:prefix/share/locale/%L/LC_MESSAGES/%N

prefix viene configurato quando si compila ed installa la GNU LIBC2, in genere o /usr o /usr/local, comunque può essere anche modificato. Comunque nella variabile cat_name si può anche specificare tutto il percorso.

Il simbolo %N sta a definire il nome del file dei messaggi, mentre %L definisce la lingua (it, de ecc).

L'X/Open definisce il formato del file dei messaggi nel modo seguente:

Vediamo adesso un esempio esplicativo in cui viene descritto come creare il programma, il file dei messaggi ed come si utilizzano.

Un classico esempio di programma in C è hello.c, il quale stampa su video la frase ``hello, world'':

#include 
#include 
#include "msgnr.h"

int main()
{
  nl_catd catdesc;
  catdesc = catopen("hello.dat",NL_CAT_LOCALE);
  printf(catgets(catdesc,MainSet,MainHello,"Hello, world!\n"));
  catclose(catdesc);
  return 0;
}

Come avete notato si include un file msgnr.h il quale viene creato dal file dei messaggi hello.msg:

$quote "

$set MainHello "Ciao, Mondo!\n"

Adesso si deve usare il programma gencat per poter creare dal file hello.msg il file hello.cat, che è quello che legge il programma mediante la funzione catopen(), ed il file msgnrs.h per poter compilare correttamente il file hello.c.

% gencat -H msgnrs.h -o hello.cat hello.msg
% gcc -o hello hello.c
% cp hello.cat /usr/share/locale/it/LC_MESSAGES

Settate la variabile LC_MESSAGES per i messaggi in italiano:

% LC_MESSAGES=it;export LC_MESSAGES

eseguendo il programma si ottiene il risultato:

Ciao, Mondo!

Vediamo invece adesso come avere il supporto per la propria lingua con l'Uniform.

Gettext

L'approccio con gettex è completamente diverso, non bisogna creare nessun file dei messaggi, né seguire le regole a riguardo la numerazione dei messaggi, basta solo usare la funzione gettext() quando si vuole visualizzare un messagio.

Per specificare il nome del file con i messaggi, ed dove si trova quest'ultimo ci sono due funzioni: textdomain() e bindtextdomain().

Vediamo come si modifica il programma hello.c:

#include 
#include 

int main()
{
  textdomain("hello");
  bindtextdomain("hello","/home/arete/devel/locale");
  printf(gettext("Hello, world!\n"));
  return 0;
}

Adesso per creare il file dei messaggi basta dare il comando:

% xgettext hello.c

Il programma crea un file messages.po il cui contenuto è il seguente:

msgid ""
msgstr ""
"Date: 1998-06-24 23:11:40+0000\n"
"From: Di Iorio Gerardo \n"
"Content-Type: text/plain; charset=\n"
"Xgettext-Options: \n"
"Files: hello.c\n"

#: hello.c:11
msgid "Hello,world!\n"
msgstr ""

Come si vede è più umanamente leggibile rispetto a quello del catgets e basta inserire nella riga sotto al messagio la traduzione per la particolare lingua. Vorrei far notare come sia più semplice da parte di terzi che non sanno niente di programmazione ed altro di tradurre questi file di messaggi; nel nostro caso il file dei messaggi, it.po, diventa:

msgid ""
msgstr ""
"Date: 1998-06-24 23:11:40+0000\n"
"From: Di Iorio Gerardo \n"
"Content-Type: text/plain; charset=\n"
"Xgettext-Options: \n"
"Files: hello.c\n"

#: hello.c:11
msgid "Hello,world!\n"
msgstr "Ciao, mondo!\n"

In genere questi file dei messaggi hanno l'estensione .po, mentre il file che il programma andrà a leggere, in genere  ha l'estensione .mo, il quale viene creato mediante il comando:

% msgfmt it .po -o hello.mo

Copiatelo nel PATH definito in bindtextdomain(), ed il gioco è fatto. Il PATH può essere anche definito al momento della compilazione, ad esempio:

#include 
#include 

int main()
{
  textdomain("hello");
  bindtextdomain("hello",LOCALEDIR);
  printf(gettext("Hello, world!\n"));
  return 0;
}

e copilato con il comando:

% gcc -o hello -DLOCALEDIR=\"/dove/si/trova\" hello.c

Devo ricordare che il file .mo, ad esempio hello.mo, si deve trovare nella directory /dove/si/trova/it/hello.mo.

I programmi xgettext e msgfmt si trovano nel pacchetto gettext, in qualsiasi sito che faccia il mirror di GNU.

Questo articolo vuol dare un esempio su come scrivere programmi con il supporto per il locale, maggiori informazioni si possono trvare nel pacchetto gettext, oppure nel manuale della GLIBC2 (nella versione 2.0.6, nel manuale questa parte non c'era, mentre c'è sicuramente nella 2.0.94, nelle altre non ne sono sicuro, controllate...).

di Gerardo Di Iorio


[precedente] Free Sofware - Copertina - Creare CD [successivo]