From 9eb144ad602449b98d189277a1b9735d730f14b2 Mon Sep 17 00:00:00 2001 From: seekskyworld Date: Thu, 3 Sep 2026 18:39:58 +0800 Subject: [PATCH] feat(web): persist language preference Signed-off-by: seekskyworld --- web/ui/app.js | 17 ++++++++++++++++- web/ui/index.html | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/web/ui/app.js b/web/ui/app.js index bcff449d..93f71ee8 100644 --- a/web/ui/app.js +++ b/web/ui/app.js @@ -1,4 +1,12 @@ const collapsedWorkspacesStorageKey = "openpi.collapsed-workspaces"; +const languageStorageKey = "openpi.language"; +function readLanguage() { + try { + const value = localStorage.getItem(languageStorageKey); + if (value === "en" || value === "zh") return value; + } catch {} + return navigator.language?.toLowerCase().startsWith("zh") ? "zh" : "en"; +} function readCollapsedWorkspaces() { try { const value = JSON.parse(sessionStorage.getItem(collapsedWorkspacesStorageKey) || "[]"); @@ -32,7 +40,7 @@ const state = { liveRetry: null, query: "", selectedWorkspace: null, - language: navigator.language?.toLowerCase().startsWith("zh") ? "zh" : "en", + language: readLanguage(), }; const translations = { @@ -125,6 +133,12 @@ function applyLanguage() { } } +function toggleLanguage() { + state.language = state.language === "zh" ? "en" : "zh"; + try { localStorage.setItem(languageStorageKey, state.language); } catch {} + applyLanguage(); +} + const $ = (id) => document.getElementById(id); const tokenStorageKey = "openpi.web.token"; const fragmentToken = new URLSearchParams(location.hash.slice(1)).get("token"); @@ -1395,4 +1409,5 @@ $("prompt-input")?.addEventListener("keydown", (event) => { }); applyLanguage(); +$("language-toggle")?.addEventListener("click", toggleLanguage); void connectEvents(); diff --git a/web/ui/index.html b/web/ui/index.html index 7aa60047..cbc4799f 100644 --- a/web/ui/index.html +++ b/web/ui/index.html @@ -85,6 +85,7 @@ New session Choose a workspace and describe the work + Connecting