Translating OpenREM strings

OpenREM’s primary language is British English (en_GB). Users and developers with knowledge of other languages can create translations of the interface strings, export file strings and the documentation. These will then be exposed when the web browser language is set to match the new translation language (OpenREM interface) or when the language is selected for the documentation.

A web-based service for managing translations has kindly been provided to OpenREM by Weblate. Their hosting is free to OpenREM, and they welcome donations.

Translators

  • Create an account at https://hosted.weblate.org

  • The OpenREM project is at https://hosted.weblate.org/projects/openrem/

  • Each page in the Read The Docs documentation (https://docs.openrem.org) is a separate ‘component’ in Weblate, and they have been named ‘RTD document name’. The web interface strings are all in one ‘component’.

  • Choose a component, and on the next page you can select one of the existing translations which you can review, edit and propose new translation strings.

  • Once approved, they will be merged in by developers

Creating new language translations

At the component level, you will see an option to create a new translation. This might need to be done for each component individually.

Code syntax in strings

Be careful not to edit code syntax within strings. For example, Python code might be:

Writing study {row} of {numrows} to All data sheet and individual protocol sheets

This is translated into Norwegian Bokmål as:

Skriver studie av {row} av {numrows} til alle datablad og individuelle protokollblader

Notice that the {} and their contents is unchanged - but may be moved around within the sentence to produce the correct grammar for the language being used.

Similarly with Django HTML template strings:

Number in last %(day_delta)s days

becomes:

Antall de siste %(day_delta)s dagene

It is essential that the %()s as well as the string inside the brackets stay intact.

For the RTD translations, there will be Sphinx codes that should be left untranslated, for example:

:ref:`genindex`

Developers

Install pre-requisites

gettext

Linux: sudo apt install gettext or equivalent for your distribution. For Windows: download a precompiled binary installer

sphinx-intl

Activate development environment - see Creating a development environment for details - and add the sphinx packages:

$ pip install sphinx
$ pip install sphinx-intl
$ pip install sphinx-argparse
$ pip install sphinx_issues
$ pip install sphinx_copybutton

Update .pot and .po files

Activate the development environment and move to the root of the OpenREM repository - with the docs folder and openrem folder etc:

$ cd docs/
$ mkdir _static
$ sphinx-build -b gettext . _build/gettext/
$ sphinx-intl update -p _build/gettext/
$ cd ../openrem/
$ django-admin makemessages -a --keep-pot

Adding new interface strings for translation

Please refer to https://docs.djangoproject.com/en/2.2/topics/i18n/translation/ for instructions.

In brief, the following will help get you started, but does not cover lazy translations, plurals and many other things!

All the Sphinx/Read The Docs strings are translatable - if a page does not appear in Weblate that is because it has not been configured as a component there yet.

Python code

First, import gettext from Django:

from django.utils.translation import gettext as _

Then wrap strings to be translated with _() so

query.stage = "Checking to see if any response studies are already in the OpenREM database"

becomes

query.stage = _(
    "Checking to see if any response studies are already in the OpenREM database"
)

The same is done for strings that contain variables. Unfortunately gettext cannot work with f-strings so we are stuck with .format() instead. It is easier to understand how to translate the text though if we use named variables rather than position based ones, like this:

query.stage = _("Filter at {level} level on {filter_name} that {filter_type} {filter_list}".format(
    level=level, filter_name=filter_name, filter_type=filter_type, filter_list=filter_list
))

Remember we cannot assume the grammar of the translated string so try and pass the whole sentence or paragraph to be translated.

Template code

Add the following at the top of the template file, just after any extends code:

{% load i18n %}

This can be done with inline translations and block translations. For inline,

<th style="width:25%">System name</th>

becomes

<th style="width:25%">{% trans "System name" %}</th>

If there are variables, a block translation is required, for example:

{% if home_config.display_workload_stats %}
    <th style="width:12.5%">{% blocktrans with home_config.day_delta_a as day_delta trimmed %}
        Number in last {{ day_delta }} days{% endblocktrans %}</th>
    <th style="width:12.5%">{% blocktrans with home_config.day_delta_b as day_delta trimmed %}
        Number in last {{ day_delta }} days{% endblocktrans %}</th>
{% endif %}

Comments can be added to aid translators, for example:

{# Translators: Number of studies in DB listed above home-page table. No final full-stop in English due to a.m./p.m. #}
{% now "DATETIME_FORMAT" as current_time %}
{% blocktrans with total_studies=homedata.total trimmed%}
    There are {{ total_studies }} studies in this database. Page last refreshed on {{ current_time }}
{% endblocktrans %}

Making use of updated strings on local system

Specify the language to build for Sphinx docs, eg for German:

$ sphinx-build -b html -D language=de . _build/html/de

For Django strings:

$ django-admin compilemessages

Incorporating translations into main repo

In the git repository:

$ git remote add weblate https://hosted.weblate.org/git/openrem/web-interface/
  • Checkout the weblate\develop branch as a new local branch

  • Push the branch to Bitbucket

  • Create a pull request to develop