feat(i18n): locale core + English catalogs + parity gates

Add the i18n foundation: src/i18n/locale.js (locale resolution with a
configurable GEV_DEFAULT_LOCALE / GEV_SECONDARY_LOCALE pair, guarded
preference storage, one-shot ?lang= override, <html lang>/<html dir>
metadata) and src/i18n/index.js (catalog registry, t(), Intl formatters,
applyDocumentTranslations, persistLocaleAndReload).

English is the only shipped locale in this PR: the four en catalogs
(shell/cockpit/layers/setup) are the reference and the always-shipped
fallback, the built-in pair degenerates to en-only, and English output
is byte-identical to the strings these replace.

Parity gates land with the core (catalog key/placeholder/plural-shape
parity, markup coverage of every data-i18n* attribute, repair-pass
anchors pinning en byte-identity); additional locales ship as stacked
follow-up PRs through the recipe in docs/TRANSLATORS.md.

Rebased onto current main: the client defines live in build/vite.js /
server/standalone/vite.config.js as before.
This commit is contained in:
Meir Michanie committed 2026-10-01 12:26:30 +02:00
1 parent e7707d9a0f
commit bde1e430ef
12 files changed
+2702

No files matched your search

+10
View File
@@ -7,6 +7,8 @@ export function createBrowserViteConfig({
publicDir,
googleApiKey,
cesiumToken,
defaultLocale = '',
secondaryLocale = '',
host = 'localhost',
port = 4173,
command,
@@ -47,6 +49,14 @@ export function createBrowserViteConfig({
define: {
'import.meta.env.GOOGLE_MAPS_API_KEY': JSON.stringify(googleApiKey),
'import.meta.env.CESIUM_ION_TOKEN': JSON.stringify(cesiumToken),
// Locale pair (i18n): the client's default + secondary UI locale. These
// are NOT secrets and are read by src/i18n/locale.js, which validates
// them against the shipped catalogs and falls back to the built-in
// en-only pair (while English is the only shipped catalog) for
// empty/invalid/unshipped values. Explicit define entries are required
// because Vite only auto-exposes VITE_-prefixed vars on import.meta.env.
'import.meta.env.GEV_DEFAULT_LOCALE': JSON.stringify(defaultLocale),
'import.meta.env.GEV_SECONDARY_LOCALE': JSON.stringify(secondaryLocale),
},
build: { chunkSizeWarningLimit: 1500 },
};