diff --git a/hifi-src/src/components/CookieConsentBanner.jsx b/hifi-src/src/components/CookieConsentBanner.jsx index f11f58a..af10d78 100644 --- a/hifi-src/src/components/CookieConsentBanner.jsx +++ b/hifi-src/src/components/CookieConsentBanner.jsx @@ -1,10 +1,12 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { Link } from 'react-router-dom'; import { useCookieConsent } from '../context/CookieConsentContext.jsx'; +import { useLanguage } from '../context/LanguageContext.jsx'; function SettingsModal({ onClose }) { const { consent, saveCustom } = useCookieConsent(); const [external, setExternal] = useState(consent.external); + const { t } = useLanguage(); return (
e.stopPropagation()} > -

Cookie-Einstellungen

+

{t('cookieConsent.modalTitle')}

- Lege fest, welche Kategorien du zulassen möchtest. Mehr dazu in unserer{' '} + {t('cookieConsent.modalIntro')}{' '} - Datenschutzerklärung + {t('cookieConsent.privacyPolicy')} .

-

Notwendig

+

{t('cookieConsent.necessaryTitle')}

- Für den Betrieb der Website erforderlich (z. B. Login-Session, Theme- und Cookie-Einstellung). - Kann nicht deaktiviert werden. + {t('cookieConsent.necessaryDesc')}

-

Externe Medien

+

{t('cookieConsent.externalTitle')}

- Google Maps und YouTube-Videos. Beim Laden werden Daten (u. a. deine IP-Adresse) an Google - übertragen. + {t('cookieConsent.externalDesc')}

- Abbrechen + {t('cookieConsent.cancel')}
@@ -73,6 +73,7 @@ function SettingsModal({ onClose }) { export default function CookieConsentBanner() { const { decided, settingsOpen, acceptAll, rejectNonEssential, openSettings, closeSettings } = useCookieConsent(); + const { t } = useLanguage(); return ( <> @@ -80,10 +81,9 @@ export default function CookieConsentBanner() {

- Wir verwenden nur technisch notwendige Cookies. Für Google Maps und YouTube-Videos benötigen wir - zusätzlich deine Zustimmung, da dabei Daten an Google übertragen werden. Mehr dazu in unserer{' '} + {t('cookieConsent.bannerText')} {t('cookieConsent.moreInfo')}{' '} - Datenschutzerklärung + {t('cookieConsent.privacyPolicy')} .

@@ -93,21 +93,21 @@ export default function CookieConsentBanner() { onClick={openSettings} className="rounded-md border border-neutral-300 px-3 py-2 text-sm dark:border-neutral-700" > - Einstellungen + {t('cookieConsent.settings')}
diff --git a/hifi-src/src/components/Footer.jsx b/hifi-src/src/components/Footer.jsx index b04a052..57bc03d 100644 --- a/hifi-src/src/components/Footer.jsx +++ b/hifi-src/src/components/Footer.jsx @@ -2,24 +2,20 @@ import { Link, useLocation } from 'react-router-dom'; import DynamicIcon from './DynamicIcon.jsx'; import { useCookieConsent } from '../context/CookieConsentContext.jsx'; import { useSiteSettings } from '../context/SiteSettingsContext.jsx'; +import { useLanguage } from '../context/LanguageContext.jsx'; const digitsOnly = (value) => (value || '').replace(/[^\d+]/g, ''); const SHOP_ADDRESS_ENCODED = encodeURIComponent('Boxbrunner Str. 20a, 63916 Amorbach'); const DIRECTIONS_URL = `https://www.google.com/maps/dir/?api=1&destination=${SHOP_ADDRESS_ENCODED}`; -const HOURS = [ - { days: 'Montag – Freitag', from: 9 * 60, to: 18 * 60, label: '9:00–18:00 Uhr' }, - { days: 'Samstag', from: 10 * 60, to: 13 * 60, label: '10:00–13:00 Uhr' }, - { days: 'Sonntag', from: null, to: null, label: 'Geschlossen' }, -]; - function isOpenNow() { const now = new Date(); const minutes = now.getHours() * 60 + now.getMinutes(); const day = now.getDay(); // 0 = Sonntag, 1-5 = Mo-Fr, 6 = Sa - const todayHours = day === 0 ? HOURS[2] : day === 6 ? HOURS[1] : HOURS[0]; - return todayHours.from !== null && minutes >= todayHours.from && minutes < todayHours.to; + if (day === 0) return false; + if (day === 6) return minutes >= 10 * 60 && minutes < 13 * 60; + return minutes >= 9 * 60 && minutes < 18 * 60; } export default function Footer() { @@ -31,6 +27,13 @@ export default function Footer() { const { pathname } = useLocation(); const isHome = pathname === '/'; const { phone, contact_email: contactEmail } = useSiteSettings(); + const { t } = useLanguage(); + + const HOURS = [ + { key: 'monFri', days: t('footer.days.monFri'), label: t('contactPage.hoursWeek') }, + { key: 'sat', days: t('footer.days.sat'), label: t('contactPage.hoursSat') }, + { key: 'sun', days: t('footer.days.sun'), label: t('footer.closed') }, + ]; return (
-

Kontakt

+

{t('footer.contactHeading')}

{phone} @@ -72,7 +75,7 @@ export default function Footer() { to="/kontakt" className="mt-4 flex items-center justify-center gap-1.5 rounded-md border border-neutral-300 px-3 py-2 text-xs font-semibold text-neutral-700 hover:border-brand-500 hover:text-brand-600 dark:border-neutral-700 dark:text-neutral-200" > - Kontaktformular + {t('footer.contactForm')}

@@ -80,7 +83,7 @@ export default function Footer() {
-

Öffnungszeiten

+

{t('footer.hoursHeading')}

- {open ? 'Geöffnet' : 'Geschlossen'} + {open ? t('footer.open') : t('footer.closed')}
{HOURS.map((row) => ( -
+
{row.days}
{row.label}
@@ -105,16 +108,16 @@ export default function Footer() {

- © {new Date().getFullYear()} HifiPlanet. Alle Angaben ohne Gewähr. + {t('footer.copyright')(new Date().getFullYear())} · - Impressum + {t('footer.imprint')} · - Datenschutz + {t('footer.privacy')} · - AGB + {t('footer.terms')} ·

diff --git a/hifi-src/src/components/Lightbox.jsx b/hifi-src/src/components/Lightbox.jsx index c29f421..4f8f5c1 100644 --- a/hifi-src/src/components/Lightbox.jsx +++ b/hifi-src/src/components/Lightbox.jsx @@ -1,7 +1,9 @@ import { useEffect } from 'react'; import { createPortal } from 'react-dom'; +import { useLanguage } from '../context/LanguageContext.jsx'; export default function Lightbox({ photos, index, onClose, onNavigate }) { + const { t } = useLanguage(); useEffect(() => { if (index == null) return undefined; const handleKey = (e) => { @@ -21,7 +23,7 @@ export default function Lightbox({ photos, index, onClose, onNavigate }) {
+ + {isOpen && ( +
+ {LANGUAGE_OPTIONS.map((opt) => ( + + ))} +
+ )} +
+ ); +} + export default function Navbar() { const [open, setOpen] = useState(false); const [mounted, setMounted] = useState(false); const [menuVisible, setMenuVisible] = useState(false); const { user } = useAuth(); const { phone, whatsapp } = useSiteSettings(); - const totalItems = whatsapp ? 8 : 7; + const { t } = useLanguage(); + const totalItems = whatsapp ? 9 : 8; const location = useLocation(); const isHome = location.pathname === '/'; const [scrolled, setScrolled] = useState(!isHome); @@ -74,8 +196,8 @@ export default function Navbar() { const AdminIcon = user && ( setOpen(false)} className={`text-3xl font-extrabold tracking-tight text-neutral-900 hover:text-brand-600 ${flyIn()}`} style={flyInStyle(0)}> - Fahrzeuge - - setOpen(false)} className={`text-3xl font-extrabold tracking-tight text-neutral-900 hover:text-brand-600 ${flyIn()}`} style={flyInStyle(1)}> - Leistungen - - setOpen(false)} className={`text-3xl font-extrabold tracking-tight text-neutral-900 hover:text-brand-600 ${flyIn()}`} style={flyInStyle(2)}> - Galerie - - setOpen(false)} className={`text-3xl font-extrabold tracking-tight text-neutral-900 hover:text-brand-600 ${flyIn()}`} style={flyInStyle(3)}> - Kontakt - + {t('nav.vehicles')} + + setOpen(false)} className={`text-3xl font-extrabold tracking-tight text-neutral-900 hover:text-brand-600 ${flyIn()}`} style={flyInStyle(1)}> + {t('nav.services')} + + setOpen(false)} className={`text-3xl font-extrabold tracking-tight text-neutral-900 hover:text-brand-600 ${flyIn()}`} style={flyInStyle(2)}> + {t('nav.gallery')} + + setOpen(false)} className={`text-3xl font-extrabold tracking-tight text-neutral-900 hover:text-brand-600 ${flyIn()}`} style={flyInStyle(3)}> + {t('nav.contact')} + -
+
- {phone && ( - - - {phone} - - )} - {whatsapp && ( +
+ +
+ + {phone && ( + + + {phone} + + )} + {whatsapp && ( + + + {t('nav.whatsapp')} + + )} - - WhatsApp - - )} - - - Zum Shop + + {t('nav.shop')}
, diff --git a/hifi-src/src/components/PublicLayout.jsx b/hifi-src/src/components/PublicLayout.jsx index ac7b878..04f8350 100644 --- a/hifi-src/src/components/PublicLayout.jsx +++ b/hifi-src/src/components/PublicLayout.jsx @@ -8,6 +8,7 @@ import MaintenanceBypassBanner from './MaintenanceBypassBanner.jsx'; import CookieConsentBanner from './CookieConsentBanner.jsx'; import { MaintenanceProvider } from '../context/MaintenanceContext.jsx'; import { SiteSettingsProvider } from '../context/SiteSettingsContext.jsx'; +import { LanguageProvider } from '../context/LanguageContext.jsx'; import { useAuth } from '../context/AuthContext.jsx'; import { api } from '../api/client.js'; @@ -49,23 +50,29 @@ export default function PublicLayout() { const isLegalPage = LEGAL_PATHS.includes(location.pathname); if (status.global.enabled && !bypass && !isLegalPage) { - return ; + return ( + + + + ); } return ( - - -
- {bypass && status.global.enabled && } - - -
- -
-
- -
-
-
+ + + +
+ {bypass && status.global.enabled && } + + +
+ +
+
+ +
+
+
+
); } diff --git a/hifi-src/src/components/ThemeToggle.jsx b/hifi-src/src/components/ThemeToggle.jsx index 722b114..22307e8 100644 --- a/hifi-src/src/components/ThemeToggle.jsx +++ b/hifi-src/src/components/ThemeToggle.jsx @@ -1,12 +1,14 @@ import { useTheme } from '../context/ThemeContext.jsx'; +import { useLanguage } from '../context/LanguageContext.jsx'; export default function ThemeToggle({ overHero = false }) { const { theme, toggleTheme } = useTheme(); + const { t } = useLanguage(); return (