Skip to content

Commit 177c749

Browse files
jiaminghuajiaminghua
authored andcommitted
fix: address CodeRabbit review feedback
- Complete tab context menu localization (rename, copy ID, flag tab, backgrounds, close tab, flag colors) - Fix 'Ok' → 'OK' capitalization in en.json - Auto-detect system language instead of hardcoding zh-CN - Persist language preference to localStorage - Support language switching via i18n.changeLanguage()
1 parent 78dcab4 commit 177c749

4 files changed

Lines changed: 255 additions & 13 deletions

File tree

frontend/app/i18n/index.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,42 @@ import { initReactI18next } from "react-i18next";
44
import en from "./locales/en.json";
55
import zhCN from "./locales/zh-CN.json";
66

7+
// Detect system language and map to supported locale
8+
function detectLanguage(): string {
9+
const sysLang = navigator.language || "en";
10+
if (sysLang.startsWith("zh")) {
11+
return "zh-CN";
12+
}
13+
return "en";
14+
}
15+
16+
// Allow override via localStorage
17+
const savedLang = localStorage.getItem("wave:language");
18+
const initialLang = savedLang || detectLanguage();
19+
720
i18n.use(initReactI18next).init({
821
resources: {
922
en: { translation: en },
1023
"zh-CN": { translation: zhCN },
1124
},
12-
lng: "zh-CN", // default language
25+
lng: initialLang,
1326
fallbackLng: "en",
1427
interpolation: {
1528
escapeValue: false,
1629
},
1730
});
1831

32+
// Save language preference on change
33+
i18n.on("languageChanged", (lng: string) => {
34+
localStorage.setItem("wave:language", lng);
35+
});
36+
1937
export default i18n;
2038

2139
// Expose a global t function for use in non-React contexts (e.g. event handlers, menus)
2240
declare global {
2341
interface Window {
24-
__waveI18n: { t: typeof i18n.t };
42+
__waveI18n: { t: typeof i18n.t; changeLanguage: typeof i18n.changeLanguage };
2543
}
2644
}
27-
window.__waveI18n = { t: i18n.t.bind(i18n) };
45+
window.__waveI18n = { t: i18n.t.bind(i18n), changeLanguage: i18n.changeLanguage.bind(i18n) };

frontend/app/i18n/locales/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"app.keybindings": "Keybindings",
5454
"app.errorRenderingViewHeader": "Error Rendering View Header: {{error}}",
5555
"app.cancel": "Cancel",
56-
"app.ok": "Ok",
56+
"app.ok": "OK",
5757
"app.aboutDescription": "Open-Source AI-Integrated Terminal",
5858
"app.aboutTagline": "Built for Seamless Workflows",
5959
"app.clientVersion": "Client Version",

frontend/app/tab/tabcontextmenu.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ export function buildTabContextMenu(
4747
): ContextMenuItem[] {
4848
const menu: ContextMenuItem[] = [];
4949
menu.push(
50-
{ label: "Rename Tab", click: () => renameRef.current?.() },
50+
{ label: t("app.renameTab"), click: () => renameRef.current?.() },
5151
{
52-
label: "Copy TabId",
52+
label: t("app.copyTabId"),
5353
click: () => fireAndForget(() => navigator.clipboard.writeText(id)),
5454
},
5555
{ type: "separator" }
@@ -58,7 +58,7 @@ export function buildTabContextMenu(
5858
const currentFlagColor = globalStore.get(getOrefMetaKeyAtom(tabORef, "tab:flagcolor")) ?? null;
5959
const flagSubmenu: ContextMenuItem[] = [
6060
{
61-
label: "None",
61+
label: t("app.none"),
6262
type: "checkbox",
6363
checked: currentFlagColor == null,
6464
click: () =>
@@ -67,7 +67,7 @@ export function buildTabContextMenu(
6767
),
6868
},
6969
...FlagColors.map((fc) => ({
70-
label: fc.label,
70+
label: t("app." + fc.label.toLowerCase()),
7171
type: "checkbox" as const,
7272
checked: currentFlagColor === fc.value,
7373
click: () =>
@@ -76,7 +76,7 @@ export function buildTabContextMenu(
7676
),
7777
})),
7878
];
79-
menu.push({ label: "Flag Tab", type: "submenu", submenu: flagSubmenu }, { type: "separator" });
79+
menu.push({ label: t("app.flagTab"), type: "submenu", submenu: flagSubmenu }, { type: "separator" });
8080
const fullConfig = globalStore.get(env.atoms.fullConfigAtom);
8181
const backgrounds = fullConfig?.backgrounds ?? {};
8282
const bgKeys = Object.keys(backgrounds).filter((k) => backgrounds[k] != null);
@@ -89,7 +89,7 @@ export function buildTabContextMenu(
8989
const submenu: ContextMenuItem[] = [];
9090
const oref = makeORef("tab", id);
9191
submenu.push({
92-
label: "Default",
92+
label: t("app.default"),
9393
click: () =>
9494
fireAndForget(async () => {
9595
await env.rpc.SetMetaCommand(TabRpcClient, {
@@ -115,9 +115,9 @@ export function buildTabContextMenu(
115115
}),
116116
});
117117
}
118-
menu.push({ label: "Backgrounds", type: "submenu", submenu }, { type: "separator" });
118+
menu.push({ label: t("app.backgrounds"), type: "submenu", submenu }, { type: "separator" });
119119
}
120120
menu.push(...buildTabBarContextMenu(env), { type: "separator" });
121-
menu.push({ label: "Close Tab", click: () => onClose(null) });
121+
menu.push({ label: t("app.closeTab"), click: () => onClose(null) });
122122
return menu;
123123
}

0 commit comments

Comments
 (0)