Because the replacement of the GPG wrapper is taking longer than I have expected, I have done something that will surely make
GnomeKeysign one step closer to become
GNOME ready - I have added support for
Internationalization and Localization.
I had no knowledge about this so I started reading this
tutorial which is more customized for C projects that use autotools.
GnomeKeysign is a Python pure project and it uses distutils/setuptools for building and installing.
I will explain step by step how to add support for translations in a Python application but first I will talk a little about
building & packaging in Python.
"Real artists ship. Or so says Steve Jobs." (taken from www.diveintopython3.net)
It seemed reasonable that Python should have a packaging framework , hence
distutils.
Distutils is many things: a build tool (for you), an installation tool (for your users), a package metadata format (for search engines), and more. It integrates with the
Python Package Index (“PyPI”), a central repository for open source Python libraries.
A good project layout could be the following
top
| -- package
| | -- __init__.py
| | -- module.py
| `-- subpackage
| | -- __init__.py
| | -- submodule.py
| -- runner
| -- MANIFEST.in
| -- README
| -- [setup.cfg]
| -- setup.py
If you want to know more about what every file does then check the
Python Packaging User Guide .
Already having a good project structure , I could easily add support for internationalization (i18n).
To add i18n support we need to accomplish these tasks:
- Configure the function that translates the strings
- Mark the strings in the code with that function
- Generate a template for the translators (the .pot file)
- Add translations
- Include the translations in the installation
Configure the '_()' macro
The Python
gettext module allows you to mark strings in source code, extract those strings for translation, and use the translated strings in your application. It is a common practice to define macros which are shorter wrappers, like the '_()' macro that replaces a gettext() call
import gettext
t = gettext.translation("gnome-keysign", PATH_TO_MO_FILES)
_ = t.ugettext
Mark strings for i18n
Search the source code files for strings that are visible in the GUI (window title, labels, button labels, messages, and so on) and wrap them inside '_()' function
print _("Getting ready for i18n.")
Generate template for translators
Using a command line tool, you generate a ".pot" file from the source code. This file contains all strings that need translation in the project. We only need to generate it once or after the strings change in the code. The file is generated inside /po folder and the command used is
xgettext --language=Python --keyword=_ --output=po/gnome-keysign.pot `find . -name "*.py"`
Add translations
Then, from the ".pot" file , using another command line tool we will generate the ".po" files for each language. These are the files that translators need to complete. Inside the po/ folder we use this command
msginit --input=PROJECTNAME.pot --locale=LOCALE
But once the program is running, it doesn't use .po files directly, but a binary (compiled) version of them: the .mo files. These .mo files must be re-created on build time (when creating the package) and installed in the right location in the system.
Include translations into the project installation
The setup.py file is where various aspects of the project are configured. Alongside with the general
setup arguments there is a `cmdclass` argument where we put the code to perform custom actions such as code generation, running tests, building translation files, etc.
I implemented a custom command derived from distutils.cmd.Command which will generate the '.mo' files in build time and in install time will include the '.mo' files into the data_files list. In this way we include the translations by overloading the default 'build' and 'install' instructions.
Now I can translate GnomeKeysign and run it in my
language :-).
That's all for now, I will be posting again after I'm done with the GPG replacement part.
~Andrei