"gettext" — Services d'internationalisation multilingue
*******************************************************

**Code source :** Lib/gettext.py

======================================================================

Le module "gettext" fournit un service d'internationalisation (*I18N*)
et de localisation linguistique (*L10N*) pour vos modules et
applications Python. Il est compatible avec l'API du catalogue de
messages GNU **gettext** et à un plus haut niveau, avec l'API basée
sur les classes qui serait peut-être plus adaptée aux fichiers Python.
L'interface décrite ci-dessous vous permet d'écrire les textes de vos
modules et applications dans une langue naturelle, puis de fournir un
catalogue de traductions pour les lancer ensuite dans d'autres langues
naturelles.

Quelques astuces sur la localisation de vos modules et applications
Python sont également données.


API GNU **gettext**
===================

Le module "gettext" définit l'API suivante, qui est très proche de
l'API de GNU **gettext**.  Si vous utilisez cette API, cela affectera
la traduction de toute votre application.  C'est souvent le
comportement attendu si votre application est monolingue, avec le
choix de la langue qui dépend des paramètres linguistiques de
l'utilisateur.  Si vous localisez un module Python ou si votre
application a besoin de changer de langue à la volée, il est plus
judicieux d'utiliser l'API basée sur des classes.

gettext.bindtextdomain(domain, localedir=None)

   Lie *domain* au répertoire *localedir* des localisations. Plus
   spécifiquement, "gettext" va chercher les fichiers binaires ".mo"
   pour un domaine donné, en utilisant le chemin suivant (sous Unix) :
   "*localedir*/*language*/LC_MESSAGES/*domain*.mo", où *language* est
   recherché dans l'une des variables d'environnement suivantes :
   "LANGUAGE", "LC_ALL", "LC_MESSAGES" et "LANG".

   Si *localedir* n'est pas renseigné ou vaut "None", alors le lien
   actuel de *domain* est renvoyé. [1]

gettext.bind_textdomain_codeset(domain, codeset=None)

   Lie *domain* à *codeset*, en changeant l'encodage des chaînes
   d'octets retournées par les fonctions "lgettext()", "ldgettext()",
   "lngettext()" et "ldngettext()".  Si *codeset* n'est pas renseigné,
   alors le lien actuel est renvoyé.

   Obsolète depuis la version 3.8, supprimé dans la version 3.10.

gettext.textdomain(domain=None)

   Change ou interroge le domaine global actuel.  Si *domain* vaut
   "None", alors le domaine global actuel est renvoyé.  Sinon, le
   domaine global est positionné à *domain*, puis renvoyé.

gettext.gettext(message)

   Renvoie la traduction localisée de *message*, en se basant sur le
   domaine global actuel, la langue et le répertoire des
   localisations. Cette fonction est typiquement renommée "_()" dans
   le namespace courant (voir les exemples ci-dessous).

gettext.dgettext(domain, message)

   Comme "gettext()", mais cherche le message dans le domaine
   spécifié.

gettext.ngettext(singular, plural, n)

   Comme "gettext()", mais prend en compte les formes au pluriel.  Si
   une traduction a été trouvée, utilise la formule pour trouver le
   pluriel à *n* et renvoie le message généré (quelques langues ont
   plus de deux formes au pluriel).  Si aucune traduction n'a été
   trouvée, renvoie *singular* si *n* vaut 1, *plural* sinon.

   La formule pour trouver le pluriel est récupérée dans l'entête du
   catalogue.  C'est une expression en C ou en Python qui a une
   variable libre *n* et qui évalue l'index du pluriel dans le
   catalogue.  Voir la documentation de GNU gettext pour la syntaxe
   précise à utiliser dans les fichiers ".po" et pour les formules
   dans différents langues.

gettext.dngettext(domain, singular, plural, n)

   Comme "ngettext()", mais cherche le message dans le domaine
   spécifié.

gettext.pgettext(context, message)

gettext.dpgettext(domain, context, message)

gettext.npgettext(context, singular, plural, n)

gettext.dnpgettext(domain, context, singular, plural, n)

   Semblable aux fonctions correspondantes sans le "p" dans le préfixe
   (c'est-à-dire "gettext()", "dgettext()", "ngettext()" et
   "dngettext()"), mais la traduction est limitée au *context* du
   message donné.

   Nouveau dans la version 3.8.

