Internationalization
UI strings go through Paraglide JS, which compiles messages/<locale>.json into typed functions
at build time.
import * as m from '$lib/paraglide/messages';m.some_key();This is separate from the operator-facing multilingual config values (DESCRIPTION,
TOPBAR.TITLE, …), which are resolved at runtime by resolveI18nValue().
- Key format is
underscore_separated—menu_graph_panel, notmenu.graphPanel. - Generated code in
src/lib/paraglide/is never hand-edited, and is gitignored. - Locales are registered in
project.inlang/settings.json(baseLocale+locales). The Vite plugin regeneratessrc/lib/paraglide/on dev, build and test. - Switch language with
setLocale('ko')(alsogetLocale,locales) from$lib/paraglide/runtime.
npm run check does not go through Vite, so on a fresh clone $lib/paraglide/* would have no
type declarations. check therefore runs npm run i18n:compile first — the Paraglide CLI with the
same options as the Vite plugin, so keep the two in sync. prepare runs it too, so a plain npm ci
leaves the tree typecheckable.
Adding a language
Section titled “Adding a language”- Add the locale code to
localesinproject.inlang/settings.json. - Create
messages/<locale>.json.
That’s it — the MiscPanel picker reads locales and labels them via Intl.DisplayNames, so no
component edit is needed. Keys fill in over time; see the fallback note above.
Translation contribution flow
Section titled “Translation contribution flow”Translators never touch messages/<locale>.json directly. They edit a generated staging file that
contains only the keys still needing work:
| Command | Who | What it does |
|---|---|---|
npm run i18n:check | anyone | Reports missing / stale keys per locale. Changes nothing. |
npm run i18n:missing | maintainer | Writes messages/_missing_translations_<locale>.json — the gap keys, pre-filled with the en source text. |
npm run i18n:apply | maintainer | Merges those staging files back into messages/<locale>.json (in en key order) and deletes them. |
- A key is added to
messages/en.json→ runnpm run i18n:missingto regenerate the staging files. - A translator edits
messages/_missing_translations_ko.jsonand opens a PR. Keys they’re unsure about can be left out entirely — those keep falling back to English. - After merging the PR, run
npm run i18n:applyand commit the result.
i18n:apply skips keys not present in en.json and keys left blank, and preserves stale keys rather
than dropping them. Use --dry-run to preview.
Paraglide ignores _missing_translations_*.json — it only compiles the locales listed in
project.inlang/settings.json.
Frequency Tutorial text
Section titled “Frequency Tutorial text”The Frequency Tutorial overlay’s labels are ordinary UI
strings, one _name / _desc pair per band, keyed tutorial_freq_<band>_name and
tutorial_freq_<band>_desc, where the bands are sub_bass, bass, lower_mids, upper_mids,
presence and brilliance:
{ "tutorial_freq_sub_bass_name": "Sub Bass", "tutorial_freq_sub_bass_desc": "The Rumble, usually out of human's hearing range...", "tutorial_freq_bass_name": "Bass", "tutorial_freq_bass_desc": "Determines how 'fat' or 'thin' the sound is..."}Because they compile into the bundle, operators on a CDN or pre-built deployment cannot change them — rewording one is a source build, or a PR.