Skip to main content

Adding a language

Ten translations ship with OpenCLI: English, 简体中文, 繁體中文, 日本語, 한국어, Español, Português (Brasil), Français, Deutsch and Русский.

Any other language is one file, and so is a correction to one of those.

Through the interface​

Customize → Language → Add a language file… takes a .json file and keeps it. It appears in the picker straight away.

By hand​

The same file, in ~/.opencli/locales, named for the language:

~/.opencli/locales/nl.json

Both routes write to the same place, so anything added through the interface can afterwards be edited by hand or copied to another machine.

What is in it​

Each entry is an English sentence exactly as it appears in the interface, and what to show instead:

{
"name": "Nederlands",
"strings": {
"Dispatch": "Verzenden",
"Scheduled tasks": "Geplande taken",
"Runs ({count})": "Uitvoeringen ({count})"
}
}

name is what the language picker shows. Leave it out and the filename is used. The bare map also works, without the envelope:

{ "Dispatch": "Verzenden" }

Starting from one that ships​

The shipped translations are the same kind of file, in web/src/locales/. Copy one, replace the right-hand side of each line, and you have a complete starting point rather than a list of sentences to hunt for.

To see every sentence the interface uses:

python3 scripts/i18n-check.py

Placeholders​

{name} in a sentence is filled in. Keep the same placeholders, in whatever order your language wants them — that reordering is most of why they exist:

{ "Allowed {count} of {total}": "{total} 中允许了 {count} 个" }

Plurals​

plural() chooses between two forms. That is enough for English, German, Spanish, French and Portuguese; it does not have the third form Russian wants for 2–4. Where a language needs more forms than two, write the sentence so the number carries the sense on its own — запусков: {count} rather than a noun that has to agree with it.

Chinese, Japanese and Korean take the singular form and let the number do the work, which is handled for you.

Correcting a shipped translation​

A file named for a language that already ships is merged into it, not substituted for it. To change one sentence, write one entry:

{ "Dispatch": "派活儿" }

Everything else keeps the shipped wording.

When it takes effect​

A file added through the interface applies at once. One placed in the directory by hand is read when a window connects, so reopen the window. A file that will not parse is skipped, with a line in the gateway log — the other languages are unaffected.

Untranslated sentences​

A sentence with no entry is shown in English, so a partial translation reads as a mix rather than as a screen of blanks. There is no need to finish one before it is useful.

Right-to-left​

Arabic, Hebrew and Persian are not among the shipped translations, and adding one as a file will produce a page laid out left to right. The interface has no dir="rtl" handling yet; that is a change to the stylesheet, not to a translation file.