mirror of
http://88.130.71.182:3000/BlitTech/badoHair_fe.git
synced 2026-06-13 08:58:31 +00:00
413 lines
47 KiB
TypeScript
413 lines
47 KiB
TypeScript
"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" },
|
||
|
||
// ── 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;
|
||
};
|