From 7e6fb5b6d1007434f2290674a7e0bd18130be0ad Mon Sep 17 00:00:00 2001 From: Till JS Date: Sat, 25 Apr 2026 12:07:35 +0200 Subject: [PATCH] docs: surface i18n validator stack + format helper convention - CLAUDE.md: validate:all section now lists every individual check (turbo / pg-schema / theme-{variables,utilities,parity} / i18n-{parity,hardcoded,keys} / crypto / encrypted-tools) instead of the stale "three invariant checks" line. - .claude/guidelines/sveltekit-web.md: new "i18n" section with the hardcoded-strings rule (use $_), the parity/missing-key gates, and the formatDate/formatNumber/getDateFnsLocale convention vs. toLocaleDateString('de-DE'). - .claude/GUIDELINES.md: index gains "i18n" tag for the SvelteKit page. Co-Authored-By: Claude Opus 4.7 (1M context) --- .claude/GUIDELINES.md | 2 +- .claude/guidelines/sveltekit-web.md | 55 +++++++++++++++++++++++++++++ CLAUDE.md | 15 ++++++-- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/.claude/GUIDELINES.md b/.claude/GUIDELINES.md index 1fa6ce832..7449d47cb 100644 --- a/.claude/GUIDELINES.md +++ b/.claude/GUIDELINES.md @@ -11,7 +11,7 @@ This directory contains comprehensive guidelines for working in the Mana Univers | [Testing](./guidelines/testing.md) | Jest/Vitest patterns, mock factories, coverage | | [Hono Server](./guidelines/hono-server.md) | Compute servers (Hono + Bun) | | [Error Handling](./guidelines/error-handling.md) | Go-style errors, error codes, Result types | -| [SvelteKit Web](./guidelines/sveltekit-web.md) | Svelte 5 runes, stores, routing | +| [SvelteKit Web](./guidelines/sveltekit-web.md) | Svelte 5 runes, stores, routing, i18n | | [Expo Mobile](./guidelines/expo-mobile.md) | React Native, NativeWind, navigation | | [Authentication](./guidelines/authentication.md) | Mana Core Auth integration | | [Design & UX](./guidelines/design-ux.md) | UI patterns, animations, accessibility | diff --git a/.claude/guidelines/sveltekit-web.md b/.claude/guidelines/sveltekit-web.md index cb7e77fb4..98c975a74 100644 --- a/.claude/guidelines/sveltekit-web.md +++ b/.claude/guidelines/sveltekit-web.md @@ -902,3 +902,58 @@ These work locally because both the browser and server access `localhost`. }); ``` + +## i18n + +The unified Mana app supports `de` (default + fallback), `en`, `it`, +`fr`, `es`. Three CI gates protect the i18n surface — read them before +adding new strings. + +### Strings → svelte-i18n + +```svelte + + + +``` + +Never hard-code German into `.svelte` markup or attributes. The +`validate:i18n-hardcoded` baseline ratchets per-file: if a file's +count of placeholder/title/aria-label/text-content strings with +umlauts goes up, CI fails. Run `pnpm run validate:i18n-hardcoded -- --update` +only after intentionally adding non-translated dev-only UI. + +Adding a new key: + +1. Drop it into `apps/mana/apps/web/src/lib/i18n/locales//de.json` +2. Add the same path to `en.json`, `it.json`, `fr.json`, `es.json` + — the `validate:i18n-parity` check requires identical key-sets + across all 5 locales. +3. New namespace = create the folder + 5 JSONs. Registration is + automatic via `import.meta.glob`; no edits to `i18n/index.ts`. + +A `$_('typo.key')` call that resolves to nothing is caught by +`validate:i18n-keys`. Existing 315 broken refs are baselined so you +can fix them gradually; new misses fail the build. + +### Dates and numbers → format helpers + +```svelte + + +

{formatDate(event.startTime, { day: 'numeric', month: 'short' })}

+

{formatCurrency(item.price, 'EUR')}

+``` + +Never call `.toLocaleDateString('de-DE', …)` or `Intl.NumberFormat('de-DE', …)` +directly — those pin output to German regardless of the active locale. +The helpers in `$lib/i18n/format.ts` pull the active locale from the +svelte-i18n store and map (`de → de-DE`, `en → en-US`, …). + +For date-fns formatters that need a locale object, use +`getDateFnsLocale()` from the same module instead of importing +`{ de }` from `'date-fns/locale'`. diff --git a/CLAUDE.md b/CLAUDE.md index c8d678df1..79f83a0f2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,13 +84,22 @@ Quality: pnpm run build pnpm run type-check pnpm run format -pnpm run validate:all # turbo recursion + pgSchema + crypto registry — run before push +pnpm run validate:all # turbo + pgSchema + theme + i18n + crypto — run before push pnpm run test:coverage # emit v8 coverage under per-package coverage/ ``` `validate:all` is the local mirror of the CI `validate` job — it runs in -seconds and fails fast on any of the three invariant checks. Use it as a -pre-push gate. +seconds and fails fast on any invariant check. Currently bundled: + +- `validate:turbo` — no recursive `turbo run` calls in non-root packages +- `validate:pg-schema` — every Drizzle table uses `pgSchema(...)` +- `validate:theme-{variables,utilities,parity}` — token coverage across CSS variants +- `validate:i18n-parity` — every namespace mirrors DE's key-set across all 5 locales +- `validate:i18n-hardcoded` — ratcheting baseline; new German strings without `$_()` fail +- `validate:i18n-keys` — `$_('key')` calls must resolve to a defined DE key (baseline-tracked) +- `check:crypto` + `audit:encrypted-tools` — every Dexie table classified, every AI tool aware of encryption + +Use it as a pre-push gate. ## Key Architecture Notes