Skip to main content

Contributing to Internationalization

This section introduces some concepts for contributing translations and is especially important when submitting a new language.

Important: If you add a new language, keep in mind that while all the specific Kubernetes components' names are translatable, not all of them will have a corresponding name in your language. Please refer to the Kubernetes localized docs in your language (if they exist) to understand which components should be translated and which should be left in their original form.

Namespaces

We have only two main i18next namespaces:

  • glossary: For Kubernetes jargon or terms/sentences that are very technical.
  • translation: Default namespace, used for everything else not in the glossary namespace.

We do have a third namespace that concerns only the desktop app related strings: app.

In Headlamp, namespaces are separated by a | character. E.g. t('glossary|Pod').

Context

In order to better express context for a translation, we use the i18next context feature. It is used like this:

return t("translation|Desired", { context: "pods" });

In the example above, we give the extra context of "pods" for the word "Desired". It refers to the concept of pod, and precisely more than one (in case the target language of the translation distinguishes between plural and singular for this word).

In the translated files, the context will show up in the respective key as:

    "Desired//context:pods": ""

And should be translated without that context suffix. For example, for Spanish:

    "Desired//context:pods": "Deseados"

Technical Jargon words

For some technical/jargon terms, there often isn't a good translation for them. To find these ones, it can be good to look at existing documentation like the k8s docs.

The word "Pods" is a good example of a technical word that is used in Spanish. Maybe it could directly translate to "Vainas", but "Pods" is used instead.

Number formatting

Numbers are formatted in a locale-specific way. For example in 'en' they are formatted like 1,000,000 but with 'de' they are formatted like 1.000.000.

Here is an example which can use number formatting:

    return t('{{numReady, number}} / {{numItems, number}} Requested', {
numReady: podsReady.length,
numItems: items.length,
});

Number formatting is being done with Intl.NumberFormat.

Date formatting

Here's an example of using date formatting:

    return t('appsection:When {{ date, date }}', {

});

Adding a new language

Create a folder using the locale code in: frontend/src/i18n/locales/ and app/electron/locales

Then run make i18n. This command parses the translatable strings in the project and creates the corresponding catalog files.

Integrated components may need to be adjusted (MaterialUI/Monaco etc).

Translating missing strings

Technical development happens more frequently than translations. Thus, chances are that developers introduce new strings that need to be translated and will be stored as empty strings (defaulting to English) in the translation files.

In order to more easily spot and translate the missing strings, we have two CLI tools:

  • extract-empty-translations.js: This script (in ./frontend/src/i18n/tools/) will extract the strings without a corresponding translation from the translation files, and copy them into a new file. E.g. $ node copy-empty-translations.js ../locales/de/translation.json will by default create a ../locales/de/translation_empty.json. This file can be used to translate the strings in a more isolated way.
  • copy-translations.js: This script (in ./frontend/src/i18n/tools/) by default copies any existing translations from one source translation file to a target one, if the same key is not translated in the destination file. E.g. $ node copy-translations.js ../locales/de/translation_no_longer_empty.json ../locales/de/translation.json will copy any new translations from the file given as the first argument to the one given as the second argument, if the same key is not translated in the second. There are some options to this script, which can be seen by running it with the --help flag.

Material UI

Some Material UI components are localized and are configured via a theme provider.

See the Material UI Localization Guide, and also frontend/src/i18n/ThemeProviderNexti18n.tsx where integration is done.

Storybook integration

TODO: not implemented. There's no working addons that let you set a language easily.

Monaco editor integration

See frontend/src/components/common/Resource/EditorDialog.tsx

Note, that Monaco editor does not support pt, ta and other languages.