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 :
- importer le module
- identifier les parties à traduire
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 :
- « .pot » est le patron de la traduction, c’est un fichier sans traduction dans lequel sont listés les éléments à traduire
- « .po » est le fichier de traduction dans lequel nous mettrons les traductions
- « .mo » est la transcription du fichier précédent mais compréhensible par l’application python
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.