cards/apps/web/src/lib/i18n/de.ts
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

220 lines
8.3 KiB
TypeScript

// Default-Locale. Schlüssel sind Punkt-getrennt nach Bereich.
// Interpolation: {n}, {name}, {count} → simple replace.
export type TranslationNode = { [key: string]: string | TranslationNode };
export const de: TranslationNode = {
app: {
name: 'Cards',
title_suffix: 'Cards',
},
nav: {
decks: 'Decks',
study: 'Lernen',
import: 'Import',
stats: 'Statistik',
login_dev: 'Login (dev)',
account: 'Account',
},
landing: {
welcome: 'Lernkarten mit Spaced-Repetition.',
intro:
'Cardecky ist die föderierte Karteikarten-App des Vereins mana e.V. — FSRS-Scheduler, Cloze-Karten, Anki-Import.',
cta_login: 'Login (dev)',
dev_user_prompt: 'User-ID (dev):',
},
decks: {
title: 'Decks',
new: 'Neues Deck',
empty: 'Noch keine Decks.',
empty_cta: 'Erstes Deck anlegen',
loading: 'Lade…',
error: 'Fehler: {msg}',
card_count: '{n} Karten',
card_count_one: '1 Karte',
due_count: '{n} fällig',
delete_confirm:
'Deck "{name}" wirklich löschen? Alle Karten + Review-Daten gehen verloren.',
deleted: 'Deck "{name}" gelöscht',
delete_failed: 'Löschen fehlgeschlagen: {msg}',
},
deck_detail: {
back: '← Zurück zu Decks',
study_button: 'Lernen',
new_card: 'Neue Karte',
empty: 'Keine Karten in diesem Deck.',
empty_cta: 'Erste Karte anlegen →',
card_summary_due: '{cards} · {due} fällig',
card_delete_aria: 'Karte löschen',
card_delete_label: 'Löschen',
card_delete_confirm: 'Karte wirklich löschen? Reviews werden mit gelöscht.',
},
deck_new: {
title: 'Neues Deck',
name_label: 'Name',
description_label: 'Beschreibung (optional)',
color_label: 'Farbe (optional)',
create: 'Deck anlegen',
creating: 'Lege an…',
cancel: 'Abbrechen',
create_failed: 'Anlegen fehlgeschlagen: {msg}',
},
card_new: {
title: 'Neue Karte',
back: '← Zurück',
deck_label: 'Deck',
type_label: 'Typ',
type_basic: 'Basic (front → back)',
type_basic_reverse: 'Basic + Reverse (front ↔ back, 2 Reviews)',
type_cloze: 'Cloze (Lückentext, 1 Review pro Cluster)',
front_label: 'Vorderseite (Markdown)',
back_label: 'Rückseite (Markdown)',
back_placeholder: 'Antwort',
front_placeholder: '# Markdown ist erlaubt\n**fett**, _kursiv_, `code`',
preview_label: 'Vorschau',
cloze_text_label: 'Text mit Lücken (Markdown)',
cloze_text_placeholder: 'Die Hauptstadt von {{c1::Frankreich}} ist {{c2::Paris}}.',
cloze_help: '{{c1::Antwort}} definiert eine Lücke. Pro Cluster-ID (c1, c2, …) entsteht ein eigenes Review.',
cloze_no_clusters: 'Mindestens ein {{cN::…}}-Cluster wird gebraucht.',
cloze_clusters_detected: '{n} Cluster erkannt: c{ids} → {n} Reviews.',
cloze_preview_label: 'Vorschau (c{first} maskiert)',
cloze_extra_label: 'Extra (optional)',
cloze_extra_placeholder: 'Zusätzlicher Kontext, wird unter der Antwort gezeigt.',
create: 'Karte anlegen',
creating: 'Speichere…',
cancel: 'Abbrechen',
create_failed: 'Anlegen fehlgeschlagen: {msg}',
toast_basic: 'Karte angelegt',
toast_basic_reverse: '2 Reviews initialisiert (front→back, back→front)',
toast_cloze: '{n} Reviews initialisiert (1 pro Cluster)',
decks_load_failed: 'Decks konnten nicht geladen werden: {msg}',
},
card_edit: {
title: 'Karte bearbeiten',
back: '← Zurück zum Deck',
type_locked_help: 'Der Card-Type kann nicht geändert werden — die Reviews-Tabelle hängt am Type.',
save: 'Speichern',
saving: 'Speichere…',
cancel: 'Abbrechen',
delete: 'Löschen',
deleting: 'Lösche…',
delete_confirm: 'Karte wirklich löschen? Reviews werden mit gelöscht.',
updated: 'Karte aktualisiert',
save_failed: 'Speichern fehlgeschlagen: {msg}',
delete_failed: 'Löschen fehlgeschlagen: {msg}',
deleted: 'Karte gelöscht',
},
study: {
title: 'Lernen',
empty: 'Keine Decks.',
none_due: 'Aktuell nichts fällig.',
study_now: 'Jetzt lernen',
due_count: '{n} fällig',
},
study_session: {
back: '← Übersicht',
all_done: 'Geschafft! Alle fälligen Karten gemacht.',
stats: 'Reviews: {reviewed} · Wieder: {again}',
reveal: 'Lösung zeigen',
reveal_hint: 'Leertaste / Enter zum Aufdecken',
grade_again: 'Wieder',
grade_hard: 'Schwer',
grade_good: 'Gut',
grade_easy: 'Leicht',
grade_hint: '1=Wieder · 2=Schwer · 3=Gut · 4=Leicht',
loading: 'Lade…',
error: 'Fehler: {msg}',
},
import: {
title: 'Importieren',
intro: 'Übernimm Decks und Karten aus einer Anki-Datei (.apkg oder .colpkg). FSRS-Verlauf wird nicht übernommen — alle Karten starten als „neu".',
what_works_title: 'Was wird übernommen',
what_works_decks: 'Decks (Anki-Hierarchie Foo::Bar wird zu Foo / Bar).',
what_works_basic: 'Basic + Basic-Reverse: Front/Back direkt.',
what_works_cloze: 'Cloze: {{c1::…}} wird mit Sub-Index pro Cluster angelegt.',
what_skipped_title: 'Was nicht übernommen wird',
what_skipped_media: 'Bilder + Audio (kommen mit der Plattform-Anbindung in einer späteren Phase).',
what_skipped_history: 'FSRS-Lernverlauf (Anki-Reviews werden bewusst neu aufgesetzt).',
what_skipped_addons: 'Add-on-spezifische Card-Types (image-occlusion etc.).',
anki_label: 'Aus Anki importieren',
dropzone: '📦 .apkg-Datei hier ablegen oder klicken',
dropzone_hint: 'Basic, Basic + Reverse, Cloze · Bilder + Audio werden in dieser Phase nicht übernommen.',
parsing: 'Lese {file}…',
preview_found: 'Gefunden in',
preview_decks_one: '1 Deck',
preview_decks: '{n} Decks',
preview_cards_one: '1 Karte',
preview_cards: '{n} Karten',
preview_breakdown: '({basic} basic, {basic_reverse} basic-reverse, {cloze} cloze)',
preview_media: '{n} Medien (werden in dieser Phase NICHT übernommen)',
preview_skipped: '{n} übersprungen (unbekannter Typ)',
preview_warnings: 'Hinweise ({n})',
cancel: 'Abbrechen',
import_now: 'Importieren',
stage_decks: 'Lege Decks an · {current} / {total}',
stage_cards: 'Importiere Karten · {current} / {total}',
stage_done: 'Fertig.',
done_summary_one: '✓ {cards} Karten in 1 Deck angelegt.',
done_summary: '✓ {cards} Karten in {decks} Decks angelegt.',
done_failures: '{n} Fehler',
done_more: 'Weitere Datei',
error_label: 'Fehler: {msg}',
retry: 'Erneut versuchen',
},
inbox_banner: {
label: '📥 Inbox',
count_one: '1 eingegangene Karte aus anderen Apps',
count: '{n} eingegangene Karten aus anderen Apps',
cta: '— sortieren →',
},
account: {
title: 'Account',
user_id_label: 'User-ID',
logout: 'Abmelden',
phase2_hint:
'Phase-2-Hinweis: aktuell ist die Identität ein Dev-Stub (sessionStorage). Mit Auth-Föderation wechselt das auf einen mana-auth-Login gegen auth.mana.how.',
export_title: 'Daten-Export',
export_intro:
'Lade alle deine Cards-Daten als JSON herunter — Decks, Karten, Reviews, Study-Sessions, Tags, Media-Refs, Import-Jobs. DSGVO Art. 15/20.',
export_button: 'Daten exportieren',
export_loading: 'Lade…',
export_done: 'Export geladen: {decks} Decks, {cards} Karten, {reviews} Reviews.',
export_failed: 'Export fehlgeschlagen: {msg}',
delete_title: 'Konto löschen',
delete_intro:
'Löscht unwiderruflich alle deine Cards-Daten. DSGVO Art. 17. Andere mana-Apps (Memoro, Who, …) behalten ihre Daten unabhängig — wenn du dort auch löschen willst, mach das jeweils dort oder nutze die Verein-DSGVO-Sammelanfrage über mana-admin.',
delete_button: 'Alle Cards-Daten löschen',
delete_loading: 'Lösche…',
delete_confirm:
'ALLE deine Cards-Daten werden unwiderruflich gelöscht. Tippe LÖSCHEN zur Bestätigung.',
delete_confirm_word: 'LÖSCHEN',
delete_done: 'Gelöscht: {decks} Decks, {imports} Import-Jobs.',
delete_failed: 'Löschen fehlgeschlagen: {msg}',
},
stats: {
title: 'Statistik',
generated_at: 'Stand {date}',
decks: 'Decks',
cards: 'Karten',
reviews: 'Reviews',
due_now: 'Fällig jetzt',
days_title: 'Lerntage',
streak: 'Streak: {n} Tage · letzte 7 Tage: {total} Reviews',
streak_one: 'Streak: 1 Tag · letzte 7 Tage: {total} Reviews',
fsrs_title: 'FSRS-Status',
fsrs_intro: 'Verteilung deiner Karten-Reviews über die FSRS-Zustände.',
fsrs_new: 'Neu',
fsrs_learning: 'Lernend',
fsrs_review: 'Review',
fsrs_relearning: 'Relearning',
loading: 'Lade…',
error: 'Fehler: {msg}',
},
common: {
empty: '(leer)',
skip_to_content: 'Zum Inhalt springen',
main_nav: 'Hauptnavigation',
notifications: 'Benachrichtigungen',
language_switcher: 'Sprache wechseln',
},
};