gettext.lgettext(message)

gettext.ldgettext(domain, message)

gettext.lngettext(singular, plural, n)

gettext.ldngettext(domain, singular, plural, n)

   Équivalent aux fonctions correspondantes non préfixées par "l"
   ("gettext()", "dgettext()", "ngettext()" et "dngettext()"), mais la
   traduction est retournée en tant que chaîne d'octets, encodée avec
   l'encodage du système si aucun autre n'a été explicitement défini
   avec "bind_textdomain_codeset()".

   Avertissement:

     Ces fonctions sont à éviter en Python 3 car elles renvoient des
     octets encodés. Il est préférable d'utiliser des alternatives qui
     renvoient de l'Unicode, puisque beaucoup d'applications Python
     voudront manipuler du texte lisible par des humains plutôt que
     des octets. En outre, il est possible que vous obteniez des
     exceptions non prévues liées à Unicode s'il y a des soucis
     d'encodage avec les chaînes de caractères traduites.

   Obsolète depuis la version 3.8, supprimé dans la version 3.10.

Notez que GNU **gettext** a aussi une méthode "dcgettext()", mais elle
a été considérée comme inutile et donc actuellement marquée comme non
implémentée.

Voici un exemple classique d'utilisation de cette API :

   import gettext
   gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
   gettext.textdomain('myapplication')
   _ = gettext.gettext
   # ...
   print(_('This is a translatable string.'))


API basée sur les classes
=========================

L'API du module "gettext" basée sur les classes vous donne plus de
flexibilité et est plus pratique que l'API de GNU **gettext**. Son
utilisation est recommandée pour localiser vos applications et modules
Python. "gettext" définit une classe "GNUTranslations" qui analyse
syntaxiquement les fichiers au format GNU ".mo", et qui possède des
méthodes pour renvoyer des chaînes de caractères. Les instances de
cette classe "translations" peuvent également s'installer dans
l'espace de nommage natif en tant que fonction "_()".

gettext.find(domain, localedir=None, languages=None, all=False)

   Cette fonction implémente l'algorithme standard de recherche de
   fichier "mo". Il prend en entrée un *domain*, tout comme la
   fonction "textdomain()". Le paramètre optionnel *localedir* est le
   même que celui de "bindtextdomain()". Le paramètre optionnel
   *langages* est une liste de chaînes de caractères correspondants au
   code d'une langue.

   Si *localedir* n'est pas renseigné, alors le répertoire de la
   locale par défaut du système est utilisé. [2]  Si *languages* n'est
   pas renseigné, alors les variables d'environnement suivantes sont
   utilisées : "LANGUAGE", "LC_ALL", "LC_MESSAGES" et "LANG".  La
   première à renvoyer une valeur non vide est alors utilisée pour
   *languages*.  Ces variables d'environnement doivent contenir une
   liste de langues, séparées par des deux-points, qui sera utilisée
   pour générer la liste des codes de langues attendue.

   Recherche avec "find()", découvre et normalise les langues, puis
   itère sur la liste obtenue afin de trouver un fichier de traduction
   existant et correspondant :

   "*localedir*/*language*/LC_MESSAGES/*domain*.mo"

   Le premier nom de fichier trouvé est renvoyé par "find()".  Si
   aucun fichier n'a été trouvé, alors "None" est renvoyé.  Si *all*
   est vrai, est renvoyée la liste de tous les noms de fichiers, dans
   l'ordre dans lequel ils apparaissent dans *languages* ou dans les
   variables d'environnement.

