Skip to content

Commit 2312fdf

Browse files
committed
feat: localize gui console
1 parent d09a5e1 commit 2312fdf

6 files changed

Lines changed: 210 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Added
66

77
- `web-tools gui` local-only management console for setup status, provider/env management, smoke tests, diagnostics export, and Agent handoff commands.
8+
- GUI language detection with Chinese UI for `zh*` browser languages and English fallback for all other languages.
89
- `web-tools setup --check --json` readiness report with non-sensitive repair suggestions for CLI and GUI consumers.
910
- `web-tools setup` for one-command Agent setup, optional provider configuration, skill install, and doctor checks.
1011
- User env file auto-loading from `~/.config/web-tools/.env`, with `WEB_TOOLS_ENV` override support.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ web-tools gui --no-open --port 0
170170

171171
The GUI binds to `127.0.0.1` by default. It can inspect setup readiness, configure the BigModel provider, write `~/.config/web-tools/.env`, run basic search/reader smoke tests, export non-sensitive diagnostics, and generate Agent handoff commands. It never displays or returns secret values; `config.json` stores only environment variable names such as `ZHIPU_APIKEY`.
172172

173+
The GUI follows the browser language by default: Chinese browsers get Chinese UI, all other languages default to English. A language selector is available in the header.
174+
173175
For agents and scripts, prefer the non-interactive CLI:
174176

175177
```bash

README.zh-CN.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ GUI 默认绑定 `127.0.0.1`。它可以检查 setup 状态、配置 BigModel pr
171171

172172
GUI 不展示、不返回 secret 明文;`config.json` 只保存 `ZHIPU_APIKEY` 这样的环境变量名,不保存 token 值。
173173

174+
GUI 默认跟随浏览器语言:中文浏览器显示中文,其他语言默认显示英文;页面右上角也可以手动切换语言。
175+
174176
Agent 和脚本默认仍然应该使用非交互 CLI:
175177

176178
```bash

internal/gui/assets/app.js

Lines changed: 138 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,122 @@
11
const state = {
22
status: null,
33
guide: null,
4+
lang: detectLanguage(),
45
};
56

67
const $ = (id) => document.getElementById(id);
78

