====== 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=", 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 char *setlocale(int categorie, const char *locale); /* Exemple : */ setlocale(LC_ALL, "fr_FR"); ====== Gettext ====== Afin d'utiliser gettext, vous devez inclure . 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 * //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 #include 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