Translating
Loomkeep’s interface is written in English first, then translated: French and Italian today. Translations come in through pull requests on GitHub. Read Contributing first for the setup and the workflow.
Where the text lives
Section titled “Where the text lives”Every visible string of the web app is in apps/web/messages/<language>/,
in seven JSON files (common, other, errors, gamification, admin,
settings, site). English (en) is the source; each other language has
the same files and the same keys.
A missing key falls back to English, key by key: a partial translation never breaks the app, it just shows English where it isn’t done yet.
Improving an existing language
Section titled “Improving an existing language”Find the key whose text shows in the app (search the English file for the English wording), fix its value in your language’s file, and open a pull request. To catch up with new features, compare your language’s keys with English and translate the missing ones.
Adding a language
Section titled “Adding a language”- Translate the catalogs: copy
apps/web/messages/en/toapps/web/messages/<code>/and translate the values. - Declare the language in two lists, which a test keeps equal:
localesinapps/web/project.inlang/settings.json, andLocaleinpackages/shared/src/enums.ts. - Add its region (
de: "de-DE") toLOCALE_REGIONSinpackages/shared/src/locale.ts, for dates and numbers. - Optionally, translate emails and notifications: add the code to
COPY_LOCALESinapps/api/src/common/copy-locale.util.ts, and the compiler lists every table missing it. Without this step, emails and notifications in that language arrive in English.
The language then shows up in every language picker, in its own name.
- Keep every key and every
{placeholder}exactly: a test rejects a translation whose placeholders differ from English. - Talk to people informally, like the English and French copy do (tu in French): pick your language’s equivalent.
- Some keys are fragments of a sentence stitched around a link or an
icon (keys ending in
_prefix,_suffix,_intro…). Check where they are used before moving words around. - Keep some text in English, as is: the catalogues’ attribution notices their terms require, and names of third-party menus (Goodreads’ “My Books → Import and export”).
- Keep the product’s words consistent across files: the same term for the library, the statuses, the ghost privacy mode, everywhere.
Testing your translation
Section titled “Testing your translation”pnpm --filter @loomkeep/web generate:paraglidepnpm --filter @loomkeep/web exec vitest run src/catalogs.spec.tspnpm devThen switch to your language in Settings › Appearance and browse the home page, a library, a title’s page and the settings.
What isn’t translated
Section titled “What isn’t translated”- Legal pages stay in French: that version is the binding one.
- Catalogue data: only TMDB answers in your language (films and series titles and overviews). IGDB, AniList and Open Library are English only.
- This documentation is in English for now.