Skip to content

Internationalization

Cory Francis Myers edited this page Jan 28, 2022 · 11 revisions

Translators: Please consult the "Translations" page of the SecureDrop documentation for specific instructions. This page gives a technical overview of how the SecureDrop Client is internationalized, localized, and translated.


Read the following workflow diagram from the bottom-right corner up, in order of the numbered steps. Dashed lines indicate manual actions. Solid lines indicate automated actions.

Flowchart of the SecureDrop Client translation workflow.

Tutorial for developers

Let's say you've made the following string change in the Client's Python source code:

$ git diff
diff --git a/securedrop_client/app.py b/securedrop_client/app.py
index 6b95eda..13ee15d 100644
--- a/securedrop_client/app.py
+++ b/securedrop_client/app.py
@@ -175,7 +175,7 @@ def prevent_second_instance(app: QApplication, unique_name: str) -> None:
         if e.errno == ALREADY_BOUND_ERRNO:
             err_dialog = QMessageBox()
             err_dialog.setText(
-                _("{application_name} is already running").format(
+                _("{application_name} is already running!").format(
                     application_name=app.applicationName()
                 )
             )

When you go to commit, you'll receive the following error:

$ git commit --all --message "changes a string"
[...]
writing PO template file to securedrop_client/locale/messages.pot
Translation catalog is out of date. Please run "make extract-strings" and commit the changes.
make: *** [check-strings] Error 1

NB. If you don't receive this error above locally, run make hooks. (Otherwise, you will receive this error when your branch fails linting in CI.)

As prompted, run make extract-strings and try again:

$ make extract-strings
[...]
writing PO template file to securedrop_client/locale/messages.pot
$ git diff
diff --git a/securedrop_client/app.py b/securedrop_client/app.py
index 6b95eda..13ee15d 100644
--- a/securedrop_client/app.py
+++ b/securedrop_client/app.py
@@ -175,7 +175,7 @@ def prevent_second_instance(app: QApplication, unique_name: str) -> None:
         if e.errno == ALREADY_BOUND_ERRNO:
             err_dialog = QMessageBox()
             err_dialog.setText(
-                _("{application_name} is already running").format(
+                _("{application_name} is already running!").format(
                     application_name=app.applicationName()
                 )
             )
diff --git a/securedrop_client/locale/messages.pot b/securedrop_client/locale/messages.pot
index 51c95cc..524cdde 100644
--- a/securedrop_client/locale/messages.pot
+++ b/securedrop_client/locale/messages.pot
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: Babel 2.9.1\n"
 
-msgid "{application_name} is already running"
+msgid "{application_name} is already running!"
 msgstr ""
 
 msgid "The SecureDrop server cannot be reached. Trying to reconnect..."
$ git commit --all --message "changes a string"
[i18n 3637b3d] changes a string
 2 files changed, 2 insertions(+), 2 deletions(-)

This check is also performed during linting in CI. When you open a pull request for your branch, a maintainer will review your string changes for their translation impact.

Overview

The SecureDrop Client is piloting a continuous translation workflow that differs from that of the SecureDrop Server:

Step SecureDrop SecureDrop Client
1. Extract strings from .py source code → .pot catalog template manual via i18n_tool.py during release make extract-strings (enforced by pre-commit hook and CI)
2. Merge .pot catalog template → .po catalogs manual via i18n_tool.py during release Weblate add-on
3. Compile .po catalogs → .mo machine objects builder playbook via i18n_tool.py during release (dev-deps during development) Weblate add-on

In this workflow, each party's localization responsibilities are simplified:

  1. Developers must use make extract-strings to keep the catalog template up to date with changes they've made to UI strings in the Python source code. Developers are encouraged to commit make extract-strings changes along with the source-code changes that caused them, for a cleaner Git history to review and (if necessary) blame and revert.

    • CI will enforce this requirement via make check-strings on branches pushed to this repository. Like the other linters, this check must pass for a pull request to be approved for merge into main.

    • Developers can run make check-strings locally or have it run automatically on every commit by running make hooks. (make hooks is included in make venv and make venv-mac as of #1348.)

  2. Maintainers should keep in mind that pull requests they review will include changes to the catalog template for any strings changed in the source code. They should consider the impact and timing of these changes on translators---just as they consider the impact and timing of code changes on other developers---as part of their review of a pull request prior to approving it for merge into main and thereby into Weblate.

  3. Translators can always see the latest strings available to translate in Weblate. They can translate new and changed strings continuously, as development progresses, and they can give feedback on strings well in advance of the release period.

  4. Release and localization managers do not need to do anything special outside of preflight testing! As summarized above, developers are responsible for keeping strings up to date; Weblate is responsible for keeping the per-language editable .po catalogs and loadable .mo machine objects up to date.

  5. The Client at startup attempts to load the .mo machine object corresponding to the value of $LANG in the environment and, if successful, displays those strings in the GUI. If $LANG is unset, or if there is no corresponding .mo machine object providing a translation, the application falls back to the English source strings.

    Note that this implementation is much simpler than that of the SecureDrop Server. As a Web application, the Server must (a) let each user change their preferred language across requests but (b) persist that preference during a session. By contrast, the SecureDrop Client need only load and use the translation specified in $LANG.

Clone this wiki locally