i18n.js
Rama main · réplica de lectura del repositorio original.
// Hearth · i18n (English fallback + zh-CN + zh-TW)
// 设计:t(英文原串) 查表;缺失键回退英文原串(零破坏)。
// 语言:en 🇬🇧 / zh-CN 🇨🇳 / zh-TW 🇹🇼。localStorage 持久化 aim.lang。
(() => {
const LANGS = [
{ code: "en", flag: "🇬🇧", label: "English" },
{ code: "zh-CN", flag: "🇨🇳", label: "简体中文" },
{ code: "zh-TW", flag: "🇹🇼", label: "繁體中文" },
];
// 字典:key = 英文原串。en 用原串本身(表里不重复列)。
const DICT = {
"zh-CN": {
// nav
"Overview": "总览", "Cluster": "集群", "Nodes": "节点", "Models": "模型",
"Telemetry": "遥测", "Fabric": "网络", "Search": "搜索",
"nodes online": "节点在线", "OFFLINE": "离线", "reconnecting…": "重连中…",
"mock data · no backend": "模拟数据 · 无后端", "LIVE": "实时", "MOCK": "模拟",
// hero
"Home": "家庭", "Compute Center": "智算中心",
"A unified telemetry surface for your home AI compute cluster — auto-discovers models, surfaces real metrics from vLLM / llama.cpp / LiteLLM, honestly labels what backends don't expose. Every token, every watt — in real time.":
"自托管的家庭 AI 算力可观测性面板 —— 自动发现模型, 从 vLLM / llama.cpp / LiteLLM 取真实指标, 后端不暴露的诚实标空。每一个 token, 每一瓦特, 实时。",
"UPTIME": "运行时长", "REQUESTS": "请求数", "TOKENS SERVED": "已服务 Token", "SCRAPE": "抓取",
// section eyebrows
"Cluster · live telemetry": "集群 · 实时遥测",
"Models · LiteLLM gateway": "模型 · LiteLLM 网关",
"Telemetry · alerts": "遥测 · 告警", "Fabric · network": "网络 · 拓扑",
// section h2 (拆分 普通 + <em> 两段)
"Real-time pulse of the ": "实时脉搏 · ", "entire fabric.": "整个集群",
"{n} machines. ": "{n} 台机器 · ", "Each a citizen.": "各为一员",
"One endpoint. ": "一个入口 · ", "Every model.": "所有模型",
"Signal, not ": "只见信号 · ", "noise.": "不见噪声",
"The wires ": "万物 · ", "between everything.": "互联之线",
// ledes
"Aggregated utilization, throughput, and thermals across all {n} nodes — sampled at 1.2 s, retained for 7 days in Prometheus, surfaced here as a single coherent picture.":
"{n} 节点的利用率、吞吐与热数据聚合 —— 1.2 秒采样,Prometheus 留存 7 天,在此汇成一张连贯全景。",
"Each host runs the LiteLLM gateway, an inference engine, or both. Click a node for the full forensic view.":
"每台主机跑 LiteLLM 网关、推理引擎,或两者皆有。点击任一节点查看完整取证视图。",
"The gateway host peers with every inference node — link intensity & pulse are driven by real node-exporter throughput. Inter-node fabric (RDMA/InfiniBand) is physical topology only (throughput not instrumented by default).":
"网关主机与各推理节点互联 —— 链路强度/脉冲由真实 node-exporter 吞吐驱动;节点间高速 fabric(RDMA/InfiniBand)为物理拓扑,默认不插桩吞吐。",
// cards / labels
"Resource pools": "资源池", "Aggregate capacity vs. live usage": "总容量 vs 实时用量",
"Hosted models": "承载模型", "Running services": "运行服务", "System": "系统",
"Quick actions": "快捷操作", "LiteLLM Gateway": "LiteLLM 网关",
"Model": "模型", "Throughput": "吞吐", "State": "状态",
"Accelerator activity": "加速器活跃度", "VRAM": "显存",
// footer
"Prometheus 2.55 · DCGM 3.3 · LiteLLM 1.52 · scrape 15 s · retention 7 d":
"Prometheus 2.55 · DCGM 3.3 · LiteLLM 1.83 · 抓取 15 秒 · 留存 7 天",
"All inference is routed through LiteLLM on ": "全部推理统一经 LiteLLM 路由 · ",
" — OpenAI-compatible API, smart routing, fallbacks, cost & token accounting. Cold models spin up on demand to fit the VRAM budget.":
" —— OpenAI 兼容 API、智能路由、回退、成本与 Token 计量。冷模型按需拉起以适配显存预算。",
"Every request that lands at the gateway, every anomaly the rules engine catches — surfaced as a quiet, structured stream. No paging unless something actually needs you.":
"每一个到达网关的请求、规则引擎捕获的每一处异常 —— 以安静、结构化的流呈现。除非真的需要你,否则不打扰。",
"Models · LiteLLM gateway": "模型 · LiteLLM 网关",
// PulseCards
"Token throughput": "Token 吞吐", "tokens / sec · all models": "tokens/秒 · 全部模型",
"Cluster power draw": "集群功耗", "watts · all PSUs": "瓦特 · 全部电源",
"KV-cache pressure": "KV 缓存压力", "% utilization, weighted mean": "% 利用率 · 加权均值",
// node detail
"forensic view": "取证视图", "Accelerator activity · 60 ticks": "加速器活跃度 · 近 60 拍",
"GPU temp": "GPU 温度", "NIC temp": "网卡温度", "Power draw": "功耗", "Disk usage": "磁盘占用",
"Net In": "入向流量", "Net Out": "出向流量",
"Hosted models": "承载模型", "Running services": "运行服务",
"Kernel": "内核", "Driver": "驱动", "Net": "网络",
"Hardware temps": "硬件温度",
"Hardware sensors": "硬件传感器", "Fans": "风扇", "+{n} more": "还有 {n} 项",
"— no temperature data (node unmanaged) —": "— 无温度数据(节点未纳管)—",
"GPU pending · maintenance window": "GPU 待维护窗口纳管",
"Open SSH session": "打开 SSH 会话", "Drain & cordon": "排空并隔离",
"Restart daemons": "重启守护进程", "Pin model…": "固定模型…",
"Run nvidia-smi dmon": "运行 nvidia-smi dmon", "Reboot": "重启节点",
// model detail / table
"Throughput · last 32 ticks": "吞吐 · 近 32 拍",
"TTFT (first token)": "TTFT(首 token)", "TPOT (per token)": "TPOT(每 token)",
"Concurrency · running": "并发 · 执行中", "running": "执行中", "queued": "排队中",
"Requests / sec": "请求/秒",
"Route · ": "路由 · ",
"TTFT / TPOT": "TTFT / TPOT", "KV-cache": "KV 缓存",
"P50 / P95 / P99": "P50 / P95 / P99", "Placement · framework": "部署 · 框架",
"no live metrics source": "无实时指标源", "vLLM not exposed": "vLLM 未暴露",
"vLLM + llama.cpp + SGLang /metrics": "vLLM + llama.cpp + SGLang /metrics", "Live throughput": "实时吞吐",
"llama.cpp /metrics does not expose TTFT / KV% / e2e histograms · shown as — honestly":
"llama.cpp /metrics 未暴露 TTFT / KV% / e2e 直方图 · 诚实显—,不伪造",
"TPOT / KV-cache / error-rate: this vLLM build does not expose them → honestly left blank, not faked.":
"TPOT / KV缓存 / 错误率:此 vLLM 构建 /metrics 未暴露 → 诚实留空,不伪造。",
"backend has no Prometheus /metrics endpoint. No live-metrics source → honestly marked, not faked. Model still serves normally via LiteLLM route":
"后端无 Prometheus /metrics 端点。实时指标无来源 → 诚实标注,不伪造。模型经 LiteLLM 路由正常可用",
// gateway stats
"Catalog models": "目录模型", "with live metrics": "有实时指标",
"Live metric sources": "实时指标源", "vLLM native /metrics": "vLLM 原生 /metrics",
"vLLM throughput": "vLLM 吞吐", "t/s · measured sum": "t/s · 实测合计",
"LiteLLM metrics": "LiteLLM 指标", "enterprise": "企业版",
"OSS not exposed · documented": "OSS 不暴露 · 已记录",
"healthy": "健康", "streaming": "流式传输中",
// filters / states
"All": "全部", "RTX": "独显", "DGX": "统一", "Active": "活跃",
"Serving": "服务中", "Idle": "空闲", "Chat": "对话",
"serving": "服务中", "idle": "空闲", "no-metrics": "无指标",
"online": "在线", "stopped": "已停",
"loading": "加载中", "cold": "冷", "down": "离线",
// cmdk
"Search nodes, models, sections…": "搜索节点、模型、板块…",
"Section · top of page": "板块 · 页面顶部",
"Section · aggregate telemetry": "板块 · 聚合遥测",
"Section · {n} machines": "板块 · {n} 台机器",
"Section · LiteLLM gateway": "板块 · LiteLLM 网关",
"Section · alerts & log stream": "板块 · 告警与日志流",
"Section · network topology": "板块 · 网络拓扑",
"No results": "无结果",
// tweaks
"Tweaks": "偏好设置", "Appearance": "外观", "Theme": "主题",
"Dark": "深色", "Light": "浅色", "Accent": "强调色", "Density": "密度",
"Compact": "紧凑", "Regular": "标准", "Comfy": "宽松",
"Live data": "实时数据", "Source": "数据源", "Auto": "自动",
"Live": "实时", "Mock": "模拟", "Tick": "刷新间隔",
"Motion / animations": "动效 / 动画", "Shortcut": "快捷键",
"Press": "按", "anywhere to open the command palette.": "可在任意处打开命令面板。",
"Click any node or model row for the forensic view.": "点击任意节点或模型行进入取证视图。",
"Framework": "框架", "Port": "端口", "Quant": "量化", "Context": "上下文",
"Placement": "部署", "Open Playground": "打开 Playground",
"Restart": "重启", "Logs": "日志", "Close": "关闭",
"— No models pinned to this node —": "— 无模型固定到此节点 —",
"ONLINE": "在线", "OFFLINE": "离线", "Power": "功率", "maint. pending": "待维护纳管",
"LiteLLM request log · OSS Postgres": "LiteLLM 请求日志 · OSS Postgres",
"East-West · 200 GbE ConnectX-7 RDMA (live)": "东西向 · 200 GbE ConnectX-7 RDMA(真实)",
"Per-node": "各节点", "heatmap": "热力图",
"Accelerator activity · last 60 ticks · 0–100%": "加速器活跃度 · 近 60 拍 · 0–100%",
"VRAM usage · last 60 ticks · 0–100%": "显存占用 · 近 60 拍 · 0–100%",
"East-West · 200 GbE ConnectX-7 (topology only, throughput not instrumented)": "东西向 · 200 GbE ConnectX-7(仅拓扑,吞吐未插桩)",
"North-South pulse ∝ real network throughput": "南北向脉冲 ∝ 真实网络吞吐",
"Hearth": "Hearth · 家庭算力监控",
"Home AI Compute Center": "家庭智算中心",
"Home AI Compute Monitor": "家庭 AI 算力监控",
// lang switcher
"Language": "语言",
// ── Training section ──
"Training": "训练",
"Training · distributed": "训练 · 分布式",
"The long ": "漫长的", "run.": "训练。",
"Substrate health for the 4×GB10 training cluster — per-rank GPU, unified-memory headroom, CX-7 RoCE collective bandwidth, and a silent-stall heuristic. Read-only from obs; zero training impact.":
"4×GB10 训练集群的底座健康 —— 逐卡 GPU、统一内存余量、CX-7 RoCE 集合通信带宽,以及静默卡死启发式检测。只读自 obs,对训练零影响。",
"Ranks active": "活跃 rank", "util ≥ 50%": "利用率 ≥ 50%", "avg util": "平均利用率",
"RoCE Σ rx+tx": "RoCE Σ 收+发", "GPU power Σ": "GPU 功率 Σ",
"healthy": "健康", "idle": "空闲", "GPU fault": "GPU 故障",
"stall suspected": "疑似卡死", "skew": "偏斜", "util": "利用率",
"straggler": "落后节点", "stall?": "卡死?", "mem": "内存", "comm stalled?": "通信卡死?",
"train loss": "训练 loss", "step": "步", "mean accept": "平均接受",
"grad norm": "梯度范数", "lr": "学习率", "logging": "记录中", "write stalled?": "写入停滞?",
"source": "来源", "refresh ~12s": "刷新 ~12s",
"MFU pending GB10 bf16 peak FLOPs.": "MFU 待 GB10 bf16 峰值 FLOPs。",
"Loss · step / ETA · accept rate — awaiting a training signal source (auto-detects JSON / Prometheus / TensorBoard from the leader). Not fabricated. See docs/training-observability.md.":
"Loss · 步 / ETA · 接受率 —— 等待训练信号源(从 leader 自动探测 JSON / Prometheus / TensorBoard)。不伪造。见 docs/training-observability.md。",
},
"zh-TW": {
"Overview": "總覽", "Cluster": "叢集", "Nodes": "節點", "Models": "模型",
"Telemetry": "遙測", "Fabric": "網路", "Search": "搜尋",
"nodes online": "節點在線", "OFFLINE": "離線", "reconnecting…": "重連中…",
"mock data · no backend": "模擬資料 · 無後端", "LIVE": "即時", "MOCK": "模擬",
"Home": "家庭", "Compute Center": "智算中心",
"A unified telemetry surface for your home AI compute cluster — auto-discovers models, surfaces real metrics from vLLM / llama.cpp / LiteLLM, honestly labels what backends don't expose. Every token, every watt — in real time.":
"自架的家庭 AI 算力可觀測性面板 —— 自動發現模型, 從 vLLM / llama.cpp / LiteLLM 取真實指標, 後端不暴露的誠實標空。每一個 token, 每一瓦特, 即時。",
"UPTIME": "運行時長", "REQUESTS": "請求數", "TOKENS SERVED": "已服務 Token", "SCRAPE": "擷取",
"Cluster · live telemetry": "叢集 · 即時遙測",
"Models · LiteLLM gateway": "模型 · LiteLLM 閘道",
"Telemetry · alerts": "遙測 · 告警", "Fabric · network": "網路 · 拓撲",
"Real-time pulse of the ": "即時脈搏 · ", "entire fabric.": "整個叢集",
"{n} machines. ": "{n} 台機器 · ", "Each a citizen.": "各為一員",
"One endpoint. ": "一個入口 · ", "Every model.": "所有模型",
"Signal, not ": "只見訊號 · ", "noise.": "不見雜訊",
"The wires ": "萬物 · ", "between everything.": "互聯之線",
"Aggregated utilization, throughput, and thermals across all {n} nodes — sampled at 1.2 s, retained for 7 days in Prometheus, surfaced here as a single coherent picture.":
"{n} 節點的利用率、吞吐與熱數據聚合 —— 1.2 秒取樣,Prometheus 留存 7 天,在此匯成一張連貫全景。",
"Each host runs the LiteLLM gateway, an inference engine, or both. Click a node for the full forensic view.":
"每台主機跑 LiteLLM 閘道、推論引擎,或兩者皆有。點擊任一節點查看完整取證視圖。",
"The gateway host peers with every inference node — link intensity & pulse are driven by real node-exporter throughput. Inter-node fabric (RDMA/InfiniBand) is physical topology only (throughput not instrumented by default).":
"閘道主機與各推論節點互聯 —— 鏈路強度/脈衝由真實 node-exporter 吞吐驅動;節點間高速 fabric(RDMA/InfiniBand)為實體拓撲,預設不插樁吞吐。",
"Resource pools": "資源池", "Aggregate capacity vs. live usage": "總容量 vs 即時用量",
"Hosted models": "承載模型", "Running services": "執行服務", "System": "系統",
"Quick actions": "快捷操作", "LiteLLM Gateway": "LiteLLM 閘道",
"Model": "模型", "Throughput": "吞吐", "State": "狀態",
"Accelerator activity": "加速器活躍度", "VRAM": "顯存",
"Prometheus 2.55 · DCGM 3.3 · LiteLLM 1.52 · scrape 15 s · retention 7 d":
"Prometheus 2.55 · DCGM 3.3 · LiteLLM 1.83 · 擷取 15 秒 · 留存 7 天",
"All inference is routed through LiteLLM on ": "全部推理統一經 LiteLLM 路由 · ",
" — OpenAI-compatible API, smart routing, fallbacks, cost & token accounting. Cold models spin up on demand to fit the VRAM budget.":
" —— OpenAI 相容 API、智慧路由、回退、成本與 Token 計量。冷模型按需拉起以適配顯存預算。",
"Every request that lands at the gateway, every anomaly the rules engine catches — surfaced as a quiet, structured stream. No paging unless something actually needs you.":
"每一個到達閘道的請求、規則引擎捕獲的每一處異常 —— 以安靜、結構化的流呈現。除非真的需要你,否則不打擾。",
"Token throughput": "Token 吞吐", "tokens / sec · all models": "tokens/秒 · 全部模型",
"Cluster power draw": "叢集功耗", "watts · all PSUs": "瓦特 · 全部電源",
"KV-cache pressure": "KV 快取壓力", "% utilization, weighted mean": "% 使用率 · 加權均值",
"forensic view": "取證視圖", "Accelerator activity · 60 ticks": "加速器活躍度 · 近 60 拍",
"GPU temp": "GPU 溫度", "NIC temp": "網卡溫度", "Power draw": "功耗", "Disk usage": "磁碟佔用",
"Net In": "入向流量", "Net Out": "出向流量",
"Hosted models": "承載模型", "Running services": "執行服務",
"Kernel": "核心", "Driver": "驅動", "Net": "網路",
"Hardware temps": "硬體溫度",
"Hardware sensors": "硬體感測器", "Fans": "風扇", "+{n} more": "還有 {n} 項",
"— no temperature data (node unmanaged) —": "— 無溫度資料(節點未納管)—",
"GPU pending · maintenance window": "GPU 待維護窗口納管",
"Open SSH session": "開啟 SSH 工作階段", "Drain & cordon": "排空並隔離",
"Restart daemons": "重啟守護程序", "Pin model…": "固定模型…",
"Run nvidia-smi dmon": "執行 nvidia-smi dmon", "Reboot": "重啟節點",
"Throughput · last 32 ticks": "吞吐 · 近 32 拍",
"TTFT (first token)": "TTFT(首 token)", "TPOT (per token)": "TPOT(每 token)",
"Concurrency · running": "並發 · 執行中", "running": "執行中", "queued": "排隊中",
"Requests / sec": "請求/秒",
"Route · ": "路由 · ",
"TTFT / TPOT": "TTFT / TPOT", "KV-cache": "KV 快取",
"P50 / P95 / P99": "P50 / P95 / P99", "Placement · framework": "部署 · 框架",
"no live metrics source": "無即時指標來源", "vLLM not exposed": "vLLM 未暴露",
"vLLM + llama.cpp + SGLang /metrics": "vLLM + llama.cpp + SGLang /metrics", "Live throughput": "即時吞吐",
"llama.cpp /metrics does not expose TTFT / KV% / e2e histograms · shown as — honestly":
"llama.cpp /metrics 未暴露 TTFT / KV% / e2e 直方圖 · 誠實顯—,不偽造",
"TPOT / KV-cache / error-rate: this vLLM build does not expose them → honestly left blank, not faked.":
"TPOT / KV快取 / 錯誤率:此 vLLM 建置 /metrics 未暴露 → 誠實留空,不偽造。",
"backend has no Prometheus /metrics endpoint. No live-metrics source → honestly marked, not faked. Model still serves normally via LiteLLM route":
"後端無 Prometheus /metrics 端點。即時指標無來源 → 誠實標註,不偽造。模型經 LiteLLM 路由正常可用",
"Catalog models": "目錄模型", "with live metrics": "有即時指標",
"Live metric sources": "即時指標來源", "vLLM native /metrics": "vLLM 原生 /metrics",
"vLLM throughput": "vLLM 吞吐", "t/s · measured sum": "t/s · 實測合計",
"LiteLLM metrics": "LiteLLM 指標", "enterprise": "企業版",
"OSS not exposed · documented": "OSS 不暴露 · 已記錄",
"healthy": "健康", "streaming": "串流中",
"All": "全部", "RTX": "独显", "DGX": "统一", "Active": "活躍",
"Serving": "服務中", "Idle": "閒置", "Chat": "對話",
"serving": "服務中", "idle": "閒置", "no-metrics": "無指標",
"online": "在線", "stopped": "已停",
"loading": "載入中", "cold": "冷", "down": "離線",
"Search nodes, models, sections…": "搜尋節點、模型、區塊…",
"Section · top of page": "區塊 · 頁面頂部",
"Section · aggregate telemetry": "區塊 · 聚合遙測",
"Section · {n} machines": "區塊 · {n} 台機器",
"Section · LiteLLM gateway": "區塊 · LiteLLM 閘道",
"Section · alerts & log stream": "區塊 · 告警與日誌流",
"Section · network topology": "區塊 · 網路拓撲",
"No results": "無結果",
"Tweaks": "偏好設定", "Appearance": "外觀", "Theme": "主題",
"Dark": "深色", "Light": "淺色", "Accent": "強調色", "Density": "密度",
"Compact": "緊湊", "Regular": "標準", "Comfy": "寬鬆",
"Live data": "即時資料", "Source": "資料來源", "Auto": "自動",
"Live": "即時", "Mock": "模擬", "Tick": "刷新間隔",
"Motion / animations": "動效 / 動畫", "Shortcut": "快捷鍵",
"Press": "按", "anywhere to open the command palette.": "可在任意處開啟命令面板。",
"Click any node or model row for the forensic view.": "點擊任一節點或模型列進入取證視圖。",
"Framework": "框架", "Port": "連接埠", "Quant": "量化", "Context": "上下文",
"Placement": "部署", "Open Playground": "開啟 Playground",
"Restart": "重啟", "Logs": "日誌", "Close": "關閉",
"— No models pinned to this node —": "— 無模型固定到此節點 —",
"ONLINE": "在線", "OFFLINE": "離線", "Power": "功率", "maint. pending": "待維護納管",
"LiteLLM request log · OSS Postgres": "LiteLLM 請求日誌 · OSS Postgres",
"East-West · 200 GbE ConnectX-7 RDMA (live)": "東西向 · 200 GbE ConnectX-7 RDMA(真實)",
"Per-node": "各節點", "heatmap": "熱力圖",
"Accelerator activity · last 60 ticks · 0–100%": "加速器活躍度 · 近 60 拍 · 0–100%",
"VRAM usage · last 60 ticks · 0–100%": "顯存佔用 · 近 60 拍 · 0–100%",
"East-West · 200 GbE ConnectX-7 (topology only, throughput not instrumented)": "東西向 · 200 GbE ConnectX-7(僅拓撲,吞吐未插樁)",
"North-South pulse ∝ real network throughput": "南北向脈衝 ∝ 真實網路吞吐",
"Hearth": "Hearth · 家庭算力监控",
"Home AI Compute Center": "家庭智算中心",
"Home AI Compute Monitor": "家庭 AI 算力監控",
"Language": "語言",
// ── Training section ──
"Training": "訓練",
"Training · distributed": "訓練 · 分散式",
"The long ": "漫長的", "run.": "訓練。",
"Substrate health for the 4×GB10 training cluster — per-rank GPU, unified-memory headroom, CX-7 RoCE collective bandwidth, and a silent-stall heuristic. Read-only from obs; zero training impact.":
"4×GB10 訓練叢集的底座健康 —— 逐卡 GPU、統一記憶體餘量、CX-7 RoCE 集合通訊頻寬,以及靜默卡死啟發式偵測。唯讀自 obs,對訓練零影響。",
"Ranks active": "活躍 rank", "util ≥ 50%": "利用率 ≥ 50%", "avg util": "平均利用率",
"RoCE Σ rx+tx": "RoCE Σ 收+發", "GPU power Σ": "GPU 功率 Σ",
"healthy": "健康", "idle": "空閒", "GPU fault": "GPU 故障",
"stall suspected": "疑似卡死", "skew": "偏斜", "util": "利用率",
"straggler": "落後節點", "stall?": "卡死?", "mem": "記憶體", "comm stalled?": "通訊卡死?",
"train loss": "訓練 loss", "step": "步", "mean accept": "平均接受",
"grad norm": "梯度範數", "lr": "學習率", "logging": "記錄中", "write stalled?": "寫入停滯?",
"source": "來源", "refresh ~12s": "刷新 ~12s",
"MFU pending GB10 bf16 peak FLOPs.": "MFU 待 GB10 bf16 峰值 FLOPs。",
"Loss · step / ETA · accept rate — awaiting a training signal source (auto-detects JSON / Prometheus / TensorBoard from the leader). Not fabricated. See docs/training-observability.md.":
"Loss · 步 / ETA · 接受率 —— 等待訓練訊號源(從 leader 自動偵測 JSON / Prometheus / TensorBoard)。不偽造。見 docs/training-observability.md。",
},
};
const saved = localStorage.getItem("aim.lang");
const navZh = (navigator.language || "en").toLowerCase().startsWith("zh");
let lang = saved || (navZh ? "zh-CN" : "en");
if (!LANGS.some((l) => l.code === lang)) lang = "en";
const subs = new Set();
function t(s, vars) {
if (s == null) return s;
let str = (lang === "en") ? s : (DICT[lang] && DICT[lang][s] !== undefined ? DICT[lang][s] : s);
if (vars) {
for (const k in vars) {
str = str.replace(new RegExp("\\{" + k + "\\}", "g"), vars[k]);
}
}
return str;
}
function setLang(code) {
if (!LANGS.some((l) => l.code === code) || code === lang) return;
lang = code;
localStorage.setItem("aim.lang", code);
subs.forEach((fn) => fn(code));
}
window.AII18N = {
LANGS,
get lang() { return lang; },
t, setLang,
subscribe(fn) { subs.add(fn); return () => subs.delete(fn); },
};
})();