// i18n.jsx — language switcher (EN/FR/DE/ES) + dictionary-based auto-translator. // Strategy: the app re-mounts on language change (key={lang}) so the DOM is fresh // English, then translateAll() rewrites text nodes + key attributes from the // dictionary. A guarded MutationObserver re-applies after dynamic re-renders. const LANGS = [['en', 'English'], ['fr', 'Français'], ['de', 'Deutsch'], ['es', 'Español']]; const T_DICT = { // chrome / cta "Register Interest": { fr: "Demander des informations", de: "Interesse anmelden", es: "Solicitar información" }, "Why Dubai": { fr: "Pourquoi Dubaï", de: "Warum Dubai", es: "Por qué Dubái" }, "The World's Smartest Place to Own.": { fr: "Le placement immobilier le plus malin au monde.", de: "Der klügste Ort der Welt für Wohneigentum.", es: "El lugar más inteligente del mundo para invertir." }, "Dubai, in Five Numbers.": { fr: "Dubaï, en cinq chiffres.", de: "Dubai, in fünf Zahlen.", es: "Dubái, en cinco cifras." }, "No annual property, income or capital-gains tax.": { fr: "Pas de taxe foncière annuelle, ni impôt sur le revenu ou les plus-values.", de: "Keine jährliche Grund-, Einkommen- oder Kapitalertragsteuer.", es: "Sin impuesto anual sobre la propiedad, la renta ni las plusvalías." }, "Golden Visa on homes of AED 2M+.": { fr: "Golden Visa pour les biens à partir de 2 M AED.", de: "Golden Visa für Immobilien ab 2 Mio. AED.", es: "Golden Visa para viviendas desde 2 M AED." }, "A leading Dubai developer. Recession-proof, risk-free investment.": { fr: "Un promoteur de premier plan à Dubaï. Un investissement anti-récession et sans risque.", de: "Ein führender Entwickler in Dubai. Rezessionssichere, risikofreie Investition.", es: "Un promotor líder en Dubái. Inversión a prueba de recesión y sin riesgo." }, "Ranked among the world\u2019s safest cities.": { fr: "Classée parmi les villes les plus sûres au monde.", de: "Zählt zu den sichersten Städten der Welt.", es: "Entre las ciudades más seguras del mundo." }, "Gross rental yields, among the world’s strongest.": { fr: "Rendements locatifs bruts, parmi les plus élevés au monde.", de: "Brutto-Mietrenditen, zu den höchsten weltweit zählend.", es: "Rentabilidad bruta del alquiler, entre las más altas del mundo." }, "Golden Visa residency on homes of AED 2M+.": { fr: "Résidence Golden Visa pour les biens à partir de 2 M AED.", de: "Golden-Visa-Aufenthalt für Immobilien ab 2 Mio. AED.", es: "Residencia Golden Visa para viviendas desde 2 M AED." }, "Golden Visa residency on homes of AED 2M+.": { fr: "Résidence Golden Visa pour les biens à partir de 2 M AED.", de: "Golden-Visa-Aufenthalt für Immobilien ab 2 Mio. AED.", es: "Residencia Golden Visa para viviendas desde 2 M AED." }, "Freehold for all nationalities. RERA escrow protected.": { fr: "Pleine propriété pour toutes les nationalités. Protégée par séquestre RERA.", de: "Volleigentum für alle Nationalitäten. Durch RERA-Treuhand geschützt.", es: "Propiedad plena para todas las nacionalidades. Protegida por depósito RERA." }, "From India, 7 from Europe. One of the world\u2019s safest cities.": { fr: "3 h de l'Inde, 7 de l'Europe. L'une des villes les plus sûres au monde.", de: "3 Std. von Indien, 7 von Europa. Eine der sichersten Städte der Welt.", es: "A 3 h de India, 7 de Europa. Una de las ciudades más seguras del mundo." }, "Market figures: Dubai Land Department / published portal data, 2025. Indicative only, not financial advice.": { fr: "Données de marché : Dubai Land Department / portails publiés, 2025. Indicatif uniquement, pas un conseil financier.", de: "Marktdaten: Dubai Land Department / veröffentlichte Portaldaten, 2025. Nur indikativ, keine Finanzberatung.", es: "Datos de mercado: Dubai Land Department / portales publicados, 2025. Solo indicativo, no es asesoramiento financiero." }, "Average rental yields, 2 to 3 times London or New York": { fr: "Rendements locatifs moyens, 2 à 3 fois Londres ou New York", de: "Durchschnittliche Mietrenditen, 2 bis 3 mal London oder New York", es: "Rentabilidad media del alquiler, 2 a 3 veces Londres o Nueva York" }, "Dirham pegged to the US dollar — no FX risk": { fr: "Dirham indexé sur le dollar — sans risque de change", de: "Dirham an den US-Dollar gekoppelt — kein Wechselkursrisiko", es: "Dírham vinculado al dólar — sin riesgo cambiario" }, "Golden Visa residency on AED 2M+ homes": { fr: "Golden Visa pour les biens à partir de 2 M AED", de: "Golden Visa für Immobilien ab 2 Mio. AED", es: "Golden Visa para viviendas desde 2 M AED" }, "Freehold ownership, RERA escrow protected": { fr: "Pleine propriété, protégée par séquestre RERA", de: "Volleigentum, durch RERA-Treuhand geschützt", es: "Propiedad plena, protegida por depósito RERA" }, "From Europe, in one of the world’s safest cities": { fr: "Depuis l'Europe, dans l'une des villes les plus sûres au monde", de: "Aus Europa erreichbar, in einer der sichersten Städte der Welt", es: "Desde Europa, en una de las ciudades más seguras del mundo" }, "Indicative figures for information only. Not financial advice.": { fr: "Chiffres indicatifs à titre informatif. Pas un conseil financier.", de: "Indikative Angaben nur zur Information. Keine Finanzberatung.", es: "Cifras orientativas solo informativas. No constituyen asesoramiento financiero." }, "View All Photos": { fr: "Voir toutes les photos", de: "Alle Fotos ansehen", es: "Ver todas las fotos" }, "Do I pay tax on a Dubai property?": { fr: "Y a-t-il des impôts sur un bien à Dubaï ?", de: "Zahle ich Steuern auf eine Dubai-Immobilie?", es: "¿Pago impuestos por una propiedad en Dubái?" }, "No. Dubai has no property tax, no tax on rental income, and no capital-gains tax for individual owners.": { fr: "Non. Dubaï n'applique ni taxe foncière, ni impôt sur les revenus locatifs, ni impôt sur les plus-values pour les particuliers.", de: "Nein. Dubai erhebt keine Grundsteuer, keine Steuer auf Mieteinnahmen und keine Kapitalertragsteuer für Privatpersonen.", es: "No. Dubái no aplica impuesto sobre la propiedad, ni sobre los ingresos por alquiler, ni sobre las plusvalías para particulares." }, "Can buying get me residency?": { fr: "L'achat donne-t-il droit à la résidence ?", de: "Erhalte ich durch den Kauf einen Aufenthaltstitel?", es: "¿La compra da derecho a residencia?" }, "Yes. A Dubai home worth AED 2M or more (including off-plan like Flare) qualifies you and your family for a 10-year renewable Golden Visa.": { fr: "Oui. Un bien à Dubaï d'au moins 2 M AED (y compris en off-plan comme Flare) vous donne droit, ainsi qu'à votre famille, à un Golden Visa de 10 ans renouvelable.", de: "Ja. Eine Dubai-Immobilie ab 2 Mio. AED (auch off-plan wie Flare) qualifiziert Sie und Ihre Familie für ein 10-jähriges, verlängerbares Golden Visa.", es: "Sí. Una vivienda en Dubái de 2 M AED o más (incluido off-plan como Flare) le da derecho, a usted y a su familia, a un Golden Visa de 10 años renovable." }, "Can I buy from overseas?": { fr: "Puis-je acheter depuis l'étranger ?", de: "Kann ich aus dem Ausland kaufen?", es: "¿Puedo comprar desde el extranjero?" }, "Yes. The full process (reservation, contracts and payments) can be completed remotely, and we guide you at every step.": { fr: "Oui. Tout le processus (réservation, contrats et paiements) peut se faire à distance, et nous vous accompagnons à chaque étape.", de: "Ja. Der gesamte Ablauf (Reservierung, Verträge und Zahlungen) kann aus der Ferne erfolgen, und wir begleiten Sie bei jedem Schritt.", es: "Sí. Todo el proceso (reserva, contratos y pagos) puede completarse a distancia, y le acompañamos en cada paso." }, // hero "A landmark collection of residences, crafted by Binghatti on an easy": { fr: "Une collection de résidences d'exception signée Binghatti, avec un confortable", de: "Eine markante Residenzen-Kollektion von Binghatti, mit einem unkomplizierten", es: "Una destacada colección de residencias de Binghatti, con un cómodo" }, "70/30 plan": { fr: "plan 70/30", de: "70/30-Plan", es: "plan 70/30" }, "Starting price": { fr: "Prix de départ", de: "Startpreis", es: "Precio inicial" }, "Studio to 4 BR": { fr: "Studio à 4 ch.", de: "Studio bis 4 Zi.", es: "Studio a 4 hab." }, "Residences & retail": { fr: "Résidences et commerces", de: "Residenzen & Handel", es: "Residencias y comercios" }, "Handover": { fr: "Livraison", de: "Übergabe", es: "Entrega" }, // facts "Why Flare": { fr: "Pourquoi Flare", de: "Warum Flare", es: "Por qué Flare" }, "A Community That Matters.": { fr: "Une communauté qui compte.", de: "Eine Gemeinschaft, die zählt.", es: "Una comunidad que importa." }, "Iconic towers · 40 & 34 floors": { fr: "Tours emblématiques · 40 & 34 étages", de: "Markante Türme · 40 & 34 Etagen", es: "Torres icónicas · 40 y 34 plantas" }, "Residences + 79 retail units": { fr: "Résidences + 79 commerces", de: "Residenzen + 79 Geschäfte", es: "Residencias + 79 locales" }, "Easy payment plan*": { fr: "Plan de paiement facile*", de: "Einfacher Zahlungsplan*", es: "Plan de pago cómodo*" }, "Minutes to Marina & Downtown": { fr: "À quelques minutes de Marina & Downtown", de: "Minuten zu Marina & Downtown", es: "A minutos de Marina y Downtown" }, // unit mix "Choose your residence": { fr: "Choisissez votre résidence", de: "Wählen Sie Ihre Residenz", es: "Elija su residencia" }, "From Studios to Four Bedroom Sky Homes": { fr: "Du studio aux appartements de quatre chambres", de: "Vom Studio bis zur Vier-Zimmer-Wohnung", es: "De estudios a viviendas de cuatro dormitorios" }, "1 Bedroom": { fr: "1 chambre", de: "1 Schlafzimmer", es: "1 dormitorio" }, "2 Bedroom": { fr: "2 chambres", de: "2 Schlafzimmer", es: "2 dormitorios" }, "3 Bedroom": { fr: "3 chambres", de: "3 Schlafzimmer", es: "3 dormitorios" }, "4 Bedroom": { fr: "4 chambres", de: "4 Schlafzimmer", es: "4 dormitorios" }, "3 & 4 Bedroom": { fr: "3 & 4 chambres", de: "3 & 4 Schlafzimmer", es: "3 y 4 dormitorios" }, "Price on request": { fr: "Prix sur demande", de: "Preis auf Anfrage", es: "Precio a consultar" }, "Investor favourite": { fr: "Favori des investisseurs", de: "Investorenliebling", es: "Favorito de inversores" }, "Balcony · skyline view": { fr: "Balcon · vue sur la skyline", de: "Balkon · Skyline-Blick", es: "Balcón · vista al skyline" }, "Family ready": { fr: "Idéal en famille", de: "Familienfreundlich", es: "Ideal para familias" }, "Sky terrace · pool": { fr: "Terrasse en hauteur · piscine", de: "Sky-Terrasse · Pool", es: "Terraza panorámica · piscina" }, "Enquire": { fr: "Demander", de: "Anfragen", es: "Consultar" }, "* Indicative starting prices. Confirm availability on enquiry.": { fr: "* Prix de départ indicatifs. Disponibilité à confirmer sur demande.", de: "* Indikative Startpreise. Verfügbarkeit auf Anfrage.", es: "* Precios iniciales orientativos. Disponibilidad a confirmar." }, // amenities "Life at Flare": { fr: "La vie à Flare", de: "Leben in Flare", es: "La vida en Flare" }, "Resort Amenities at Your Door.": { fr: "Des équipements de resort à votre porte.", de: "Resort-Annehmlichkeiten vor Ihrer Tür.", es: "Servicios de resort a su puerta." }, "Artificial beach": { fr: "Plage artificielle", de: "Künstlicher Strand", es: "Playa artificial" }, "Sand & pool deck": { fr: "Sable et terrasse piscine", de: "Sand & Pooldeck", es: "Arena y solárium" }, "Private sky pools": { fr: "Piscines privées en hauteur", de: "Private Sky-Pools", es: "Piscinas privadas en altura" }, "Sky-terrace homes": { fr: "Appartements avec terrasse", de: "Wohnungen mit Sky-Terrasse", es: "Viviendas con terraza" }, "Gym & running lane": { fr: "Salle de sport et piste de course", de: "Fitness & Laufstrecke", es: "Gimnasio y pista de carrera" }, "Wellness floor": { fr: "Étage bien-être", de: "Wellness-Etage", es: "Planta de bienestar" }, "Paddle court": { fr: "Terrain de padel", de: "Padel-Platz", es: "Pista de pádel" }, "Active living": { fr: "Vie active", de: "Aktives Leben", es: "Vida activa" }, "Kids wet & dry play": { fr: "Aire de jeux enfants", de: "Kinder-Spielbereiche", es: "Zona de juegos infantil" }, "Family zones": { fr: "Espaces famille", de: "Familienbereiche", es: "Zonas familiares" }, "Luxury lobby": { fr: "Lobby de luxe", de: "Luxuriöse Lobby", es: "Vestíbulo de lujo" }, "Signature arrival": { fr: "Arrivée signature", de: "Stilvoller Empfang", es: "Llegada de autor" }, "Retail & shopping": { fr: "Commerces et boutiques", de: "Handel & Shopping", es: "Comercios y tiendas" }, "79 units below": { fr: "79 commerces en contrebas", de: "79 Geschäfte darunter", es: "79 locales debajo" }, "Skyline views": { fr: "Vues sur la skyline", de: "Skyline-Ausblicke", es: "Vistas al skyline" }, "Burj on the horizon": { fr: "Burj à l'horizon", de: "Burj am Horizont", es: "Burj en el horizonte" }, // floor plans "Layouts": { fr: "Plans", de: "Grundrisse", es: "Distribuciones" }, "Floor Plans": { fr: "Plans d'étage", de: "Grundrisse", es: "Planos" }, "Floor plans available on request": { fr: "Plans disponibles sur demande", de: "Grundrisse auf Anfrage", es: "Planos disponibles a petición" }, "Tap to unlock": { fr: "Appuyez pour débloquer", de: "Zum Freischalten tippen", es: "Toque para desbloquear" }, "Unlock floor plan": { fr: "Débloquer le plan", de: "Grundriss freischalten", es: "Desbloquear plano" }, "Indicative layout. Request the full floor plan pack with sizes and the current price list.": { fr: "Plan indicatif. Demandez le dossier complet avec les surfaces et la liste de prix actuelle.", de: "Indikativer Grundriss. Fordern Sie das komplette Paket mit Flächen und aktueller Preisliste an.", es: "Distribución orientativa. Solicite el dossier completo con superficies y la lista de precios actual." }, "Request Full Floor Plan": { fr: "Demander le plan complet", de: "Vollständigen Grundriss anfordern", es: "Solicitar plano completo" }, // gallery "See it": { fr: "À découvrir", de: "Ansehen", es: "Descúbralo" }, "The Gallery": { fr: "La galerie", de: "Die Galerie", es: "La galería" }, "View image": { fr: "Voir l'image", de: "Bild ansehen", es: "Ver imagen" }, // location "Where it is": { fr: "Emplacement", de: "Lage", es: "Ubicación" }, "JVT. Central and Connected.": { fr: "JVT. Central et connecté.", de: "JVT. Zentral und vernetzt.", es: "JVT. Céntrico y conectado." }, "Drive times indicative.": { fr: "Temps de trajet indicatifs.", de: "Fahrzeiten indikativ.", es: "Tiempos de trayecto orientativos." }, // payment "Easy to own": { fr: "Facile à acquérir", de: "Einfach zu erwerben", es: "Fácil de adquirir" }, "Built for Buyers and Investors": { fr: "Pensé pour acheteurs et investisseurs", de: "Für Käufer und Investoren gemacht", es: "Pensado para compradores e inversores" }, "Book": { fr: "Réservation", de: "Buchung", es: "Reserva" }, "Down payment": { fr: "Acompte", de: "Anzahlung", es: "Entrada" }, "Build": { fr: "Construction", de: "Bau", es: "Construcción" }, "During construction": { fr: "Pendant la construction", de: "Während des Baus", es: "Durante la construcción" }, "On completion": { fr: "À la livraison", de: "Bei Fertigstellung", es: "A la entrega" }, "Book Now": { fr: "Réserver", de: "Jetzt buchen", es: "Reservar ahora" }, // faq "Good to know": { fr: "Bon à savoir", de: "Gut zu wissen", es: "Conviene saber" }, "Questions, Answered": { fr: "Vos questions, nos réponses", de: "Fragen, beantwortet", es: "Preguntas, respondidas" }, "What types of residences are available?": { fr: "Quels types de résidences sont disponibles ?", de: "Welche Wohnungstypen gibt es?", es: "¿Qué tipos de residencias hay disponibles?" }, "Studios to four bedroom apartments across two towers, plus retail.": { fr: "Du studio à l'appartement de quatre chambres répartis sur deux tours, plus des commerces.", de: "Vom Studio bis zur Vier-Zimmer-Wohnung in zwei Türmen, dazu Handelsflächen.", es: "Desde estudios hasta apartamentos de cuatro dormitorios en dos torres, más comercios." }, "Who is the developer?": { fr: "Qui est le promoteur ?", de: "Wer ist der Entwickler?", es: "¿Quién es el promotor?" }, "Binghatti is one of Dubai's leading developers, known for its bold, sculptural towers and a portfolio of landmark residences across the city.": { fr: "Binghatti est l'un des principaux promoteurs de Dubaï, reconnu pour ses tours sculpturales audacieuses et un portefeuille de résidences emblématiques dans toute la ville.", de: "Binghatti ist einer der führenden Entwickler Dubais, bekannt für markante, skulpturale Türme und ein Portfolio prägender Residenzen in der ganzen Stadt.", es: "Binghatti es uno de los principales promotores de Dubái, reconocido por sus torres escultóricas y una cartera de residencias emblemáticas en toda la ciudad." }, "What is the payment plan?": { fr: "Quel est le plan de paiement ?", de: "Wie sieht der Zahlungsplan aus?", es: "¿Cuál es el plan de pago?" }, "70/30: 20% on booking, 50% during construction, 30% on handover.": { fr: "70/30 : 20 % à la réservation, 50 % pendant la construction, 30 % à la livraison.", de: "70/30: 20 % bei Buchung, 50 % während des Baus, 30 % bei Übergabe.", es: "70/30: 20 % en la reserva, 50 % durante la construcción, 30 % en la entrega." }, "When is handover?": { fr: "Quand a lieu la livraison ?", de: "Wann ist die Übergabe?", es: "¿Cuándo es la entrega?" }, "Targeted for Q2 2027. Indicative, confirmed at booking.": { fr: "Prévue pour le 2e trimestre 2027. Indicative, confirmée à la réservation.", de: "Geplant für Q2 2027. Indikativ, bestätigt bei Buchung.", es: "Prevista para el 2.º trimestre de 2027. Orientativa, se confirma en la reserva." }, "Can foreign nationals buy?": { fr: "Les étrangers peuvent-ils acheter ?", de: "Können Ausländer kaufen?", es: "¿Pueden comprar extranjeros?" }, "Yes. Flare is freehold, open to all nationalities.": { fr: "Oui. Flare est en pleine propriété, ouvert à toutes les nationalités.", de: "Ja. Flare ist Eigentum (Freehold), offen für alle Nationalitäten.", es: "Sí. Flare es en propiedad plena (freehold), abierto a todas las nacionalidades." }, "What are the starting prices?": { fr: "Quels sont les prix de départ ?", de: "Wie hoch sind die Einstiegspreise?", es: "¿Cuáles son los precios iniciales?" }, // final cta "Own a Piece of the Skyline.": { fr: "Possédez un morceau de la skyline.", de: "Sichern Sie sich ein Stück Skyline.", es: "Posea un trozo del skyline." }, "Get the price list and floor plans on WhatsApp in minutes.": { fr: "Recevez la liste des prix et les plans sur WhatsApp en quelques minutes.", de: "Erhalten Sie Preisliste und Grundrisse in Minuten per WhatsApp.", es: "Reciba la lista de precios y los planos por WhatsApp en minutos." }, "Chat on WhatsApp": { fr: "Discuter sur WhatsApp", de: "Auf WhatsApp chatten", es: "Chatear por WhatsApp" }, // sticky "Call": { fr: "Appeler", de: "Anrufen", es: "Llamar" }, // footer "Marketed by": { fr: "Commercialisé par", de: "Vermarktet von", es: "Comercializado por" }, "Privacy Policy": { fr: "Politique de confidentialité", de: "Datenschutz", es: "Política de privacidad" }, "Cookie Policy": { fr: "Politique de cookies", de: "Cookie-Richtlinie", es: "Política de cookies" }, "Disclaimer": { fr: "Mentions légales", de: "Haftungsausschluss", es: "Aviso legal" }, // cookie "We use cookies to improve your experience.": { fr: "Nous utilisons des cookies pour améliorer votre expérience.", de: "Wir verwenden Cookies, um Ihre Erfahrung zu verbessern.", es: "Usamos cookies para mejorar su experiencia." }, "Learn more": { fr: "En savoir plus", de: "Mehr erfahren", es: "Más información" }, "Accept": { fr: "Accepter", de: "Akzeptieren", es: "Aceptar" }, // lead form "Get the price list & floor plans": { fr: "Recevez la liste des prix et les plans", de: "Preisliste & Grundrisse erhalten", es: "Reciba la lista de precios y los planos" }, "Instant reply on WhatsApp. No spam.": { fr: "Réponse immédiate sur WhatsApp. Sans spam.", de: "Sofortige Antwort per WhatsApp. Kein Spam.", es: "Respuesta inmediata por WhatsApp. Sin spam." }, "Full name": { fr: "Nom complet", de: "Vollständiger Name", es: "Nombre completo" }, "Your name": { fr: "Votre nom", de: "Ihr Name", es: "Su nombre" }, "Mobile number": { fr: "Numéro de mobile", de: "Mobilnummer", es: "Número de móvil" }, "Email address": { fr: "Adresse e-mail", de: "E-Mail-Adresse", es: "Correo electrónico" }, "Interested in": { fr: "Intéressé par", de: "Interesse an", es: "Interesado en" }, "Select a residence": { fr: "Sélectionnez une résidence", de: "Residenz auswählen", es: "Seleccione una residencia" }, "Send me the details": { fr: "Envoyez-moi les détails", de: "Senden Sie mir die Details", es: "Envíenme la información" }, "Sending…": { fr: "Envoi…", de: "Senden…", es: "Enviando…" }, "I agree to be contacted about this project.": { fr: "J'accepte d'être contacté au sujet de ce projet.", de: "Ich stimme zu, zu diesem Projekt kontaktiert zu werden.", es: "Acepto ser contactado sobre este proyecto." }, "Search country": { fr: "Rechercher un pays", de: "Land suchen", es: "Buscar país" }, "No match": { fr: "Aucun résultat", de: "Keine Treffer", es: "Sin coincidencias" }, "Thank you": { fr: "Merci", de: "Danke", es: "Gracias" }, "We'll send the price list and floor plans on WhatsApp shortly.": { fr: "Nous vous enverrons la liste des prix et les plans sur WhatsApp sous peu.", de: "Wir senden Ihnen in Kürze Preisliste und Grundrisse per WhatsApp.", es: "Le enviaremos la lista de precios y los planos por WhatsApp en breve." }, "Chat now on WhatsApp": { fr: "Discuter maintenant sur WhatsApp", de: "Jetzt auf WhatsApp chatten", es: "Chatear ahora por WhatsApp" }, // aria "Please enter your name": { fr: "Veuillez saisir votre nom", de: "Bitte geben Sie Ihren Namen ein", es: "Introduzca su nombre" }, "Please enter a valid name": { fr: "Veuillez saisir un nom valide", de: "Bitte geben Sie einen gültigen Namen ein", es: "Introduzca un nombre válido" }, "Enter a valid mobile number": { fr: "Saisissez un numéro de mobile valide", de: "Geben Sie eine gültige Mobilnummer ein", es: "Introduzca un número de móvil válido" }, "Enter a valid email address": { fr: "Saisissez une adresse e-mail valide", de: "Geben Sie eine gültige E-Mail-Adresse ein", es: "Introduzca un correo electrónico válido" }, "Please tick the box to continue": { fr: "Cochez la case pour continuer", de: "Bitte ankreuzen, um fortzufahren", es: "Marque la casilla para continuar" }, "A 360° Walk Through Flare.": { fr: "Une visite à 360° de Flare.", de: "Ein 360°-Rundgang durch Flare.", es: "Un recorrido de 360° por Flare." }, "Step inside": { fr: "Entrez", de: "Treten Sie ein", es: "Entre" }, "Close": { fr: "Fermer", de: "Schließen", es: "Cerrar" }, "Previous": { fr: "Précédent", de: "Zurück", es: "Anterior" }, "Next": { fr: "Suivant", de: "Weiter", es: "Siguiente" }, }; const I18N_ATTRS = ['placeholder', 'aria-label', 'title']; let _obs = null, _busy = false, _raf = 0; function translateAll() { const lang = window.__lang || 'en'; const root = document.getElementById('root'); if (!root) return; _busy = true; if (_obs) _obs.disconnect(); if (lang !== 'en') { const w = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null); const list = []; while (w.nextNode()) list.push(w.currentNode); for (const n of list) { const raw = n.nodeValue; if (!raw) continue; const key = raw.trim(); if (!key) continue; const e = T_DICT[key]; if (e && e[lang]) { const t = raw.replace(key, e[lang]); if (n.nodeValue !== t) n.nodeValue = t; } } root.querySelectorAll('[placeholder],[aria-label],[title]').forEach(el => { for (const a of I18N_ATTRS) { const raw = el.getAttribute(a); if (!raw) continue; const key = raw.trim(); const e = T_DICT[key]; if (e && e[lang]) { const t = raw.replace(key, e[lang]); if (raw !== t) el.setAttribute(a, t); } } }); } if (_obs) _obs.observe(root, { childList: true, subtree: true, characterData: true, attributes: true, attributeFilter: I18N_ATTRS }); _busy = false; } function scheduleTranslate() { if ((window.__lang || 'en') === 'en') return; if (_raf) cancelAnimationFrame(_raf); _raf = requestAnimationFrame(() => { _raf = 0; translateAll(); }); } (function setupObserver() { const root = document.getElementById('root'); if (!root) { setTimeout(setupObserver, 60); return; } _obs = new MutationObserver(() => { if (!_busy) scheduleTranslate(); }); _obs.observe(root, { childList: true, subtree: true, characterData: true, attributes: true, attributeFilter: I18N_ATTRS }); })(); const LangCtx = React.createContext(['en', () => {}]); function useLang() { return React.useContext(LangCtx); } function LangSwitcher() { const [lang, setLang] = useLang(); const [open, setOpen] = React.useState(false); const ref = React.useRef(null); React.useEffect(() => { const onDoc = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener('mousedown', onDoc); return () => document.removeEventListener('mousedown', onDoc); }, []); const cur = LANGS.find(l => l[0] === lang) || LANGS[0]; return (