gettext.translation(domain, localedir=None, languages=None, class_=None, fallback=False, codeset=None)

   Renvoie une instance de la classe "*Translations" en se basant sur
   *domain*, *localedir* et *languages*, qui sont d'abord passés en
   argument de "find()" afin d'obtenir une liste de chemin des
   fichiers ".mo" associés. Les instances avec des noms de fichiers
   ".mo" identiques sont mises en cache. La classe réellement
   instanciée est soit *class_* si renseigné, soit une classe
   "GNUTranslations". Le constructeur de cette classe doit prendre en
   argument un seul *file object*. Si renseigné, *codeset* modifiera
   le jeu de caractères utilisé pour encoder les chaînes de caractères
   traduites, dans les méthodes "lgettext()" et "lngettext()".

   Si plusieurs fichiers ont été trouvés, les derniers sont utilisés
   comme substitut des premiers.  Pour rendre possible cette
   substitution, "copy.copy()" est utilisé pour copier chaque objet
   traduit depuis le cache ; les vraies données de l'instance étant
   toujours recopiées dans le cache.

   Si aucun fichier ".mo" n'a été trouvé, soit *fallback* vaut *False*
   (valeur par défaut) et une exception "OSError" est levée, soit
   *fallback* vaut *True* et une instance "NullTranslations" est
   renvoyée.

   Modifié dans la version 3.3: Avant, c'était l'exception "IOError"
   qui était levée, au lieu de "OSError".

   Obsolète depuis la version 3.8, supprimé dans la version 3.10: Le
   paramètre *codeset*.

gettext.install(domain, localedir=None, codeset=None, names=None)

   Positionne la fonction "_()" dans l'espace de nommage natif de
   Python, en se basant sur *domain*, *localedir* et *codeset*, qui
   sont passés en argument de la fonction "translation()".

   Concernant le paramètre *names*, se référer à la description de la
   méthode "install()".

   Habituellement, la fonction "_()" est appliquée aux chaînes de
   caractères qui doivent être traduites comme suit :

      print(_('This string will be translated.'))

   Pour plus de confort, il vaut mieux positionner la fonction "_()"
   dans l'espace de nommage natif de Python pour la rendre plus
   accessible dans tous les modules de votre application.

   Obsolète depuis la version 3.8, supprimé dans la version 3.10: Le
   paramètre *codeset*.


La classe "NullTranslations"
----------------------------

Les classes de traduction implémentent le fait de passer d'une chaîne
de caractères du fichier original à traduire à la traduction de celle-
ci.  La classe de base utilisée est "NullTranslations".  C'est
l'interface de base à utiliser lorsque vous souhaitez écrire vos
propres classes spécifiques à la traduction.  Voici les méthodes de
"NullTranslations" :

