// i18n.jsx — Locale detection, dictionaries, slug routing for Saloria. // Loaded before every other Saloria script. Exposes window.SaloriaI18n. // // Locale is detected from the URL path: /it/, /es/, /fr/, /en/, /pt/. // Fallback is 'it' (Italian source). Each helper accepts an optional locale. (function () { const LOCALES = ["it", "es", "fr", "en", "pt"]; const DEFAULT_LOCALE = "it"; function detectLocale() { if (typeof window === "undefined") return DEFAULT_LOCALE; const m = window.location.pathname.match(/^\/(it|es|fr|en|pt)(\/|$)/i); return m ? m[1].toLowerCase() : DEFAULT_LOCALE; } // ── Page slug map ──────────────────────────────────────────────────────── // Each main page has a localized slug per locale. Keys are stable IDs. const PAGE_SLUGS = { home: { it: "", es: "", fr: "", en: "", pt: "" }, pricing: { it: "pricing", es: "precios", fr: "tarifs", en: "pricing", pt: "precos" }, salesFlow: { it: "inizia-subito", es: "empezar-ahora", fr: "commencer", en: "start-now", pt: "comecar-agora" }, contact: { it: "contatti", es: "contacto", fr: "contact", en: "contact", pt: "contato" }, howItWorks: { it: "come-funziona", es: "como-funciona", fr: "comment-ca-marche", en: "how-it-works", pt: "como-funciona" }, aiAnalysis: { it: "analisi-ai", es: "analisis-ai", fr: "analyse-ai", en: "ai-analysis", pt: "analise-ai" }, capabilities: { it: "capabilities", es: "funcionalidades", fr: "fonctionnalites", en: "capabilities", pt: "funcionalidades" }, blog: { it: "blog", es: "blog", fr: "blog", en: "blog", pt: "blog" }, login: { it: "login", es: "login", fr: "login", en: "login", pt: "login" }, resourcesHub: { it: "risorse/", es: "recursos/", fr: "ressources/", en: "resources/", pt: "recursos/" }, }; const RESOURCES_FOLDER = { it: "risorse", es: "recursos", fr: "ressources", en: "resources", pt: "recursos", }; // ── UI labels (header, footer, buttons, breadcrumbs) ───────────────────── const UI = { nav: { home: { it: "Home", es: "Inicio", fr: "Accueil", en: "Home", pt: "Início" }, aiAnalysis: { it: "Analisi AI", es: "Análisis IA", fr: "Analyse IA", en: "AI Analysis", pt: "Análise IA" }, howItWorks: { it: "Come funziona", es: "Cómo funciona", fr: "Comment ça marche", en: "How it works", pt: "Como funciona" }, pricing: { it: "Pricing", es: "Precios", fr: "Tarifs", en: "Pricing", pt: "Preços" }, contact: { it: "Contatti", es: "Contacto", fr: "Contact", en: "Contact", pt: "Contato" }, bookDemo: { it: "Prenota una demo", es: "Reserva una demo", fr: "Réserver une démo", en: "Book a demo", pt: "Agendar uma demo" }, }, footer: { tagline: { it: "L'AI Beauty Advisor per saloni d'autore. Made in Italy.", es: "El AI Beauty Advisor para salones de autor. Made in Italy.", fr: "L'AI Beauty Advisor pour salons d'auteur. Made in Italy.", en: "The AI Beauty Advisor for signature salons. Made in Italy.", pt: "O AI Beauty Advisor para salões autorais. Made in Italy.", }, product: { it: "Prodotto", es: "Producto", fr: "Produit", en: "Product", pt: "Produto" }, salon: { it: "Salone", es: "Salón", fr: "Salon", en: "Salon", pt: "Salão" }, contact: { it: "Contatti", es: "Contacto", fr: "Contact", en: "Contact", pt: "Contato" }, resources: { it: "Risorse", es: "Recursos", fr: "Ressources", en: "Resources", pt: "Recursos" }, bookDemo: { it: "Prenota demo", es: "Reserva demo", fr: "Réserver une démo", en: "Book demo", pt: "Agendar demo" }, partnerLogin:{ it: "Login partner", es: "Login partner", fr: "Login partenaire", en: "Partner login", pt: "Login parceiro" }, onboarding: { it: "Onboarding", es: "Onboarding", fr: "Onboarding", en: "Onboarding", pt: "Onboarding" }, systemStatus:{ it: "Stato sistema", es: "Estado del sistema", fr: "État du système", en: "System status", pt: "Status do sistema" }, requestDemo: { it: "Richiedi demo", es: "Solicitar demo", fr: "Demander une démo", en: "Request a demo", pt: "Solicitar demo" }, salonSupport:{ it: "Supporto saloni", es: "Soporte a salones", fr: "Support salons", en: "Salon support", pt: "Suporte a salões" }, copyright: { it: "© SALORIA 2025 · TUTTI I DIRITTI RISERVATI", es: "© SALORIA 2025 · TODOS LOS DERECHOS RESERVADOS", fr: "© SALORIA 2025 · TOUS DROITS RÉSERVÉS", en: "© SALORIA 2025 · ALL RIGHTS RESERVED", pt: "© SALORIA 2025 · TODOS OS DIREITOS RESERVADOS", }, vatLine: { it: "P.IVA 12867410969 · SALORIA CLOUD", es: "P.IVA 12867410969 · SALORIA CLOUD", fr: "P.IVA 12867410969 · SALORIA CLOUD", en: "VAT 12867410969 · SALORIA CLOUD", pt: "NIF 12867410969 · SALORIA CLOUD", }, }, languageSwitcher: { label: { it: "Lingua", es: "Idioma", fr: "Langue", en: "Language", pt: "Idioma" }, flags: { it: { code: "IT", name: "Italiano" }, es: { code: "ES", name: "Español" }, fr: { code: "FR", name: "Français" }, en: { code: "EN", name: "English" }, pt: { code: "PT", name: "Português" }, }, }, common: { readMore: { it: "Continua a leggere", es: "Sigue leyendo", fr: "Lire la suite", en: "Read more", pt: "Continuar lendo" }, backToHome: { it: "Torna alla home", es: "Volver al inicio", fr: "Retour à l'accueil", en: "Back to home", pt: "Voltar ao início" }, backToHub: { it: "Torna alle risorse", es: "Volver a recursos", fr: "Retour aux ressources", en: "Back to resources", pt: "Voltar aos recursos" }, bookDemo: { it: "Prenota una demo", es: "Reserva una demo", fr: "Réserver une démo", en: "Book a demo", pt: "Agendar uma demo" }, newsletter: { it: "Newsletter", es: "Newsletter", fr: "Newsletter", en: "Newsletter", pt: "Newsletter" }, }, }; // ── HTML lang attribute / OG locale / JSON-LD inLanguage ───────────────── const META_LANG = { htmlLang: { it: "it", es: "es", fr: "fr", en: "en", pt: "pt-BR" }, inLanguage: { it: "it-IT", es: "es-ES", fr: "fr-FR", en: "en-US", pt: "pt-BR" }, ogLocale: { it: "it_IT", es: "es_ES", fr: "fr_FR", en: "en_US", pt: "pt_BR" }, }; // ── Helpers ────────────────────────────────────────────────────────────── function t(dict, locale) { locale = locale || detectLocale(); if (!dict) return ""; return dict[locale] || dict[DEFAULT_LOCALE] || ""; } // Build absolute URL for a logical page in a given locale. // pageKey: 'home' | 'pricing' | 'contact' | ... function pageHref(pageKey, locale) { locale = locale || detectLocale(); const slug = (PAGE_SLUGS[pageKey] || {})[locale]; if (slug == null) return "/" + locale + "/"; return "/" + locale + "/" + slug; } // Build absolute URL for a resource article. articleSlug is locale-specific. function articleHref(articleSlug, locale) { locale = locale || detectLocale(); return "/" + locale + "/" + RESOURCES_FOLDER[locale] + "/" + String(articleSlug || ""); } function resourcesHubHref(locale) { locale = locale || detectLocale(); return "/" + locale + "/" + RESOURCES_FOLDER[locale] + "/"; } // Switch the *current* URL to the equivalent URL in another locale. // For main pages we recognise the slug and map it across locales. function switchLocaleHref(targetLocale) { if (typeof window === "undefined") return "/" + targetLocale + "/"; const path = window.location.pathname; const current = detectLocale(); // Main page detection: /xx/ const m = path.match(/^\/(it|es|fr|en|pt)\/([^/]*)$/i); if (m) { const file = m[2]; // find which pageKey produced this slug for the current locale for (const key of Object.keys(PAGE_SLUGS)) { if ((PAGE_SLUGS[key][current] || "") === file) { return pageHref(key, targetLocale); } } // unknown file → fall through to locale root return "/" + targetLocale + "/"; } // Resource hub: /xx// const hub = path.match(/^\/(it|es|fr|en|pt)\/(risorse|recursos|ressources|resources)\/?$/i); if (hub) return resourcesHubHref(targetLocale); // Resource article: /xx// const art = path.match(/^\/(it|es|fr|en|pt)\/(risorse|recursos|ressources|resources)\/([^/]+?)$/i); if (art) { // We don't have a synchronous slug map for 168 articles here. // Fallback: send to localized resources hub. Article-level cross-links // are rendered with hreflang in each article's so search // engines still discover the localized equivalents. return resourcesHubHref(targetLocale); } return "/" + targetLocale + "/"; } const SaloriaI18n = { LOCALES, DEFAULT_LOCALE, PAGE_SLUGS, RESOURCES_FOLDER, UI, META_LANG, detectLocale, t, pageHref, articleHref, resourcesHubHref, switchLocaleHref, }; if (typeof window !== "undefined") { window.SaloriaI18n = SaloriaI18n; // Persist the current locale so /Nginx and the Accept-Language fallback // respect the user's last-visited locale on their next hit to "/". try { const locale = detectLocale(); document.cookie = "saloria_locale=" + locale + "; path=/; max-age=31536000; SameSite=Lax"; } catch (_) {} } })();