home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-03-14 | 45.4 KB | 1,160 lines |
- MANUEL "Locale"
-
- Ecrit par Patrick D'Cruze
- (pdcruze@orac.iinet.com.au, pdcruze@li.org)
-
- avec l'aide de Mitchum Dsouza
- (m-dsouza@mrc-applied-psychologie.cambridge.ac.uk)
-
- ---------------------------------------------------------------------------
- Traduction Francaise : Eric DUMAS dumas@emi.u-bordeaux.fr
- ---------------------------------------------------------------------------
- Note du traducteur :
-
- Le texte original peut etre trouve sur ftp.sunsite.edu.
- La version francaise sera deposee sur ftp.sunsite.edu et sur
- ftp.ibp.fr (/pub/linux/french/docs).
-
- La traduction de notes anglaises est un sport assez difficile,
- surtout lorsqu'il s'agit d'un texte technique. Bien souvent, j'ai essaye de
- traduire les termes techniques par leur equivalent en francais. J'ai conserve
- les termes anglais lorsqu'il n'y avait pas d'equivalent.
-
- Le terme central de ce texte est "Local". Ce terme peut etre traduit
- par milieu. Toutefois, a de nombreuses occasions, je conserverai le terme
- anglais pour des raisons de comprehension.
-
- Ce texte ne possede par d'accents. Une version accentuee sera
- disponible sous peu, sous la forme d'un fichier postscript ou d'un fichier
- LaTeX.
-
- En esperant qu'il n'y ait pas trop d'erreurs.
-
- Fevrier 1995, Bordeaux - France
- Eric DUMAS
- dumas@emi.u-bordeaux.fr
-
- -------------------------------------------------------------------------
- Sommaire :
- I Une Introduction a "Locale" et aux catalogues.
- I.1 Qu'est-ce que "Locale" ?
- I.2 Qu'est-ce que sont les catalogues ?
- I.3 Quel est le format d'un message du catalogue ?
- II Quelles sont les routines appelees ?
- II.1 SetLocale().
- II.2 CatOpen().
- II.3 CatGets().
- II.4 CatClose().
- II.5 Xtract.
- II.6 Gencat.
- III Ecrire des programmes avec "Locale".
- III.1 Ecrire et modifier des programmes pour qu'ils puissent
- utiliser le catalogue des messages.
- 3.2 Ecrire des programmes qui doivent etre utilises sur des
- systemes se servant de "Locale" ou non.
- IV Ou sont stockes mes messages ?
- V Questions les plus frequemment posees. (F.A.Q.)
- -------------------------------------------------------------------------
-
- I- Introduction a "Locale" et aux catalogues :
- ----------------------------------------------
-
- I-1 : Qu'est-ce que "Locale" ?
-
- Il y a un bon nombre de parametres necessaires pour definir les
- conventions culturelles d'un pays. Ces attributs incluent la langage du
- pays, le format de la date et de l'heure, la representation des nombres,
- les caracteres pour la monnaie, etc. Ces "regles" locales definissent les
- specification pour le milieu du pays. Le "Locale" represente la
- connaissance necessaire pour supporter les specificitees d'un pays.
-
- Il y a cinq principales zones qui risquent differer entre les
- pays et les zones de milieu.
-
- Caracteres et Codage des caracteres :
- -------------------------------------
- Le codage le plus repandu aux USA et dans la majorite des pays
- anglo-saxons est le codage ASCII. Toutefois, il y a de nombreux caracteres
- necessaires par divers pays qui ne sont pas fournis avec ce codage. Le
- systeme de codage ISO 8859-1 (8 bits) possede la plupart des caracteres
- necessaires pour gerer la plupart des langages europeens. Toutefois, dans
- beaucoup de cas, la police de caracteres ISO-8859-1 n'est pas adequate. A
- partir de la, chaque milieu aura besoin de specifier le type de codage des
- caracteres dont il a besoin et devra avoir les routines de gestion de ces
- caracteres pour pouvoir les utiliser.
-
- Monnaie :
- --------
- Les symboles utilises changent suivant les pays comme le fait la
- position de ces symboles. Les programmes doivent etre capables d'afficher les
- chiffres monetaires dans leur forme exacte, suivant les differents pays.
-
- Dates :
- -------
- Le format varie suivant les milieux. Le jour de noel en 1994 s'ecrit
- 12/25/94 aux USA mais 25/12/94 en Australie et en France. Certains milieux
- desirent la date sur 24 heures plutot que le format AM/PM.
-
- Nombres :
- ---------
- Les nombres peuvent etre representes de manieres differentes suivant
- les milieux. Par exemple, les nombres suivants sont ecrits suivant plusieurs
- formats, en fonction du milieu :
-
- 12.345,67 Francais
- 12,345.67 Anglais/Americain
- 1,2345.67 Asiatique
-
- Messages :
- ----------
- L'application la plus evidente est sans nulle doute le support des
- messages en fonction du milieu. Un mecanisme facile a utiliser doit etre
- fournis pour que les developeurs et les utilisateurs puissent selectionner la
- langue que le logiciel utilise.
-
- Ce document ne se concentrera que sur le support des messages pour
- les programmes. Dans une prochaine etape, il sera mis a jour pour illustrer
- la facilite avec laquelle les developeurs peuvent ajouter d'autres
- specificites nationales. En plus, on peut preciser que les routines et
- fonctions "Locales" sont utilisees la plupart du temps par des programmes en
- mode texte, c'est a dire des programmes fonctionnant sur des xterm ou des
- consoles virtuelles. D'autres routines existent pour des programmes utilisant
- XWindows. Elles seront decrites lors d'une prochaine mise a jour de ce
- document.
-
-
- I.2 Qu'est-ce que sont les catalogues ?
-
- Les programmes communiquent avec l'utilisateur en ecrivant des
- messages (du texte) a l'ecran. Ces messages peuvent etre eparpilles dans tout
- le code source d'un progamme. Pour pouvoir supporter plusieurs langages, il
- est necessaire de traduire ces messages dans differentes langues. Cela est
- impossible a faire dans le code source pour deux raisons :
-
- 1- Pour traduire les messages dans une autre langue, les traducteurs
- devraient aller a la recherche des messages dans le code source. Cela
- est une pure perte de temps. De plus, bon nombre de traducteurs risquent
- de ne meme pas avoir acces au code source.
-
- 2- Gerer une nouvelle langue signifie que les messages a l'interieur
- du code source, doivent etre traduits, puis il faut recompiler le code source.
- Ce qui devra etre fait pour tout langage.
-
- La solution est d'avoir tous les messages enregistres dans un fichier
- externe, appelle catalogue des messages. A chaque fois que le programme a
- besoin d'afficher un message, le programme demande au systeme d'exploitation
- de chercher le message approprie dans le catalogue et de l'afficher sur l'ecran.
-
- Les avantages sont les suivants :
- - Le catalogue peut etre traduit sans qu'il soit necessaire d'avoir
- acces au code source.
- - Le code source est compile une et une seule fois. Pour gerer un
- nouveau langage, il suffit de traduire les messages et de l'envoyer
- a l'utilisateur.
- - Tous les messages sont stockes en un seul endroit.
-
-
- I.3 Quel est le format d'un message du catalogue ?
-
- Une fois que tous les messages ont ete extraits du code source, ils
- sont ranges dans un fichier texte ordinaire qui est reference comme etant
- le fichier des messages. Le fichier possede souvent la structure suivante :
-
- 1 Impossible d'ouvrir le fichier foo.bar
- 2 Impossible d'ecrire dans le fichier foo.bar
- 3 Impossible d'acceder au repertoire
-
- Bien que cela soit une representation utile pour les programmeurs et
- pour les traducteurs, cela se revele insuffisant pour le systeme
- d'exploitaton. En effet, le systeme d'exploitation doit pouvoir y acceder
- pour rechercher le message d'une maniere la plus rapide possible. Un fichier
- binaire correspond a cet etat d'esprit, et c'est ce qui est fait dans la
- realite.
-
- Un catalogue de messages est une representation binaire des messages
- utilises dans le logiciel. Les fichiers textes de messages sont compiles
- en utilisant le programme "gencat" en un format binaire. Le catalogue ainsi
- compile dans un format depend de la machine et il n'est pas portable. Il est
- tres facile de recompiler les fichiers textes de messages sur d'autres
- architectures (plateformes).
-
- Les programmeurs et les traducteurs ecrivent les messages utilises
- par leur programme dans des fichiers et ces fichiers sont compiles en un
- catalogue de messages. Toutefois, une seule partie d'un logiciel peut
- contenir des centaines d'instructions printf(), chacune etant constituee
- d'un seul message. Chacun de ces messages devant etre stocke dans un fichier
- de messages. Il n'est pas tres raisonnable de supposer d'avoir tous ces
- messages dans un seul fichier texte de messages. Editer, modifier, detruire
- et ajouter de nouveaux messages risquent de faire grossir le fichier jusqu'a
- ce que cela pose des problemes.
-
- La solution consiste a fractionner les messages en modules. Chacun de
- ces modules contient les messages pour une partie specifique de
- l'application. En combinant tous les modules, on obtient tous les messages
- utilises. Ces modules peuvent etre compiles dans un seul catalogue de
- messages. Le programme peut alors acceder a un message particulier situe
- dans un module specifique a l'interieur du catalogue de messages.
-
- Cela rend le travail du programmeur (et du traducteur) plus facile.
- Le programme peut assigner des modules separes pour des routines importantes.
- Alors, lorsqu'une routine est modifee, il suffit de modifier uniquement
- le module dans lequel se trouve le message correspondant. Tous les autres
- modules restent tels qu'il sont.
-
- Exemple :
- Pour le programme gnubar, nous avons deux endroits qui utilisent les
- communications avec l'utilisateur (affichage d'erreurs et des resultats).
- Les catalogues resultant sont normalement appelles : errors.m et results.m.
-
- (Rq :Nous avons adopte la convention d'utiliser .m pour une fichier de
- message)
-
- Toutes les messages d'erreur se trouvent dans errors.m. Nous modifions
- alors le programme pour que lorsqu'une erreur se produit, le programme accede au
- module des messages d'erreurs et affiche le message d'erreur. De meme avec
- les resultats.
-
- Ces deux fichiers sont alors compiles pour former le catalogue des
- messages pour gnubar. Le fichier resultant de la compilation est appelle
- gnubar.cat. Ce catalogue est constitue de deux modules, errors et results,
- chacun contenant les messages numerotes.
-
- Pour acceder a un message particulier, le programme a besoin de
- specifier quel module doit etre utilise et le numero du messsage qui doit etre
- affiche.
-
-
-
- II Quelles sont les routines appellees ?
- ----------------------------------------------
-
- Les quatre routines centrales pour acceder et utiliser les catalogues
- de messages dans votre code source sont setlocale(), catopen(), catgets() et
- catclose().
-
- NB: Souvenez-vous que les Catalogues de Messages ne sont qu'un element
- du milieu. Les autres elements seront traites dans les versions futures de ce
- document.
-
- NB pour LINUX : Pour acceder et utiliser les fonctions "locale", vous
- aurez besoin de libc.so.4.4.4c ou version ulterieure. (Je vous recommande
- d'utiliser au moins libc.so.4.5.26 ou superieur etant donne qu'elle inclue
- de nombreuses ameliorations dans la gestion des milieux.). Vous aurez
- egalement besoin des fichiers d'entete <locale.h> et <nl_types.h>. Si vous
- avez une libc qui supporte les fonctions locales, alors il est fort
- probable que vous possediez les fichiers d'entete egalement. (/usr/include)
-
- II-1. SETLOCALE() :
-
- La premier chose qu'un programme doit faire est de positionner le milieu
- dans lequel il va s'executer. Cette operation est realisee avec la fonction
- setlocale(). Elle est definie comme etant :
- #include <locale.h>
-
- char *setlocale(int categorie, const char *locale);
-
- L'argument "categorie" indique a la fonction quel attribut positionner.
- Les differents attributs sont :
-
- - LC_COLLATE : Modifie le fonctionnement de strcoll() et strxfrm()
- - LC_CTYPE : Modifie le fonctionnement de la gestion des caracteres
- isalpha(), islower(), isupper(), isprint(),...
- - LC_MESSAGE : Positionne la langue dans laquelle les messages seront
- affiches.
- - LC_MONETARY : Modifie les informations retournees par localeconv()
- - LC_NUMERIC : Positionne le caractere decimal pour les nombres
- - LC_TIME : Modifie le fonctionnement de strftime()
- - LC_ALL : Change tout !
-
- Dans notre exemple, nous allons nous occuper uniquement des catalogues de
- messages. C'est pourquoi nous allons uniquement positionner l'attribut
- LC_MESSAGES avec la fonction setlocale(). L'attribut LC_ALL aurait egalement
- pu etre utilise. Toutefois, il est bon d'utiliser uniquement les attributs
- dont vous avez besoin dans votre programme. La raison sera expliquee
- rapidement ulterieurement.
-
- L'argument "locale" est le nom du milieu. Deux noms speciaux du milieux sont :
- C Cela rend les prototypes des fonctions standard a la norme du C...
- POSIX idem, mais pour la norme POSIX.
-
- Generalement, l'argument du milieu sera : "" (guillemets vides). Cela
- pour effet de selectionner le milieu par defaut de l'utilisateur. Cela est
- realise par le systeme d'exploitation de cette maniere :
- 1- Si l'utilisateur possede la variable d'environnement LC_ALL , et
- qui n'est pas nulle, alors la valeur de cette variable est utilisee comme
- l'argument du milieu.
-
- 2- Si l'utilisateur possede une variable d'environnement ayant le meme
- nom que l'attribut, et qui est non nul, alors cette variable est utilisee comme
- l'argument du milieu.
-
- 3- Si la variable LANG est positionnee et non nulle alors cette valeur
- est utilisee comme argument du milieu.
-
- Si la valeur est valide, supportee par le milieu, alors le milieu est
- modifie. Toutefois, si la valeur est non nulle et contient une valeur non
- suportee par le milieu alors setlocale() revera un pointeur NULL et le
- milieu ne sera pas change par rapport a la valeur du mileu par defaut "C".
-
- Au debut du programme, le systeme d'exploitation execute la fonction
- suivante :
- setlocale(LC_ALL, "C");
-
- Si votre programme n'utilise pas setlocale() ou ne peut pas changer le
- milieu (en raison d'un mauvais environnement de variables), alors le
- programme utilisera le milieu par defaut : "C".
- Si setlocale() n'est pas capable de changer le milieu, NULL est retourne.
-
- Une bonne methode de programmation consiste a uniquement utiliser les
- attributs qui conviennent a votre logiciel. Un exemple va en illustrer les
- raisons :
-
- main()
- {
- setlocale( LC_ALL, "");
- ....
- }
-
- Le programme va maintenant positionner tous les attributs du milieu
- avec soit la valeur de la variable d'environnement LC_ALL si elle est
- positionnee, soit avec la valeur de la variable d'environnement LANG ou bien
- dans le dernier cas, le milieu par defaut "C".
-
- Maintenant supposez que l'utilisateur souhaite avoir tous les messages
- affiches sur son ecran en Anglais, mais il desire utiliser les autres
- attributs du milieu Francais. L'utilsateur realise ceci en positionnant la
- variable LC_MESSAGES pour le milieu Anglais, et la variable LANG pour le
- Francais.
-
- L'exemple ci-dessus (utilise LC_ALL) ignore la varible LC_MESSAGES et
- va utiliser a la place la variable LANG ... donc tous les messages seront
- affiches en Francais. L'utilsateur peut soit avoir tous les attributs
- positionnes pour le Francais, soit pour l'Anglais.
-
- Admetons que cette situation est un peu exceptionnelle, mais si votre
- programme a juste besoin d'avoir acces aux messages, alors il est juste
- necessaire de positionner cet attribut. Si votre programme a besoin de
- quatre attributs alors, vous devrez utiliser quatre fois setlocale().
-
- C'est a l'utilisateur de bien positionner ses variables
- d'environnement. Il lui est aussi tres facile de le deteriorer, simplement en
- modifiant ses variables. Il est donc plus prudent d'include des informations
- dans votre programme pour que l'utilisateur configure d'une maniere correcte
- son environnement. Cette question sera vue dans une section ulterieure.
-
- II-2 CATOPEN()
-
- La fonction setlocale() etablit uniquement le bon milieu que doit
- utiliser le programme. Pour acceder au catalogue, il faut d'abord l'ouvrir.
- Cette fonction realise cette operation. Elle est definie de la maniere
- suivante :
-
- #include <nl_types.h>
- nl_catd catopen(char *nom, int option);
-
- catopen() ouvre le catalogue des messages et retourne un descripteur de
- catalogue. Le "nom" correspond au nom du catalogue qui doit etre ouvert. Si
- le nom correspond a un chemin absolu (Contient un /), le nom correspond au
- chemin d'acces a ce fichier. Sinon, la variable NLSPATH est utilisee. Si
- NLSPATH n'existe pas, ou si le catalogue ne peux pas etre trouve ou ouvert
- dans les repertoires specifies dans NLSPATH, alors le catalogue est recherche
- dans les repertoires suivants, dans l'ordre :
- /usr/lib/locale/LC_MESSAGES
- /usr/lib/locale/name/LC_MESSAGES
-
- L'argument option est utilise pour indiquer le type de chargement
- desire. Cela peut etre soit MCLoadBySet ou soit MCLoadAll. Le premier indique
- que l'on ne charge que le module necessaire, le dernier specifie que l'on
- charge TOUT le catalogue en memoire.
-
- catopen() renvoie soir un descripteur de catalogue nl_catd, soit -1 en cas
- d'erreur.
-
- Exemple d'utilisation :
- static nl_catd catdc = 0;
-
- catdc = catopen("foo.cat", MCLoadBySet);
-
- if ( catdc == -1)
- printf(" Impossible d'ouvrir le catalogue des messages \n');
-
- II-3 CATGETS ()
-
- Une fois que le catalogue des messages a ete ouvert, nous avons besoin
- d'une routine pour acceder au catalogue et recuperer les messages. C'est la
- fonction de catgets()
-
- #include <nl_types.h>
-
- char *catgets(nl_catd catdc, int numero_module, int numero_message \
- char *message);
-
- catgets() lit le message "numero_message", dans "numero_module", dans
- le catalogue des messages identifie par catdc. catfd est le descripteur du
- catalogue (cf catopen()). Le quatrieme argument est un pointeur sur une
- chaine par defaut qui sera retournee si le catalogue n'est pas ouvert, ou
- s'il est endommage. Le texte du message est stocke dans un tampon interne
- et doit etre copie par l'application s'il doit etre conserve ou modifie.
- La chaine retournee est toujours terminee par \0.
-
- En cas d'erreur, catgets renvoie un pointeur sur "message" si le
- cataloguen'est pas ouvert. Dans le cas ou le message n'est pas trouve, catgets
- retourne un pointeur sur une chaine vide.
-
- Exemple d'utilisation :
-
- printf( catgets( catdc, 3, 7, "Erreur d'acces au bloc No %d"),Num_Bloc );
-
- La fonction ci-dessus essaye d'acceder au 7eme message du 3eme module du
- catalogue des messages. Si ce message ne peut etre trouve pour n'importe
- quelle raison, alors le message "Erreur d'acces au bloc No %d" est affiche a
- la place.
-
- II-4 CATCLOSE ()
-
- Une fois qu'un programme a termine d'utiliser un catalogue de messages,
- le catalogue doit etre ferme pour que la memoire utilisee soit liberee.
-
- #include <nl_types.h>
-
- void catclose(nl_catd catdc);
-
- catclose() ferme le catalogue specifie par catdc.
- catclose() retourne 0 en cas de succes, -1 en cas d'echec.
-
- Exemple d'utilisation :
- {
- ...
- catclose(catdc);
- exit(0);
- }
-
- Nous vous avons presente les quatre fonctions C dont vous avez besoin
- pour utiliser les catalogues de messages dans votre logiciel. La prochaine
- partie traitera les outils qui sont disponibles pour vous aider a extraire les
- messages existants dans votre application, et detaillera le programme gencat
- utilise pour compiler les messages.
-
- Avant tout, voici le format du fichier de messages. Gencat a besoin
- d'un fichier d'un format special pour qu'il puisse compiler les messages.
-
- Exemple de fichier de messages :
- $set 2 #chmod
- $ #1 Original Message:(invalid mode)
- # invalid mode
- $ #2 Original Message:(virtual memory exhausted)
- # virtual memory exhausted
- ...
-
- La premiere ligne est utilisee pour definir le numero du module. Le mot
- clef "set" doit etre present dans TOUS les fichiers de messages. Le second champ
- est le numero du module et doit etre unique pour le catalogue de message.
- Le troisieme est utilise pour identifier le module (Le numero peut etre
- egalement utilise):
- $set <No Module> #<Identificateur du Module >
-
- La seconde ligne est l'unique identificateur du message. Il est
- important de remarquer la present du signe $ et du deuxieme champ #<No>. Le
- signe $ est necessaire pour permettre de differencier un message de son
- identificateur. Le second champ (sans #) est l'identificateur du message. Le
- reste est ignore. C'est souvent utile pour inclure le message original pour le
- suivi du code, la traduction, etc
- $ #<No_Message> [ Texte Ignore ]
-
- La troisieme ligne est le texte du message. Dans ce cas, c'est le
- texte pour le premier message dans le deuxieme module.
- # < Texte du Message >
-
- Lorsque vous traduisez les fichiers de messages dans d'autres langues,
- il est juste necessaire de traduire les lignes de texte
- ( < Texte du Message > ),c'est a dire les lignes commencant par #. Aucune ligne
- debutant par $ ne sera a modifier.
-
- Le format du fichier ci-dessus correspond parfaitement aux arguments de
- la fonction catgets(). La fonction catgets a besoin de No_Module et de
- No_Message (deux entiers). Pour affichier le premier message du second
- module,
-
- $set 2 #chmod
- +------^
- | +------v
- | | $ #1 Original Message:(invalid mode)
- | | # invalid mode
- | | $ #2 Original Message:(virtual memory exhausted)
- | | # virtual memory exhausted
- | |
- | | printf( catgets(catdc, 2, 1, "Mode Invalide") );
- | +---------------------------^
- +--------------------------^
-
- Bien que ces fonctions fonctionnent sans probleme, leur utilisation
- n'est pas intuitive lors de la creation d'un programme. Par exemple, a chaque
- fois qu'un programmer a besoin d'afficher un message, il doit tout d'abords
- chercher le message dans le bon module, trouver son numero et le reporter
- dans son code source. Cela peut rapidement devenir rapidement penible
- lorsque les programmes ont besoin d'acceder a plusieurs modules ou a
- plusieurs catalogues. Autant chercher une aiguille dans une bote de foin !
-
- Au lieu d'utiliser un entier comme numero de module ou numero de
- message, il serait plus facile d'utiliser des noms (texte ASCII). On peut
- utiliser ce systeme si l'on emploi un #define pour faire correspondre le texte
- a un entier.
-
- Au lieu d'avoir :
- $set 2 #chmod
- $ #1 Original Message:(invalid mode)
- # invalid mode
- $ #2 Original Message:(virtual memory exhausted)
- # virtual memory exhausted
- ...
-
- on aurait :
- $set 2 #chmod
- $ #Invalid_Mode
- # invalid mode
- $ #VM_exhausted
- # virtual memory exhausted
- ...
-
- On peut remarquer qu'aucun changement n'est a effectuer pour le nom du
- module car la troisieme partie de cette ligne est le nom du module.
-
- Pour acceder au second message, on peut utiliser le code suivant :
- printf( catgets(catdc, chmodSet, chmodVM_exhausted, \
- "Plus de memoire virtuelle"));
-
- L'argument No_Module de la fonction catopen() est toujours le nom du
- module (chmod ici), rattache au mot "Set" => "chmodSet". Le numero du
- message est toujours le nom du module (chmod) ajoute avec
- l'identificateur du message (VM_exhausted) =>chmodVM_exhausted.
-
- Pour pouvoir utiliser ces noms, le programme doit associer les noms avec
- des entiers car la fonction catopen() n'accepte que des entiers comme
- parametre. On realise cette association en utilsant le programme gencat qui
- va generer les fichiers d'entetes qui sont utilises par le programme.
-
- Pour les message ci-dessus, le fichier d'entete ainsi genere ressemble a :
- #define chmodSet 0x2
- #define chmodInvalid_Mode 0x1
- #define chmodVM_exhausted 0x2
-
- Ce fichier d'entete a ete genere a partir du fichier chmod.m. Nous avons
- decide d'appeler les fichiers d'entete xxx-nls.h donc dans notre cas, le
- fichier d'entete est appele : chmod-nls.h
-
- Il ne reste plus qu'a rajouter la ligne
- #include "chmod-nls.h"
- au debut du programme..
-
- II-5 XTRACT :
-
- xtract est un programme ecrit avec yacc pour extraire les messages
- d'un code source. Vous pouvez le trouver sur le site ftp :
- sunsite.unc.edu:/pub/Linux/utils/nls/catalogs/locale-package.tar.gz (US)
-
- xtract recherche dans les sources toutes les chaines de caracteres etant
- entre quotes. Il affiche a l'ecran tout ce qu'il trouve.
-
- Il s'utilise de la maniere suivante :
- xtract < source.c > message.m
-
- Le fichier message.m contient alors tous les message que xtract a trouve
- dans le source. Les messages sont places dans le format habituel.
-
- Toutefois, il est necessaire d'editer le fichier :
- - les deux premieres lignes doivent etre detruites
- - la ligne $set <No_Module> #<Nom_Module> doit etre ajoutee.
-
- Exemple :
- Le message original ressemble a cela :
-
- $ #0 Message Original :(Probleme de Configuration)
- # Probleme de Configuration
- $ #1 Message Original :(Impossible d'ouvir le fichier)
- # Impossible d'ouvir le fichier
- $ #2 Message Original :(Erreur lors de l'acces au fichier)
- # Erreur lors de l'acces au fichier
- ...
-
- Ce n'est un format correct car il manque ke numero du module. Il suffit de
- rajouter alors la ligne
- $set X #Descripteur
- au tout debut du fichier. X represente le numero du module.
-
- Le fichier ressemble alors a :
-
- $set 17 #Descripteur
- $ #0 Message Original :(Probleme de Configuration)
- # Probleme de Configuration
- $ #1 Message Original :(Impossible d'ouvir le fichier)
- # Impossible d'ouvir le fichier
- $ #2 Message Original :(Erreur lors de l'acces au fichier)
- # Erreur lors de l'acces au fichier
- ...
-
- II-6 GENCAT
-
- (Remarque du traducteur : Il semble qu'il y ait plusieurs versions de
- gencat. Je travaille sur un systeme Linux mais aussi sur Solaris 4.2.3 et le
- gencat standard sun ne possede pas les options qui vont etre expliquees
- ci-dessous.)
-
- Gencat est le programme utilise pour compiler les fichiers de messages.
- Le resultat de la compilation est le catalogue des messages. Voici le detail
- des options de la ligne de commande :
-
- gencat [-new] [-lang C | C++ | ANSIC ] fic_cat fic_msg [ -h <header_file>]
-
- Description :
- -new Detruit le catalogue des message et en cree un nouveau.
- Le comportement par defaut est de mettre a jour le catalogue
- avec le(s) fic_msg(s).
- -lang <l> Indique le format du fichier d'entete. Pour le moment, les
- trois formats suportes sont les langages C, C++ et ANSIC. Les
- deux derniers sont identiques. Cet argument peut etre place
- n'importe ou dans la ligne de commande.
- -h <hfile> Identificateurs des fichiers d'entete crees en sortie.
-
- Cela cree un fichier d'entete avec tous les #define
- appropries. Sans cela, ca serait a vous de verifier que
- votre code soit coherent avec le catalogue. Le fichier
- d'entete est cree a partir de tous les fic_msg de la ligne de
- commande, donc l'ordre dans la ligne de commande est
- important. Cela signifie que si vous mettez a la fin l'entete,
- toutes les entetes seront dans un seul fichier :
- gencat vodka.m pineau.m gin.m -h cuite.h
- Si vous preferez conserver la dependance, vous pouvez
- specifier un fichier entete par fichier de messages :
- gencat vodka.m -h beurk.h pineau.m -h c1.h gin.m -h \
- cuite.h
- De plus, si vous executez l'instruction suivante,
- gencat vodka.m -h beurk.h
- le fichier beurk.h ne sera pas modifie la deuxieme fois.
- Gencat verifie si le contenu a ete modifie avant de le
- retraiter. Vous pouvez egalement utiliser un fichier
- Makefile de ce genre:
-
- MSGSRC=vodka.m gin.m
- GENFLAGS=-new -lang C
- GENCAT=gencat
- NLSLIB=nlslib/OM/C
- $(NLSLIB): $(MSGSRC)
- @for i in $?; do cmd="$(GENCAT) $(GENFLAGS) $@$$i -h \
- basename $$i .m'.H"; echo $$cmd; $$cmd; done
- vodka.o: vodka.h
-
- La boucle for/loop n'est pas tres jolie mais elle marche.
- Pour chacun des fichier .m qui ont ete modifies, on
- relance gencat.
-
- Le programme gencat possede deux fonctions et il est utilise
- generalement en deux fois.
-
- La premiere fonction est de generer les fichiers d'entete a partir
- des fichiers de messages pour que les programmes puissent utiliser des noms
- quand ils font referenceaux modules et aux messages. La commande suivante
- realise cette operation :
- gencat -new /dev/null foobar.m -h foobar-nls.h
-
- Le -new /dev/null signifie que le catalogue des messages est envoye dans
- le fichier null.
-
- La deuxieme fonction est la generation du catalogue des messages :
-
- gencat -new foobar.cat foobar.m
-
- Pour generer le catalogue a partir d'un Makefile :
- MESSAGEFILES = toto.m titi.m tata.m
- gencat -new tttt.cat $(MESSAGEFILES)
-
-
-
- III Ecrire des programmes avec "Locale".
- --------------------------------------------
-
- III.1 Ecrire et modifier des programmes pour qu'ils puissent utiliser le
- catalogue des messages.
-
- Le probleme est donc de savoir comment modifier ou ecrire un nouveau
- programme qui utilise les catalogues de messages. Voici les etapes
- necessaires :
-
- 1ere etape : (Modification d'un programme existant)
-
- La premiere chose a faire est d'extraire tous les messages du
- programme existant et de les placer dans un fichier de messages. Le
- programme xtract a ete concu pour cela. Cette operation est expliquee
- ailleur dans ce document mais en voici un petit resume :
-
- Code source == toto.c
- Fichier de messages == toto.m
-
- xtract < toto.c > toto.m
-
- Il suffit d'inserer le numero du module approprie dans le fichier toto.m :
- $set X #n
-
- ou X est le numero du module
- et n est le nom de la variable utilise pour acceder a ce fichier.
-
- 2eme etape : (Creation d'un nouveau fichier de messages)
-
- Si vous debutez un nouveau fichier de messages, il est utile de
- rappeler l'ordre et la structure du fichier de messages . Il est compose
- de trois elements :
- - L'identificateur du module
- - l'identificateur du message
- - le texte de chaque identifiaceur des messages
-
- Le format a ete detaille dans un paragraphe precedent. Ce format de
- fichier doit permettre de resoudre tout probleme de compilation du
- catalogue de messages.
-
- Brievement, en voici la structure :
- $set 2 #chmod
- $ #Invalid_Mode Message Initial : (Mode Invalide)
- # Mode Invalide
- $ #VM_exhausted Message Initial : (Plus de Memoire Virtuelle)
- # Plus de memoire virtuelle
- ...
-
- La premiere ligne est l'identificateur du module. Toutes les autres
- lignes debutant par le caractere $ sont les identificateurs de message. Les
- lignes suivantes sont les messages a afficher.
-
- 3eme Etape :
-
- Pendant que vous etes en train de modifier un fichier de message
- genere par la premiere etape, ou que vous etes en train de creer un nouveau
- fichier, il est plus facile d'utiliser des noms pour se referencer aux
- messages et aux modules plutot qu'aux nombres. Pour utiliser des noms, nous
- avons besoin d'assigner un nom unique a chacun des modules, et des noms
- uniques pour chacun des messages par modules.
-
- La premiere ligne de chacun des fichiers de messages est
- l'identificateur du module :
- $set X #Mon_Module
-
- X : numero du module pour ce fichier de messages
- Mon_Module : Le nom utilise
-
- X doit etre un nombre unique pour ce module. Il en va de meme pour le
- nom du module. On peut alors acceder a ce module d'une maniere indiferente :
- soit par le nombre, soit par le nom. C'est a vous de choisir. Toutefois, si
- vous vous decidez a utiliser le nom pour acceder au module, pensez a rajouter
- le mot "Set" : le mot complet devient alors : Mon_ModuleSet.
-
- 4eme Etape :
- Maintenant que nous utilisons des noms comme identificateurs de
- modules et de messages, nous devons creer le fichier d'entete qui va faire
- correspondre les numeros avec ces noms. Le programme gencat peut etre
- utilise pour generer le fichier d'entete a partir d'un fichier de message.
- Cette operation a ete expliquee precedemment dans le document. Brievement,
- non executons la commande suivante :
- gencat -new /dev/null foobar.m -h foobar-nls.h
-
- Gencat va donc generer le fichier d'entete. Ce fichier doit etre inclue
- dans notre programme.
- Il vaut mieux prendre l'habitude de nommer ses fichiers d'entete "xxx-nls.h".
- Le "-nls" permet de mieux distinguer les fichier d'entete pour les messages.
-
- 5eme Etape :
- Nous sommes maintenant prets a modifier le code source. La premiere
- chose a faire est d'inclure les fichiers d'entete. Nous avons besoin de
- trois fichiers :
- #include <locale.h>
- #include <nl_types.h>
- #include <foobar-nls.h>
-
- Le premier fichier (locale.h) contient plusieurs constantes
- utilisees par setlocale et par d'autres fonctions : LC_*, etc...
-
- Le second fichier contient les constantes et les prototypes pour
- les fonctions catopen, catclose, etc...
-
- Le dernier contient toutes les declarations des messages et des
- modules utilises, ce qui va nous permettre d'utiliser les noms dans les
- fonctions.
-
- 6eme Etape :
-
- La prochaine etape constiste a declare une ou plusieures variables
- globales pour les catalogues. Nous avons besoin d'un descripteur de
- catalogue uniquement lorsque nous accedons a un catalogue de messages.
- Normalement, un programme n'aura besoin d'acceder qu'a ses propres messages
- de catalogue et donc, nous n'aurons besoin de definir qu'un seul descripteur
- de catalogue de messages. Cela doit etre defini avant le main() :
-
- /* Variable Globale au module : descripteur de catalogue */
- static nl_catd catfd = -1;
-
- Pour acceder au catalogue de messages nous utiliserons maintenant
- la varibale catfd.
-
- 7eme Etape :
- A l'interieur de la fonction main, la premiere chose a faire est de
- positionner le milieu dans lequel le programme va evoluer. Cette operation
- est realisee en utilisant la fonction setlocale() :
- setlocale( LC_MESSAGE , "");
-
- (Voir plus haut pour la description de la fonction setlocale)
-
- 8eme Etape :
- Notre programme peut donc acceder au bon repertoire lorsqu'il a
- besoin d'acceder au catalogue des messages ou a d'autre informations sur
- le milieu. Nous devons maintenant ouvrir le catalogue des messages utilise
- par notre programme :
- catfd = catopen("foobar",MCLoadBySet);
-
- Cette operation va ouvrir le fichier de messages foobar.cat (Rq: Ne pas
- specifier .cat). Le type de chargement est specifie dans le deuxieme
- arguement : chargement global en memoire ou chargement module par module.
- Cette derniere option utilise moins de memoire mais elle est plus couteuse
- en temps. Le choix est laisse au programmeur.
-
- Une solution plus solide pour ouvrir et initialiser le catalogue des
- messages est presentee ci-dessous. Le programme risque devoir ouvrir, fermer,
- manipuler le catalogue des messages a de nombreux endroits dans le programme.
- Il est donc utilise d'utiliser une fonction d'initialisation qui ouvre le
- catalogue de message s'il ne l'est pas deja :
-
- catinit()
- {
- if (catfd == (nl_catd) -1)
- catfd = catopen("foobar", MCLoadBySet);
- }
- La routine verifie que le catalogue est ferme. Si c'est le cas, elle
- l'ouvre. Il vous est tres facile de rajouter des fonctionnalites a cette
- routine. Le premier appel a cette fonction doit etre fait apres l'appel a
- setlocale() dans la fonction main(). Apres cela, vous pouvez l'appler autant
- de fois que vous voulez, si vous n'etes pas sur que le catalogue soit ouvert
- ou ferme.
-
- 9eme Etape
- Nous sommes desormais pret pour utiliser le catalogue des messages. Nous
- allons utiliser la fonction catgets.
-
- Cette fonction possede quatre arguments :
- catgets(catfd, Id_Module, Id_Message, *message);
-
- La variable catfd represente le descripteur de catalogue retourne par la
- fonction catinit ou catopen. C'est utilise par catgets pour determiner le
- catalogue a utiliser(plusieurs catalogues peuvent etre ouverts en meme temps
- dans un programme).
-
- Id_Module represente le module a manipuler. Cela peut etre soit un entier,
- soit le nom du module (+"Set").
-
- Id_Message represente le numero ou le nom du message situe dans Id_Module.
- Si le nom est utilise, souvenez vous que le nom du module doit etre accole au
- nom du message.
-
- *message est la chaine par defaut qui sera utilisee s'il n'est pas possible
- d'acceder au message, etc.
-
- exemple :
- catgets(catfd, erreursSet, erreursVM_Exhausted, "Plus de memoire virtuelle");
-
- Cette operation va recuperer le message VM_Exhausted dans le module erreurs
- du catalogue. Dans le cas d'une erreur, la chaine "Plus de memoire virtuelle"
- sera utilisee.
-
- Nous vous recommandons de prendre l'habitude de toujours utiliser la chaine
- anglaise par defaut (Note Traducteur : Bof,...pourquoi pas le francais !).
-
- La routine catgets() retourne un pointeur sur un tampon interne termine
- par un caractere NULL (\0). Nous avons besoin d'afficher la chaine :
-
- printf("%s\n", catgets(catfd, erreursSet, erreursVM_Exhausted,
- "Plus de memoire virtuelle");
-
- Voici quelques exemples de l'ancienne approche (codage en dur), a opposer
- avec la nouvelle methode :
-
- Exemple 1 :
- Avant :
- printf("Incorrect read permission");
-
- Apres :
- printf("%s\n", catgets(catfd, errorsSet, errorsIncorrect_Perm,
- "incorrect read permission");
-
-
- Exemple 2:
- Avant :
- printf("Cannot change to directory %s", dir_name);
-
- Apres :
- (Extrait du catalogue des messages)
- ...
- $ #Cant_chdir
- # Cannot change to directory %s
- ...
-
- printf("%s \n",
- catgets(catfd, errorsSet, errorsCant_chdir,
- "Cannot change to directory %s"), dir_name);
-
-
- 10eme Etape :
- Juste avant que le programme ne se termine, nous devons fermer le catalogue
- des messages. Il suffit d'utiliser la ligne suivante :
- catclose(catfd);
-
- Il est necessaire de faire quelques verifications d'erreurs. Si le
- catalogue des messages ne peut etre ouvert pour n'importe quelle raison,
- alors le programme utilise les messages par defauts, dans le code source.
- Cela peut etre une bonne idee de reperer les erreurs pendant le debogage du
- progamme. Il peut y avoir un bon nombre de raisons pour lesquelles le catalogue
- ne peut etre ouvert par le systeme d'exploitation. (Repertoire incorrect,
- mauvais nom, mauvais droits de fichiers, module incorrect, etc).
-
- Voici un exemple de programme utilisant toutes les fonctionalites :
-
- ---
- #include <stdio.h>
- #include <nl_types.h>
- #include <locale.h>
- #include "foobar-nls.h"
-
- static nl_catd catfd = -1;
-
- void main()
- {
- char temp_name;
-
- setlocale(LC_MESSAGES,"");
- catinit ();
-
- printf(catgets(catfd, foobarSet, foobarRandom_Name,
- "Random text with string %s"), temp_name);
- catclose(catfd);
- exit(0);
- }
-
- catinit ()
- {
- if (catfd != (nl_catd)-1)
- catfd = catopen("foobar",MCLoadBySet);
- }
- ---
-
- Un fichier Makefile :
-
- -------
- all: foobar catalog
-
- foobar: foobar.o
- gcc -o foobar -O2 foobar.c
-
- foobar.o: foobar-nls.h
-
- foobar-nls.h: foobar-nls.m
- gencat -new /dev/null foobar-nls.m -h foobar-nls.h
-
- catalog:
- gencat -new foobar.cat foobar.m
-
-
- install: all
- install -o root -m 0755 foobar /usr/local/bin
- install -o root -m 0755 foobar.cat /etc/locale/C
-
- clean:
- /bin/rm -f foobar *.o foobar-nls.h foobar.cat core
-
- -------
- C'est a vous de choisir l'endroit ou vous aller mettre les catalogues
- des messages. Il est surement plus facile de les regrouper dans un repertoire
- different du code source de votre programme.
-
-
- III.2 Ecrire des programmes qui doivent etre utilises sur des
- systemes se servant de "Locale" ou non.
-
- Il est relativement facile soustraire les fonctions de specification
- du milieu au reste du code. La methode habituelle est de definir un DEFINE :
-
- Dans le fichier Makefile, rajoutez les lignes suivantes :
-
- DEFINES = -DNLS
- foobar.o: foobar.c
- gcc $(DEFINES) foobar.c
-
- Maintenant, dans foobar.c, nous avons :
-
- #ifdef NLS
- printf(catgets(catfd, chmodSet, chmodVM_Exausted,
- "Virtual Memory Exausted");
- #else
- printf("Virtual Memory Exausted");
- #endif
-
- Les instructions #ifdef, #endif devront entourer chacune des fonctions
- specifiques a la gestion du milieu. De meme pour les fichiers <locale.h>,
- <nl_types.h>, les declaration des descripteurs de catalogues, etc
-
- Exemple :
-
- #ifdef NLS
- #include <locale.h>
- #include <nl_types.h>
-
- extern nl_catd catfd;
- void catinit ();
- #endif
-
- /* Definition des Macros utilisee */
-
- #ifdef NLS
- #define NLS_CATCLOSE(catfd) catclose (catfd);
- #define NLS_CATINIT catinit ();
- #define NLS_CATGETS(catfd, arg1, arg2, fmt) \
- catgets ((catfd), (arg1), (arg2), (fmt))
- #else
- #define NLS_CATCLOSE(catfd) /* vide */
- #define NLS_CATINIT /* vide */
- #define NLS_CATGETS(catfd, arg1, arg2, fmt) fmt
- #endif
- ---
-
- Maintenant, au lieu d'ecrire cela,
- #ifdef NLS
- printf(catgets(catfd, chmodSet, chmodVM_exhausted, "Virtual Memory
- exhausted"));
- #else
- printf("Virtual Memory exhausted");
- #endif
-
- on peut ecrire ceci :
-
- printf(NLS_CATGETS(catfd, chmodSet, chmodVM_exhausted, "Virtual Memory
- exhausted"));
-
- Cela simplifie enormement les choses. Pour pouvoir supporter le milieu,
- ou au contraire ne pas le supporter, il suffit de rajouter un -DNLS dans
- le fichier Makefile, rajouter un #include pour le fichier des macros,
- et enfin, entourer chacun des #include "xxxx-nls.h" par des #ifdef, #endif.
-
-
- IV Ou sont stockes mes messages ?
- --------------------------------------
- Cette section peut etre consideree comme une section d'information. Elle
- ne devrait etre consideree que comme etant un guide approximatif en attendant
- que j'ai le temps de regarder le quatres guides standards de Portabilite
- d'XOpen.
-
- Les catalogues de messages ainsi que d'autres composantes du milieu sont
- stockes dans deux repertoires :
- /usr/lib/locale
- /usr/local/lib/locale
-
- Le premier est utilise par les programmes faisant partie du systeme
- d'exploitation(programmes standards Unix). Le second est utilise pour des
- programmes personnels, qui ne font pas partit de la distribution standard.
-
- On peut trouver des sous-repertoires :
- LC_COLLATE
- LC_CTYPE
- LC_MESSAGES
- LC_MONETARY
- LC_NUMERIC
- LC_TIME
-
- NB : Ils ne doivent pas etre confondus avec les variables du meme nom. Ce
- sont les noms actuels de ces repertoires et ne risquent pas de changer.
- Pour eviter les confusions, nous nous refererons a $(LC_MESSAGES), etc...
-
- A l'interieur de ces sous repertoires, on peut y trouver les
- sous-repertoires pour les pays. Par exemple, sous /usr/lib/locale/LC_MESSAGES,
- on peut y trouver les repertoires suivants :
- C
- POSIX -> C
- en_US.88591
- de_DE.88591
- fr_BE.88591
-
- Dans chacun de ces sous-repertoires se trouvent les messages
- specifiques a la langue. Par exemple, les messages en anglais pour
- l'executable "ls" serait :
- /usr/lib/locale/LC_MESSAGES/en_US.88591/ls.cat
-
- Le format est le suivant :
- /usr/lib/locale/LC_MESSAGES/xx_YY.ZZZ/mm.cat
- ^^^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^
- racine categorie langue catalogue
-
- La racine ne change pas : c'est soit /usr/lib/locale pour les programmes
- systemes soit /usr/local/lib/locale pour les autres programmes.
-
- La categorie depend seulement des fonctions auxquelles le programmes va
- faire appel. Si le programme a besoin d'informations sur la monaie, il va
- chercher les informations dans :
- /usr/lib/locale/LC_MONETARY/xx_YY.ZZZ/
-
- L'attribut de la langue est probablement le plus important car il
- determine quelles variables et quels repertoires vont etre utilises. Le format
- de la langue est le suivant :
- Langue_Pays.TypeDeCaracteres
-
- Voici un exemple :
- en_US.88591 Anglais(USA), utilisation du type de caracteres ISO 88591
- de_DE.88591 Allemand(Allemagne), utilisation du type de caracteres ISO 88591
- fr_BE.88591 Francais(Belgique), utilisation du type de caracteres ISO 88591
-
- Le langue est positionnee par la variable d'environement $(LANG).
- L'utilisateur devra positioner la langue, le pays et le type de caractere d'une
- maniere correcte. Ainsi, le systeme d'exploitation utilisera la variable
- lorsqu'il cherchera le sous-repertoire approprie pour trouver les informations
- ou les catalogues de messages dont il a besoin.
-
- Nous avons mis en evidence les deux endroits par defaut que le systeme
- utilise pour stocker ses catalogues de messages et les autres attributs.
- Toutefois, le systeme doit aussi etre capable de gerer les utilisateurs
- qui ne peuvent installer les catalogues dans ces repertoires (Pour le faire,
- ils devraient avoir les droits du super-utilisateur). Donc, il doivent
- installer leurs propres catalogues dans leur repertoire personnel.
- Le systeme peut gerer cette situation : il suffut d'utiliser la variable
- d'environnement NLSPATH.
-
- Cette variable contient la liste des repertoires dans lesquels le systeme
- d'exploitation va rechercher les catalogues des messages.
- Exemple :
- NLSPATH=/usr/lib/locale/LC_MESSAGES/%L/%N:/usr/local/lib/locale/LC_MESSAGES/%L
- /%N:~/messages/%N
- %L => Valeur de la variable LANG
- %N => Nom du catalogue
-
- Ces deux valeurs sont substituees par le systeme d'exploitation (Note
- traducteur : en fait, c'est le shell...) lors de l'evaluation. L'utilsateur
- peut alors ranger ses catalogues de messages dans ses repertoires personnels.
-
- Il peux meme courcicuiter les repertoires pat defaut en changeant
- l'ordre des repertoires dans la variable d'environement NLSPATH.
-
- V Questions les plus frequemment posees. (F.A.Q.)
- -------------------------------------------------------
-
- Question : Comment puis-je savoir si mon systeme Unix supporte l'utilisation
- des fonctions de gestion du milieu ?
-
- Reponse : Un systeme Unix qui supporte toutes les fonctionnalites de ces
- fonctions doit avoir ces fichiers d'entete :
- locale.h et nl_types.h
- Il sont en general situes dans le repertoire /usr/include. Si un de ces
- fichiers est absent, alors votre systeme risque de ne supporter qu'une
- partie de ces fonctions. Ces deux fichiers sont inclus dans Linux.
-
- ============================================================================
- Le sujet traite dans ce document possede plusieurs copyrights :
- Alfalfa Software, Mitchum DSouza et Patrick D'Cruze - 1989-1994.
-
- Envoyez vos suggestions, vos remarques a l'auteur de ce document a
- pdcruze@orac.iinet.com.au
- pdcruze@li.org
-
- Si jamais des erreurs se sont glissees dans ce documents, envoyez un mail :
- dumas@emi.u-bordeaux.fr
- ============================================================================
-
-