Getting Started¶
Modern Python packaging¶
You might be familiar with requirements.txt or setup.py for describing your project dependencies. Since then, a lot has changed in the Python world. At some point, we had multiple tools like poetry, pipenv, dephell, flit, and so on, each with its own file format. Luckily, now everyone is settled on a singe universal approach. There are the standards that set the ground:
PEP 517 introduced
pyproject.toml
as a single configuration file for all Python tools.PEP 518 intorduced a
[build-system]
section inpyproject.toml
that says what tool should be used to buid your project.PEP 621 intorduced a
[project]
section inpyproject.toml
that described all project metadata, like name, version, authors, dependencies.
You don’t have to use all this to work with l10n but if you do, l10n will be better at finding your project metadata. In this section, we will use the modern packaging approach for all examples.
Installation¶
Let’s start a new project:
mkdir l10n-playground
cd l10n-playground
Now, let’s create a pyproject.toml
with your project metadata and add l10n
into dependencies. In this example, we will use flit for dependency management.
Add into pyproject.toml
:
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "l10n_playground"
dynamic = ["version", "description"]
requires-python = ">=3.7"
dependencies = ["l10n"]
[project.optional-dependencies]
dev = ["l10n[cli]"]
And into l10n_playground/__init__.py
:
"""Experimenting with l10n"""
__version__ = "1.0.0"
Now, you can install your project:
python3 -m pip install -U flit
flit install --deps=develop --symlink
The environment is ready! It’s time to write some code.
Writing code¶
In l10n, your code is the single source of truth, and translation files are generated from it. So you always start from writing code, and translations go later.
The class Locales
provides a runtime catalog of translation for different languages. Create an instance of it (usually, no need to pass any arguments, defaults are good) and use it as mapping where keys are language codes. Sounds vague so far, so let’s get our hands dirty.
Create l10n_playground/example.py
:
from argparse import ArgumentParser
from l10n import Locales
locales = Locales()
def say_hello(lang: str = 'en') -> None:
loc = locales[lang]
msg = loc.get('Hello, world!')
print(msg)
def main() -> None:
parser = ArgumentParser()
parser.add_argument('--lang', default='en')
args = parser.parse_args()
say_hello(lang=args.lang)
And l10n_playground/__main__.py
:
from .example import main
main()
If you try to run it, it will fail with KeyError
because there is no en
language in the catalogue. So, it’s time to make some.
Extracting messages¶
Now, let’s generate translation files from our code for English and Russian:
python3 -m l10n extract --lang=en
python3 -m l10n extract --lang=ru
These commands will create locales/en.po
and locales/ru.po
respectively. PO file format is a standard text format for translations introduced in GNU (Linux) and used in many places. it’s kind of a de facto standard for translations, so it’s supported by most of the tools. But since it’s a text format, you can open it in any text editor, it’s very readable. Inside, you’ll see some headers (feel free to edit them) and the text message to be translated extracted from your code. Now, it’s time to translate.
Translating messages¶
At this point, we have a file to store translations. The file contains the messages from our code (currently, only "Hello, world!"
) but no actual translation. Usually, this is where you send the file to a translator and forget about it while they are doing their job. But if you don’t have a translator just yet, don’t worry, we’ve got you covered.
English you can translate yourself, just edi en.po
file in any text editor:
#: ./l10n_playground/example.py:9
msgid "Hello, world!"
msgstr "Hello, world!"
And for Russian, we’ll use l10n translate
command which will automatically translate all messages using Google Translate unofficial API:
python3 -m l10n translate
And this is what you now sohuld see in ru.po
:
#: ./l10n_playground/example.py:9
#, fuzzy
msgid "Hello, world!"
msgstr "Привет, мир!"
Now, it’s time to get it back into your app.
Compiling messages¶
PO file format is a readable text format for humans. For machines, we need mo files which are binary and optimized for machines. The po files are used by you and translators during the app development, mo files are used by your app (or library) to get translations for messages in runtime. So, before we can run the app, we need to compile mo files:
python3 -m l10n compile
The command will create en.mo
and ru.mo
binary files inside of l10n_playground/locales/
.
Running the app¶
Now, it’s time to run the app!
$ python3 -m l10n_playground
Hello, world!
$ python3 -m l10n_playground --lang=ru
Привет, мир!
It works!
Updating messages¶
When you update a message or add a new one:
Run
l10n extract
to update po files. No need to specify--lang
, by default it will just update all po files you already have.Run
l10n translate
if you want it to be auto-translated (or translate it manually).Run
l10n compile
to generate mo files.
Cheat sheet¶
po file is a text file with translations.
mo file is a binary file compiled out of mo files.
l10n.Locales
is a mapping of locales (mo files) with language codes as keys.l10n extract --lang=nl
to generate po file fornl
langauge.l10n extract
to update all po files you have.l10n translate
to run Google Translate on all po files you have.l10n compile
to generate mo files from po files.
See also the advanced usage to get more out of l10n.