Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More

How to contribute translations

Here is how you can help translating Lino into your language.

We assume that you have installed a developer environment.

You also need to read Legal considerations for contributors before you can start contributing.

Basic knowledge

You are going to edit a series of .po files that are part of the Lino source code. Each Lino repository has its own series of .po files. Their place is given by the locale_dir setting in the tasks.py file (see Project configuration settings). Here are some examples:

If the .po files do not yet exist in your language, read Add support for a new language before going on.

If you are the first to provide translations to some source code that has new or changed translatable strings, you must run inv mm (“make message files”) in order to make sure that the .po files are in sync with the source code. The inv mm command never deletes any messages, so you can run it also when you aren’t sure whether it has run.

To edit these .po files you can use either your preferred text editor or a tool like Poedit. We recommend the latter.

Before you can use Poedit, you must install it:

$ sudo apt install poedit

Choose a site to work on

Go to some demo project or to some local site directory (e.g. the one you created in Install your Lino developer environment):

$ go first

Edit your project’s settings.py file so that it specifies a language distribution (in the languages setting) consisting of

  • English as first language

  • your language as the second language.

For example:

class Site(Site):
    languages = 'en es'
    # languages = 'es en'

In case you wonder: your language can’t be the first language because some demo fixtures would probably fail because babel fields require at least the site’s main language to be set.

Your settings.py file should look similar to this:

# -*- coding: UTF-8 -*-

from lino_book.projects.min9.settings import *


class Site(Site):
    title = "My Lino Mini site"
    languages = 'en es'


SITE = Site(globals())

Run prep to initialize the demo database:

$ pm prep

Run the development server:

$ runserver

Point your browser to view the site. Sign in as the user in your language.

../../_images/translate_1.png

The translatable strings on this page are for example the menu labels (“Contacts”, “Products” etc), or content texts like “Welcome”, “Hi, Rodrigo!” or “This is a Lino demo site.”

Find out where translatable strings are defined

Now you must find out which repository defines these strings. gettext stores these strings in .pot files. There is one .pot file per repository, and in Lino it is always named django.pot.

You can use your editor’s file search function, but you can also open a terminal window and use a combination of find and grep to find the file:

$ cd ~/lino/env/repositories  # root directory of your repositories

$ find -name '*.pot' | xargs grep Contacts
./xl/lino_xl/lib/xl/locale/django.pot:msgid "Client Contacts"
./xl/lino_xl/lib/xl/locale/django.pot:msgid "Contacts"
./welfare/userdocs/translations/contacts.pot:msgid "Contacts"
./welfare/lino_welfare/modlib/welfare/locale/django.pot:msgid "The list that opens by Contacts ‣ Clients."

$ find -name '*.pot' | xargs grep "This is a Lino demo site"
./lino/lino/locale/django.pot:msgid "This is a Lino demo site."

This tells us that the string “Contacts” is used in two directories: xl and welfare.

And the string “This is a Lino demo site” is contained in only one directory: lino.

Now you must know the following:

  • Each directory containing a file django.pot has also one subdirectory per supported language. Each of these subdirectories has a single subdirectory LC_MESSAGES, which contains a single file named django.po (without a “t”).

  • That’s the file you want to edit.

  • This directory structure is imposed by gettext.

Translate

So if your language is “es” and you want to edit the .po file of the xl repository, then you say:

$ poedit ./xl/lino_xl/lib/xl/locale/es/LC_MESSAGES/django.po

It looks similar to this screenshot:

../../_images/poedit_es_1.png

Translate a few messages.

Warning: Don’t try to translate all the messages at once! Because there are a lot of them, and because it’s more rewarding to start with the most visible ones and and watch the results of your work while you are advancing. Also because translations can depend on the context. It’s better that you see where a message is being used before you decide how to translate it.

In our example we translated the following message:

Hi, %(first_name)s!

into:

¡Hola, %(first_name)s!

Save your work in Poedit. Poedit will automatically compile the django.po file into a corresponding django.mo file.

Now you should first touch your settings.py file in order to tell runserver that something has changed. Open a third terminal window and type:

$ go first
$ touch settings.py

This will trigger the runserver process (which is running in the first terminal window) to reload and to rewrite any cache files.

Refresh your browser page:

../../_images/cosi_es_hola.png

Submit your work

When you are satisfied with your work, you must make a pull request to ask us to integrate your changes into the public Lino repositories. More about pull requests in Git cheat sheet.

Add support for a new language

Lino uses the same language codes as Django. You can see the list of available languages in django/conf/global_settings.py.

Every repository has a list of languages for which it provides translations. This list is in the languages parameter in the repository’s tasks.py file. If your language is not yet mentioned there, then add it.

After adding a language, you must run inv mm, which will create the new catalogue files.

And then you need to create a demo user for your language. Otherwise pm prep gives a warning:

No demo user for language 'bn'.

There are three ways to do it:

  • Do this manually by signing in as robin and changing the language field in robin’s user settings. You will have to do this again and again after each pm prep.

  • Edit the demo_users.py file in your local copy of the lino repository and add a fictive root user for your language.

    And don’t forget to include this change in your pull request (see Submit your work)

  • Create a local fixture that creates the user:

    $ mkdir fixtures
    $ touch fixtures/__init__.py
    $ nano fixtures/demo.py
    

The demo.py file should look as follows:

# This is needed only if Lino does not yet have a default site
# administrator for your language.

from django.conf import settings
from lino.modlib.users.choicelists import UserTypes


def objects():
    yield settings.SITE.user_model(username="roberto",
                                   language="es",
                                   first_name="Roberto",
                                   last_name="Spanish",
                                   email=settings.SITE.demo_email,
                                   user_type=UserTypes.admin)

Workarounds

Here is a pitfall. Imagine you want to translate the following string:

msgid "%(person)s has been unregistered from %(course)s"

Here is a translation that makes sense but is wrong:

msgstr "%(personne)s a été désinscrit du %(cours)"

Here is the correct translation:

msgstr "%(person)s a été désinscrit du %(course)s"

C.-à-d. les mots-clés entre parenthèses sont des variables, et il ne faut pas les modifier.

À noter également que le s derrière la parenthèse ne sera pas imprimé mais est obligatoire (il indique à Python qu’il s’agit d’un remplacement de type string).