9+
const messages = {
10+
en: {
11+
appTitle: "Local Console",
12+
languageLabel: "Language",
13+
setupStatus: "Setup Status",
14+
refresh: "Refresh",
15+
provider: "Provider",
16+
pending: "pending",
17+
authEnv: "Auth env",
18+
searchAuto: "Search auto",
19+
readerFallback: "Reader fallback",
20+
saveProvider: "Save Provider",
21+
envFile: "Env File",
22+
key: "Key",
23+
value: "Value",
24+
overwrite: "Overwrite",
25+
saveEnv: "Save Env",
26+
searchTest: "Search Test",
27+
query: "Query",
28+
runSearch: "Run Search",
29+
readerTest: "Reader Test",
30+
runReader: "Run Reader",
31+
agentGuide: "Agent Guide",
32+
copy: "Copy",
33+
copied: "Copied",
34+
diagnostics: "Diagnostics",
35+
exportJson: "Export JSON",
36+
version: "version",
37+
skillInstalled: "skill installed",
38+
skillMissing: "skill missing",
39+
authReady: "auth ready",
40+
authMissing: "auth missing",
41+
readerAutoOn: "reader auto on",
42+
readerAutoOff: "reader auto off",
43+
configured: "configured",
44+
missing: "missing",
45+
repository: "Repository",
46+
installCLI: "Install CLI",
47+
installSkill: "Install or update skill",
48+
check: "Check",
49+
usage: "Usage",
50+
readerAuto: "Reader auto",
51+
repair: "Repair",
52+
},
53+
zh: {
54+
appTitle: "本地控制台",
55+
languageLabel: "语言",
56+
setupStatus: "设置状态",
57+
refresh: "刷新",
58+
provider: "Provider",
59+
pending: "待检查",
60+
authEnv: "认证环境变量",
61+
searchAuto: "搜索自动链",
62+
readerFallback: "读取 fallback",
63+
saveProvider: "保存 Provider",
64+
envFile: "Env 文件",
65+
key: "键",
66+
value: "值",
67+
overwrite: "覆盖已有值",
68+
saveEnv: "保存 Env",
69+
searchTest: "搜索测试",
70+
query: "查询",
71+
runSearch: "运行搜索",
72+
readerTest: "读取测试",
73+
runReader: "运行读取",
74+
agentGuide: "Agent 指引",
75+
copy: "复制",
76+
copied: "已复制",
77+
diagnostics: "诊断",
78+
exportJson: "导出 JSON",
79+
version: "版本",
80+
skillInstalled: "skill 已安装",
81+
skillMissing: "skill 缺失",
82+
authReady: "认证可用",
83+
authMissing: "认证缺失",
84+
readerAutoOn: "reader auto 已启用",
85+
readerAutoOff: "reader auto 未启用",
86+
configured: "已配置",
87+
missing: "缺失",
88+
repository: "仓库",
89+
installCLI: "安装 CLI",
90+
installSkill: "安装或更新 skill",
91+
check: "检查",
92+
usage: "使用示例",
93+
readerAuto: "Reader auto",
94+
repair: "修复建议",
95+
},
96+
};
97+
98+
function t(key) {
99+
return messages[state.lang][key] || messages.en[key] || key;
100+
}
101+
102+
function detectLanguage() {
103+
const saved = localStorage.getItem("web-tools-language");
104+
if (saved === "zh" || saved === "en") return saved;
105+
const langs = navigator.languages && navigator.languages.length ? navigator.languages : [navigator.language || "en"];
106+
return langs.some((lang) => String(lang).toLowerCase().startsWith("zh")) ? "zh" : "en";
107+
}
108+
109+
function applyLanguage() {
110+
document.documentElement.lang = state.lang === "zh" ? "zh-CN" : "en";
111+
document.title = state.lang === "zh" ? "web-tools 控制台" : "web-tools console";
112+
document.querySelectorAll("[data-i18n]").forEach((el) => {
113+
el.textContent = t(el.dataset.i18n);
114+
});
115+
$("refresh").title = t("refresh");
116+
const selector = $("language-select");
117+
selector.value = state.lang;
118+
}
119+
8120
async function api(path, options = {}) {
9121
const res = await fetch(path, {
10122
headers: { "Content-Type": "application/json" },
@@ -30,15 +142,15 @@ function renderStatus(data) {
30142
const setup = data.setup;
31143
$("summary").innerHTML = "";
32144
$("summary").append(
33-
pill(`version ${data.version || "dev"}`, "ok"),
34-
pill(setup.skill.installed ? "skill installed" : "skill missing", setup.skill.installed ? "ok" : "warn"),
35-
pill(setup.provider.auth_configured ? "auth ready" : "auth missing", setup.provider.auth_configured ? "ok" : "warn"),
36-
pill(setup.reader_auto.contains ? "reader auto on" : "reader auto off", setup.reader_auto.contains ? "ok" : "warn"),
145+
pill(`${t("version")} ${data.version || "dev"}`, "ok"),
146+
pill(setup.skill.installed ? t("skillInstalled") : t("skillMissing"), setup.skill.installed ? "ok" : "warn"),
147+
pill(setup.provider.auth_configured ? t("authReady") : t("authMissing"), setup.provider.auth_configured ? "ok" : "warn"),
148+
pill(setup.reader_auto.contains ? t("readerAutoOn") : t("readerAutoOff"), setup.reader_auto.contains ? "ok" : "warn"),
37149
);
38150

39-
$("provider-pill").textContent = setup.provider.configured ? "configured" : "missing";
151+
$("provider-pill").textContent = setup.provider.configured ? t("configured") : t("missing");
40152
$("provider-pill").className = `pill ${setup.provider.configured ? "ok" : "warn"}`;
41-
$("env-pill").textContent = setup.env_file.user_exists ? setup.env_file.user_permission : "missing";
153+
$("env-pill").textContent = setup.env_file.user_exists ? setup.env_file.user_permission : t("missing");
42154
$("env-pill").className = `pill ${setup.env_file.user_permission === "ok" ? "ok" : "warn"}`;
43155

44156
$("checks").innerHTML = setup.checks
@@ -57,25 +169,25 @@ function renderStatus(data) {
57169

58170
function renderGuide(guide) {
59171
const lines = [
60-
`Repository: ${guide.repository_url}`,
172+
`${t("repository")}: ${guide.repository_url}`,
61173
"",
62-
"Install CLI:",
174+
`${t("installCLI")}:`,
63175
...guide.install_cli.map((line) => ` ${line}`),
64176
"",
65-
"Install or update skill:",
177+
`${t("installSkill")}:`,
66178
...guide.install_skill.map((line) => ` ${line}`),
67179
"",
68-
"Check:",
180+
`${t("check")}:`,
69181
...guide.check_commands.map((line) => ` ${line}`),
70182
"",
71-
"Usage:",
183+
`${t("usage")}:`,
72184
...guide.usage_examples.map((line) => ` ${line}`),
73185
];
74186
if (guide.reader_auto_note) {
75-
lines.push("", `Reader auto: ${guide.reader_auto_note}`);
187+
lines.push("", `${t("readerAuto")}: ${guide.reader_auto_note}`);
76188
}
77189
if (guide.repair_commands && guide.repair_commands.length) {
78-
lines.push("", "Repair:");
190+
lines.push("", `${t("repair")}:`);
79191
guide.repair_commands.forEach((item) => {
80192
lines.push(` # ${item.message}`, ` ${item.command}`);
81193
});
@@ -137,6 +249,13 @@ function escapeHTML(value) {
137249
}
138250

139251
$("refresh").addEventListener("click", refresh);
252+
$("language-select").addEventListener("change", (event) => {
253+
state.lang = event.target.value === "zh" ? "zh" : "en";
254+
localStorage.setItem("web-tools-language", state.lang);
255+
applyLanguage();
256+
if (state.status) renderStatus(state.status);
257+
if (state.guide) renderGuide(state.guide);
258+
});
140259
$("provider-form").addEventListener("submit", (event) => {
141260
event.preventDefault();
142261
submitForm(event.currentTarget, "/api/setup/provider");
@@ -155,6 +274,11 @@ $("reader-form").addEventListener("submit", (event) => {
155274
});
156275
$("copy-guide").addEventListener("click", async () => {
157276
await navigator.clipboard.writeText($("agent-guide").textContent);
277+
const button = $("copy-guide");
278+
button.textContent = t("copied");
279+
setTimeout(() => {
280+
button.textContent = t("copy");
281+
}, 1200);
158282
});
159283
$("download-diagnostics").addEventListener("click", async () => {
160284
const data = await api("/api/diagnostics");
@@ -167,6 +291,7 @@ $("download-diagnostics").addEventListener("click", async () => {
167291
URL.revokeObjectURL(url);
168292
});
169293

294+
applyLanguage();
170295
refresh().catch((err) => {
171296
$("output").textContent = err.message;
172297
});

0 commit comments

Comments
 (0)