Internationalization¶
The portal uses Paraglide (@inlang/paraglide-js 2.x), which compiles JSON
catalogues into typed functions. It runs as a Vite plugin, so vite dev and
vite build both compile it:
src/hooks.server.ts applies paraglideMiddleware and writes the locale into
%paraglide.lang% in app.html.
Locales¶
Configured in project.inlang/settings.json, base locale en, catalogues in
messages/{locale}.json.
| Code | Language | Keys | Status |
|---|---|---|---|
en |
English | 2275 | base locale |
fr |
French | 2275 | complete; maintained with en |
fr-CA |
Canadian French | 764 | partial |
es |
Spanish | 758 | partial |
de |
German | 758 | partial |
Counts as of origin/main on 2026-10-17. Paraglide falls back to en for a
missing key, so the partial locales build and render, partly in English.
src/lib/i18n-coverage.test.ts enforces the maintained pair:
- every
enkey exists infr; - a French value identical to its English one fails unless the key is in
IDENTICAL_ON_PURPOSE(brand names, placeholders, words spelled the same) or the string is shorter than 12 characters; - every device sub-route has a label in
src/lib/device-sections.ts.
Nothing checks es, de or fr-CA.
Usage¶
<script lang="ts">
import * as m from '$lib/paraglide/messages';
</script>
<h1>{m.gw_fw_rules()}</h1>
$lib/paraglide/ is generated; do not edit it.
Adding a message¶
- Add the key and English string to
messages/en.json. - Add the French string to
messages/fr.json. - Call
m.your_key(); the accessor exists after the next compile.
Interpolation uses named parameters (m.org_plan({ plan })) and the generated
signature enforces them.
Verify a compile produced messages
paraglide-js compile can print "Successfully compiled" while emitting
a near-empty messages/ directory — for instance when the inlang plugins
in node_modules are missing in a fresh worktree. The page then renders
key names or blanks with no error. Confirm by comparing the number of
generated message modules with the key count in en.json.
Writing the strings¶
- French is a first-class product language. Guillemets (
« ») and the spaces before: ; ! ?are correct French; do not "fix" them. - Catalogues are tab-indented JSON. Edit them in place; do not run
prettier --writeacrossmessages/or the repo, which reformats unrelated files and buries the real change.
Selecting the locale¶
LanguageModal calls Paraglide's setLocale; the bindings update reactively.