Welcome | Get started | Dive into Lino | Contribute | Topics | Reference | More

Introduction to internationalization (i18n)

Lino uses Django, and Django uses the gettext system for providing internationalization.

Read the Django documentation about Internationalization

See also How to contribute translations

A translatable text is a text that we want to be displayed in the language of the end user.

>>> from lino import startup
>>> startup('lino_book.projects.min9.settings')
>>> from lino.api.shell import *

In your application code, you import Django's ugettext() function (usually aliased as _()) and call it on any string that you want the user to see in their language.

>>> from django.utils.translation import gettext as _

If no language is activated, ugettext() just returns the English text:

>>> print(_("January"))

In Lino we usually use the translation.override() context when we want to translate:

>>> from django.utils import translation
>>> with translation.override('fr'):
...     print(_("January"))

How does the ugettext() function know that "January" is "janvier" in French? See inv mm and How to contribute translations.

Note that ugettext() will do the lookup in-place. The following code prints English and not German:

>>> s = _("January")
>>> with translation.override('de'):
...     print(s)

But Django has a lazy version of ugettext(), which does the lookup only when it is really needed.

>>> from django.utils.translation import gettext_lazy as _
>>> s = _("January")
>>> with translation.override('de'):
...     print(str(s))

This is also the version you get when you say:

from lino.api import _

A lazy translation returned by ugettext_lazy() is actually not a string, it is rather an object that will be translated when needed.

>>> from django.utils.translation import gettext_lazy
>>> from django.utils.translation import gettext
>>> gettext("January").__class__
<class 'str'>
>>> gettext_lazy("January").__class__
<class 'django.utils.functional.lazy.<locals>.__proxy__'>

The format_lazy() function

Django has a function lazy_format(), which we sometimes use. Here is an example.

>>> from lino import startup
>>> startup('lino_book.projects.min2.settings.demo')
>>> from django.utils.text import format_lazy
>>> from lino.api import dd, rt, _
>>> M = rt.models.cal.Event
>>> s = format_lazy(
...   _("Only for {model} instances."),
...   model=M._meta.verbose_name)
>>> print(s)
Only for Calendar entry instances.
>>> with dd.translation.override('de'):
...     print(s)
Only for Kalendereintrag instances.

Note that we care only for the "Calendar entry" text. The surrounding text Only for {model} instances. is not translated to German because it is a fictive example of a translatable string for which there is no translation.

See also Django ticket #14174.