import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; export type Lang = "en" | "es"; interface Panel { title: string; body: string; } interface Dict { appTitle: string; nav: { monitor: string; simulator: string; metrics: string; presentation: string }; monitor: { mostAnomalous: string; offline: string; actual: string; reconstructed: string; scoreTitle: string }; alert: { alert: string; nominal: string; peak: string; threshold: string; latency: string }; simulator: { baseFlight: string; injectedAnomaly: string; intensity: string; onset: string; onsetSuffix: string; original: string; injected: string; kinds: Record; }; metrics: { title: string; model: string; realRoc: string; realPr: string; synRoc: string; none: string; selected: string; }; timeline: { threshold: string }; scenes: { skip: string; enter: string; finalNav: string; continueToConsole: string; terminal: { kicker: string; title: string; sub: string }; jetbridge: { kicker: string; title: string }; cabin: { kicker: string; title: string; sub?: string }; closing: { kicker: string; title: string }; explainHeader: string; panels: Panel[]; opening: { kicker: string; title: string }; leaving: { kicker: string; title: string }; ack: { kicker: string; subtitle: string; teamHeader: string; thanks: string; roles: { tower1: string; pilot: string; tower2: string }; }; }; } const EN: Dict = { appTitle: "TOWER CONSOLE · LEMD-9F4C", nav: { monitor: "Monitor", simulator: "Simulator", metrics: "Metrics", presentation: "Presentation" }, monitor: { mostAnomalous: "Most anomalous windows", offline: "backend offline. start it with: make serve", actual: "actual", reconstructed: "reconstructed", scoreTitle: "Anomaly score", }, alert: { alert: "ALERT", nominal: "NOMINAL", peak: "peak", threshold: "thr", latency: "latency" }, simulator: { baseFlight: "Base flight (normal)", injectedAnomaly: "Injected anomaly", intensity: "Intensity", onset: "Onset", onsetSuffix: "% into the window", original: "original", injected: "injected", kinds: { route_deviation: "Route deviation", altitude: "Altitude bust", speed: "Speed anomaly", holding: "Holding turns", freeze: "Transponder cut", }, }, metrics: { title: "Model comparison on held-out data", model: "Model", realRoc: "real ROC", realPr: "real PR-AUC", synRoc: "syn ROC", none: "no metrics yet. generate them with: make compare", selected: "selected final model", }, timeline: { threshold: "THRESHOLD" }, scenes: { skip: "Skip", enter: "Enter the console", finalNav: "Final ▸", continueToConsole: "Continue to the console", terminal: { kicker: "Madrid Barajas / LEMD", title: "You walk through the terminal", sub: "Every day, around a thousand flights follow the same quiet pattern.", }, jetbridge: { kicker: "Boarding", title: "Down the jet bridge" }, cabin: { kicker: "On board", title: "Take your seat" }, closing: { kicker: "Doors closed", title: "The flight begins" }, explainHeader: "Air traffic control / LEMD", panels: [ { title: "From the ground, we look after every flight", body: "While you fly, the control tower keeps watch, making sure your route is the one it should be.", }, { title: "Every route checked against the pattern", body: "We watch over your flight from start to finish, and anything that breaks the rhythm of flight stands out.", }, { title: "Deviations and incidents, caught early", body: "An odd route, an altitude that does not fit, a transponder that goes silent: spotted as it begins, not after.", }, ], opening: { kicker: "Destination", title: "Arrived safely" }, leaving: { kicker: "Conformance confirmed", title: "You walk out" }, ack: { kicker: "Thank you", subtitle: "Smart Anomaly Detection for Aviation Routes", teamHeader: "The team", thanks: "Thank you.", roles: { tower1: "Approach controller", pilot: "Pilot", tower2: "Tower controller", }, }, }, }; const ES: Dict = { appTitle: "TOWER CONSOLE · LEMD-9F4C", nav: { monitor: "Monitor", simulator: "Simulador", metrics: "Métricas", presentation: "Presentación" }, monitor: { mostAnomalous: "Ventanas más anómalas", offline: "backend apagado. arráncalo con: make serve", actual: "real", reconstructed: "reconstruido", scoreTitle: "Score de anomalía", }, alert: { alert: "ALERTA", nominal: "NORMAL", peak: "pico", threshold: "umbral", latency: "latencia" }, simulator: { baseFlight: "Vuelo base (normal)", injectedAnomaly: "Anomalía inyectada", intensity: "Intensidad", onset: "Inicio", onsetSuffix: "% de la ventana", original: "original", injected: "inyectado", kinds: { route_deviation: "Desvío de ruta", altitude: "Anomalía de altitud", speed: "Anomalía de velocidad", holding: "Giros de espera", freeze: "Corte de transpondedor", }, }, metrics: { title: "Comparativa de modelos (datos no vistos)", model: "Modelo", realRoc: "ROC real", realPr: "PR-AUC real", synRoc: "ROC sint", none: "sin métricas. genéralas con: make compare", selected: "modelo final elegido", }, timeline: { threshold: "UMBRAL" }, scenes: { skip: "Saltar", enter: "Entrar a la consola", finalNav: "Final ▸", continueToConsole: "Continuar a la consola", terminal: { kicker: "Madrid Barajas / LEMD", title: "Cruzas la terminal", sub: "Cada día, unos mil vuelos siguen el mismo patrón tranquilo.", }, jetbridge: { kicker: "Embarque", title: "Por el pasillo de embarque" }, cabin: { kicker: "A bordo", title: "Toma asiento" }, closing: { kicker: "Puertas cerradas", title: "Comienza el vuelo" }, explainHeader: "Control de tráfico aéreo / LEMD", panels: [ { title: "Desde tierra, cuidamos de cada vuelo", body: "Mientras vuelas, la torre de control vigila, asegurándose de que tu ruta es la que debe ser.", }, { title: "Cada ruta, comparada con el patrón", body: "Vigilamos tu vuelo de principio a fin, y todo lo que rompa la cadencia del vuelo salta a la vista.", }, { title: "Desviaciones e incidencias, a tiempo", body: "Una ruta rara, una altitud que no encaja, un transpondedor que se calla: se detecta en cuanto empieza, no después.", }, ], opening: { kicker: "Destino", title: "Has llegado" }, leaving: { kicker: "Conformidad confirmada", title: "Sales caminando" }, ack: { kicker: "", subtitle: "Detección inteligente de anomalías en rutas aéreas", teamHeader: "El equipo", thanks: "Gracias.", roles: { tower1: "Control de aproximación", pilot: "Piloto", tower2: "Torre de control", }, }, }, }; const DICTS: Record = { en: EN, es: ES }; interface LangContextValue { lang: Lang; setLang: (lang: Lang) => void; toggle: () => void; } const LangContext = createContext({ lang: "en", setLang: () => { }, toggle: () => { } }); export function LanguageProvider({ children }: { children: ReactNode }) { const [lang, setLang] = useState(() => { const saved = localStorage.getItem("sadar-lang"); if (saved === "en" || saved === "es") return saved; return navigator.language.startsWith("es") ? "es" : "en"; }); useEffect(() => { localStorage.setItem("sadar-lang", lang); }, [lang]); const value = useMemo( () => ({ lang, setLang, toggle: () => setLang(lang === "en" ? "es" : "en") }), [lang], ); return {children}; } export function useLang(): LangContextValue { return useContext(LangContext); } export function useT(): Dict { return DICTS[useContext(LangContext).lang]; }