← Dokumentáció
Dokumentáció

Languages

Wish of the owner (22-10-2026): "We moeten alle Europese talen ondersteunen, inclusief Turks." ("We must support all European languages, including Turkish.") Phase 1 is described here: the translation system, all user texts as keys, a first translation in 34 languages, the typeface, the language choice and the design of the keyboard layouts.

The API of libs/i18n (Language, t, tv, tn, uppercase, format::date, …) and the translation keys are English (since 27-10-2026).

The languages

The 24 official languages of the EU, and Turkish, Ukrainian, Serbian (Latin and Cyrillic), Albanian, Macedonian, Bosnian, Norwegian (Bokmål), Icelandic and Catalan. Not (now): Russian, Belarusian.

CodeOwn nameEnglishScriptStatus
nlNederlandsDutchLatinreviewed (development language)
enEnglishEnglishLatinreviewed (fallback)
bgБългарскиBulgarianCyrillicdraft
bsBosanskiBosnianLatindraft
caCatalàCatalanLatindraft
csČeštinaCzechLatindraft
daDanskDanishLatindraft
deDeutschGermanLatindraft
elΕλληνικάGreekGreekdraft
esEspañolSpanishLatindraft
etEestiEstonianLatindraft
fiSuomiFinnishLatindraft
frFrançaisFrenchLatindraft
gaGaeilgeIrishLatindraft
hrHrvatskiCroatianLatindraft
huMagyarHungarianLatindraft
isÍslenskaIcelandicLatindraft
itItalianoItalianLatindraft
ltLietuviųLithuanianLatindraft
lvLatviešuLatvianLatindraft
mkМакедонскиMacedonianCyrillicdraft
mtMaltiMalteseLatindraft
nbNorsk bokmålNorwegian (Bokmål)Latindraft
plPolskiPolishLatindraft
ptPortuguêsPortuguese (Portugal)Latindraft
roRomânăRomanianLatindraft
skSlovenčinaSlovakLatindraft
slSlovenščinaSlovenianLatindraft
sqShqipAlbanianLatindraft
sr-LatnSrpskiSerbian (latinica, default for sr)Latindraft
sr-CyrlСрпскиSerbian (ćirilica)Cyrillicdraft
svSvenskaSwedishLatindraft
trTürkçeTurkishLatindraft
ukУкраїнськаUkrainianCyrillicdraft

All languages write from left to right (Language::direction; the type leaves room for a right-to-left language).

Draft ("concept") means: translated by Claude (phase 1), not yet reviewed by a native speaker. In Settings › Language the explanation is then followed by "(Deutsch: Entwurf)" and the contact sheet (make ui, build/ui/talen/talen.png) puts "(concept)" after the name. The doubts of the translators are under "Review".

How it works

libs/i18n (crate euzos-i18n, no_std + alloc, without float, no external crate):

  • Language: the 34 languages with code() (BCP-47), name() (own name), script(), direction(), from_code() ("no" → nb, "sr" → sr-Latn, a region is dropped), accept_language() and CHOICE_LIST (alphabetical by own name: first Latin script, then Greek, then Cyrillic).
  • translations/<code>.txt: per language key = text, with # status: draft or # status: reviewed. nl.txt determines which keys exist. build.rs turns them into static tables: per language one long text and a table of u32 start offsets (u16 until 27-10-2026, when Greek passed 64 KB; no thousands of &str pointers with relocations in the kernel), and per key a constant: s::LOGOUT, and for a plural m::ITEMS. A typo in a key does not compile; a key in a language that is not in nl.txt, a duplicate key or an unknown plural form stops the build with file and line number.
  • t(lang, s::X): the text; if it is missing in that language, the English, and otherwise the name of the key (visibly wrong, never empty). tv(lang, s::X, &[..]) fills in {0}, {1} (the word order may differ per language), tn(lang, m::X, n) chooses the plural form and fills in {n} as a number of the language.
  • Plurals: the CLDR forms for integers (zero, one, two, few, many, other), in the file as items[one] = {n} item. plural_form(lang, n) knows the rules of all 34 languages (Polish 2-4/5+, Ukrainian, Croatian/Serbian/Bosnian, Slovenian with dual, Lithuanian, Latvian with zero, Romanian, Irish and Maltese with five forms, Icelandic and Macedonian 1/21/31, French and Portuguese 0 and 1).
  • Capitals: uppercase(lang, ..) and lowercase(lang, ..): Turkish i ↔ İ and ı ↔ I, Greek in capitals without tonos ("Ρυθμίσεις" → "ΡΥΘΜΙΣΕΙΣ"), a Greek Σ at the end of a word becomes ς, German ß → SS. The headings (APPS, NETWORK, …) are written normally in the files and are drawn with desktop::main. The browser does text-transform according to <html lang> of the page.
  • Formatting (format): time (24-hour clock, "14:05"; Finnish "14.05"), date ("22-10-2026" nl, "22/10/2026" en/fr/es/it/pt/el/ga/mt, "22.10.2026" de/pl/tr/…, "2026. 10. 22." hu, "2026-10-22" sv/lt, "22. 10. 2026." hr/bs/sr, "22.10.2026 г." bg), number (thousands from 10 000 with a point, comma or narrow space) and decimal (decimal sign: point in en/ga/mt, otherwise comma). The sizes in the apps ("7,8 GB" / "7.8 GB") and the duration ("2 u 05 min" / "2 h 05 min") follow the language.
  • find_nl(nl): the key for a Dutch text that comes from outside (the profile server sends "Gisteren", the kernel "Interne SSD", "toetsenbord (PS/2)"); desktop::t_nl translates such a text if there is a key for it and otherwise leaves it as it is.

Where the language comes from (kernel, kernel/src/lang.rs): the language of the profile as long as someone is logged in, otherwise that of the PC. The language of the PC is in PROFILE.TXT as language=<code> (before 27-10-2026 taal=<code>, still read; default nl; docs/PROFILE-PROTOCOL.md) and applies to the login screen (also the power menu there) and the boot screen (until PROFILE.TXT has been read: Dutch). Toasts of sshd and the Wi-Fi, the browser (start page, about:browser, error pages, messages in the bar) and the Accept-Language header of every HTTP request (sites and the profile server) ask lang::current(). The kernel log and the console are in English (since the English conversion of 27-10-2026; before that Dutch). On the login screen anyone can choose the language of the PC with the language card at the bottom (docs/DESKTOP-DESIGN.md 13); that choice is in \EOS\FW\LANG.TXT (language=<code>, nothing else; the old name TAAL.TXT and the old line taal=<code> are still read) and wins over language= in PROFILE.TXT.

Choosing the language: Settings › Language shows all 34 languages in their own name as buttons in a grid (Language::CHOICE_LIST). A click applies immediately: desktop, bar, menu, the titles and content of open apps and the terminal bar are redrawn (redraw_all). The choice goes with profile::setting_changed("taal", code) to the profile server (taal= in the profile, all 34 codes).

Typeface

The subset of Inter (make letters, tools/ui/src/subset.rs) now also has Greek (U+0384-U+03CE), Cyrillic (U+0400-U+045F and Ґ ґ), the digraphs DŽDždžLJLjljNJNjnj, the narrow no-break space (U+202F, thousands) and the Ukrainian apostrophe (U+02BC), next to ASCII, Latin-1, Latin Extended-A and Ș ș Ț ț. Inter has all those characters. A test (desktop::tests::all_chars_in_the_typeface) checks that every character of every translation, of the own names, of the headings in capitals and of the dates in both weights is in the typeface.

beforeafter
INTER-R.TTF28 832 B41 072 B
INTER-B.TTF28 644 B40 864 B
kernel x86-642 525 000 B2 836 608 B (+311 608, +12.3 %)
kernel ARM642 190 112 B2 506 256 B (+316 144)

(main at de01b30 against this branch.) Of the growth ~24 KB is typeface and ~299 KB translations (270 KB text in 34 languages, ~23 KB start offsets, ~6 KB key names); the old nl/en table and the Dutch texts in the code come off that. Can be smaller later: load the tables of only the chosen language of the stick, or compress. The glyph cache (Fonts::in_cache) only grows with what is drawn: per language the characters of that script are added, not the whole typeface.

The bitmap font of the console stays ASCII; the terminal already draws non-ASCII with Inter.

Translating and reviewing

  1. A new text: key and Dutch text in nl.txt (in the right section), English in en.txt, in the code t(lang, s::KEY) (or in an app tt(st, s::KEY), a heading main_tt). A text with a value: {0} in the text and tv; with a count: a plural and tn.
  2. The other languages: the test all_languages_complete (cargo test -p euzos-i18n, also in make ui) lists per language what is missing, which placeholders differ and which plural forms are missing. If a text is missing, the user sees the English.
  3. Checking whether it fits: make ui renders menu, Settings (Language and Appearance), Files, Hardware, the login screen (with power menu) and the power menu with the Log out question in nl, en, de, fr, tr, pl, el, bg, uk, fi, hu and mt to build/ui/talen/<code>-*.png, and a contact sheet with all 34 languages (talen.png). Other languages: build/target/release/euzos-ui-preview talen <dir> <code> .... Texts that do not fit are shortened with "…" (buttons, labels, menu items, task buttons, the explanation in Settings); the explanation on the login screen runs over two lines.
  4. Review by a native speaker: read the file next to nl.txt/en.txt and the PNGs, improve, and replace the header # status: draft — to be reviewed by a native speaker with # status: reviewed (<name>, <date>). Then "concept" disappears from Settings and the contact sheet.

Review: doubts of the translators

  • Form of address: informal in nl (je/jij), de (du), da/nb/sv/is, es, it, fi, et, pl, ga, mt; polite form in fr (vous), pt, ca (vós in sentences), cs, sk, sl, lt, lv, el, ro, sq, tr, bg, mk, uk, hr, bs, sr and, since the review of 28-10-2026, hu (Ön, as Windows and macOS do). Please confirm German "du" or "Sie" and Estonian informal address. The terms per language are in docs/i18n/GLOSSARY.md; the expert review of 28-10-2026 and its open questions in docs/i18n/REVIEW-2026-10-28.md.
  • Words: German "WLAN" (the rest "Wi-Fi"); Maltese keeps English loanwords (Settings, Boot, Input); Ukrainian "Застосунки", "ШІ-асистенти"; Macedonian the least certain ("USB-меморија", "Безбедно по основно"); Irish mutations after numbers ("huaire", "n-ordú").
  • Numbers in sentences: where a word would have to inflect with the number ("{0} nu actief", "{0} gekozen": "{0} now active", "{0} selected") many languages chose "label: {0}".
  • Welcome without gender in es/it/pt/ca ("Te damos la bienvenida"); Icelandic "Velkomin" depends on gender.

