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 translate helper

The pybabel command line is wrapped into the translate helper for convenience. It is designed to be used by developers, to run tests with fixtures and during packaging.

Updating strings to be translated

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

./ --verbose translate --extract-update

The updated securedrop/translations/messages.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:

./ --verbose translate --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:

./ run

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

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


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/ or securedrop/tests/pages-layout/

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
$ cd securedrop
$ git remote add lab
$ git fetch lab
$ git checkout -b wip-i18n origin/develop
$ git checkout lab/i18n -- securedrop/translations
$ git add translations
$ git commit -m 'sync with weblate' translations
$ git push wip-i18n

Go to and propose a pull request.

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
$ cd securedrop
$ git remote add lab
$ git fetch lab
$ git checkout -b i18n lab/i18n
$ git merge origin/develop
$ ./ translate --extract-update

The 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

  • Click Unlock

Weblate commit Unlocked