
Cockpit Internationalization
============================

All human-visible strings on Cockpit's web pages should be translatable. This
document describes the entire internationalization process, which uses [GNU gettext](https://www.gnu.org/software/gettext/) and related tools as much as possible.

Marking strings
---------------
Strings that are visible to humans and which should be translated must be
marked as such on Cockpit pages, in one of two ways:

 * If the string appears in a HTML source, it must be enclosed in a tag with
   the `translate="yes"` attribute. Example:

   ```html
   <span translate="yes">Image</span>
   ```

 * If the string appears in JavaScript source, it must use the
   [cockpit.gettext()](https://cockpit-project.org/guide/latest/cockpit-locale.html#cockpit-locale-gettext)
   or a related function, commonly called through an alias `_()`, with double-quoted
   strings so that `xgettext` can recognize it. Example:

   ```js
   const _ = cockpit.gettext;

   var translated = _("Time");

   // in a JSX block:
   <tr>
     <th>{ _("Image") }</th>
   </tr>
   ```
   For strings that involve numbers you need to use
   [cockpit.ngettext()](https://cockpit-project.org/guide/latest/cockpit-locale.html#cockpit-locale-ngettext)
   instead:

   ```js
   var translated = cockpit.ngettext("This thing", "The things", numberOfThings);
   ```

   The [cockpit.format()](https://cockpit-project.org/guide/latest/cockpit-util.html#cockpit-format)
   function is useful for parameterized strings where the order of parameters
   might change between languages.

Translation process
-------------------

 * Translatable strings from HTML, JavaScript (as above) and C files get
   extracted with various invocations of
   [xgettext](https://linux.die.net/man/1/xgettext), see
   [po/Makefile.am](https://github.com/cockpit-project/cockpit/blob/main/po/Makefile.am).
   Running `make po/cockpit.pot` will generate a standard PO template.

 * With `make upload-pot` the PO template gets uploaded to the
   [Weblate translation platform](https://translate.stg.fedoraproject.org/projects/cockpit/)
   where everybody can contribute translations to various languages.

 *  With `make download-po` Weblate's translations are downloaded to
    `po/XX.po`. This is done by
   [bots/po-refresh](https://github.com/cockpit-project/cockpit/blob/main/bots/po-refresh)
   which is invoked regularly by
   [bots/po-trigger](https://github.com/cockpit-project/cockpit/blob/main/bots/po-trigger).

 * Translations can also be done using any other tool or platform and be
   submitted via pull requests that update the `po/XX.po` files. In this case
   they should then also be uploaded to Weblate either manually using Weblate UI
   or by pushing these files into [cockpit-weblate](https://github.com/cockpit-project/cockpit-weblate)
   repository.

Using translations at runtime
-----------------------------
HTML and JavaScript don't directly support gettext po and mo files. The
translations from po files are converted to a JavaScript function by
[cockpit-po-plugin](../pkg/lib/cockpit-po-plugin.js)
which inserts the actual translations into a
[cockpit.locale()](https://cockpit-project.org/guide/latest/cockpit-locale.html#cockpit-locale-locale) call.
The resulting files are written to `dist/<page>/po.XX.js` from where they
can be imported by the page and used by `cockpit.gettext()`.

HTML pages which use `translate="yes"` tags need to call
[cockpit.translate()](https://cockpit-project.org/guide/latest/cockpit-locale.html#cockpit-locale-translate) which will iterate over all such tags and replace their content with the result of calling `cockpit.gettext()` on their original content.

Opening a new branch
--------------------
Occasionally we create a new upstream branch for e. g. a new stable RHEL
release. Run these steps to initialize translations for it:

 * In [cockpit-weblate](https://github.com/cockpit-project/cockpit-weblate) create a new branch
   with the same name.
   Upload there `cockpit.pot` that you generated from the new upstream branch with `make po/cockpit.pot`.
   If you have also `.po` files, you can also add them into this branch.

 * On the [Weblate Cockpit project page](https://translate.stg.fedoraproject.org/projects/cockpit/),
   click the "Add new translation component" button and create a new component. Give it a name
   that matches the new branch. Point it to [cockpit-weblate](https://github.com/cockpit-project/cockpit-weblate)
   repository to a branch you created in the previous step.

 * On the new cockpit branch, change `WEBLATE_REPO_BRANCH` in
   [po/Makefile.am](https://github.com/cockpit-project/cockpit/blob/main/po/Makefile.am)
   from "main" to the new branch name.
