feat: implement comprehensive i18n system with German and English support
- Created type-safe i18n system with TranslationKeys interface - Added German (de) and English (en) translations with 160+ keys - Implemented I18nContext provider and useI18n hook - Added LanguageSwitcher component for language selection - Refactored all major components to use translations: * Home page, StatsDashboard, DramOfTheDay * BottleGrid, EditBottleForm, CameraCapture * BuddyList, SessionList, TastingNoteForm * StatusSwitcher and bottle management features - Implemented locale-aware currency formatting (EUR) - Implemented locale-aware date formatting - Added localStorage persistence for language preference - Added automatic browser language detection - Organized translations into 8 main categories - System is extensible for additional languages
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Sparkles, GlassWater, Dices, X } from 'lucide-react';
|
||||
import { useI18n } from '@/i18n/I18nContext';
|
||||
import Link from 'next/link';
|
||||
|
||||
interface Bottle {
|
||||
@@ -16,6 +17,7 @@ interface DramOfTheDayProps {
|
||||
}
|
||||
|
||||
export default function DramOfTheDay({ bottles }: DramOfTheDayProps) {
|
||||
const { t } = useI18n();
|
||||
const [suggestion, setSuggestion] = useState<Bottle | null>(null);
|
||||
const [isRolling, setIsRolling] = useState(false);
|
||||
|
||||
@@ -24,7 +26,7 @@ export default function DramOfTheDay({ bottles }: DramOfTheDayProps) {
|
||||
const openBottles = bottles.filter(b => b.status === 'open' || b.status === 'sampled');
|
||||
|
||||
if (openBottles.length === 0) {
|
||||
alert('Keine offenen Flaschen gefunden! Vielleicht Zeit für ein neues Tasting? 🥃');
|
||||
alert(t('home.dramOfDay.noOpenBottles'));
|
||||
setIsRolling(false);
|
||||
return;
|
||||
}
|
||||
@@ -49,7 +51,7 @@ export default function DramOfTheDay({ bottles }: DramOfTheDayProps) {
|
||||
) : (
|
||||
<Sparkles size={18} />
|
||||
)}
|
||||
Dram of the Day
|
||||
{t('home.dramOfDay.button')}
|
||||
</button>
|
||||
|
||||
{suggestion && (
|
||||
@@ -68,7 +70,7 @@ export default function DramOfTheDay({ bottles }: DramOfTheDayProps) {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-amber-600">Dein heutiger Dram</h3>
|
||||
<h3 className="text-[10px] font-black uppercase tracking-[0.2em] text-amber-600">{t('home.dramOfDay.title')}</h3>
|
||||
<h2 className="text-2xl font-black text-zinc-900 dark:text-white leading-tight">
|
||||
{suggestion.name}
|
||||
</h2>
|
||||
@@ -83,13 +85,13 @@ export default function DramOfTheDay({ bottles }: DramOfTheDayProps) {
|
||||
onClick={() => setSuggestion(null)}
|
||||
className="block w-full py-4 bg-zinc-900 dark:bg-zinc-100 text-white dark:text-zinc-900 rounded-2xl font-black uppercase tracking-widest text-xs hover:bg-amber-600 dark:hover:bg-amber-600 hover:text-white transition-all shadow-xl"
|
||||
>
|
||||
Flasche anschauen
|
||||
{t('home.dramOfDay.viewBottle')}
|
||||
</Link>
|
||||
<button
|
||||
onClick={suggestDram}
|
||||
className="w-full mt-3 py-2 text-zinc-400 hover:text-amber-600 text-[10px] font-black uppercase tracking-widest transition-colors"
|
||||
>
|
||||
Nicht heute, noch mal würfeln
|
||||
{t('home.dramOfDay.rollAgain')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user