Site icon La programmation sur le web

Python, créer des traductions pour son application

Afin de toucher un publique plus large, il est parfois utile d’avoir une application traduite dans plusieurs langues. Le module gettext de Python permet la mise en place de traduction facilement, le tout dans un environnement Linux.

Mise en place d’une traduction

Pour montrer son fonctionnement, on va utiliser un exemple simple mais qui sera efficace, tout d’abord, on s’occupe de notre dossier de travail :

mkdir -p traduction/src
nano traduction/src/main.py

Et on copie le code suivant dans le fichier main.py.

def print_some_strings():
        print("Bonjour le monde")
        print("C'est une phrase traduite")

if __name__ == '__main__':
        print_some_strings()

Les différentes traductions seront placées dans des dossiers, une branche pour une langue, dans notre cas, en français et en anglais :

mkdir -p locales/fr/LC_MESSAGES
mkdir -p locales/en/LC_MESSAGES

L’arborescence devrait ressembler à cela :

Une fois cela fait, nous allons nous concentrer sur notre script main.py, il va falloir :

import gettext

_ = gettext.gettext

def print_some_strings():
        print(_("Bonjour le monde"))
        print(_("C'est une phrase traduite"))

if __name__ == '__main__':
        print_some_strings()

Sur la première ligne, nous reconnaissons l’import du module, rien de compliqué, nous venons marquer le texte avec le « _« .

Maintenant, passons à l’édition de nos différents fichiers, nous allons éditer plusieurs fichiers :

Commençons par générer le fichier « .pot » :

pygettext -d main -o locales/main.pot src/main.py

Cela va générer notre fichier brut :

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2021-05-05 20:33+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"


#: src/main.py:13
msgid "Bonjour le monde"
msgstr ""

#: src/main.py:14
msgid "C'est une phrase traduite"
msgstr ""

Tu peux déjà y mettre les adresses mail, il faut surtout remplacer CHARSET et ENCODING respectivement par UTF-8 et 8-bit.

On va générer le fichier pour chaque langue avec la commande suivante (à faire pour chaque langue, ici le français):

msginit -l fr -i locales/main.pot -o locales/fr/LC_MESSAGES/main.po

Il faut mettre en place dans chacun de ces nouveaux fichiers les traductions, une fois cela fait, il nous reste à créer le .mo qui sera utilisé par l’application :

cd locales/fr/LC_MESSAGES # ou fr est à remplacer en fonction des langues
msgfmt main.po -o main.mo

Maintenant, retournons au code Python, pour utiliser l’une ou l’autre traduction :

import gettext

en = gettext.translation('main', localedir='locales', languages=['en'])
en.install()
_ = en.gettext # en anglais
ngettext = en.ngettext

def print_some_strings():
        print(_("Bonjour le monde"))
        print(_("C'est une phrase traduite"))

if __name__ == '__main__':
        print_some_strings()

Une fois exécuté, le résultat sera les phrases traduites.

Mise à jour de la traduction

Pour mettre à jour la traduction, bien entendu sans perdre celles déjà faite, après avoir modifié le fichier main.py, Lance la commande :

pygettext -p locales -d main src/main.py
cd locales
msgmerge --update en/LC_MESSAGES/main.po main.pot

Mettre en place la traduction, puis regénérer le fichier .mo :

cd fr/LC_MESSAGES/ # à faire pour chaque langue
msgfmt main.po -o main.mo

Cas de la pluralisation

Nous pouvons prendre en compte la pluralisation dans la langue à traduire.

Nous allons continuer de prendre notre exemple, en y ajoutant une fonction pour illustrer ce cas :

import gettext

en = gettext.translation('main', localedir='locales', languages=['en'])
en.install()
_ = en.gettext # en anglais

def print_some_strings():
        print(_("Bonjour le monde"))
        print(_("C'est une phrase traduite"))
def print_some_plural_strings(num):
    message1 = ngettext('{0} homme', '{0} hommes', num)
    message2 = ngettext('Je possede {0} portable', 'Je possede {0} portables', num)

if __name__ == '__main__':
        print_some_plural_strings(1)
        print_some_plural_strings(5)

La commande pygettext ne fonctionne pas dans mon cas pour générer le template (.pot), utilise la commande suivante :

xgettext -L Python -o locales/main.pot src/main.py

Cela va générer le nouveau template :

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-05-08 10:26+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#: src/main.py:9
msgid "Bonjour le monde"
msgstr ""

#: src/main.py:10
msgid "C'est une phrase traduite"
msgstr ""

#: src/main.py:12
#, python-brace-format
msgid "{0} homme"
msgid_plural "{0} hommes"
msgstr[0] ""
msgstr[1] ""

#: src/main.py:13
#, python-brace-format
msgid "Je possede {0} portable"
msgid_plural "Je possede {0} portables"
msgstr[0] ""
msgstr[1] ""

Nous allons fusionner ce nouveau template pour obtenir notre nouveau fichier .po pour chaque langue :

# Si besoin se mettre dans locales avec cd locales
msgmerge --update fr/LC_MESSAGES/main.po main.pot # remplacer fr par sa langue

Une fois cela fait, tu peux traduire les fichiers pour chaque langue.

Pour finir, nous mettrons à jour les fichiers .mo :

# faire en fonction de la langue
cd locales/fr/LC_MESSAGES
msgfmt main.po -o main.mo

Une fois cela fait, en lançant le script, tu devrais obtenir :

Si il y a une erreur dans le fichier .po de langue qui s’affiche, le terminal indiquera une erreur dans le script main.py sans préciser que l’erreur vient de l’autre fichier.

Conclusion

Bien que cela peut paraître fastidieux, il est simple de mettre en place une appli multilingue en python grâce à la librairie gettext. Celle-ci est également disponible dans d’autres langage.

Quitter la version mobile