Projet

Général

Profil

Gestion traduction » Historique » Version 34

« Précédent - Version 34/38 (diff) - Suivant » - Version actuelle
Fabrice Barconnière, 13/11/2014 08:59


Gestion traduction

Besoins

Pouvoir mettre à jour les fichiers de traduction distribués dans les paquets.

Idéalement, il faut :
  • un mécanisme permettant de mettre à jour les fichiers .po pour chaque langue déjà traduite et le fichier .pot pouvant servir de point de départ à la traduction dans une nouvelle langue ;
  • un mécanisme permettant d'être sûr que la version compilée installée est bien à jour.

Procédures

Les fichiers de traduction sont installés sous forme compilée (.mo).
Ces fichiers compilés ne sont pas éditables directement.
Ils sont générés à partir de fichiers texte (.po).

La mise à jour des fichiers de traduction est faite en trois étapes :
  1. extraction des chaînes de caractères à traduire dans un ensemble de fichiers (création ou mise à jour des fichiers .po),
  2. édition des fichiers .po,
  3. compilation des fichiers .mo à partir des fichiers .po.

L'extraction des chaînes de caractères à traduire est possible par l'emploi de la commande xgettext (également conseillée par l'auteur de pygettext depuis qu'elle gère le code python).
Le passage des .po aux .mo et inversement est possible par l'emploi des commandes msgfmt et msgunfmt réciproquement.

Les fichiers .po et .mo sont redondants et il n'est pas nécessaire de conserver les deux formats dans les dépôts.
Les fichiers .mo ne sont utiles que pour l'exécution des programmes traduits et les fichiers .po sont plus facilement exploitables dans un contexte de dépôt git.

Implémentation

  1. si nécessaire, mettre à jour tous les fichiers .po déjà créés et écraser le fichier .pot servant à créer le point de départ des nouvelles traductions (script lancé par le développeur après changement du code contenant les chaînes à traduire),
  2. si les fichiers .po ont été mis à jour, les éditer,
  3. compiler les fichiers .mo dans un répertoire installé à chaque construction de paquet (cible Makefile lancée automatiquement).
Les utilitaires à disposition (voir également la documentation gettext au format texinfo, chapitre 9):
  • xgettext : extraction de chaînes de caractères et création d'un catalogue vide ou ajout des chaînes à un catalogue déjà existant ;
  • msginit : création d'un catalogue .po pour une langue donnée, à partir d'un catalogue vide .pot ;
  • msgfmt : compilation d'un catalogue .po au format binaire .mo ;
  • msgunfmt : décompilation d'un catalogue au format binaire .mo en un catalogue .po ;
  • msgmerge : assemblage d'un catalogue avec traductions et d'un catalogue avec références mises à jour.

Arborescence des projets

Le fonctionnement de gettext nécessite de disposer, pour chaque langue, d'un fichier portant le même nom.
Sur le serveur, cela est rendu possible par l'organisation en arborescence avec un répertoire par langue, variante linguistique.

Dans le dépôt, on propose de distinguer les différentes langues en utilisant également une arborescence :

|
`-- translation
    |-- creole.pot
    |-- en
    |   `-- creole.po
    `-- fr
        `-- creole.po

Le niveau de répertoire LC_MESSAGES présent sur les serveurs n'est pas reproduit dans les dépôts.