class gettext.NullTranslations(fp=None)

   Prend un paramètre optionnel un *file object* *fp*, qui est ignoré
   par la classe de base.  Initialise les variables d'instance
   "protégées" *_info* et *_chardet*, définies par des classes
   dérivées, tout comme *_fallback* qui est définie au travers de
   "add_fallback()".  Puis appelle "self._parse(fp)" si *fp* ne vaut
   pas "None".

   _parse(fp)

      Cette méthode, non exécutée dans la classe de base, prend en
      paramètre un objet fichier *fp* et lit les données de ce
      dernier.  Si vous avez un catalogue de messages dont le format
      n'est pas pris en charge, vous devriez surcharger cette méthode
      pour analyser votre format.

   add_fallback(fallback)

      Ajoute *fallback* comme objet de substitution pour l'objet de
      traduction courant.  Un objet de traduction devrait interroger
      cet objet de substitution s'il ne peut fournir une traduction
      pour un message donné.

   gettext(message)

      Si un objet de substitution a été défini, transmet "gettext()" à
      celui-ci.  Sinon, renvoie *message*.  Surchargé dans les classes
      dérivées.

   ngettext(singular, plural, n)

      Si un objet de substitution a été défini, transmet "ngettext()"
      à celui-ci.  Sinon, renvoie *singular* si *n* vaut 1, *plural*
      sinon.  Surchargé dans les classes dérivées.

   pgettext(context, message)

      Si un objet de substitution a été défini, transmet "pgettext()"
      à celui-ci. Sinon, renvoie le message traduit. Surchargé dans
      les classes dérivées.

      Nouveau dans la version 3.8.

   npgettext(context, singular, plural, n)

      Si un objet de substitution a été défini, transmet "npgettext()"
      à celui-ci. Sinon, renvoie le message traduit. Surchargé dans
      les classes dérivées.

      Nouveau dans la version 3.8.

   lgettext(message)

   lngettext(singular, plural, n)

      Équivalent de "gettext()" et "ngettext()", mais la traduction
      est renvoyée sous la forme d'une chaîne d'octets, encodée avec
      l'encodage du système si aucun autre n'a été défini avec
      "set_output_charset()".  Surchargé dans les classes dérivées.

      Avertissement:

        L'utilisation de ces méthodes doivent être évitée en Python 3.
        Voir l'avertissement de la fonction "lgettext()".

      Obsolète depuis la version 3.8, supprimé dans la version 3.10.

   info()

      Renvoie l'attribut "protégé" "_info", dictionnaire contenant les
      métadonnées trouvées dans le fichier de catalogue de messages.

   charset()

      Renvoie l'encodage du fichier du catalogue de messages.

   output_charset()

      Renvoie l'encodage utilisé par "lgettext()" et "lngettext()"
      pour la traduction des messages.

      Obsolète depuis la version 3.8, supprimé dans la version 3.10.

   set_output_charset(charset)

      Modifie l'encodage utilisé pour la traduction des messages.

      Obsolète depuis la version 3.8, supprimé dans la version 3.10.

   install(names=None)

      Cette méthode positionne "gettext()" dans l'espace de nommage
      natif, en le liant à "_".

      Si le paramètre *names* est renseigné, celui-ci doit être une
      séquence contenant les noms des fonctions que vous souhaitez
      positionner dans l'espace de nommage natif, en plus de "_()".
      Les noms pris en charge sont "'gettext'", "'ngettext'",
      "'pgettext'", "'npgettext'", "'lgettext'" et "'lngettext'".

      Notez que ce n'est là qu'un moyen parmi d'autres, quoique le
      plus pratique, pour rendre la fonction "_()" accessible à votre
      application.  Puisque cela affecte toute l'application, et plus
      particulièrement l'espace de nommage natif, les modules
      localisés ne devraient jamais y positionner "_()".  Au lieu de
      cela, ces derniers doivent plutôt utiliser le code suivant pour
      rendre "_()" accessible par leurs modules :

         import gettext
         t = gettext.translation('mymodule', ...)
         _ = t.gettext

      Cela met "_()" dans l'espace de nommage global du module
      uniquement et donc n'affectera ses appels que dans ce module.

      Modifié dans la version 3.8: Ajout de "'pgettext'" et
      "'npgettext'".


La classe "GNUTranslations"
---------------------------

Le module "gettext" fournit une classe supplémentaire qui hérite de
"NullTranslations" : "GNUTranslations".  Cette classe surcharge
"_parse()" pour permettre de lire les fichiers GNU **gettext** ".mo"
au format petit et gros-boutiste.

"GNUTranslations" analyse les métadonnées optionnelles du catalogue de
traduction. Il est d'usage avec GNU **gettext** d'utiliser une
métadonnée pour traduire la chaîne vide. Cette métadonnée est un
ensemble de paires de la forme "clef: valeur" comme définie par la
**RFC 822**, et doit contenir la clef "Project-Id-Version". Si la clef
"Content-Type" est trouvée dans une métadonnée, alors la propriété
"charset" (jeu de caractères) est utilisée pour initialiser la
variable d'instance "protégée" "_charset", sinon cette dernière est
positionnée à "None". Si l'encodage du jeu de caractères est spécifié,
tous les messages (identifiants et chaînes de caractères) lus depuis
le catalogue sont convertis en chaînes Unicode via cet encodage, ou
via l'encodage ASCII si non renseigné.

Et puisque les identifiants des messages sont également lus comme des
chaînes Unicode, toutes les méthodes "*gettext()" les considéreront
ainsi, et pas comme des chaînes d'octets.

La totalité des paires clef / valeur est insérée dans un dictionnaire
et représente la variable d'instance "protégée" "_info".

Si le nombre magique du fichier ".mo" est invalide, le numéro de la
version majeure inattendu, ou si d'autres problèmes apparaissent
durant la lecture du fichier, instancier une classe "GNUTranslations"
peut lever une exception "OSError".

