Commit graph

2 commits

Author SHA1 Message Date
Till JS
fd86d968a4 Phase 9h: A11y-Pass
Globaler :focus-visible-Outline (var(--color-primary), 2px) — Tailwind 4
strippt die Browser-Defaults, ohne Fokus-Ring sind Tastatur-Nutzer blind.
.sr-only-Utility (Standard-Rezept) und .skip-link in app.css. prefers-
reduced-motion: schaltet alle Transitions/Animationen auf 0.01ms.

Layout: Skip-Link "Zum Inhalt springen" → #main, main bekommt tabindex="-1"
und id, html-lang wird via $effect reaktiv mit i18n.current synchronisiert
(Initial-SSR rendert "de", Browser zieht nach).

Header: nav-aria-label aus i18n (common.main_nav), Locale-Switcher-Label
aus common.language_switcher. ToastStack: role=region + aria-live=polite,
einzelne Toasts role=alert (error) bzw. status (success/warning), Schließen-
Button-Label i18n-konform.

Hover-only Delete-Buttons (Decks-Liste, Deck-Detail-Karten) bekommen
focus-visible:opacity-100 — bisher waren sie für Tastatur-Nutzer
unsichtbar. opacity-0 statt hidden, damit Tab-Order intakt bleibt.

svelte-check 379 files 0 errors, prod-Build sauber.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 18:24:33 +02:00
Till JS
c25c1d0dc4 Phase 9g: i18n DE/EN über alle Routes
Schmale Eigen-Lösung statt svelte-i18n: $lib/i18n mit de.ts + en.ts
(je ~150 Strings, flat-with-nesting), index.svelte.ts liefert reaktiven
i18n-Store als Svelte-5-Rune plus t()/tn()-Helper. Locale wird in
localStorage persistiert, Default = navigator.language (DE/EN-Erkennung),
Fallback = de.

Header bekommt einen DE/EN-Toggle-Switcher (role=group, aria-pressed).
Alle Routes (decks, decks/[id], decks/new, cards/new, cards/[id]/edit,
study, study/[deckId], import, account, stats, +page) und alle
Komponenten (Header, AnkiImport, InboxBanner) ziehen jetzt durch t().

tn(key, n) wählt zwischen `<key>_one` (n=1) und `<key>` — minimaler
Plural-Helper, reicht für DE/EN-MVP. Komplexere Pluralregeln (FR/IT)
bräuchten Intl.PluralRules, kommen wenn die Locales dazukommen.

Begleitend ein paar A11y-Vorbereitungen mitgenommen: aria-label am
Locale-Switcher, role=group für Grade-Buttons, role=button +
keyboard-handler für die Anki-Dropzone, role=progressbar mit
aria-valuemin/max/now, role=alert für Error-States,
aria-live=polite für Lade-Meldungen, sr-only-Heading im
Study-Card-Render, aria-hidden für rein dekorative Elemente.

svelte-check 379 files 0 errors, 94 Tests grün (41 Domain + 48 API
+ 5 Web).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 18:22:00 +02:00