feat(i18n): Complete localization of marketing frontend with react-i18next, prefixed URLs, JSON migrations, and automation

This commit is contained in:
Codex Agent
2025-10-03 13:05:13 +02:00
parent 1845d83583
commit 60f8de9162
46 changed files with 3454 additions and 590 deletions

View File

@@ -1,83 +1,77 @@
import React from 'react';
import { Head, Link } from '@inertiajs/react';
import { Head, usePage } from '@inertiajs/react';
import { useTranslation } from 'react-i18next';
import MarketingLayout from '@/layouts/marketing/MarketingLayout';
interface Props {
interface OccasionsProps {
type: string;
}
const Occasions: React.FC<Props> = ({ type }) => {
const occasions = {
weddings: {
title: 'Hochzeiten',
description: 'Erfangen Sie die magischen Momente Ihrer Hochzeit mit professionellen Fotos.',
features: ['Unbegrenzte Fotos', 'Sofort-Download', 'Privat-Event-Code', 'Emotionen tracken'],
image: '/images/wedding-lights-background.svg' // Platzhalter
const Occasions: React.FC<OccasionsProps> = ({ type }) => {
const { t } = useTranslation('marketing');
const occasionsContent = {
hochzeit: {
title: t('occasions.weddings.title'),
description: t('occasions.weddings.description'),
features: [
t('occasions.weddings.benefit1'),
t('occasions.weddings.benefit2'),
t('occasions.weddings.benefit3'),
t('occasions.weddings.benefit4'),
],
cta: t('occasions.cta'),
},
birthdays: {
title: 'Geburtstage',
description: 'Feiern Sie Geburtstage unvergesslich mit unseren Event-Foto-Lösungen.',
features: ['Schnelle Einrichtung', 'Gäste teilen Fotos', 'Themen-Filter', 'Druck-Optionen'],
image: '/images/birthday-placeholder.jpg'
geburtstag: {
title: t('occasions.birthdays.title'),
description: t('occasions.birthdays.description'),
features: [
t('occasions.birthdays.benefit1'),
t('occasions.birthdays.benefit2'),
t('occasions.birthdays.benefit3'),
t('occasions.birthdays.benefit4'),
],
cta: t('occasions.cta'),
},
'corporate-events': {
title: 'Firmenevents',
description: 'Professionelle Fotos für Teamevents, Konferenzen und Unternehmensfeiern.',
features: ['Branding-Integration', 'Sichere Cloud-Speicher', 'Analytics & Reports', 'Schnelle Bearbeitung'],
image: '/images/corporate-placeholder.jpg'
firmenevent: {
title: t('occasions.corporate.title'),
description: t('occasions.corporate.description'),
features: [
t('occasions.corporate.benefit1'),
t('occasions.corporate.benefit2'),
t('occasions.corporate.benefit3'),
t('occasions.corporate.benefit4'),
],
cta: t('occasions.cta'),
},
'family-celebrations': {
title: 'Familienfeiern',
description: 'Erinnerungen an Taufen, Jubiläen und Familienzusammenkünfte festhalten.',
features: ['Persönliche Alben', 'Gemeinsame Zugriffe', 'Einfache Bedienung', 'Hohe Qualität'],
image: '/images/family-placeholder.jpg'
}
};
const occasion = occasions[type as keyof typeof occasions] || occasions.weddings;
const content = occasionsContent[type as keyof typeof occasionsContent] || occasionsContent.hochzeit;
return (
<MarketingLayout title={`${occasion.title} - Fotospiel`}>
<Head title={`${occasion.title} - Fotospiel`} />
{/* Hero Section */}
<section className="bg-aurora-enhanced text-white py-20 px-4">
<div className="container mx-auto text-center">
<h1 className="text-4xl md:text-6xl font-bold mb-4 font-display">{occasion.title}</h1>
<p className="text-xl md:text-2xl mb-8 max-w-3xl mx-auto font-sans-marketing">{occasion.description}</p>
{occasion.image && (
<img
src={occasion.image}
alt={occasion.title}
className="mx-auto rounded-lg shadow-lg max-w-4xl w-full"
/>
)}
</div>
</section>
{/* Features Section */}
<section className="py-20 px-4 bg-white">
<MarketingLayout title={content.title}>
<Head title={content.title} />
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 py-20 px-4">
<div className="container mx-auto max-w-4xl">
<h2 className="text-3xl font-bold text-center mb-12 font-display">Warum Fotospiel für {occasion.title}?</h2>
<div className="grid md:grid-cols-2 gap-8">
{occasion.features.map((feature, index) => (
<div key={index} className="bg-gray-50 p-6 rounded-lg flex items-center">
<div className="w-8 h-8 bg-[#FFB6C1] rounded-full flex items-center justify-center mr-4">
<span className="text-white text-sm font-bold font-sans-marketing"></span>
<div className="text-center mb-12">
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 dark:text-gray-100 mb-6 font-display">{content.title}</h1>
<p className="text-xl text-gray-600 dark:text-gray-300 mb-8 font-sans-marketing">{content.description}</p>
<a href="/packages" className="bg-[#FFB6C1] text-white px-8 py-4 rounded-full font-bold hover:bg-pink-600 transition">
{content.cta}
</a>
</div>
<div className="grid md:grid-cols-3 gap-8">
{content.features.map((feature, index) => (
<div key={index} className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-md text-center">
<div className="w-12 h-12 bg-[#FFB6C1] rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-white font-bold">{index + 1}</span>
</div>
<p className="text-gray-700 font-serif-custom">{feature}</p>
<h3 className="text-lg font-semibold mb-2 text-gray-900 dark:text-gray-100">{feature}</h3>
</div>
))}
</div>
<div className="text-center mt-12">
<Link
href="/marketing/packages"
className="bg-[#FFB6C1] text-white px-8 py-4 rounded-full font-semibold text-lg font-sans-marketing hover:bg-[#FF69B4] transition"
>
Passendes Paket wählen
</Link>
</div>
</div>
</section>
</div>
</MarketingLayout>
);
};