class gettext.GNUTranslations

   Les méthodes suivantes, provenant de l'implémentation de la classe
   de base, ont été surchargée :

   gettext(message)

      Recherche l'identifiant de *message* dans le catalogue et
      renvoie le message de la chaîne de caractères correspondante
      comme une chaîne Unicode.  Si aucun identifiant n'a été trouvé
      pour *message* et qu'un substitut a été défini, la recherche est
      transmise à la méthode "gettext()" du substitut.  Sinon,
      l'identifiant de *message* est renvoyé.

   ngettext(singular, plural, n)

      Effectue une recherche sur les formes plurielles de
      l'identifiant d'un message.  *singular* est utilisé pour la
      recherche de l'identifiant dans le catalogue, alors que *n*
      permet de savoir quelle forme plurielle utiliser.  La chaîne de
      caractère du message renvoyée est une chaîne Unicode.

      Si l'identifiant du message n'est pas trouvé dans le catalogue
      et qu'un substitut a été spécifié, la requête est transmise à la
      méthode "ngettext()" du substitut.  Sinon, est renvoyé
      *singular* lorsque *n* vaut 1, *plural* dans tous les autres
      cas.

      Voici un exemple :

         n = len(os.listdir('.'))
         cat = GNUTranslations(somefile)
         message = cat.ngettext(
             'There is %(num)d file in this directory',
             'There are %(num)d files in this directory',
             n) % {'num': n}

   pgettext(context, message)

      Recherche le *contexte* et l'identifiant de *message* dans le
      catalogue et renvoie le message de la chaîne de caractères
      correspondante comme une chaîne Unicode. Si aucun identifiant
      n'a été trouvé pour l'identifiant du *message* et du *context*
      et qu'un substitut a été défini, la recherche est transmise à la
      méthode "pgettext()" du substitut. Sinon, l'identifiant de
      *message* est renvoyé.

      Nouveau dans la version 3.8.

   npgettext(context, singular, plural, n)

      Effectue une recherche sur les formes plurielles de
      l'identifiant d'un message. *singular* est utilisé pour la
      recherche de l'identifiant dans le catalogue, alors que *n*
      permet de savoir quelle forme plurielle utiliser.

      Si l'identifiant du message pour le *context* n'est pas trouvé
      dans le catalogue et qu'un substitut a été spécifié, la requête
      est transmise à la méthode "npgettext()" du substitut. Sinon,
      est renvoyé *singular* lorsque *n* vaut 1, *plural* dans tous
      les autres cas.

      Nouveau dans la version 3.8.

   lgettext(message)

   lngettext(singular, plural, n)

      Équivalent de "gettext()" et "ngettext()", mais la traduction
      est renvoyée sous la forme d'une chaîne d'octets, encodée avec
      l'encodage du système si aucun autre n'a été défini avec
      "set_output_charset()".

      Avertissement:

        L'utilisation de ces méthodes doivent être évitée en Python 3.
        Voir l'avertissement de la fonction "lgettext()".

      Obsolète depuis la version 3.8, supprimé dans la version 3.10.


Support du catalogue de message de Solaris
------------------------------------------

Le système d'exploitation Solaris possède son propre format de fichier
binaire ".mo", mais pour l'heure, puisqu'on ne peut trouver de
documentation sur ce format, il n'est pas géré.


Le constructeur *Catalog*
-------------------------

GNOME utilise une version du module "gettext" de James Henstridge,
mais qui a une API légèrement différente.  D'après la documentation,
elle s'utilise ainsi :

   import gettext
   cat = gettext.Catalog(domain, localedir)
   _ = cat.gettext
   print(_('hello world'))

Pour des raisons de compatibilité avec cet ancien module, la fonction
"Catalog()" est un alias de la fonction "translation()" décrite ci-
dessous.

Une différence entre ce module et celui de Henstridge : les objets de
son catalogue étaient accessibles depuis un schéma de l'API, mais cela
semblait ne pas être utilisé et donc n'est pas pris en charge.


Internationaliser vos programmes et modules
===========================================

L'internationalisation (*I18N*) consiste à permettre à un programme de
recevoir des traductions dans plusieurs langues.  La localisation
(*L10N*) consiste à adapter un programme à la langue et aux habitudes
culturelles locales, une fois celui-ci internationalisé.  Afin de
fournir du texte multilingue à votre programme Python, les étapes
suivantes sont nécessaires :

