Introduction

gettext est un mécanisme permettant de traduire facilement un programme en plusieurs langue. La langue utilisé peut être choisie automatiquement à partir des valeurs des variables d'environnement (si disponible) ou sélectionnée depuis le programme.

Rappel sur les locales

Les variables d'environnement LANG et LC_ALL indiquent la langue à utiliser, et les variables LC_xxx indique un réglage particulier pour chaque paramètre (comme les dates, les nombres, la monnaie…). Ces variables sont les suivantes :

  • LC_CTYPE : Classification des caractère et conversion majuscules/minuscules ;
  • LC_COLLATE : ?
  • LC_TIME : Format de date et d'heures ;
  • LC_NUMERIC : Format des nombres hors monnaie ;
  • LC_MONETARY : Format monétaires ;
  • LC_MESSAGES : Format des messages, aussi bien informatifs qu'interactifs ;
  • LC_PAPER : Dimensions du papier ;
  • LC_NAME : Format des noms ;
  • LC_MEASUREMENT : Unités de mesure ;
  • LC_IDENTIFICATION : Metadonnées sur les informations de la locale ?

Les locales en cours peuvent être modifiées dans un terminal via “LC_xxx=<locale>”, par exemple “LC_ALL=fr_FR ; export LC_ALL” utilisera les paramètres pour la langue française.

Les locales utilisées peuvent être modifié dans un programme via setlocale() :

#include <locale.h>
char *setlocale(int categorie, const char *locale);
 
/* Exemple : */
setlocale(LC_ALL, "fr_FR");

Gettext

Afin d'utiliser gettext, vous devez inclure <libintl.h>. Pour permettre à votre programme d'être utilisable dans plusieurs langues, vous devez changer toutes vos chaînes littérales en des appels à gettext(), dgettext(), etc :

printf("%s\n", gettext("Hello, world !"));

Les variantes de cette fonction sont :

  • gettext(msgid) : msgid est la chaîne à traduire, classiquement la version anglaise approximative du message. Cette chaîne sera retournée si aucune traduction n'est trouvée, ou si la locale est “C” ; le domain utilisé est celui qui a été passé lors du dernier appel à textdomain() (voir plus bas).
  • dgettext(domainname, msgid) : utilise le domain domainname, ou celui qui a été passé lors du dernier appel à textdomain() si dommainname est NULL, pour traduire msgid.
  • dcgettext(domainname, msgid, category) : utilise la catégorie category, qui doit être l'une des constantes LC_xxx définies dans <locale.h>
  • ngettext(msgid, msgid_plural, n) : fonction à utiliser lorsque le message à traduire contient un paramètre numérique, par exemple printf("encore %d fichiers à copier", num) ; suivant la valeur de n, la bonne traduction pour la langue cible sera utilisée. Cette fonction doit être utilisée, car il y a des irrégularités sur les pluriels dans de nombreuses langues, notamment la possession de plusieurs pluriels, ou l'utilisation ou nom du singulier pour 0.
  • Notez la présence de dngettext(domainname, msgid, msg_plural, n) et dcngettext(domainname, msgid, msgid_plural, n, category) dont vous devriez pouvoir déduire le comportement des lignes ci-dessus.

Pour traduire un message, gettext cherche un fichier .mo pour la langue adéquate en se basant sur les locales en cours. La plupart du temps, ce fichier se trouve à “DIR_NAME/LOCALE/LC_CATEGORY/DOMAIN_NAME.mo”, où :

  • DIR_NAME est ”/usr/share/locale par défaut, ou un autre chemin choisi par un appel à bindtextdomain(domainname, dirname) pour le domain domainname ;
  • LOCALE est le code de la locale, par exemple “fr” ;
  • LC_CATEGORY est toujours “LC_MESSAGES” ;
  • DOMAIN_NAME est le domain actuellement sélectionné.

Les fonctions bindtextdomain(domainname, dirname) et textdomain(domainname) permettent respectivement de choisir le chemin à utiliser pour chercher les traductions associées à un domain, et à changer le domain par défaut pour les prochains appels aux fonctions xxgettext().
Notez également la présence d'une fonction bind_textdomain_codeset(domainname, codeset) permettant de choisir le codeset (character-set) utilisé par les chaînes retournées par les fonctions xxgettext().

Exemple :

#include <locale.h>
#include <libintl.h>
 
int main(void)
{
    bindtextdomain("test", ".");
    textdomain("test");
 
    setlocale(LC_MESSAGES, "");
    /* "" indique que l'ont utilise les variables d'environnement */
 
    printf("%s\n", gettext("Hello, world !"));
    /* la traduction de "Hello, world !" sera cherchée dans le fichier
    "./fr/LC_MESSAGES/test.mo" */
 
    return 0;
}

Génération des fichiers de traduction

Template de traductions : fichier .pot

Vous pouvez générer un template contenant l'ensemble des chaînes à traduire de votre programme, portant habituellement l'extension .pot, en utilisant le programme xgettext :

xgettext src/*.c # scan tous les fichiers .c
xgettext -D src # scan les fichiers du dossier src/

xgettext cherche les appels xxgettext() dans les fichiers-sources, dont il détermine le type grace à l'extension, et génère un fichier messages.po. Vous pouvez immédiatement renommer ce fichier pour lui donner l'extension .pot, et placer quelques informations pour vos traducteurs (ou vous même) dans le fichier.

Traduction : fichiers .po et .mo

Ensuite, pour traduire le programme dans une langue supplémentaire, vos traducteurs (ou vous-même) créez un nouveau fichier de traduction en utilisant msginit :

msginit --locale=fr_FR --input=messages.pot

Un fichier .po est créé ; vous devez l'éditer de façon à faire correspondre à chaque msgid le msgstr traduit dans la langue voulue. Une fois ce travail fini, vous pouvez générer le précieux fichier .mo contenant les chaînes traduites et utilisable directement par votre programme en utilisant msgfmt :

msgfmt -o fr/LC_MESSAGES/test.mo fr.po
 
gettext.txt · Dernière modification: 2008/07/09 22:33 (édition externe)
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki