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) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-25 12:07:35 +02:00
parent 01e6b9f044
commit 7e6fb5b6d1
3 changed files with 68 additions and 4 deletions

View file

@ -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 | | [Testing](./guidelines/testing.md) | Jest/Vitest patterns, mock factories, coverage |
| [Hono Server](./guidelines/hono-server.md) | Compute servers (Hono + Bun) | | [Hono Server](./guidelines/hono-server.md) | Compute servers (Hono + Bun) |
| [Error Handling](./guidelines/error-handling.md) | Go-style errors, error codes, Result types | | [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 | | [Expo Mobile](./guidelines/expo-mobile.md) | React Native, NativeWind, navigation |
| [Authentication](./guidelines/authentication.md) | Mana Core Auth integration | | [Authentication](./guidelines/authentication.md) | Mana Core Auth integration |
| [Design & UX](./guidelines/design-ux.md) | UI patterns, animations, accessibility | | [Design & UX](./guidelines/design-ux.md) | UI patterns, animations, accessibility |

View file

@ -902,3 +902,58 @@ These work locally because both the browser and server access `localhost`.
}); });
</script> </script>
``` ```
## 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
<script>
import { _ } from 'svelte-i18n';
</script>
<button>{$_('common.save')}</button>
```
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/<ns>/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
<script>
import { formatDate, formatNumber, formatCurrency } from '$lib/i18n/format';
</script>
<p>{formatDate(event.startTime, { day: 'numeric', month: 'short' })}</p>
<p>{formatCurrency(item.price, 'EUR')}</p>
```
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'`.

View file

@ -84,13 +84,22 @@ Quality:
pnpm run build pnpm run build
pnpm run type-check pnpm run type-check
pnpm run format 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/ 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 `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 seconds and fails fast on any invariant check. Currently bundled:
pre-push gate.
- `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 ## Key Architecture Notes