1. préparer votre programme ou module en marquant spécifiquement les
   chaînes à traduire

2. lancer une suite d'outils sur les fichiers contenant des chaînes à
   traduire pour générer des catalogues de messages brut

3. créer les traductions spécifiques à une langue des catalogues de
   messages

4. utiliser le module "gettext" pour que les chaînes de caractères
   soient bien traduites

Afin de préparer votre code à être traduit (*I18N*), vous devrez
rechercher toutes les chaînes de caractères de vos fichiers.  À chaque
chaîne de caractères à traduire doit être appliqué le marqueur
"_('...')" --- c'est-à-dire en appelant la fonction "_()".  Par
exemple :

   filename = 'mylog.txt'
   message = _('writing a log message')
   with open(filename, 'w') as fp:
       fp.write(message)

Dans cet exemple, la chaîne "'writing a log message'" est maquée comme
traduite, contrairement aux chaînes "'mylog.txt'" et "'w'".

There are a few tools to extract the strings meant for translation.
The original GNU **gettext** only supported C or C++ source code but
its extended version **xgettext** scans code written in a number of
languages, including Python, to find strings marked as translatable.
Babel is a Python internationalization library that includes a
"pybabel" script to extract and compile message catalogs.  François
Pinard's program called **xpot** does a similar job and is available
as part of his po-utils package.

(Python inclut également des versions en Python de ces programmes,
**pygettext.py** et **msgfmt.py**, que certaines distributions Python
installeront pour vous.  **pygettext.py** est similaire à
**xgettext**, mais ne comprend que le code source écrit en Python et
ne peut prendre en charge d'autres langages de programmation tels que
le C ou C++.  **pygettext.py** possède une interface en ligne de
commande similaire à celle de **xgettext** --- pour plus de détails
sur son utilisation, exécuter "pygettext.py --help".  **msgfmt.py**
est compatible avec GNU **msgfmt**.  Avec ces deux programmes, vous ne
devriez pas avoir besoin du paquet GNU **gettext** pour
internationaliser vos applications en Python.)

**xgettext**, **pygettext** et d'autres outils similaires génèrent des
fichiers ".po" représentant les catalogues de messages.  Il s'agit de
fichiers structurés et lisibles par un être humain, qui contiennent
toutes les chaînes du code source marquées comme traduisible, ainsi
que leur traduction à utiliser.

Les copies de ces fichiers ".po" sont ensuite remises à des êtres
humains qui traduisent le contenu pour chaque langue naturelle prise
en charge.  Pour chacune des langues, ces derniers renvoient la
version complétée sous la forme d'un fichier "<code-langue>.po" qui a
été compilé dans un fichier binaire ".mo" représentant le catalogue
lisible par une machine à l'aide du programme **msgfmt**.  Les
fichiers ".mo" sont utilisés par le module "gettext" pour la
traduction lors de l'exécution.

La façon dont vous utilisez le module "gettext" dans votre code dépend
de si vous internationalisez un seul module ou l'ensemble de votre
application.  Les deux sections suivantes traitent chacune des cas.


Localiser votre module
----------------------

Si vous localisez votre module, veillez à ne pas faire de changements
globaux, e.g. dans l'espace de nommage natif. Vous ne devriez pas
utiliser l’API GNU **gettext** mais plutôt celle basée sur les
classes.

Disons que votre module s'appelle "spam" et que les fichiers ".mo" de
traduction dans les différentes langues naturelles soient dans
"/usr/share/locale" au format GNU **gettext**.  Voici ce que vous
pouvez alors mettre en haut de votre module :

   import gettext
   t = gettext.translation('spam', '/usr/share/locale')
   _ = t.gettext


Localiser votre application
---------------------------

Si vous localisez votre application, vous pouvez positionner la
fonction "_()" de manière globale dans l'espace de nommage natif,
généralement dans le fichier principal de votre application.  Cela
permettra à tous les fichiers de votre application de n'utiliser que
"_('...')" sans devoir le redéfinir explicitement dans chaque fichier.

Dans ce cas, vous n'aurez à ajouter que le bout de code suivant au
fichier principal de votre application :

   import gettext
   gettext.install('myapplication')

