Add i18n support: per-locale catalogs, URL-driven locale, translated core and examples #44
Reference in New Issue
Block a user
Delete Branch "i18n"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Every user-facing string now comes from a per-locale catalog:
src/i18n/locales/<tag>.tsfor the host,plugins/<id>/i18n/<tag>.tsfor a plugin (looked up plugin-first, then core). en-US and sv-SE ship.A request is served by
?locale=sv-SE→Accept-Language→ en-US. Exact on a full tag; a lone language takes the first regional catalog for it. No cookie — when the URL asked for a language, the host carries?localeonto the links it renders andctx.localeHref()does the same for a plugin's.ctx.t(key, vars)in handlers;t/locale/locales/localeHref/dirare merged into every view at any include depth.{{var}}interpolation, plurals via Intl.PluralRules, and an unknown key renders as itself — which is what lets a nav label be either a catalog key or plain text.Every catalog is checked against its set's en-US at boot (keys, string-vs-plural kind, plural categories); a mismatch stops startup. Kratos' own flow text is mapped by numeric id (only ids verified against a live Kratos; its generic trait-label id is deliberately unmapped, field labels key on the input name instead).
Also: zero-JS language picker in the shell and on the auth/consent pages,
<html lang dir>from the locale, and both example plugins translated with their own catalogs.apiVersion stays 1.0.0 — the contract additions are additive and nothing is installed against it yet.