Skip to content

Instantly share code, notes, and snippets.

@olberger
Created April 6, 2020 17:47
Show Gist options
  • Save olberger/684ef625048f2af5b91e859c86608ad5 to your computer and use it in GitHub Desktop.
Save olberger/684ef625048f2af5b91e859c86608ad5 to your computer and use it in GitHub Desktop.
Quick & dirty Python 3 i18n (with babel) MVP

Quick & dirty Python 3 i18n (with babel) MVP

Install Python 3 + i18n + gettext + babel

We’ll use the pybabel-python3 utility to manage GNU Gettext compatible catalog files. On my Debian, it is in /usr/bin/pybabel-python3 :

dpkg -L python3-babel
/.
/usr
/usr/bin
/usr/bin/pybabel-python3
/usr/lib
/usr/lib/python3
/usr/lib/python3/dist-packages
/usr/lib/python3/dist-packages/Babel-2.8.0.egg-info
/usr/lib/python3/dist-packages/Babel-2.8.0.egg-info/PKG-INFO
/usr/lib/python3/dist-packages/Babel-2.8.0.egg-info/dependency_links.txt
/usr/lib/python3/dist-packages/Babel-2.8.0.egg-info/entry_points.txt
/usr/lib/python3/dist-packages/Babel-2.8.0.egg-info/not-zip-safe
/usr/lib/python3/dist-packages/Babel-2.8.0.egg-info/requires.txt
/usr/lib/python3/dist-packages/Babel-2.8.0.egg-info/top_level.txt
/usr/lib/python3/dist-packages/babel
/usr/lib/python3/dist-packages/babel/__init__.py
/usr/lib/python3/dist-packages/babel/_compat.py
/usr/lib/python3/dist-packages/babel/core.py
/usr/lib/python3/dist-packages/babel/dates.py
/usr/lib/python3/dist-packages/babel/languages.py
/usr/lib/python3/dist-packages/babel/lists.py
/usr/lib/python3/dist-packages/babel/localedata.py
/usr/lib/python3/dist-packages/babel/localtime
/usr/lib/python3/dist-packages/babel/localtime/__init__.py
/usr/lib/python3/dist-packages/babel/localtime/_unix.py
/usr/lib/python3/dist-packages/babel/localtime/_win32.py
/usr/lib/python3/dist-packages/babel/messages
/usr/lib/python3/dist-packages/babel/messages/__init__.py
/usr/lib/python3/dist-packages/babel/messages/catalog.py
/usr/lib/python3/dist-packages/babel/messages/checkers.py
/usr/lib/python3/dist-packages/babel/messages/extract.py
/usr/lib/python3/dist-packages/babel/messages/frontend.py
/usr/lib/python3/dist-packages/babel/messages/jslexer.py
/usr/lib/python3/dist-packages/babel/messages/mofile.py
/usr/lib/python3/dist-packages/babel/messages/plurals.py
/usr/lib/python3/dist-packages/babel/messages/pofile.py
/usr/lib/python3/dist-packages/babel/numbers.py
/usr/lib/python3/dist-packages/babel/plural.py
/usr/lib/python3/dist-packages/babel/support.py
/usr/lib/python3/dist-packages/babel/units.py
/usr/lib/python3/dist-packages/babel/util.py
/usr/share
/usr/share/doc
/usr/share/doc/python3-babel
/usr/share/doc/python3-babel/AUTHORS
/usr/share/doc/python3-babel/changelog.Debian.gz
/usr/share/doc/python3-babel/changelog.gz
/usr/share/doc/python3-babel/copyright
/usr/lib/python3/dist-packages/babel/global.dat
/usr/lib/python3/dist-packages/babel/locale-data

MVP Python source file

The following Python source includes translatable strings using _( ) convention, and produces the expected output when run :

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import gettext

_ = gettext.gettext

def print_some_strings():
    print(_("Hello world"))
    print(_("This is a translatable string"))
 
if __name__=='__main__':
    print_some_strings()
Hello world
This is a translatable string

Creating translatable catalog files

Extracting strings from the source

produces :

# Translations template for PROJECT.
# Copyright (C) 2020 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-04-06 19:18+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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.8.0\n"

#: mvp.py:22
msgid "Hello world"
msgstr ""

#: mvp.py:23
msgid "This is a translatable string"
msgstr ""

Creating the catalog hierarchy

locale
locale/fr
locale/fr/LC_MESSAGES
locale/en
locale/en/LC_MESSAGES

Initializing .po translation files

cp mvp.pot locale/en/LC_MESSAGES/mvp.po
cp mvp.pot locale/fr/LC_MESSAGES/mvp.po

Translating

Translating the .po files

The french translation in locale/fr/LC_MESSAGES/mvp.po may be replaced by

# Translations template for PROJECT.
# Copyright (C) 2020 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-04-06 19:18+0200\n"
"PO-Revision-Date: 2020-04-06 19:26+0200\n"
"Last-Translator: Olivier Berger <olivier.berger@telecom-sudparis.eu>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.8.0\n"

#: mvp.py:22
msgid "Hello world"
msgstr "Bonjour tout le monde"

#: mvp.py:23
msgid "This is a translatable string"
msgstr "Cette chaîne peut être traduite"

Generating the .mo files

pybabel-python3 compile -D mvp -l fr -d locale 2>&1
compiling catalog locale/fr/LC_MESSAGES/mvp.po to locale/fr/LC_MESSAGES/mvp.mo

Testing

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import gettext

#_ = gettext.gettext
fr = gettext.translation('mvp', localedir='locale', languages=['fr'])
fr.install()
_ = fr.gettext

def print_some_strings():
    print(_("Hello world"))
    print(_("This is a translatable string"))

if __name__=='__main__':
    print_some_strings()
Bonjour tout le monde
Cette chaîne peut être traduite
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment