Internationalization (i18n)

The code, templates and JavaScript user visible strings must all be wrapped with gettext functions to be substituted at runtime with the equivalent localized string. These function names are used as markers to collect the strings to be translated and store them into the securedrop/translations/messages.pot file. For each language to be translated, a directory is created such as securedrop/translations/fr_FR and populated with files derived from securedrop/translations/messages.pot, for translators to work with and for the gettext substitution at runtime.

The desktop icon are in the install_files/ansible-base/roles/tails-config/templates directory. Their labels are collected in the desktop.pot file and translated in the corresponding .po files in the same directory (fr.po, de.po etc.)

The manage.py translate helper

The pybabel and gettext command line is wrapped into the manage.py translate-messages and manage.py translate-desktop helpers for convenience. It is designed to be used by developers, to run tests with fixtures and for packaging.

Creating new translations

For the applications, a user with weblate admin rights must visit the Weblate translation creation page and add the desired languages.

For the desktop, the translations must be suspended in Weblate to avoid conflicts.

Weblate commit Lock

  • Click Lock

Weblate commit Locked

Now new files must be created and pushed to weblate with:

$ git clone -b i18n http://lab.securedrop.club/bot/securedrop
$ cd securedrop/install_files/ansible-base/roles/tails-config/templates
$ msginit --no-translator --locale ar --output ar.po --input desktop.pot
$ git add ar.po
$ git commit -m 'i18n: add ar.po' ar.po
$ git push

Where ar is the name of the locale, exactly matching the name of the corresponding application translation.

After pushing the new translation, make sure to unlock the translations.

The list of supported languages in the SecureDrop installation documentation must be updated.

Updating strings to be translated

After modifying a string in the code, templates, JavaScript or desktop labels, the securedrop/translations/messages.pot files must be updated by running the following command in /vagrant/securedrop, in the development virtual machine:

make translate

which wraps manage.py translate-messages and manage.py translate-desktop. The updated securedrop/translations/messages.pot and install_files/ansible-base/roles/tails-config/templates/desktop.pot should then be reviewed and commited. Once merged in develop, the changes will be visible in the Weblate web interface used by translators because it watches the develop branch of the SecureDrop repository.

Compiling translations

gettext needs a compiled file for each language (the *.mo files). This can be done by running the following command in /vagrant/securedrop, in the development virtual machine:

./manage.py --verbose translate-messages --compile

For desktop files the compilation phases creates a modified version of the original file which includes all the translations collected from the .po files.

This can be done by running the following command in /vagrant/securedrop, in the development virtual machine:

./manage.py --verbose translate-desktop --compile

Verifying translations

After a translation is compiled, the web page in which it shows can be verified visually by navigating to the corresponding state from http://localhost:8080 for the source interface or http://localhost:8081 for the journalist interface after running the following:

./manage.py run

An easier way is to generate screenshots for each desired language with:

$ export PAGE_LAYOUT_LOCALES=en_US,fr_FR
$ pytest -v --page-layout tests/pages-layout
...
...TestJournalistLayout::test_col_no_documents[en_US] PASSED
...TestJournalistLayout::test_col_no_documents[fr_FR] PASSED
...

Note

if unset, PAGE_LAYOUT_LOCALES defaults to en_US

The screenshots for fr_FR are available in securedrop/tests/pages-layout/screenshots/fr_FR and the name of the file can be found in the function that created it in securedrop/tests/pages-layout/test_journalist.py or securedrop/tests/pages-layout/test_source.py.

Merging translations back to develop

Weblate automatically pushes the translations done via the web interface as a series of commit to the i18n branch in the Weblate SecureDrop branch which is a fork of the develop branch of the SecureDrop git repository. These translations need to be submitted to the develop branch via pull requests for merge on a regular basis.

$ git clone https://github.com/freedomofpress/securedrop
$ cd securedrop
$ git remote add lab http://lab.securedrop.club/bot/securedrop/tree/i18n
$ git fetch lab
$ git checkout -b wip-i18n origin/develop
$ git checkout lab/i18n -- securedrop/translations
$ sm="nl fr_FR de_DE nb_NO pt_BR es_ES zh_Hant tr it_IT ar"
$ sd="nl fr de_DE nb_NO pt_BR es_ES zh_Hant tr it ar"
$ for l in $sm ; do \
     git add securedrop/translations/$l/LC_MESSAGES/messages.po ; \
  done
