Files
badoHair_fe/contexts/LanguageContext.tsx
belviskhoremk 53365b9dbf changes after second dev test
fixed full name issue, refresh issue on reservation and user/admin login issue
2026-05-27 23:04:32 +00:00

420 lines
48 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useContext, useState, ReactNode, createContext } from "react";
export type Language = "fr" | "de" | "en";
interface LanguageContextType {
language: Language;
setLanguage: (lang: Language) => void;
t: (key: string, vars?: Record<string, string | number>) => string;
locale: string;
}
const translations: Record<string, Record<Language, string>> = {
// ── Public nav ────────────────────────────────────────────────────────────────
"nav.home": { fr: "Accueil", de: "Startseite", en: "Home" },
"auth.confirm_email": { fr: "Vérifiez votre email pour confirmer votre compte", de: "Überprüfen Sie Ihre E-Mail, um Ihr Konto zu bestätigen", en: "Check your email to confirm your account" },
"nav.shop": { fr: "Boutique", de: "Shop", en: "Shop" },
"nav.booking": { fr: "Réservation", de: "Terminbuchung", en: "Book Appointment" },
"nav.about": { fr: "À propos", de: "Über uns", en: "About" },
"nav.contact": { fr: "Contact", de: "Kontakt", en: "Contact" },
"nav.account": { fr: "Mon compte", de: "Mein Konto", en: "My Account" },
// ── Public pages ─────────────────────────────────────────────────────────────
"hero.title": { fr: "Sublimez votre beauté naturelle", de: "Unterstreichen Sie Ihre natürliche Schönheit", en: "Enhance your natural beauty" },
"hero.subtitle": { fr: "Extensions de cheveux 100% naturels, qualité premium", de: "100% natürliche Haarverlängerungen, Premium-Qualität", en: "100% natural hair extensions, premium quality" },
"hero.cta": { fr: "Découvrir la collection", de: "Kollektion entdecken", en: "Discover the collection" },
"categories.title": { fr: "Nos Collections", de: "Unsere Kollektionen", en: "Our Collections" },
"bestsellers.title": { fr: "Les Plus Vendus", de: "Bestseller", en: "Bestsellers" },
"booking.title": { fr: "Réservez votre rendez-vous", de: "Termin buchen", en: "Book your appointment" },
"booking.subtitle": { fr: "Consultation gratuite et personnalisée", de: "Kostenlose und persönliche Beratung", en: "Free personalized consultation" },
"booking.cta": { fr: "Prendre rendez-vous", de: "Termin vereinbaren", en: "Book now" },
"reviews.title": { fr: "Ce que disent nos clientes", de: "Was unsere Kundinnen sagen", en: "What our clients say" },
"shop.title": { fr: "Notre Boutique", de: "Unser Shop", en: "Our Shop" },
"shop.filter.all": { fr: "Tous", de: "Alle", en: "All" },
"shop.no_products": { fr: "Aucun produit trouvé.", de: "Keine Produkte gefunden.", en: "No products found." },
"about.title": { fr: "Notre Histoire", de: "Unsere Geschichte", en: "Our Story" },
"contact.title": { fr: "Contactez-nous", de: "Kontaktieren Sie uns", en: "Contact us" },
"contact.send": { fr: "Envoyer", de: "Senden", en: "Send" },
"contact.message": { fr: "Votre message", de: "Ihre Nachricht", en: "Your message" },
"footer.rights": { fr: "Tous droits réservés", de: "Alle Rechte vorbehalten", en: "All rights reserved" },
"footer.tagline": { fr: "Extensions de cheveux 100% naturels. Qualité premium pour sublimer votre beauté.", de: "100% natürliche Haarverlängerungen. Premium-Qualität für Ihren Auftritt.", en: "100% natural hair extensions. Premium quality to enhance your beauty." },
"footer.follow_us": { fr: "Suivez-nous", de: "Folgt uns", en: "Follow us" },
// ── Cart ─────────────────────────────────────────────────────────────────────
"cart.title": { fr: "Mon Panier", de: "Warenkorb", en: "My Cart" },
"cart.empty": { fr: "Votre panier est vide", de: "Ihr Warenkorb ist leer", en: "Your cart is empty" },
"cart.total": { fr: "Total", de: "Gesamt", en: "Total" },
"cart.checkout": { fr: "Commander", de: "Bestellen", en: "Checkout" },
"cart.add": { fr: "Ajouter au panier", de: "In den Warenkorb", en: "Add to cart" },
"cart.confirmed_title": { fr: "Commande confirmée", de: "Bestellung bestätigt", en: "Order confirmed" },
"cart.confirmed_desc": { fr: "Votre commande a été enregistrée. Vous recevrez un email de confirmation avec les détails du paiement.", de: "Ihre Bestellung wurde aufgenommen. Sie erhalten eine Bestätigungs-E-Mail mit den Zahlungsdetails.", en: "Your order has been placed. You will receive a confirmation email with payment details." },
"cart.continue_shopping": { fr: "Continuer les achats", de: "Weiter einkaufen", en: "Continue shopping" },
"cart.login_link": { fr: "Connectez-vous", de: "Melden Sie sich an", en: "Log in" },
"cart.login_suffix": { fr: "pour passer commande", de: "um zu bestellen", en: "to place your order" },
"cart.login_required": { fr: "Connectez-vous pour passer commande", de: "Melden Sie sich an, um zu bestellen", en: "Log in to place your order" },
"cart.processing": { fr: "Traitement…", de: "Wird verarbeitet…", en: "Processing…" },
"cart.error": { fr: "Erreur lors de la commande", de: "Bestellfehler", en: "Order error" },
"cart.payment_note": { fr: "Nous vous contacterons pour finaliser le paiement.", de: "Wir werden Sie kontaktieren, um die Zahlung abzuschließen.", en: "We will contact you to finalize the payment." },
// ── Product ───────────────────────────────────────────────────────────────────
"product.similar": { fr: "Produits similaires", de: "Ähnliche Produkte", en: "Similar products" },
"product.color": { fr: "Couleur", de: "Farbe", en: "Color" },
"product.length": { fr: "Longueur", de: "Länge", en: "Length" },
"product.features": { fr: "Caractéristiques", de: "Eigenschaften", en: "Features" },
"product.badge_new": { fr: "Nouveau", de: "Neu", en: "New" },
"product.reviews": { fr: "avis", de: "Bewertungen", en: "reviews" },
"product.not_found": { fr: "Produit non trouvé", de: "Produkt nicht gefunden", en: "Product not found" },
"product.added_to_cart": { fr: "Ajouté au panier", de: "In den Warenkorb gelegt", en: "Added to cart" },
// ── Auth ──────────────────────────────────────────────────────────────────────
"auth.login": { fr: "Connexion", de: "Anmelden", en: "Login" },
"auth.register": { fr: "Inscription", de: "Registrieren", en: "Sign Up" },
"auth.email": { fr: "Adresse email", de: "E-Mail-Adresse", en: "Email address" },
"auth.password": { fr: "Mot de passe", de: "Passwort", en: "Password" },
"auth.name": { fr: "Nom complet", de: "Vollständiger Name", en: "Full name" },
"auth.login_subtitle": { fr: "Accédez à votre espace personnel", de: "Zugang zu Ihrem persönlichen Bereich", en: "Access your personal space" },
"auth.register_subtitle": { fr: "Créez votre compte en quelques secondes", de: "Erstellen Sie Ihr Konto in wenigen Sekunden", en: "Create your account in seconds" },
"auth.login_success": { fr: "Connexion réussie", de: "Erfolgreich angemeldet", en: "Successfully logged in" },
"auth.register_success": { fr: "Compte créé avec succès !", de: "Konto erfolgreich erstellt!", en: "Account created successfully!" },
"auth.error": { fr: "Une erreur est survenue", de: "Ein Fehler ist aufgetreten", en: "An error occurred" },
"auth.loading": { fr: "Chargement…", de: "Wird geladen…", en: "Loading…" },
"auth.no_account": { fr: "Pas encore de compte ?", de: "Noch kein Konto?", en: "No account yet?" },
"auth.has_account": { fr: "Déjà un compte ?", de: "Bereits ein Konto?", en: "Already have an account?" },
"auth.logout": { fr: "Se déconnecter", de: "Abmelden", en: "Log out" },
"auth.forgot_link": { fr: "Mot de passe oublié ?", de: "Passwort vergessen?", en: "Forgot password?" },
"auth.forgot_title": { fr: "Réinitialiser le mot de passe", de: "Passwort zurücksetzen", en: "Reset password" },
"auth.forgot_subtitle": { fr: "Entrez votre email pour recevoir un lien de réinitialisation", de: "E-Mail eingeben, um einen Reset-Link zu erhalten", en: "Enter your email to receive a reset link" },
"auth.forgot_send": { fr: "Envoyer le lien", de: "Link senden", en: "Send link" },
"auth.forgot_sent": { fr: "Email envoyé ! Vérifiez votre boîte mail.", de: "E-Mail gesendet! Prüfen Sie Ihren Posteingang.", en: "Email sent! Check your inbox." },
"auth.back_to_login": { fr: "Retour à la connexion", de: "Zurück zur Anmeldung", en: "Back to login" },
"auth.admin_not_allowed": { fr: "Les administrateurs doivent utiliser l'espace admin", de: "Administratoren müssen den Admin-Bereich verwenden", en: "Administrators must use the admin login" },
// ── Booking (public page) ────────────────────────────────────────────────────
"booking.select_service": { fr: "Choisir un service", de: "Service wählen", en: "Select service" },
"booking.select_date": { fr: "Choisir une date", de: "Datum wählen", en: "Select date" },
"booking.select_time": { fr: "Choisir un créneau", de: "Zeitfenster wählen", en: "Select time" },
"booking.confirm": { fr: "Confirmer la réservation", de: "Buchung bestätigen", en: "Confirm booking" },
"booking.phone": { fr: "Téléphone", de: "Telefon", en: "Phone" },
"booking.free": { fr: "Gratuit", de: "Kostenlos", en: "Free" },
"booking.confirmed_title": { fr: "Réservation confirmée", de: "Buchung bestätigt", en: "Booking confirmed" },
"booking.confirmed_at": { fr: "à", de: "um", en: "at" },
"booking.confirmed_desc": { fr: "Vous recevrez une confirmation par email. Nous vous contacterons pour finaliser le paiement.", de: "Sie erhalten eine Bestätigungs-E-Mail. Wir werden Sie kontaktieren, um die Zahlung abzuschließen.", en: "You will receive a confirmation email. We will contact you to finalize the payment." },
"booking.no_services": { fr: "Aucun service disponible pour le moment.", de: "Derzeit keine Dienstleistungen verfügbar.", en: "No services available at the moment." },
"booking.no_slots": { fr: "Aucun créneau disponible ce jour. Choisissez une autre date.", de: "Keine Zeitfenster an diesem Tag. Wählen Sie ein anderes Datum.", en: "No slots available this day. Choose another date." },
"booking.new_booking": { fr: "Faire une nouvelle réservation", de: "Neue Buchung", en: "Make another booking" },
"booking.submitting": { fr: "Envoi en cours…", de: "Wird gesendet…", en: "Submitting…" },
"booking.success": { fr: "Réservation confirmée !", de: "Buchung bestätigt!", en: "Booking confirmed!" },
"booking.error": { fr: "Erreur lors de la réservation", de: "Buchungsfehler", en: "Booking error" },
// ── Contact ───────────────────────────────────────────────────────────────────
"contact.description": { fr: "Une question sur nos produits, un conseil personnalisé ou une demande de rendez-vous ? N'hésitez pas à nous contacter.", de: "Haben Sie Fragen zu unseren Produkten, wünschen Sie eine persönliche Beratung oder möchten einen Termin anfragen? Zögern Sie nicht, uns zu kontaktieren.", en: "Have a question about our products, need personalized advice, or want to book an appointment? Feel free to contact us." },
"contact.hours_title": { fr: "Horaires d'ouverture", de: "Öffnungszeiten", en: "Opening hours" },
"contact.hours_weekdays":{ fr: "Lundi - Vendredi : 9h - 18h", de: "Mo. - Fr.: 9:00 - 18:00 Uhr", en: "Mon - Fri: 9am - 6pm" },
"contact.hours_saturday":{ fr: "Samedi : 10h - 16h", de: "Samstag: 10:00 - 16:00 Uhr", en: "Saturday: 10am - 4pm" },
"contact.hours_sunday": { fr: "Dimanche : Fermé", de: "Sonntag: Geschlossen", en: "Sunday: Closed" },
"contact.success": { fr: "Nous vous répondrons dans les plus brefs délais.", de: "Wir werden Ihnen so schnell wie möglich antworten.", en: "We will get back to you as soon as possible." },
"contact.error": { fr: "Erreur lors de l'envoi", de: "Fehler beim Senden", en: "Error sending message" },
"contact.sending": { fr: "Envoi en cours…", de: "Wird gesendet…", en: "Sending…" },
// ── About ─────────────────────────────────────────────────────────────────────
"about.p1": { fr: "Passionnée par la beauté et le bien-être capillaire depuis toujours, j'ai créé BADO HAIR pour offrir à chaque femme la possibilité de sublimer sa chevelure avec des extensions de qualité exceptionnelle.", de: "Als leidenschaftliche Verfechterin von Schönheit und Haarpflege habe ich BADO HAIR gegründet, um jeder Frau die Möglichkeit zu geben, ihr Haar mit hochwertigen Extensions zu veredeln.", en: "Passionate about beauty and hair wellness, I created BADO HAIR to give every woman the opportunity to enhance their hair with exceptional quality extensions." },
"about.p2": { fr: "Chaque produit est sélectionné avec soin : des cheveux 100% naturels Remy, sourcés de manière éthique, traités avec les technologies les plus avancées pour garantir douceur, brillance et longévité.", de: "Jedes Produkt wird sorgfältig ausgewählt: 100% natürliches Remy-Haar, ethisch beschafft und mit modernsten Technologien behandelt, um Weichheit, Glanz und Langlebigkeit zu gewährleisten.", en: "Each product is carefully selected: 100% natural Remy hair, ethically sourced, treated with the most advanced technologies to ensure softness, shine, and longevity." },
"about.p3": { fr: "Mon objectif est simple : vous aider à vous sentir belle et confiante, que ce soit pour un événement spécial ou au quotidien. Chaque cliente mérite une expérience personnalisée et des conseils adaptés à ses besoins.", de: "Mein Ziel ist einfach: Ihnen zu helfen, sich schön und selbstbewusst zu fühlen ob für ein besonderes Event oder den Alltag. Jede Kundin verdient ein persönliches Erlebnis und auf ihre Bedürfnisse zugeschnittene Beratung.", en: "My goal is simple: to help you feel beautiful and confident, whether for a special event or everyday life. Every client deserves a personalized experience and advice tailored to their needs." },
"about.value1_title":{ fr: "Passion", de: "Leidenschaft", en: "Passion" },
"about.value1_desc": { fr: "Chaque produit est choisi avec amour et expertise pour garantir votre satisfaction.", de: "Jedes Produkt wird mit Liebe und Fachkenntnis ausgewählt, um Ihre Zufriedenheit zu garantieren.", en: "Each product is chosen with love and expertise to guarantee your satisfaction." },
"about.value2_title":{ fr: "Qualité Premium", de: "Premium-Qualität", en: "Premium Quality" },
"about.value2_desc": { fr: "100% cheveux naturels Remy, sourcés éthiquement et contrôlés rigoureusement.", de: "100% natürliches Remy-Haar, ethisch bezogen und streng kontrolliert.", en: "100% natural Remy hair, ethically sourced and rigorously controlled." },
"about.value3_title":{ fr: "Expertise", de: "Expertise", en: "Expertise" },
"about.value3_desc": { fr: "Conseils personnalisés et pose professionnelle pour un résultat naturel.", de: "Persönliche Beratung und professionelle Anwendung für ein natürliches Ergebnis.", en: "Personalized advice and professional application for a natural result." },
// ── Account (mon-compte) ─────────────────────────────────────────────────────
"account.title": { fr: "Mon espace", de: "Mein Bereich", en: "My Space" },
"account.tab_profile": { fr: "Mon profil", de: "Mein Profil", en: "My Profile" },
"account.tab_bookings": { fr: "Mes réservations", de: "Meine Buchungen", en: "My Bookings" },
"account.tab_orders": { fr: "Mes commandes", de: "Meine Bestellungen", en: "My Orders" },
"account.personal_info": { fr: "Informations personnelles", de: "Persönliche Daten", en: "Personal information" },
"account.profile_saved": { fr: "Profil mis à jour", de: "Profil aktualisiert", en: "Profile updated" },
"account.booking_cancelled": { fr: "Réservation annulée", de: "Buchung storniert", en: "Booking cancelled" },
"account.no_bookings": { fr: "Aucune réservation pour le moment.", de: "Noch keine Buchungen.", en: "No bookings yet." },
"account.no_orders": { fr: "Aucune commande pour le moment.", de: "Noch keine Bestellungen.", en: "No orders yet." },
"account.appt_default": { fr: "Rendez-vous", de: "Termin", en: "Appointment" },
"account.cancel": { fr: "Annuler", de: "Stornieren", en: "Cancel" },
// ── Shop ─────────────────────────────────────────────────────────────────────
// ── Admin — Layout & common ───────────────────────────────────────────────────
"admin.loading": { fr: "Chargement…", de: "Wird geladen…", en: "Loading…" },
"admin.header": { fr: "Tableau de bord", de: "Dashboard", en: "Dashboard" },
"admin.save": { fr: "Enregistrer", de: "Speichern", en: "Save" },
"admin.saving": { fr: "Enregistrement…", de: "Wird gespeichert…", en: "Saving…" },
"admin.cancel": { fr: "Annuler", de: "Abbrechen", en: "Cancel" },
"admin.delete": { fr: "Supprimer", de: "Löschen", en: "Delete" },
"admin.add": { fr: "Ajouter", de: "Hinzufügen", en: "Add" },
"admin.edit": { fr: "Modifier", de: "Bearbeiten", en: "Edit" },
"admin.create": { fr: "Créer", de: "Erstellen", en: "Create" },
"admin.refresh": { fr: "Actualiser", de: "Aktualisieren", en: "Refresh" },
"admin.search": { fr: "Rechercher…", de: "Suchen…", en: "Search…" },
"admin.actions": { fr: "Actions", de: "Aktionen", en: "Actions" },
"admin.irreversible": { fr: "Cette action est irréversible.", de: "Diese Aktion ist nicht rückgängig zu machen.", en: "This action is irreversible." },
// ── Admin — Status labels ─────────────────────────────────────────────────────
"admin.status.pending": { fr: "En attente", de: "Ausstehend", en: "Pending" },
"admin.status.confirmed": { fr: "Confirmé", de: "Bestätigt", en: "Confirmed" },
"admin.status.cancelled": { fr: "Annulé", de: "Storniert", en: "Cancelled" },
"admin.status.completed": { fr: "Terminé", de: "Abgeschlossen", en: "Completed" },
"admin.status.paid": { fr: "Payé", de: "Bezahlt", en: "Paid" },
"admin.status.shipped": { fr: "Expédié", de: "Versendet", en: "Shipped" },
"admin.status.delivered": { fr: "Livré", de: "Geliefert", en: "Delivered" },
"admin.status.refunded": { fr: "Remboursé", de: "Erstattet", en: "Refunded" },
"admin.status.active": { fr: "Actif", de: "Aktiv", en: "Active" },
"admin.status.inactive": { fr: "Inactif", de: "Inaktiv", en: "Inactive" },
"admin.status.blocked": { fr: "Bloqué", de: "Gesperrt", en: "Blocked" },
"admin.status.booked": { fr: "Réservé", de: "Gebucht", en: "Booked" },
"admin.status.free": { fr: "Libre", de: "Frei", en: "Free" },
"admin.status.no_show": { fr: "Absent", de: "Nicht erschienen", en: "No show" },
// ── Admin — Sidebar ───────────────────────────────────────────────────────────
"admin.nav.management": { fr: "Gestion", de: "Verwaltung", en: "Management" },
"admin.nav.overview": { fr: "Vue d'ensemble", de: "Übersicht", en: "Overview" },
"admin.nav.products": { fr: "Produits", de: "Produkte", en: "Products" },
"admin.nav.orders": { fr: "Commandes", de: "Bestellungen", en: "Orders" },
"admin.nav.bookings": { fr: "Réservations", de: "Reservierungen", en: "Bookings" },
"admin.nav.planning": { fr: "Planning", de: "Planung", en: "Planning" },
"admin.nav.services": { fr: "Services", de: "Dienstleistungen", en: "Services" },
"admin.nav.customers": { fr: "Clients", de: "Kunden", en: "Customers" },
"admin.nav.settings": { fr: "Paramètres", de: "Einstellungen", en: "Settings" },
"admin.nav.view_site": { fr: "Voir le site", de: "Website ansehen", en: "View site" },
"admin.logout": { fr: "Déconnexion", de: "Abmelden", en: "Logout" },
// ── Admin — Dashboard ─────────────────────────────────────────────────────────
"admin.overview.title": { fr: "Vue d'ensemble", de: "Übersicht", en: "Overview" },
"admin.overview.subtitle": { fr: "Aperçu de votre activité", de: "Ihre Aktivitätsübersicht", en: "Your activity overview" },
"admin.overview.activity_section": { fr: "Activité", de: "Aktivität", en: "Activity" },
"admin.overview.revenue_section": { fr: "Revenus & Clients", de: "Einnahmen & Kunden", en: "Revenue & Customers" },
"admin.overview.orders_pending": { fr: "Commandes en attente", de: "Ausstehende Bestellungen", en: "Pending orders" },
"admin.overview.bookings_pending": { fr: "RDV en attente", de: "Ausstehende Termine", en: "Pending bookings" },
"admin.overview.bookings_confirmed": { fr: "RDV confirmés (à venir)", de: "Bestätigte Termine (bevorstehend)", en: "Confirmed bookings (upcoming)" },
"admin.overview.products_count": { fr: "Produits", de: "Produkte", en: "Products" },
"admin.overview.revenue_today": { fr: "Chiffre d'affaires aujourd'hui", de: "Umsatz heute", en: "Revenue today" },
"admin.overview.revenue_week": { fr: "Cette semaine", de: "Diese Woche", en: "This week" },
"admin.overview.revenue_month": { fr: "Ce mois", de: "Diesen Monat", en: "This month" },
"admin.overview.new_customers": { fr: "Nouveaux clients ce mois", de: "Neue Kunden diesen Monat", en: "New customers this month" },
"admin.overview.upcoming_title": { fr: "Prochains rendez-vous", de: "Bevorstehende Termine", en: "Upcoming appointments" },
"admin.overview.no_upcoming": { fr: "Aucun rendez-vous à venir.", de: "Keine bevorstehenden Termine.", en: "No upcoming appointments." },
"admin.overview.low_stock": { fr: "{n} produit(s) en stock faible (≤ 5 unités). Pensez à réapprovisionner.", de: "{n} Produkt(e) mit niedrigem Bestand (≤ 5 Stück). Bitte nachbestellen.", en: "{n} product(s) low in stock (≤ 5 units). Please restock." },
// ── Admin — Orders ────────────────────────────────────────────────────────────
"admin.orders.title": { fr: "Commandes", de: "Bestellungen", en: "Orders" },
"admin.orders.subtitle": { fr: "commande(s)", de: "Bestellung(en)", en: "order(s)" },
"admin.orders.tab_all": { fr: "Toutes", de: "Alle", en: "All" },
"admin.orders.tab_pending": { fr: "En attente", de: "Ausstehend", en: "Pending" },
"admin.orders.tab_paid": { fr: "Payées", de: "Bezahlt", en: "Paid" },
"admin.orders.tab_shipped": { fr: "Expédiées", de: "Versendet", en: "Shipped" },
"admin.orders.tab_delivered": { fr: "Livrées", de: "Geliefert", en: "Delivered" },
"admin.orders.tab_cancelled": { fr: "Annulées", de: "Storniert", en: "Cancelled" },
"admin.orders.col_ref": { fr: "Référence", de: "Referenz", en: "Reference" },
"admin.orders.col_customer": { fr: "Cliente", de: "Kundin", en: "Customer" },
"admin.orders.col_date": { fr: "Date", de: "Datum", en: "Date" },
"admin.orders.col_total": { fr: "Total", de: "Gesamt", en: "Total" },
"admin.orders.none": { fr: "Aucune commande", de: "Keine Bestellungen", en: "No orders" },
"admin.orders.update_btn": { fr: "Modifier", de: "Aktualisieren", en: "Update" },
// ── Admin — Bookings ─────────────────────────────────────────────────────────
"admin.bookings.title": { fr: "Réservations", de: "Reservierungen", en: "Bookings" },
"admin.bookings.subtitle": { fr: "réservation(s) au total", de: "Reservierung(en) gesamt", en: "booking(s) total" },
"admin.bookings.tab_all": { fr: "Toutes", de: "Alle", en: "All" },
"admin.bookings.tab_pending": { fr: "En attente", de: "Ausstehend", en: "Pending" },
"admin.bookings.tab_confirmed": { fr: "Confirmées", de: "Bestätigt", en: "Confirmed" },
"admin.bookings.tab_cancelled": { fr: "Annulées", de: "Storniert", en: "Cancelled" },
"admin.bookings.col_client": { fr: "Cliente", de: "Kundin", en: "Customer" },
"admin.bookings.col_contact": { fr: "Contact", de: "Kontakt", en: "Contact" },
"admin.bookings.col_service": { fr: "Service", de: "Dienstleistung", en: "Service" },
"admin.bookings.col_datetime": { fr: "Date & Heure", de: "Datum & Uhrzeit", en: "Date & Time" },
"admin.bookings.none": { fr: "Aucune réservation", de: "Keine Reservierungen", en: "No bookings" },
"admin.bookings.confirmed_toast": { fr: "Réservation confirmée", de: "Reservierung bestätigt", en: "Booking confirmed" },
"admin.bookings.cancelled_toast": { fr: "Réservation annulée", de: "Reservierung storniert", en: "Booking cancelled" },
"admin.bookings.deleted_toast": { fr: "Réservation supprimée", de: "Reservierung gelöscht", en: "Booking deleted" },
"admin.bookings.delete_title": { fr: "Supprimer cette réservation ?", de: "Diese Reservierung löschen?", en: "Delete this booking?" },
// ── Admin — Planning ─────────────────────────────────────────────────────────
"admin.planning.title": { fr: "Planning & Disponibilités", de: "Planung & Verfügbarkeit", en: "Planning & Availability" },
"admin.planning.subtitle": { fr: "Gérez vos horaires hebdomadaires et vos créneaux de disponibilité", de: "Verwalten Sie Ihren Wochenplan und Verfügbarkeitsslots", en: "Manage your weekly schedule and available time slots" },
"admin.planning.tab_schedule": { fr: "Horaires", de: "Zeiten", en: "Schedule" },
"admin.planning.tab_calendar": { fr: "Calendrier", de: "Kalender", en: "Calendar" },
"admin.planning.tab_blocked": { fr: "Dates bloquées", de: "Gesperrte Daten", en: "Blocked dates" },
"admin.planning.weekly_title": { fr: "Horaires hebdomadaires", de: "Wochenplan", en: "Weekly schedule" },
"admin.planning.add_title": { fr: "Ajouter un horaire", de: "Zeitplan hinzufügen", en: "Add a schedule" },
"admin.planning.not_available": { fr: "Pas disponible", de: "Nicht verfügbar", en: "Not available" },
"admin.planning.day": { fr: "Jour", de: "Tag", en: "Day" },
"admin.planning.start": { fr: "Début", de: "Beginn", en: "Start" },
"admin.planning.end": { fr: "Fin", de: "Ende", en: "End" },
"admin.planning.duration_min": { fr: "Durée (min)", de: "Dauer (Min)", en: "Duration (min)" },
"admin.planning.adding": { fr: "Ajout…", de: "Wird hinzugefügt…", en: "Adding…" },
"admin.planning.generate_title": { fr: "Générer les créneaux", de: "Slots generieren", en: "Generate slots" },
"admin.planning.generate_desc": { fr: "Génère automatiquement les créneaux disponibles à partir des horaires ci-dessus.", de: "Generiert automatisch verfügbare Slots aus dem obigen Zeitplan.", en: "Automatically generates available slots from the schedule above." },
"admin.planning.from": { fr: "Du", de: "Von", en: "From" },
"admin.planning.to": { fr: "Au", de: "Bis", en: "To" },
"admin.planning.generating": { fr: "Génération…", de: "Wird generiert…", en: "Generating…" },
"admin.planning.generate_btn": { fr: "Générer", de: "Generieren", en: "Generate" },
"admin.planning.slots_for": { fr: "Créneaux du", de: "Slots für den", en: "Slots for" },
"admin.planning.no_slots": { fr: "Aucun créneau ce jour.", de: "Keine Slots an diesem Tag.", en: "No slots on this day." },
"admin.planning.block_title": { fr: "Bloquer une date", de: "Datum sperren", en: "Block a date" },
"admin.planning.block_desc": { fr: "Les dates bloquées n'apparaissent pas dans le calendrier de réservation.", de: "Gesperrte Daten erscheinen nicht im Buchungskalender.", en: "Blocked dates do not appear in the booking calendar." },
"admin.planning.reason": { fr: "Raison (optionnel)", de: "Grund (optional)", en: "Reason (optional)" },
"admin.planning.reason_ph": { fr: "Congés, férié…", de: "Urlaub, Feiertag…", en: "Vacation, holiday…" },
"admin.planning.blocking": { fr: "Ajout…", de: "Wird gesperrt…", en: "Blocking…" },
"admin.planning.block_btn": { fr: "Bloquer", de: "Sperren", en: "Block" },
"admin.planning.blocked_list": { fr: "Dates bloquées", de: "Gesperrte Daten", en: "Blocked dates" },
"admin.planning.no_blocked": { fr: "Aucune date bloquée.", de: "Keine gesperrten Daten.", en: "No blocked dates." },
"admin.planning.generated": { fr: "{n} créneaux générés", de: "{n} Slots generiert", en: "{n} slots generated" },
"admin.planning.slot_unblocked": { fr: "Créneau débloqué", de: "Slot entsperrt", en: "Slot unblocked" },
"admin.planning.slot_blocked": { fr: "Créneau bloqué", de: "Slot gesperrt", en: "Slot blocked" },
"admin.planning.slot_deleted": { fr: "Créneau supprimé", de: "Slot gelöscht", en: "Slot deleted" },
"admin.planning.date_unblocked": { fr: "Date débloquée", de: "Datum entsperrt", en: "Date unblocked" },
"admin.planning.date_blocked": { fr: "Date bloquée", de: "Datum gesperrt", en: "Date blocked" },
"admin.planning.schedule_added": { fr: "Horaire ajouté", de: "Zeitplan hinzugefügt", en: "Schedule added" },
"admin.planning.schedule_deleted": { fr: "Horaire supprimé", de: "Zeitplan gelöscht", en: "Schedule deleted" },
"admin.planning.unblock_title": { fr: "Débloquer", de: "Entsperren", en: "Unblock" },
// ── Admin — Day names ─────────────────────────────────────────────────────────
"admin.day.0": { fr: "Lundi", de: "Montag", en: "Monday" },
"admin.day.1": { fr: "Mardi", de: "Dienstag", en: "Tuesday" },
"admin.day.2": { fr: "Mercredi", de: "Mittwoch", en: "Wednesday" },
"admin.day.3": { fr: "Jeudi", de: "Donnerstag", en: "Thursday" },
"admin.day.4": { fr: "Vendredi", de: "Freitag", en: "Friday" },
"admin.day.5": { fr: "Samedi", de: "Samstag", en: "Saturday" },
"admin.day.6": { fr: "Dimanche", de: "Sonntag", en: "Sunday" },
// ── Admin — Month names ───────────────────────────────────────────────────────
"admin.month.0": { fr: "Janvier", de: "Januar", en: "January" },
"admin.month.1": { fr: "Février", de: "Februar", en: "February" },
"admin.month.2": { fr: "Mars", de: "März", en: "March" },
"admin.month.3": { fr: "Avril", de: "April", en: "April" },
"admin.month.4": { fr: "Mai", de: "Mai", en: "May" },
"admin.month.5": { fr: "Juin", de: "Juni", en: "June" },
"admin.month.6": { fr: "Juillet", de: "Juli", en: "July" },
"admin.month.7": { fr: "Août", de: "August", en: "August" },
"admin.month.8": { fr: "Septembre", de: "September", en: "September" },
"admin.month.9": { fr: "Octobre", de: "Oktober", en: "October" },
"admin.month.10": { fr: "Novembre", de: "November", en: "November" },
"admin.month.11": { fr: "Décembre", de: "Dezember", en: "December" },
// ── Admin — Products ─────────────────────────────────────────────────────────
"admin.products.title": { fr: "Produits", de: "Produkte", en: "Products" },
"admin.products.subtitle": { fr: "produit(s) au catalogue", de: "Produkt(e) im Katalog", en: "product(s) in catalog" },
"admin.products.col_image": { fr: "Image", de: "Bild", en: "Image" },
"admin.products.col_name": { fr: "Nom", de: "Name", en: "Name" },
"admin.products.col_category": { fr: "Catégorie", de: "Kategorie", en: "Category" },
"admin.products.col_price": { fr: "Prix", de: "Preis", en: "Price" },
"admin.products.col_stock": { fr: "Stock", de: "Bestand", en: "Stock" },
"admin.products.col_status": { fr: "Statut", de: "Status", en: "Status" },
"admin.products.badge_new": { fr: "Nouveau", de: "Neu", en: "New" },
"admin.products.create_title": { fr: "Nouveau produit", de: "Neues Produkt", en: "New product" },
"admin.products.edit_title": { fr: "Modifier le produit", de: "Produkt bearbeiten", en: "Edit product" },
"admin.products.form_desc": { fr: "Renseignez les informations du produit", de: "Produktinformationen eingeben", en: "Fill in the product information" },
"admin.products.name": { fr: "Nom", de: "Name", en: "Name" },
"admin.products.category": { fr: "Catégorie", de: "Kategorie", en: "Category" },
"admin.products.price": { fr: "Prix (€)", de: "Preis (€)", en: "Price (€)" },
"admin.products.original_price": { fr: "Prix barré (€)", de: "Durchgestrichener Preis (€)", en: "Original price (€)" },
"admin.products.stock_quantity": { fr: "Quantité en stock", de: "Lagerbestand", en: "Stock quantity" },
"admin.products.optional": { fr: "Optionnel", de: "Optional", en: "Optional" },
"admin.products.image": { fr: "Image", de: "Bild", en: "Image" },
"admin.products.description": { fr: "Description", de: "Beschreibung", en: "Description" },
"admin.products.colors": { fr: "Couleurs (séparées par des virgules)", de: "Farben (kommagetrennt)", en: "Colors (comma-separated)" },
"admin.products.lengths": { fr: "Longueurs (séparées par des virgules)", de: "Längen (kommagetrennt)", en: "Lengths (comma-separated)" },
"admin.products.mark_new": { fr: "Marquer comme Nouveau", de: "Als Neu markieren", en: "Mark as New" },
"admin.products.mark_bestseller": { fr: "Marquer comme Bestseller", de: "Als Bestseller markieren", en: "Mark as Bestseller" },
"admin.products.change_image": { fr: "Changer l'image", de: "Bild ändern", en: "Change image" },
"admin.products.choose_image": { fr: "Choisir une image", de: "Bild auswählen", en: "Choose an image" },
"admin.products.valid_required": { fr: "Nom et prix valides requis", de: "Gültiger Name und Preis erforderlich", en: "Valid name and price required" },
"admin.products.saved": { fr: "Produit modifié", de: "Produkt aktualisiert", en: "Product updated" },
"admin.products.added": { fr: "Produit ajouté", de: "Produkt hinzugefügt", en: "Product added" },
"admin.products.deleted": { fr: "Produit supprimé", de: "Produkt gelöscht", en: "Product deleted" },
"admin.products.delete_title": { fr: "Supprimer ce produit ?", de: "Dieses Produkt löschen?", en: "Delete this product?" },
// ── Admin — Services ─────────────────────────────────────────────────────────
"admin.services.title": { fr: "Services", de: "Dienstleistungen", en: "Services" },
"admin.services.subtitle": { fr: "Ces services apparaissent sur la page de réservation publique.", de: "Diese Dienstleistungen erscheinen auf der öffentlichen Buchungsseite.", en: "These services appear on the public booking page." },
"admin.services.new_btn": { fr: "Nouveau service", de: "Neue Dienstleistung", en: "New service" },
"admin.services.col_name": { fr: "Nom", de: "Name", en: "Name" },
"admin.services.col_desc": { fr: "Description", de: "Beschreibung", en: "Description" },
"admin.services.col_duration": { fr: "Durée", de: "Dauer", en: "Duration" },
"admin.services.col_price": { fr: "Prix", de: "Preis", en: "Price" },
"admin.services.none": { fr: "Aucun service. Créez-en un pour que la page de réservation affiche des options.", de: "Keine Dienstleistungen. Erstellen Sie eine, damit die Buchungsseite Optionen anzeigt.", en: "No services. Create one for the booking page to show options." },
"admin.services.create_title": { fr: "Nouveau service", de: "Neue Dienstleistung", en: "New service" },
"admin.services.edit_title": { fr: "Modifier le service", de: "Dienstleistung bearbeiten", en: "Edit service" },
"admin.services.name_req": { fr: "Le nom est requis", de: "Name ist erforderlich", en: "Name is required" },
"admin.services.name_ph": { fr: "Ex : Pose perruque", de: "z.B. Perückenanlage", en: "e.g. Wig application" },
"admin.services.desc_ph": { fr: "Courte description du service", de: "Kurze Beschreibung", en: "Short description" },
"admin.services.duration": { fr: "Durée (minutes)", de: "Dauer (Minuten)", en: "Duration (minutes)" },
"admin.services.price": { fr: "Prix (€)", de: "Preis (€)", en: "Price (€)" },
"admin.services.active_label": { fr: "Service actif (visible sur la page de réservation)", de: "Dienst aktiv (auf Buchungsseite sichtbar)", en: "Service active (visible on booking page)" },
"admin.services.free": { fr: "Gratuit", de: "Kostenlos", en: "Free" },
"admin.services.created": { fr: "Service créé", de: "Dienstleistung erstellt", en: "Service created" },
"admin.services.updated": { fr: "Service mis à jour", de: "Dienstleistung aktualisiert", en: "Service updated" },
"admin.services.deleted": { fr: "Service supprimé", de: "Dienstleistung gelöscht", en: "Service deleted" },
"admin.services.delete_title": { fr: "Supprimer ce service ?", de: "Diese Dienstleistung löschen?", en: "Delete this service?" },
// ── Admin — Customers ─────────────────────────────────────────────────────────
"admin.customers.title": { fr: "Clients", de: "Kunden", en: "Customers" },
"admin.customers.subtitle": { fr: "client(s)", de: "Kunde/n", en: "customer(s)" },
"admin.customers.search_ph": { fr: "Rechercher par nom ou email…", de: "Nach Name oder E-Mail suchen…", en: "Search by name or email…" },
"admin.customers.col_name": { fr: "Nom", de: "Name", en: "Name" },
"admin.customers.col_email": { fr: "Email", de: "E-Mail", en: "Email" },
"admin.customers.col_phone": { fr: "Téléphone", de: "Telefon", en: "Phone" },
"admin.customers.col_orders": { fr: "Commandes", de: "Bestellungen", en: "Orders" },
"admin.customers.col_bookings":{ fr: "RDV", de: "Termine", en: "Bookings" },
"admin.customers.col_spent": { fr: "Total dépensé", de: "Gesamtausgaben", en: "Total spent" },
"admin.customers.col_joined": { fr: "Inscrit le", de: "Beigetreten am", en: "Joined" },
"admin.customers.none": { fr: "Aucun client trouvé", de: "Keine Kunden gefunden", en: "No customers found" },
"admin.customers.blocked": { fr: "Client bloqué", de: "Kunde gesperrt", en: "Customer blocked" },
"admin.customers.unblocked": { fr: "Client débloqué", de: "Kunde entsperrt", en: "Customer unblocked" },
// ── Admin — Settings ─────────────────────────────────────────────────────────
"admin.settings.title": { fr: "Paramètres", de: "Einstellungen", en: "Settings" },
"admin.settings.subtitle": { fr: "Configuration générale de la boutique", de: "Allgemeine Shop-Konfiguration", en: "General store configuration" },
"admin.settings.bookings": { fr: "Réservations", de: "Reservierungen", en: "Bookings" },
"admin.settings.no_settings": { fr: "Aucun paramètre configuré. Les valeurs par défaut sont utilisées.", de: "Keine Einstellungen konfiguriert. Standardwerte werden verwendet.", en: "No settings configured. Default values are used." },
"admin.settings.other": { fr: "Autres paramètres", de: "Weitere Einstellungen", en: "Other settings" },
"admin.settings.last_updated": { fr: "Dernière modification :", de: "Zuletzt geändert:", en: "Last updated:" },
"admin.settings.saved": { fr: "Paramètre enregistré", de: "Einstellung gespeichert", en: "Setting saved" },
"admin.settings.booking_price_label": { fr: "Prix de réservation par défaut (€)", de: "Standardpreis für Reservierungen (€)", en: "Default booking price (€)" },
"admin.settings.booking_price_desc": { fr: "Prix appliqué à chaque rendez-vous (0 = gratuit)", de: "Preis pro Termin (0 = kostenlos)", en: "Price applied to each appointment (0 = free)" },
};
const LOCALE_MAP: Record<Language, string> = {
fr: "fr-FR",
de: "de-DE",
en: "en-GB",
};
const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
export const LanguageProvider = ({ children }: { children: ReactNode }) => {
const [language, setLanguage] = useState<Language>("fr");
const t = (key: string, vars?: Record<string, string | number>): string => {
let str = translations[key]?.[language] ?? key;
if (vars) {
Object.entries(vars).forEach(([k, v]) => {
str = str.replace(`{${k}}`, String(v));
});
}
return str;
};
return (
<LanguageContext.Provider value={{ language, setLanguage, t, locale: LOCALE_MAP[language] }}>
{children}
</LanguageContext.Provider>
);
};
export const useLanguage = () => {
const context = useContext(LanguageContext);
if (!context) throw new Error("useLanguage must be used within LanguageProvider");
return context;
};