## Summary Fixes all 31 ❌ FAILs and most ⚠️ WARNs from the QA audit (113✅/33⚠️/31❌). ## Changes ### FIX 1 — Loading Skeleton - Replace full-screen GlobalLoader with PageBody-scoped animate-pulse skeleton - Sidebar stays visible during page transitions ### FIX 2 — Status Badges i18n (15 files, 12 label maps) - Add *_LABEL_KEYS maps to lib/status-badges.ts (i18n keys instead of German) - Update all 15 consumer files to use t(*_LABEL_KEYS[status]) - Add status namespace to finance.json (de+en) - Add registration_open to events.json status (de+en) - Add status block to cms.json events section (de+en) - Add missing pending/bounced keys to newsletter.json (de+en) - Add active key to courses.json status (de+en) ### FIX 3 — Error Page i18n - Replace 4 hardcoded German strings with useTranslations('common') - Add error.* keys to common.json (de+en) ### FIX 4 — Account Not Found i18n - Convert AccountNotFound to async Server Component - Resolve default props from getTranslations('common') - Add accountNotFoundCard.* keys to common.json (de+en) ### FIX 5 — Publish Toggle Button (6 strings + 2 bugs) - Add useTranslations('siteBuilder'), replace 6 German strings - Fix: add response.ok check before router.refresh() - Fix: add disabled={isPending} to AlertDialogAction - Fix: use Base UI render= prop pattern (not asChild) - Add pages.hide/publish/hideTitle/publishTitle/hideDesc/publishDesc/ toggleError/cancelAction to siteBuilder.json (de+en) ### FIX 6 — Cancel Booking Button (7 strings + bugs) - Add useTranslations('bookings'), replace all strings - Fix: use render= prop pattern, add disabled={isPending} - Add cancel.* and calendar.* keys to bookings.json (de+en) ### FIX 7 — Portal Pages i18n (5 files, ~40 strings) - Create i18n/messages/de/portal.json and en/portal.json - Add 'portal' to i18n/request.ts namespace list - Rewrite portal/page.tsx, invite/page.tsx, profile/page.tsx, documents/page.tsx with getTranslations('portal') - Fix portal-linked-accounts.tsx: add useTranslations, replace hardcoded strings, fix AlertDialogTrigger render= pattern ### FIX 8 — Invitations View (1 string) - Replace hardcoded string with t('invitations.emptyDescription') - Add key to members.json (de+en) ### FIX 9 — Dead Navigation Link - Comment out memberPortal nav entry (page does not exist) ### FIX 10 — Calendar Button Accessibility - Add aria-label + aria-hidden to all icon buttons in bookings/calendar - Add aria-label + aria-hidden to all icon buttons in courses/calendar - Add previousMonth/nextMonth/backToBookings/backToCourses to bookings.json and courses.json (de+en) ### FIX 11 — Pagination Aria Labels - Add aria-label to icon-only pagination buttons in finance/page.tsx - Fix Link/Button nesting in newsletter/page.tsx, add aria-labels - Add pagination.* to common.json (de+en) - Add common.previous/next to newsletter.json (de+en) ### FIX 12 — Site Builder Type Safety - Add SitePage interface, replace Record<string,unknown> in page.tsx - Add SitePost interface, replace Record<string,unknown> in posts/page.tsx - Remove String() casts on typed properties ### FIX 14 — EmptyState Heading Level - Change <h3> to <h2> in empty-state.tsx (WCAG heading sequence) ### FIX 16 — CmsPageShell Nullish Coalescing - Change description ?? <AppBreadcrumbs /> to !== undefined check ### FIX 17 — Meetings Protocol Hardcoded Strings - Replace 5 hardcoded German strings with t() in protocol detail page - Add notFound/back/backToList/statusPublished/statusDraft to meetings.json ### FIX 18 — Finance Toolbar Hardcoded Strings - Replace toolbar filter labels with t() calls in finance/page.tsx ### FIX 19 — Admin Audit Hardcoded Strings - Add getTranslations('cms.audit') to audit page - Replace title, description, column headers, pagination labels - Add description/timestamp/paginationPrevious/paginationNext to cms.json ## Verification - tsc --noEmit: 0 errors - Turbopack: Compiled successfully in 9.3s - Lint: 0 new errors introduced - All 8 audit verification checks pass
203 lines
7.0 KiB
JSON
203 lines
7.0 KiB
JSON
{
|
||
"nav": {
|
||
"members": "Mitglieder",
|
||
"newMember": "Neues Mitglied",
|
||
"applications": "Aufnahmeanträge",
|
||
"dues": "Beitragskategorien",
|
||
"departments": "Abteilungen",
|
||
"cards": "Mitgliedsausweise",
|
||
"import": "Import",
|
||
"statistics": "Statistiken",
|
||
"invitations": "Portal-Einladungen"
|
||
},
|
||
"list": {
|
||
"searchPlaceholder": "Name, E-Mail oder Mitgliedsnr. suchen...",
|
||
"title": "Mitglieder ({count})",
|
||
"noMembers": "Keine Mitglieder gefunden",
|
||
"createFirst": "Erstellen Sie Ihr erstes Mitglied, um loszulegen.",
|
||
"newMember": "Neues Mitglied"
|
||
},
|
||
"detail": {
|
||
"personalData": "Persönliche Daten",
|
||
"firstName": "Vorname",
|
||
"lastName": "Nachname",
|
||
"dateOfBirth": "Geburtsdatum",
|
||
"gender": "Geschlecht",
|
||
"salutation": "Anrede",
|
||
"age": "{age} Jahre",
|
||
"contactData": "Kontaktdaten",
|
||
"email": "E-Mail",
|
||
"phone": "Telefon",
|
||
"mobile": "Mobil",
|
||
"address": "Adresse",
|
||
"street": "Straße",
|
||
"houseNumber": "Hausnummer",
|
||
"postalCode": "PLZ",
|
||
"city": "Ort",
|
||
"country": "Land",
|
||
"membership": "Mitgliedschaft",
|
||
"memberNumber": "Mitgliedsnr.",
|
||
"status": "Status",
|
||
"entryDate": "Eintrittsdatum",
|
||
"exitDate": "Austrittsdatum",
|
||
"exitReason": "Austrittsgrund",
|
||
"membershipYears": "{years} Jahre",
|
||
"bankData": "Bankdaten",
|
||
"iban": "IBAN",
|
||
"bic": "BIC",
|
||
"accountHolder": "Kontoinhaber",
|
||
"editMember": "Bearbeiten",
|
||
"terminateMember": "Kündigen",
|
||
"terminateConfirm": "Möchten Sie {name} wirklich kündigen?",
|
||
"terminated": "Mitglied wurde gekündigt",
|
||
"errorTerminating": "Fehler beim Kündigen",
|
||
"reactivated": "Mitglied wurde reaktiviert",
|
||
"errorReactivating": "Fehler beim Reaktivieren",
|
||
"notFound": "Mitglied nicht gefunden"
|
||
},
|
||
"form": {
|
||
"createTitle": "Neues Mitglied anlegen",
|
||
"editTitle": "Mitglied bearbeiten",
|
||
"newMemberTitle": "Neues Mitglied",
|
||
"newMemberDescription": "Mitglied manuell anlegen",
|
||
"created": "Mitglied erfolgreich erstellt",
|
||
"updated": "Mitglied aktualisiert",
|
||
"errorCreating": "Fehler beim Erstellen",
|
||
"errorUpdating": "Fehler beim Aktualisieren",
|
||
"gdprConsent": "DSGVO-Einwilligung",
|
||
"notes": "Notizen"
|
||
},
|
||
"status": {
|
||
"active": "Aktiv",
|
||
"inactive": "Inaktiv",
|
||
"pending": "Ausstehend",
|
||
"resigned": "Ausgetreten",
|
||
"excluded": "Ausgeschlossen",
|
||
"deceased": "Verstorben"
|
||
},
|
||
"invitations": {
|
||
"title": "Portal-Einladungen",
|
||
"subtitle": "Einladungen zum Mitgliederportal verwalten",
|
||
"emailPlaceholder": "E-Mail eingeben...",
|
||
"emptyDescription": "Senden Sie die erste Einladung zum Mitgliederportal."
|
||
},
|
||
"applications": {
|
||
"title": "Aufnahmeanträge ({count})",
|
||
"subtitle": "Mitgliedsanträge bearbeiten",
|
||
"noApplications": "Keine offenen Aufnahmeanträge",
|
||
"approve": "Genehmigen",
|
||
"reject": "Ablehnen",
|
||
"approved": "Antrag genehmigt – Mitglied erstellt",
|
||
"rejected": "Antrag abgelehnt",
|
||
"errorApproving": "Fehler bei der Genehmigung",
|
||
"errorRejecting": "Fehler bei der Ablehnung",
|
||
"approveConfirm": "Antrag von {name} genehmigen?",
|
||
"rejectConfirm": "Antrag von {name} ablehnen? Bitte Grund angeben:",
|
||
"submitted": "Eingereicht"
|
||
},
|
||
"dues": {
|
||
"title": "Beitragskategorien",
|
||
"subtitle": "Mitgliedsbeiträge verwalten",
|
||
"name": "Name",
|
||
"description": "Beschreibung",
|
||
"amount": "Betrag",
|
||
"interval": "Intervall",
|
||
"default": "Standard",
|
||
"monthly": "Monatlich",
|
||
"quarterly": "Vierteljährlich",
|
||
"semiannual": "Halbjährlich",
|
||
"annual": "Jährlich",
|
||
"create": "Erstellen",
|
||
"created": "Beitragskategorie erstellt",
|
||
"deleted": "Beitragskategorie gelöscht",
|
||
"errorCreating": "Fehler beim Erstellen",
|
||
"errorDeleting": "Fehler beim Löschen",
|
||
"deleteConfirm": "Beitragskategorie \"{name}\" wirklich löschen?",
|
||
"noCategories": "Keine Beitragskategorien vorhanden."
|
||
},
|
||
"mandates": {
|
||
"title": "SEPA-Mandate",
|
||
"iban": "IBAN *",
|
||
"bic": "BIC",
|
||
"accountHolder": "Kontoinhaber *",
|
||
"mandateDate": "Mandatsdatum",
|
||
"primary": "Primär",
|
||
"createMandate": "Mandat anlegen",
|
||
"revoke": "Widerrufen",
|
||
"revokeConfirm": "Mandat \"{reference}\" wirklich widerrufen?",
|
||
"created": "SEPA-Mandat erstellt",
|
||
"revoked": "Mandat widerrufen",
|
||
"errorCreating": "Fehler beim Erstellen",
|
||
"errorRevoking": "Fehler beim Widerrufen"
|
||
},
|
||
"departments": {
|
||
"title": "Abteilungen",
|
||
"subtitle": "Sparten und Abteilungen verwalten",
|
||
"noDepartments": "Keine Abteilungen vorhanden.",
|
||
"createFirst": "Erstellen Sie Ihre erste Abteilung.",
|
||
"newDepartment": "Neue Abteilung",
|
||
"name": "Name",
|
||
"namePlaceholder": "z. B. Jugendabteilung",
|
||
"description": "Beschreibung",
|
||
"descriptionPlaceholder": "Kurze Beschreibung",
|
||
"actions": "Aktionen",
|
||
"created": "Abteilung erstellt",
|
||
"createError": "Fehler beim Erstellen der Abteilung",
|
||
"createDialogDescription": "Erstellen Sie eine neue Abteilung oder Sparte für Ihren Verein.",
|
||
"descriptionLabel": "Beschreibung (optional)",
|
||
"creating": "Wird erstellt…",
|
||
"create": "Erstellen",
|
||
"deleteTitle": "Abteilung löschen?",
|
||
"deleteConfirm": "\"{name}\" wird unwiderruflich gelöscht. Mitglieder dieser Abteilung werden keiner Abteilung mehr zugeordnet.",
|
||
"delete": "Löschen",
|
||
"deleteAria": "Abteilung löschen",
|
||
"cancel": "Abbrechen"
|
||
},
|
||
"cards": {
|
||
"title": "Mitgliedsausweise",
|
||
"subtitle": "Ausweise erstellen und verwalten",
|
||
"noMembers": "Keine aktiven Mitglieder",
|
||
"noMembersDesc": "Erstellen Sie zuerst Mitglieder, um Ausweise zu generieren.",
|
||
"inDevelopment": "Feature in Entwicklung",
|
||
"inDevelopmentDesc": "Die Ausweiserstellung für {count} aktive Mitglieder wird derzeit entwickelt. Diese Funktion wird in einem kommenden Update verfügbar sein.",
|
||
"manageMembersLabel": "Mitglieder verwalten",
|
||
"memberCard": "MITGLIEDSAUSWEIS",
|
||
"memberSince": "Mitglied seit",
|
||
"validUntil": "Gültig bis",
|
||
"generate": "Ausweise generieren",
|
||
"download": "Herunterladen"
|
||
},
|
||
"import": {
|
||
"title": "Mitglieder importieren",
|
||
"subtitle": "CSV-Datei importieren",
|
||
"selectFile": "CSV-Datei auswählen",
|
||
"mapColumns": "Spalten zuordnen",
|
||
"preview": "Vorschau",
|
||
"importing": "Wird importiert...",
|
||
"imported": "{count} Mitglieder erfolgreich importiert",
|
||
"errorImporting": "Fehler beim Import"
|
||
},
|
||
"statistics": {
|
||
"title": "Mitglieder-Statistiken",
|
||
"totalMembers": "Gesamtmitglieder",
|
||
"activeMembers": "Aktive Mitglieder",
|
||
"newThisYear": "Neue dieses Jahr",
|
||
"resignedThisYear": "Ausgetreten dieses Jahr"
|
||
},
|
||
"export": {
|
||
"csv": "CSV exportieren",
|
||
"excel": "Excel exportieren",
|
||
"memberNumber": "Mitgliedsnr.",
|
||
"firstName": "Vorname",
|
||
"lastName": "Nachname",
|
||
"email": "E-Mail",
|
||
"phone": "Telefon",
|
||
"postalCode": "PLZ",
|
||
"city": "Ort",
|
||
"status": "Status",
|
||
"entryDate": "Eintrittsdatum",
|
||
"iban": "IBAN",
|
||
"bic": "BIC",
|
||
"accountHolder": "Kontoinhaber"
|
||
}
|
||
} |