Si vous avez besoin de définir le dossier des localisations, vous
pouvez le mettre en argument de la fonction "install()" :

   import gettext
   gettext.install('myapplication', '/usr/share/locale')


Changer de langue à la volée
----------------------------

Si votre programme a besoin de prendre en charge plusieurs langues en
même temps, vous pouvez créer plusieurs instances de traduction, puis
basculer entre elles de façon explicite, comme ceci :

   import gettext

   lang1 = gettext.translation('myapplication', languages=['en'])
   lang2 = gettext.translation('myapplication', languages=['fr'])
   lang3 = gettext.translation('myapplication', languages=['de'])

   # start by using language1
   lang1.install()

   # ... time goes by, user selects language 2
   lang2.install()

   # ... more time goes by, user selects language 3
   lang3.install()


Traductions différées
---------------------

Dans la plupart des cas, en programmation, les chaînes de caractères
sont traduites à l'endroit où on les écrit.  Cependant, il peut
arriver que vous ayez besoin de traduire une chaîne de caractères un
peu plus loin.  Un exemple classique est :

   animals = ['mollusk',
              'albatross',
              'rat',
              'penguin',
              'python', ]
   # ...
   for a in animals:
       print(a)

Ici, vous voulez marquer les chaînes de caractères de la liste
"animals" comme étant traduisibles, mais ne les traduire qu'au moment
de les afficher.

Voici un moyen de gérer ce cas :

   def _(message): return message

   animals = [_('mollusk'),
              _('albatross'),
              _('rat'),
              _('penguin'),
              _('python'), ]

   del _

   # ...
   for a in animals:
       print(_(a))

Cela fonctionne car la définition factice de "_()" renvoie simplement
la chaîne de caractères passée en entrée.  Et cette définition factice
va temporairement outrepasser toute autre définition de "_()" dans
l'espace de nommage natif (jusqu'à l'utilisation de la commande
"del").  Attention toutefois si vous avez déjà une autre définition de
"_()" dans l'espace de nommage local.

À noter qu'à la deuxième utilisation de "_()", "a" ne sera pas vue
comme traduisible par le programme **gettext** car ce n'est pas un
chaîne au sens propre.

Voici une autre solution :

   def N_(message): return message

   animals = [N_('mollusk'),
              N_('albatross'),
              N_('rat'),
              N_('penguin'),
              N_('python'), ]

   # ...
   for a in animals:
       print(_(a))

Dans ce cas, les chaînes à traduire sont identifiées avec la fonction
"N_()", qui n'entre pas en conflit avec  définition de "_()".
Cependant, il faudra apprendre à votre programme d'extraction de
messages à rechercher les chaînes de caractères à traduire parmi
celles ayant le marqueur "N_()".  **xgettext**, **pygettext**,
"pybabel extract" et **xpot** prennent tous en charge cela grâce à
l'option en ligne de commande "-k".  Le choix du nom "N_()" ici est
totalement arbitraire et aurait très bien pu être
"MarqueurDeTraduction()".


Remerciements
=============

Les personnes suivantes ont contribué au code, ont fait des retours,
ont participé aux suggestions de conception et aux implémentations
précédentes, et ont partagé leur expérience précieuse pour la création
de ce module :

* Peter Funk

* James Henstridge

* Juan David Ibáñez Palomar

* Marc-André Lemburg

* Martin von Löwis

* François Pinard

* Barry Warsaw

* Gustavo Niemeyer

-[ Notes ]-

[1] Le dossier par défaut pour les localisations dépend du système :
    par exemple, sur RedHat c'est "/usr/share/locale", mais sur
    Solaris c'est "/usr/lib/locale". Le module "gettext" n'essaie pas
    de prendre en charge ce paramètre système dépendant du système
    d'exploitation, mais utilise le dossier
    "*sys.base_prefix*/share/locale" (voir "sys.base_prefix"). C'est
    pour cette raison qu'il est toujours préférable d'appeler
    "bindtextdomain()" en donnant explicitement un chemin absolu au
    début de votre application.

[2] Voir la note de "bindtextdomain()" ci-dessus.