$ for l in $sd ; do \
     git checkout lab/i18n -- \
         install_files/ansible-base/roles/tails-config/templates/$l.po ; \
     git add install_files/ansible-base/roles/tails-config/templates/$l.po ; \
  done
$ vagrant ssh development
$ cd /vagrant/securedrop ; ./manage.py --verbose translate-desktop --compile
$ git commit -m 'sync with weblate' translations
$ git push wip-i18n

List contributors for each supported language:

$ for l in $sm ; do echo -n "$l " ; git log --format=%aN lab/i18n -- install_files/ansible-base/roles/tails-config/templates/$l.po securedrop/translations/$l/LC_MESSAGES/messages.po | sort -u | tr '\n' ',' | sed -e 's/,/, /g' ; echo ; done
nl Anne M, kwadronaut, Yarno Ritzen,
fr Alain-Olivier,
...

Verify the translations are not broken:

$ vagrant ssh development
$ cd /vagrant/securedrop
$ PAGE_LAYOUT_LOCALES=$(echo $sm | tr ' ' ',') \
    pytest -v --page-layout tests/pages-layout

Go to https://github.com/freedomofpress/securedrop and propose a pull request.

Note

contrary to the applications translations, the desktop translations are compiled and merged into the repository. They need to be available in their translated form when securedrop-admin tailsconfig is run because the development environment is not available.

Merging develop into the weblate fork

Weblate works on a long standing fork of the SecureDrop git repository and is exclusively responsible for the content of the *.pot and *.po files. It needs to merge the content of the develop branch back into its i18n branch to be able to extract from the sources new strings to translate or existing strings that have been updated.

The translations must be suspended in Weblate to avoid conflicts.

Weblate commit Lock

  • Click Lock

Weblate commit Locked

The develop branch can now be merged into i18n as follows:

$ git clone https://github.com/freedomofpress/securedrop
$ cd securedrop
$ git remote add lab http://lab.securedrop.club/bot/securedrop/tree/i18n
$ git fetch lab
$ git checkout -b i18n lab/i18n
$ git merge origin/develop
$ make translate

The manage.py command examines all the source files, looking for strings that need to be translated (i.e. gettext(‘translate me’) etc.) and update the files used by Weblate, removing, updating and inserting strings to keep them in sync withe the sources. Carefully review the output of git diff. Check messages.pot first for updated strings, looking for formatting problems. Then review the messages.po of one existing translation, with a focus on fuzzy translations. There is no need to review other translations because they are processed in the same way. When you are satisfied with the result, it can be merged with:

$ git commit -a -m 'l10n: sync with upstream origin/develop'
$ git push lab i18n
  • Go to the Weblate commit page for SecureDrop and verify the commit hash matches the last commit of the i18n branch. This must happen instantly after the branch is pushed because Weblate is notified by GitLab via a webhook. If it is different, ask for help.

Weblate commit Unlock

Weblate pushes the translations done via the web interface to the develop branch in a fork of the SecureDrop git repository. These commits must be manually cherry-picked and proposed as pull requests for the SecureDrop git repository.

Weblate commit Unlocked

Updating the full text index

The full text index can occasionally not be up to date. The symptom may be that the search function fails to find a word that you know exists in the source strings. If that happens you can rebuild the index from scratch with:

$ ssh [email protected]
$ cd /app/weblate
$ sudo docker-compose run weblate rebuild_index --all --clean

Note that the new index will not be used right away, some workers may still have the old index open. Rebooting the machine is an option, waiting for a few hours is another option.

Translator credits

Verify the names and emails look ok, otherwise add to .mailmap until it does:

$ git clone https://github.com/freedomofpress/securedrop
$ cd securedrop
$ git remote add lab http://lab.securedrop.club/bot/securedrop/tree/i18n
$ git fetch lab
$ previous_version=0.4.4
$ git log --pretty='%aN <%aE>' $previous_version..lab/i18n -- \
   securedrop/translations install_files/ansible-base/roles/tails-config/templates | sort -u

We do not want to publish the translator emails so we strip them:

git log --pretty='%aN' $previous_version..lab/i18n -- \
 securedrop/translations install_files/ansible-base/roles/tails-config/templates | sort -u