Internationalization
Parallax Designer uses a custom typed i18n system with no external dependency (no vue-i18n). The system provides compile-time type safety for translation keys and runtime parameter interpolation.
Supported Locales
| Code | Language | Catalog File |
|---|---|---|
en | English | src/i18n/locales/en.ts |
fr | French | src/i18n/locales/fr.ts |
Locale Files
| File | Purpose |
|---|---|
src/i18n/config.ts | Supported locale metadata, default locale, storage key |
src/i18n/locales/en.ts | English source-of-truth catalog |
src/i18n/locales/fr.ts | French catalog |
src/i18n/locales/index.ts | Locale registry used by the app runtime |
Runtime Behavior
Locale Detection
On startup, the locale is determined by this priority chain:
- localStorage —
parallax-designer-localekey - Browser locale —
navigator.languages, normalized to base tag (e.g.,fr-CA→fr) - Default —
en
Locale Persistence
- Language changes are persisted immediately to
localStorage - The active locale updates the
<html lang>attribute viauseI18n - Locale preference is app-level state — it is not stored in the project payload/schema
Translation API
The useI18n composable exposes:
| Method / Property | Description |
|---|---|
locale | Readonly reactive ref to the active locale code |
setLocale(code) | Switch to a specific locale |
toggleLocale() | Cycle to the next supported locale |
t(key, params?) | Typed translation lookup with {name} parameter interpolation |
getHelp(helpKey) | Retrieve localized help panel content for a given control key |
formatDateTime(epochMs, options?) | Locale-aware date/time formatting |
Type Safety
Translation keys are fully type-safe. The TranslationKey type is derived from the English catalog structure via a recursive LeafPaths<T> utility type that extracts all dot-separated paths to leaf string values.
// If the catalog has:
// { scene: { maxRot: { label: "Max Rotation" } } }
// Then valid keys include: "scene.maxRot.label"Using an invalid key in t() produces a TypeScript compile error.
Parameter Interpolation
Translations can include {name} placeholders:
// Catalog: "Layer limit reached ({maxLayers})"
t("layers.limitReached", { maxLayers: 30 });
// → "Layer limit reached (30)"Catalog Rules
- Keep all keys identical across all locale files (mirror the
en.tsstructure exactly) - Keep placeholders exactly the same (
{count},{name}, etc.) - Project payload/schema values are language-neutral — only UI copy is localized
- Translate the full UI surface: labels, tooltips, help content, dialogs, toasts, placeholders, and ARIA text
Build-Time Validation
The check:i18n script (scripts/check-i18n.mjs) validates key parity between English and all other locales at build time:
npm run check:i18nThe script:
- Uses the TypeScript compiler API to transpile each locale
.tsfile to CommonJS - Runs the transpiled code in a Node
vmsandbox to extract the catalog object - Extracts all leaf paths from each catalog
- Compares every locale's leaf paths against the English catalog
- Reports any missing or extra keys
This runs automatically as part of the npm run check pipeline.
Adding a New Locale
- Register the locale in
src/i18n/config.ts— add the locale code and display metadata - Create the catalog — Copy
src/i18n/locales/en.tstosrc/i18n/locales/<code>.ts, export a<CODE>_LOCALEconstant, and translate all values - Register the export in
src/i18n/locales/index.ts— import and add to the locale map - Validate:bash
npm run check:i18n # Verify key parity npm run typecheck # Ensure typed key usage stays valid npm run build # Build app assets