Skip to content

emlys/python-gettext-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 

Repository files navigation

python-gettext-demo

Minimal example of translating an application with python gettext, including packaging and language switching at runtime

Illustrates gettext with a simple command line application that repeatedly prompts you to enter a language code, then displays a message translated to your language. A sample language is provided. Entering the language code ll will display the "translated" message fσσ вαя вαz. Entering any other value will fall back to the default message foo bar baz.

Project structure:

python-gettext-demo/
|-- a/
|   |-- __init__.py              # installs languages
|   |-- b.py                     # module with translated strings
|   |-- c.py                     # module with translated strings
|   |-- interface.py             # entrypoint
|   |-- locales/                 # locale directory with structure that gettext expects
|       |-- ll/                  # translation data for language 'll'
|           |-- LC_MESSAGES      # gettext expects this directory to exist
|               |-- messages.po  # human-readable message catalog for language 'll'
|-- pyproject.toml               # tells pip to install babel before installing this package
|-- setup.py                     # includes message catalog in wheel distribution

packaging

gettext uses non-python files, so you need to specially include them in the packaged application.

wheel

$ git clone https://github.com/emlys/python-gettext-demo.git
$ cd python-gettext-demo
$ pip install .
$ demo_gettext
Enter your language: ll
foo bar baz in your language: fσσ вαя вαz
Enter your language: en
foo bar baz in your language: foo bar baz

pyinstaller executable

$ git clone https://github.com/emlys/python-gettext-demo.git
$ cd python-gettext-demo
$ pip install pyinstaller
$ pyinstaller \   # include compiled message catalog in executable bundle
    --add-data \  # you can also add this data with a hook or spec file
    a/locales/ll/LC_MESSAGES/messages.mo:a/locales/ll/LC_MESSAGES \
    a/interface.py
$ dist/interface/interface
Enter your language: ll
foo bar baz in your language: fσσ вαя вαz
Enter your language: en
foo bar baz in your language: foo bar baz

about language switching

The _(...) function translates strings. The definition of _ depends on which language is installed: calling gettext.install updates the definition of _. So to translate to a language, you need to be sure that every use of _ is evaluated after installing the desired language.

If a program only needs to execute in one language per run (such as a command line tool that takes a --language argument) it's easy enough to guarantee this. Translated strings might be defined in places that complicate the order of execution. Module-level strings are evaluated at import time. Class attributes are evaluated when an object is instantiated. There's lots of ways that a translated string can get evaluated before the right language is installed. For a single language, you can rearrange things to guarantee the right evaluation order.

Switching between multiple languages during execution (like in a server module, or a loop like in this example) is tricky because there's no getting around having to re-evaluate the translated strings. Some options are:

  • use importlib.reload to re-evaluate module-level variables
  • use lazy strings like this one from Flask-Babel
  • define strings within functions

None of the options are perfect and you have to design around the constraint of controlling when strings are evaluated. See this stackoverflow post for details.

About

Minimal example of translating an application with python gettext, including packaging and language switching at runtime

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages