Translating the interface
The panel interface is available in English and Brazilian Portuguese (pt-BR, the source language). Adding another language
needs only new files: no component changes.
How it works
Section titled “How it works”- Texts live in
apps/web/src/locales/<language>/<area>.ts, one flat object per area (common,projects,mail,backups…). - A text is read by its key,
area.key, for examplet("projects.list.empty"). {name}inserts a value. Plurals use the suffixes_one/_other(and_zero,_few,_manywhen the language needs them) and acountvalue.<b>...</b>-style tags mark bold text, code and links in a few long texts. Keep the same tags and the same{variables}as the source text.- A key missing in a language falls back to
pt-BR. If it is missing there too, nothing is shown (empty text) and the browser console warns in development. The parity test keeps a key from being missing in a language, and the type check rejects a misspelled key in the code, so committed dictionaries do not get there. - Values inserted with
{name}are always plain text, even inside<b>...</b>: they never become markup. - On the first visit the language comes from the browser: the first of its languages that the panel has (
pt*becomespt-BR; if none matches, English). After that it is the language selector (always visible in the panel header, next to the user menu; with the side menu layout, at the bottom of the sidebar, above the user menu, with the full language name), on the sign-in and setup pages and under Settings → Appearance. In the header it shows the short code from the"language.short"key ofcommon.ts(for exampleEN); a language without that key shows its folder name in capitals. The choice is kept in the browser (localStorage, keypaas.locale). - Dates, times, numbers and sorting use the language through
Intl. The configured time zone is never changed by the language.
Add a language (for example, Spanish)
Section titled “Add a language (for example, Spanish)”-
Copy the folder
apps/web/src/locales/en/toapps/web/src/locales/es/(the folder name is the language code). -
Translate the values in every file. Do not rename keys. Keep
{variables}and tags as they are. Followapps/web/src/locales/GLOSSARY.mdso the same concept always has the same word. -
In
common.ts, set"language.name"to the language written in itself (for example"Español"): this is what the selector shows. -
Run the checks from
apps/web:Terminal window pnpm test -- tests/i18n-parity.test.ts # same keys, variables and tags as pt-BRpnpm test:coverage # whole suitepnpm typecheck && pnpm build -
Open the panel, pick the language in the selector and click through the main pages. No raw key such as
projects.list.emptyshould appear, and no label or button should be empty. Keep in mind that the messages written by the server are still in Portuguese. -
Open a pull request. See CONTRIBUTING.md.
The new language is picked up automatically: the selector, the browser detection (es-MX becomes es) and the fallback all read the folders in locales/.
Change or add a text
Section titled “Change or add a text”Edit the pt-BR and en files together. A test fails if a key exists in only one of them, if the variables differ, or if a component brings back fixed Portuguese text instead of using a key.