From 0a203d16cfd190d1296eddba5ba434caa454247a Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 9 Jul 2025 09:25:15 +0200 Subject: [PATCH] Fix translation issues in event creation and detail pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add missing translation keys for event creation form - Replace all hardcoded strings with translation keys in CreateEventPage - Add validation error message translations - Add event types and color theme translations - Add errors and validation sections to translation files - Update German translations with corresponding keys 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- frontend/src/i18n/locales/de.json | 59 +++++++++- frontend/src/i18n/locales/en.json | 42 ++++++- frontend/src/pages/admin/CreateEventPage.tsx | 110 +++++++++---------- 3 files changed, 153 insertions(+), 58 deletions(-) diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index b6cc87b..05b1ad5 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -28,7 +28,8 @@ "refresh": "Aktualisieren", "preview": "Vorschau", "processing": "Wird verarbeitet...", - "upload": "Hochladen" + "upload": "Hochladen", + "days": "Tage" }, "upload": { "photoCategory": "Fotokategorie", @@ -245,6 +246,30 @@ "days365": "1 Jahr", "createNewEvent": "Neue Veranstaltung erstellen", "setupNewGallery": "Richten Sie eine neue Fotogalerie für Ihre Veranstaltung ein", + "createNewEventSubtitle": "Richten Sie eine neue Fotogalerie für Ihre Veranstaltung ein", + "eventNamePlaceholder": "z.B. Max & Maria's Hochzeit", + "welcomeMessageOptional": "Willkommensnachricht (Optional)", + "welcomeMessagePlaceholder": "Willkommen zu unserem besonderen Tag! Laden Sie diese Erinnerungen gerne herunter und teilen Sie sie...", + "hostEmailPlaceholder": "gastgeber@beispiel.de", + "adminEmailPlaceholder": "admin@beispiel.de", + "securityAndAccess": "Sicherheit & Zugriff", + "enterPassword": "Passwort eingeben", + "confirmPasswordPlaceholder": "Passwort bestätigen", + "galleryExpiresOn": "Galerie läuft ab am {{date}}", + "guestsWillReceiveWarning": "Gäste erhalten 7 Tage vor Ablauf eine Warn-E-Mail.", + "types": { + "wedding": "Hochzeit", + "birthday": "Geburtstag", + "corporate": "Geschäftlich", + "other": "Andere" + }, + "themes": { + "default": "Standard", + "oceanBlue": "Ozeanblau", + "royalPurple": "Königliches Lila", + "roseGold": "Roségold", + "sunsetAmber": "Sonnenuntergang Bernstein" + }, "adminNotificationEmail": "Admin-Benachrichtigungs-E-Mail", "inactive": "Inaktiv", "expired": "Abgelaufen", @@ -602,6 +627,38 @@ "datenschutz": "Datenschutzerklärung", "pageUpdated": "Seite erfolgreich aktualisiert" }, + "errors": { + "notFound": "Nicht gefunden", + "galleryNotFound": "Galerie nicht gefunden", + "galleryNotFoundMessage": "Diese Galerie existiert nicht oder wurde entfernt.", + "galleryArchived": "Galerie archiviert", + "galleryArchivedMessage": "Diese Galerie wurde archiviert und ist nicht mehr zugänglich. Bitte kontaktieren Sie den Veranstalter, wenn Sie Zugriff auf diese Fotos benötigen.", + "unauthorized": "Nicht autorisiert", + "forbidden": "Verboten", + "serverError": "Serverfehler", + "somethingWentWrong": "Etwas ist schiefgelaufen", + "tryAgainLater": "Bitte versuchen Sie es später erneut", + "refreshPage": "Seite aktualisieren", + "oopsSomethingWentWrong": "Hoppla! Etwas ist schiefgelaufen", + "unexpectedError": "Ein unerwarteter Fehler ist aufgetreten. Keine Sorge, Ihre Daten sind sicher.", + "goToHomepage": "Zur Startseite", + "errorDetails": "Fehlerdetails", + "requiredFields": "Bitte füllen Sie alle Pflichtfelder aus", + "enterTestEmail": "Bitte geben Sie eine Test-E-Mail-Adresse ein", + "failedToCreateEvent": "Veranstaltung konnte nicht erstellt werden", + "networkError": "Netzwerkfehler. Bitte überprüfen Sie Ihre Verbindung und versuchen Sie es erneut.", + "sessionExpired": "Sitzung abgelaufen. Bitte melden Sie sich erneut an." + }, + "validation": { + "eventNameRequired": "Veranstaltungsname ist erforderlich", + "hostEmailRequired": "Gastgeber-E-Mail ist erforderlich", + "adminEmailRequired": "Admin-E-Mail ist erforderlich", + "invalidEmailFormat": "Ungültiges E-Mail-Format", + "passwordRequired": "Passwort ist erforderlich", + "passwordMinLength": "Passwort muss mindestens 6 Zeichen lang sein", + "passwordsDoNotMatch": "Passwörter stimmen nicht überein", + "expirationRange": "Ablauf muss zwischen 1 und 365 Tagen liegen" + }, "maintenance": { "title": "Systemwartung", "message": "Wir führen derzeit geplante Wartungsarbeiten durch, um unseren Service zu verbessern. Wir sind in Kürze wieder online.", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 0ccc1d6..2539e92 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -28,7 +28,8 @@ "refresh": "Refresh", "preview": "Preview", "processing": "Processing...", - "upload": "Upload" + "upload": "Upload", + "days": "days" }, "upload": { "photoCategory": "Photo Category", @@ -165,6 +166,30 @@ "createEvent": "Create Event", "createNewEvent": "Create New Event", "setupNewGallery": "Set up a new photo gallery for your event", + "createNewEventSubtitle": "Set up a new photo gallery for your event", + "eventNamePlaceholder": "e.g., John & Jane's Wedding", + "welcomeMessageOptional": "Welcome Message (Optional)", + "welcomeMessagePlaceholder": "Welcome to our special day! Feel free to download and share these memories...", + "hostEmailPlaceholder": "host@example.com", + "adminEmailPlaceholder": "admin@example.com", + "securityAndAccess": "Security & Access", + "enterPassword": "Enter password", + "confirmPasswordPlaceholder": "Confirm password", + "galleryExpiresOn": "Gallery will expire on {{date}}", + "guestsWillReceiveWarning": "Guests will receive a warning email 7 days before expiration.", + "types": { + "wedding": "Wedding", + "birthday": "Birthday", + "corporate": "Corporate", + "other": "Other" + }, + "themes": { + "default": "Default", + "oceanBlue": "Ocean Blue", + "royalPurple": "Royal Purple", + "roseGold": "Rose Gold", + "sunsetAmber": "Sunset Amber" + }, "eventDetails": "Event Details", "eventName": "Event Name", "eventType": "Event Type", @@ -548,7 +573,20 @@ "goToHomepage": "Go to Homepage", "errorDetails": "Error Details", "requiredFields": "Please fill in all required fields", - "enterTestEmail": "Please enter a test email address" + "enterTestEmail": "Please enter a test email address", + "failedToCreateEvent": "Failed to create event", + "networkError": "Network error. Please check your connection and try again.", + "sessionExpired": "Session expired. Please login again." + }, + "validation": { + "eventNameRequired": "Event name is required", + "hostEmailRequired": "Host email is required", + "adminEmailRequired": "Admin email is required", + "invalidEmailFormat": "Invalid email format", + "passwordRequired": "Password is required", + "passwordMinLength": "Password must be at least 6 characters", + "passwordsDoNotMatch": "Passwords do not match", + "expirationRange": "Expiration must be between 1 and 365 days" }, "legal": { "impressum": "Legal Notice", diff --git a/frontend/src/pages/admin/CreateEventPage.tsx b/frontend/src/pages/admin/CreateEventPage.tsx index 5419de4..a7756a1 100644 --- a/frontend/src/pages/admin/CreateEventPage.tsx +++ b/frontend/src/pages/admin/CreateEventPage.tsx @@ -34,16 +34,16 @@ interface FormData { } const EVENT_TYPES = [ - { value: 'wedding', label: 'Wedding', emoji: '💒' }, - { value: 'birthday', label: 'Birthday', emoji: '🎂' }, - { value: 'corporate', label: 'Corporate', emoji: '🏢' }, - { value: 'other', label: 'Other', emoji: '📸' }, + { value: 'wedding', labelKey: 'events.types.wedding', emoji: '💒' }, + { value: 'birthday', labelKey: 'events.types.birthday', emoji: '🎂' }, + { value: 'corporate', labelKey: 'events.types.corporate', emoji: '🏢' }, + { value: 'other', labelKey: 'events.types.other', emoji: '📸' }, ]; const COLOR_THEMES = [ { value: 'default', - label: 'Default (Green)', + labelKey: 'events.themes.default', color: 'bg-primary-600', theme: { primaryColor: '#5C8762', @@ -55,7 +55,7 @@ const COLOR_THEMES = [ }, { value: 'blue', - label: 'Ocean Blue', + labelKey: 'events.themes.oceanBlue', color: 'bg-blue-600', theme: { primaryColor: '#2563eb', @@ -67,7 +67,7 @@ const COLOR_THEMES = [ }, { value: 'purple', - label: 'Royal Purple', + labelKey: 'events.themes.royalPurple', color: 'bg-purple-600', theme: { primaryColor: '#9333ea', @@ -79,7 +79,7 @@ const COLOR_THEMES = [ }, { value: 'rose', - label: 'Rose Gold', + labelKey: 'events.themes.roseGold', color: 'bg-rose-600', theme: { primaryColor: '#e11d48', @@ -91,7 +91,7 @@ const COLOR_THEMES = [ }, { value: 'amber', - label: 'Sunset Amber', + labelKey: 'events.themes.sunsetAmber', color: 'bg-amber-600', theme: { primaryColor: '#d97706', @@ -142,7 +142,7 @@ export const CreateEventPage: React.FC = () => { mutationFn: eventsService.createEvent, onSuccess: (data) => { if (isMountedRef.current) { - toast.success('Event created successfully!'); + toast.success(t('toast.eventCreated')); // Add a small delay to ensure navigation works properly setTimeout(() => { if (isMountedRef.current && data?.id) { @@ -157,7 +157,7 @@ export const CreateEventPage: React.FC = () => { if (!isMountedRef.current) return; if (error.code === 'ERR_NETWORK' || error.code === 'ERR_CONNECTION_RESET') { - toast.error('Network error. Please check your connection and try again.'); + toast.error(t('errors.networkError')); } else if (error.response?.data?.errors) { const newErrors: Record = {}; error.response.data.errors.forEach((err: any) => { @@ -165,10 +165,10 @@ export const CreateEventPage: React.FC = () => { }); setErrors(newErrors); } else if (error.response?.status === 401) { - toast.error('Session expired. Please login again.'); + toast.error(t('errors.sessionExpired')); navigate('/admin/login'); } else { - toast.error(error.response?.data?.error || 'Failed to create event'); + toast.error(error.response?.data?.error || t('errors.failedToCreateEvent')); } }, }); @@ -177,33 +177,33 @@ export const CreateEventPage: React.FC = () => { const newErrors: Partial> = {}; if (!formData.event_name.trim()) { - newErrors.event_name = 'Event name is required'; + newErrors.event_name = t('validation.eventNameRequired'); } if (!formData.host_email) { - newErrors.host_email = 'Host email is required'; + newErrors.host_email = t('validation.hostEmailRequired'); } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.host_email)) { - newErrors.host_email = 'Invalid email format'; + newErrors.host_email = t('validation.invalidEmailFormat'); } if (!formData.admin_email) { - newErrors.admin_email = 'Admin email is required'; + newErrors.admin_email = t('validation.adminEmailRequired'); } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.admin_email)) { - newErrors.admin_email = 'Invalid email format'; + newErrors.admin_email = t('validation.invalidEmailFormat'); } if (!formData.password) { - newErrors.password = 'Password is required'; + newErrors.password = t('validation.passwordRequired'); } else if (formData.password.length < 6) { - newErrors.password = 'Password must be at least 6 characters'; + newErrors.password = t('validation.passwordMinLength'); } if (formData.password !== formData.confirm_password) { - newErrors.confirm_password = 'Passwords do not match'; + newErrors.confirm_password = t('validation.passwordsDoNotMatch'); } if (formData.expires_in_days < 1 || formData.expires_in_days > 365) { - newErrors.expires_in_days = 'Expiration must be between 1 and 365 days'; + newErrors.expires_in_days = t('validation.expirationRange'); } setErrors(newErrors); @@ -257,23 +257,23 @@ export const CreateEventPage: React.FC = () => { onClick={() => navigate('/admin/events')} className="mb-4" > - Back to Events + {t('events.backToEvents')} -

Create New Event

-

Set up a new photo gallery for your event

+

{t('events.createNewEvent')}

+

{t('events.createNewEventSubtitle')}

{/* Event Details */} -

Event Details

+

{t('events.eventDetails')}

{/* Event Type */}
{EVENT_TYPES.map(type => ( @@ -288,7 +288,7 @@ export const CreateEventPage: React.FC = () => { }`} >
{type.emoji}
-
{type.label}
+
{t(type.labelKey)}
))}
@@ -297,7 +297,7 @@ export const CreateEventPage: React.FC = () => { {/* Event Name */}
{ value={formData.event_name} onChange={handleInputChange('event_name')} error={errors.event_name} - placeholder="e.g., Smith-Jones Wedding" + placeholder={t('events.eventNamePlaceholder')} leftIcon={} />
@@ -313,7 +313,7 @@ export const CreateEventPage: React.FC = () => { {/* Event Date */}
{ {/* Welcome Message */}