Au moment de la compilation, on recherchera tous les fichiers correspondant au motif translation/*/*.po.

Mise à jour des .pot et des .po

La mise à jour des fichiers .pot et .po est une opération lancée si besoin au moyen du script po_update.sh.

Ce script commence par créer (en écrasant si nécessaire) une version à jour du modèle .pot.
Il met ensuite à jour les fichiers de traduction existant déjà dans l'arborescence.
Il gére le cas particulier du fichier de traduction en langue anglaise en le créant si il n'existe pas.
Il lui suffit pour cela de recopier les chaînes à traduire dans les chaînes traduites.
Attention donc à bien utiliser la langue anglaise dans le corps du code pour les chaînes de caractères à traduire.

Les informations nécessaires pour générer le .pot sont un nom de projet (domaine, également utilisé pour le nom de paquet) et les répertoires ou fichiers dans lesquels chercher les chaînes de caractères.
Ces informations doivent être fournies en paramètres au script assurant la génération du .pot et la mise à jour des .po (en cas de chaîne vide, le message d'origine est utilisé).
Ces informations seront fournies sous la forme du fichier texte po_list structuré comme suit :

projet fichier1.py fichiers2*.py

Le premier mot est le nom du projet, les autres mots de la ligne, des motifs désignant les fichiers (et non les répertoires).

Attention : le langage défini, en dur, dans le script générant le .pot est python

Compilation des .mo

La compilation des .mo sera faite à la compilation des paquets : le .mo ne sera pas présent dans le dépôt.
Les cibles ajoutées dans eole.mk seront tous les fichiers .po disponibles.
La recette compilera les .po en .mo directement dans $(DESTDIR)/usr/share/locale/…

Préparation des programmes à traduire

Bibliothèques python

Les bibliothèques python peuvent utiliser gettext pour afficher les chaînes de caractères dans une langue spécifique.
Il faut utiliser les fonctions du module gettext auxquelles on passe toutes les chaînes de caractères à traduire.
Ces fonctions retournent les chaînes de caractères traduites.

modèle de fichier i18n.py

i18n.py à l'échelle du module
import gettext
import os
import sys

# Application Name
APP_NAME = 'creole'

# Traduction dir
APP_DIR = os.path.join(sys.prefix, 'share')
LOCALE_DIR = os.path.join(APP_DIR, 'locale')

mo_location = LOCALE_DIR

t = gettext.translation(APP_NAME, fallback=True)

_ = t.ugettext

La variable LOCALE_DIR pointe vers /usr/share/locale.

La variable APP_NAME définit le nom du domaine, soit le nom permettant d'associer le bon fichier .mo à la bibliothèque.

_ est utilisé comme "alias" pour la fonction gettext.translation(APP_NAME, "UTF-8").ugettext.
_() sera appelée dans le code à chaque fois qu'une chaîne de caractère devra être traduite.

L'utilisation de ugettext plutôt que gettext fait que la chaîne retournée sera de l' unicode.

Dans le cas d'un fichier i18n dans chaque projet :

from i18n import _

i18n à l'échelle du projet EOLE

Pour limiter le nombre de fichiers i18n.py, il est possible d'utiliser une fonction générique apportée par pyeole.

# -*- coding: UTF-8 -*-
# Copyright (C) 2014 Équipe EOLE.
#
"internationalisation utility" 
import gettext

system_locale_dir = "/usr/share/locale" 

class i18n(object):
    """callable version of gettext
    """ 
    def __init__(self, app_name):
        self.t = gettext.translation(app_name, localedir=system_locale_dir, fallback=True)

    def __call__(self, *args):
        # "polymorphism" rather than duck-typing to ease xgettext extraction work (keywordspec format)
        if len(args) == 1:
            return self.t.ugettext(*args)
        else:
            return self.t.ungettext(*args)

L'appel dans les bibliothèques se fait en deux temps : import de la classe i18n et assignation de la variable _ pour disposer d'un appel peu intrusif.

from pyeole.i18n import i18n
_ = i18n('lib')

Le contructeur de la classe i18n prend en argument le nom du projet utilisé pour nommer le fichier .po et identifier le domaine de l'application.

exemple d'utilisation

traduction d'une chaîne de caractères
# -*- coding: UTF-8 -*-
""" 
Translation test file 1
""" 

from pyeole.i18n import i18n
_ = i18n('project_name')

# chaîne non traduite
print u"some words" 

#chaîne qui sera traduite 
#en fonction des paramètres linguistiques du contexte d'exécution de la bibliothèque
#et de la disponibilité de la traduction dans /usr/share/locale
print _(u"some words")

#chaîne incluant des variations entre pluriel et singulier
#appel valide uniquement avec la classe i18n (voir i18n à l'échelle du projet EOLE)
num_phrase = 1|2
print _(u"{0} phrase traduite", u"{0} phrases traduites", num_phrase).format(num_phrase)

Attention : toujours garder à l'esprit que la chaîne retournée par la fonction _() est de l'unicode si la fonction ugettext a été utilisée dans le fichier i18n.py.
Il peut être nécessaire de l'encoder.

Par convention, on utilisera la langue anglaise dans le code et on fournira la traduction française dans les fichiers de traduction.

Étapes de mise en oeuvre

Le projet eole-skeletor intègre les fichiers nécessaires à la mise en oeuvre de la traduction.
Pour cela, dans votre projet, il faudra reprendre ces fichiers de la façon suivante :
  • Vérifier que eole.mk soit à jour pour prendre en compte la compilation des fichiers de traduction ;
  • ajouter po_update.sh à la racine du projet ;
  • créer un fichier po_list à la racine du projet ;
  • utiliser la classe i18n de pyeole pour indiquer ce qu'il faut traduire, exemple : _ = i18n('project_name') ;
  • les messages en anglais à traduire apparaissent ainsi dans le code python : _(u"English message") ;
  • exécuter po_update.sh pour créer ou actualiser l'arborescence de traduction des projets ;
  • effectuer la traduction en français dans les fichier .po du répertoire translation/fr/ ;
  • ajouter le répertoire de traduction au projet ;
  • commiter les changements ;