Open points

  • Keyboard layouts (see below): the conversion layer is in place, the drivers do not use it yet; a choice in Settings and toetsenbord= in the profile will follow.
  • Phone app (Flutter, app/lib/texts.dart): now a class T with _('nl', 'en'). Approach: the same files libs/i18n/translations/*.txt as source, with a small Dart script (in app/tool/) that converts them to app/lib/teksten_<code>.dart (a Map<String, String> per language) and the keys of the app (an own section # --- App in nl.txt, or an own app/vertalingen/). T.of(context) then chooses by staat.taal (the same 34 codes), with fallback to English; plurals with the same CLDR rules (a Dart copy of euzos_i18n::plural_form, with a test that compares the outcomes). Not built yet.
  • Mails of the profile server (server/profile/src/mail.rs): now nl or en (the language of the account). Approach: the server reads the same translation files (it is Rust: euzos-i18n as a dependency, with an own section # --- Mail in the files) and chooses the language of the account (taal=, all 34 codes); unknown → English.
  • Browser content: the Accept-Language header now goes along (the language of the user, then English with q=0.5), so sites that support it answer in that language. The interface of the browser is translated; the pages themselves are not (no translation service: own-code rule).
  • Installer (libs/ui/src/installer.rs): still Dutch only; the installer runs before there is a PROFILE.TXT with language=. A choice of the language as the first step of the installer, which immediately writes language= to PROFILE.TXT, is the obvious approach.
  • The boot screen is Dutch until PROFILE.TXT has been read (the stick is then not always readable yet); the bootloader can pass language= later.
  • Smaller: the translations cost ~299 KB in the kernel; later load only the chosen languages or compress.
  • Texts of the kernel that come in as data in Dutch (hardware info "Aanraakscherm (I2C-HID, …)", "UEFI (EUZOS-lader), proefstart", places "poort 1.2") are only translated if they are exactly a key; better to have those come from the kernel as keys.

Keyboards

A layout belongs to the user (profile: toetsenbord=, proposal) and, before login, to the PC (PROFILE.TXT: toetsenbord=). Needed for these languages:

LayoutFor
QWERTY US, US International (dead ' ` ^ ~ ")nl, en, programmers; also pt/es/it/ca without own keyboard
QWERTY UKen (Ireland, Malta: UK and Maltese 47/48)
QWERTZ German, Austrian, Swiss (German/French)de
QWERTZ Czech, Slovak, Hungarian, Slovenian/Croatian/Bosnian/Serbian (Latin)cs, sk, hu, sl, hr, bs, sr-Latn
AZERTY French, Belgianfr, nl (Belgium)
Turkish Q and Turkish Ftr
Greekel
Cyrillic Bulgarian (phonetic and BDS), Ukrainian, Serbian, Macedonianbg, uk, sr-Cyrl, mk
Nordic: Danish, Norwegian, Swedish/Finnish, Icelandicda, nb, sv, fi, is
Estonian, Latvian (QWERTY with dead key), Lithuanianet, lv, lt
Spanish, Portuguese, Italian, Catalan (Spanish), Polish (programmer), Romanian (standard), Albanianes, pt, it, ca, pl, ro, sq
Irish, Maltesega, mt

Design (libs/input/src/layout.rs, tested with cargo test -p euzos-input):

  • A key is a HID usage (page 0x07), as USB sends it; PS/2 (set 1) goes via from_set1 to the same usage. One table per layout for both drivers.
  • Per layout four layers (plain, Shift, AltGr, AltGr+Shift) of 49 characters in a fixed order (a-z, 1-0, the punctuation, the ISO keys # and <). A combining accent (U+0300 …) in a layer is a dead key.
  • Converter::key(usage, shift, altgr) keeps track of Caps Lock (Turkish: i → İ) and a pending dead key: dead key + letter → composed character (á à â ã ä ç …), + space or twice → the accent itself, + something else → accent and character separately. US International: ' + c → ç.
  • Built now: US, US International, German, French (AZERTY) and Turkish Q. The rest follows the same pattern (tables only).

What the drivers still need (phase 2): the input buffer of the kernel (kernel/src/input.rs) now carries u32 (done for the on-screen keyboard): 0x00-0x7F ASCII, 0x80-0x9F the special codes (arrows, volume, windows; in Unicode the C1 control characters), from 0xA0 a Unicode character (input::push_char); the browser, the installer and the shell already take characters. Still to do: the PS/2 driver (arch/x86_64/keyboard.rs) and the USB driver pass usage + Shift/AltGr (right Alt; Ctrl+Alt as AltGr) to Converter and put the character in the buffer with input::push_char. The font of the console only knows ASCII.