-
Notifications
You must be signed in to change notification settings - Fork 640
feat: Add i18n internationalization support with Chinese language #2667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Add i18n internationalization support with Chinese language #2667
Conversation
本次提交实现了Wave Terminal的国际化(i18n)基础架构:
**基础设施:**
- 安装i18next, react-i18next, i18next-browser-languagedetector依赖
- 创建i18n配置和类型系统(frontend/app/i18n/)
- 更新tsconfig.json添加@/locales/*路径别名
- 在wave.ts主入口集成i18n
**翻译文件架构:**
- 创建10个命名空间的英文和中文翻译文件骨架
- 组织结构: frontend/locales/{en,zh-CN}/{common,modals,editor...}.json
- 支持动态语言检测(localStorage > 系统语言 > 默认英文)
**组件改造:**
- Modal组件: "Cancel/OK/Close"等默认文本国际化
- About Modal: 完整国际化包含参数插值(版本号、年份等)
- 创建LanguageSwitcher语言切换组件
**功能特性:**
- 支持运行时语言切换,无需重启
- TypeScript类型安全的翻译key提示
- 保持向后兼容,支持自定义label
本次改造遵循项目代码规范,使用memo/forwardRef模式,保持代码质量。
移除独立的语言切换组件,改为集成到Wave现有的settings.json配置系统。
**后端变更:**
- 在SettingsType添加`app:language`配置项(pkg/wconfig/settingsconfig.go)
- 更新TypeScript类型定义(frontend/types/gotypes.d.ts)
**前端变更:**
- 重构i18n配置,从Wave settings读取语言(frontend/app/i18n/config.ts)
- 优先级: Wave settings > localStorage > 系统语言
- 创建useLanguageSync hook监听settings变化(frontend/app/i18n/hooks.ts)
- 在AppInner集成hook实现自动语言同步(frontend/app/app.tsx)
- 删除独立的LanguageSwitcher组件(不再需要)
**使用方法:**
用户可通过以下方式切换语言:
1. 编辑~/.config/waveterm/settings.json: {"app:language": "zh-CN"}
2. 使用wsh命令: wsh setconfig app:language zh-CN
3. 通过设置界面修改(未来实现)
支持的语言代码: "en"(英文), "zh-CN"(简体中文)
本次提交完成第二批组件国际化:
**翻译内容扩充:**
- common.json: 添加更多通用操作(new/add/remove/update/reload/rename/duplicate)
- common.json: 添加通用状态文本(loading/error/warning/info/success)
- onboarding.json: 完整的用户引导流程翻译
- 欢迎页面(Welcome/Support GitHub/Join Community)
- 遥测说明页面
- 功能介绍页面
**组件国际化:**
- 上下文菜单(frontend/app/app.tsx)
- Cut/Copy/Paste → t("actions.cut/copy/paste")
- "Open Clipboard URL" → t("actions.openClipboardUrl")
- 动态从i18n实例获取翻译函数
**技术实现:**
- 在非React组件中使用i18n: 通过动态import获取翻译实例
- 支持参数插值: t("actions.openClipboardUrl", { hostname })
现已国际化的组件:
- Modal组件(按钮)
- About对话框(完整)
- 上下文菜单(完整)
- Onboarding翻译文件(完整)
本次提交完成用户引导流程和配置错误提示的国际化改造。
**Onboarding组件完整国际化 (frontend/app/onboarding/onboarding.tsx):**
- InitPage:
- 欢迎标题 → t("welcome.title")
- GitHub支持 → t("welcome.supportGithub/supportGithubDesc")
- 社区邀请 → t("welcome.joinCommunity/joinCommunityDesc/joinDiscord")
- 遥测说明 → t("welcome.telemetryDesc/telemetryPrivacy")
- Enabled/Disabled → t("welcome.telemetryEnabled/Disabled")
- Continue按钮 → t("welcome.continue")
- NoTelemetryStarPage:
- 标题 → t("notelemetrystar.title")
- 隐私尊重 → t("notelemetrystar.noProblem")
- GitHub支持请求 → t("notelemetrystar.needSupport")
- 按钮 → t("notelemetrystar.starOnGithub/maybeLater")
**ConfigErrorMessage国际化 (frontend/app/tab/tabbar.tsx):**
- "Configuration Clean" → t("modals.titleClean")
- "Configuration Error" → t("modals.title")
- 错误描述 → t("modals.noErrors/singleError/configErrors")
- 支持参数插值(file, error)
**翻译文件更新:**
- en/onboarding.json: 完整的用户引导流程文本(14个条目)
- zh-CN/onboarding.json: 完整的中文翻译
已国际化组件:
- Modal (✅)
- About Dialog (✅)
- Context Menu (✅)
- Onboarding (✅)
- ConfigErrorMessage (✅)
本次提交完成用户主要交互界面的国际化改造。
**WorkspaceSwitcher国际化 (frontend/app/tab/workspaceswitcher.tsx):**
- 工作区切换器标题 → t("workspace.switchWorkspace/openWorkspace")
- "Create new workspace" → t("workspace.createNew")
- "Save workspace" → t("workspace.save")
- "Edit workspace" → t("workspace.edit")
- Tooltip文本 → t("workspace.currentWorkspace/openInWindow")
**TabContent国际化 (frontend/app/tab/tabcontent.tsx):**
- "Tab Loading" → t("tab.loading")
- "Tab Not Found" → t("tab.notFound")
**WaveConfig设置界面国际化 (frontend/app/view/waveconfig/waveconfig.tsx):**
- "Config Files" → t("configFiles.title")
- "deprecated" → t("configFiles.deprecated")
**翻译文件更新 (frontend/locales/):**
- common.json: 添加workspace, tab, configFiles命名空间
- 完整的工作区相关翻译(9个条目)
- 完整的标签页相关翻译(3个条目)
- 配置文件相关翻译(2个条目)
现已国际化的主页面组件:
- ✅ WorkspaceSwitcher (工作区切换器)
- ✅ TabContent (标签页内容)
- ✅ WaveConfig (配置文件侧边栏)
- ✅ ConfigErrorMessage (配置错误提示)
用户可通过设置 app:language=zh-CN 查看中文界面。
本次提交完成Wave Terminal核心交互界面的国际化改造。
**Tab菜单完整国际化 (frontend/app/tab/tab.tsx):**
- Tab右键菜单所有选项:
- Pin/Unpin Tab → 固定/取消固定标签页
- Rename Tab → 重命名标签页
- Copy TabId → 复制标签ID
- Backgrounds → 背景
- Close Tab → 关闭标签页
- TabBar新建按钮 → t("tab.newTab")
- 应用菜单按钮 → t("tab.appMenu")
**WorkspaceEditor国际化 (frontend/app/tab/workspaceeditor.tsx):**
- 删除工作区按钮 → t("workspace.delete")
**AI面板完整国际化 (frontend/app/aipanel/):**
- AIPanelHeader: Wave AI标题、上下文切换、更多选项
- AIPanelInput: 输入框占位符、附件和发送按钮tooltip
- AIMessage: 等待批准、AI思考中、无内容提示
- AIFeedbackButtons: 好评/差评/复制按钮
- TelemetryRequired: 完整的遥测说明页面
- BYOKAnnouncement: BYOK功能公告
- AIDragOverlay: 文件拖放提示
**翻译文件 (frontend/locales/):**
- en/ai.json: 完整的AI面板翻译(40+ 条目)
- zh-CN/ai.json: 完整的中文翻译
- common.json: 补充tab.appMenu翻译
已国际化组件总计: Modal, About, ContextMenu, Onboarding,
ConfigError, WorkspaceSwitcher, TabContent, WaveConfig, Tab菜单,
WorkspaceEditor, AI面板(8个组件)
WalkthroughThis PR adds full i18n scaffolding and translations: a planning document for i18n, a runtime config (i18n language detector/initializer), a language-sync hook, module typing augmentation, aggregated resource registration, and a locales path alias. ~20+ frontend components were updated to use react-i18next translation keys. English and zh-CN JSON resources were added and exported. Frontend types and a settings key were extended for Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/app/aipanel/aipanelinput.tsx (1)
11-165: Add localizedaria-labelto the icon-only buttons (tooltip text isn’t a reliable accessible name).<Tooltip content={t("input.attachFiles")} placement="top" divClassName="absolute bottom-6.5 right-1"> <button type="button" onClick={handleUploadClick} + aria-label={t("input.attachFiles")} className={cn( "w-5 h-5 transition-colors flex items-center justify-center text-gray-400 hover:text-accent cursor-pointer" )} > <i className="fa fa-paperclip text-sm"></i> </button> </Tooltip> <Tooltip content={t("input.sendMessage")} placement="top" divClassName="absolute bottom-1.5 right-1"> <button type="submit" disabled={status !== "ready" || !input.trim()} + aria-label={t("input.sendMessage")} className={cn( "w-5 h-5 transition-colors flex items-center justify-center", status !== "ready" || !input.trim() ? "text-gray-400" : "text-accent/80 hover:text-accent cursor-pointer" )} >frontend/app/tab/tabbar.tsx (1)
67-101: Removemodals.prefix from translation keys.With
useTranslation("modals"), the namespace is already scoped tomodals. The translation file keys aretitleClean,title,noErrors,singleError, andconfigErrors(not prefixed withmodals.). Change:
t("modals.titleClean")→t("titleClean")t("modals.title")→t("title")t("modals.noErrors")→t("noErrors")t("modals.configErrors")→t("configErrors")t("modals.singleError", ...)→t("singleError", ...)
🧹 Nitpick comments (20)
frontend/locales/zh-CN/ai.json (1)
1-59: Keys/structure align; consider minor zh-CN copy/punctuation polish for consistency (optional).frontend/locales/en/terminal.json (1)
1-3: Avoid shipping “placeholder” keys that can be accidentally depended on.
Consider using an empty object{}or a reserved_metasection so missing real keys fail loudly during development.frontend/locales/zh-CN/help.json (1)
1-3: Same concern: placeholder keys can mask missing translations.
If this namespace isn’t ready, prefer{}(or a reserved_meta) to reduce accidental usage.frontend/locales/en/settings.json (1)
1-3: Consider removing placeholder entry once real keys exist.
Otherwise, it’s easy to ship UI that “looks translated” but is actually just the placeholder.frontend/locales/en/help.json (1)
1-3: Prefer{}over placeholder text for incomplete namespaces.
Keeps missing-key detection effective.frontend/locales/en/notifications.json (1)
1-3: Optional: replace placeholder with empty object or_meta.
Reduces the chance of accidental production dependency.frontend/locales/zh-CN/settings.json (1)
1-3: Optional: avoid placeholder translations in shipped locales.
Prefer{}or_metato make missing keys obvious.frontend/locales/zh-CN/notifications.json (1)
1-3: Optional: avoid placeholder translations.
Consider{}/_metafor incomplete namespaces.frontend/locales/en/errors.json (1)
1-3: Placeholder content noted – track completion of error translations.This namespace currently contains only a placeholder. Since error messages are user-facing and important for debugging, ensure that actual error translation keys are added before the i18n feature is released.
Would you like me to open an issue to track the completion of the errors namespace translations?
frontend/locales/zh-CN/terminal.json (1)
1-3: Placeholder content noted – track completion of terminal translations.This namespace currently contains only a placeholder. Ensure terminal-related translation keys are added before release.
frontend/locales/zh-CN/errors.json (1)
1-3: Placeholder content noted – track completion of error translations.This namespace currently contains only a placeholder. Since error messages are critical for user experience, ensure actual error translation keys are added before release.
frontend/locales/zh-CN/editor.json (1)
1-3: Placeholder content noted – track completion of editor translations.This namespace currently contains only a placeholder. Ensure editor-related translation keys are added as the editor features are internationalized.
frontend/locales/en/editor.json (1)
1-3: Placeholder content noted – track completion of editor translations.This namespace currently contains only a placeholder. Ensure actual editor translation keys are added as editor features are internationalized.
frontend/app/view/waveconfig/waveconfig.tsx (1)
90-293: Consider internationalizing additional hardcoded strings in WaveConfigView.The WaveConfigView component contains several hardcoded user-facing strings that should be internationalized:
- Line 199: "Unsaved changes"
- Line 211: "Saving..." and "Save"
- Line 229: "Visual"
- Line 240: "Raw JSON"
- Line 269: "Loading..."
These strings would benefit from translation support for consistency with the i18n implementation.
frontend/locales/en/modals.json (1)
1-13: Key parity with zh-CN looks correct.
Optional: consider"OK"vs"Ok"if you standardize button casing elsewhere.frontend/app/aipanel/aipanelheader.tsx (1)
7-12: Good conversion toaitranslations; consider localizing the ON/OFF toggle text too.
Keepingtitle={...}translated is great; finishing the toggle label would avoid mixed-language UI.Also applies to: 29-33, 36-52, 69-73
schema/settings.json (1)
26-28: Consider adding enum validation for supported languages.The schema accepts any string for
app:language. For better validation and IDE autocompletion, consider restricting to supported language codes."app:language": { - "type": "string" + "type": "string", + "enum": ["en", "zh-CN"], + "description": "Application UI language (e.g., 'en', 'zh-CN')" },Alternatively, if you want to allow auto-detection or additional languages in the future, keep it as-is but add a description for documentation purposes.
frontend/app/i18n/config.ts (1)
10-28: Improve type safety for global store access.The custom detector uses
(window as any)to accessglobalStoreandglobalAtoms, bypassing TypeScript's type checking. While the try-catch provides runtime safety, this pattern can mask type errors.Consider defining proper TypeScript interfaces for these globals:
+// Add type definitions at the top of the file +interface WaveGlobals { + globalStore?: { + get: (atom: any) => any; + }; + globalAtoms?: { + settingsAtom?: any; + }; +} + +declare global { + interface Window { + globalStore?: WaveGlobals['globalStore']; + globalAtoms?: WaveGlobals['globalAtoms']; + } +} + const waveSettingsDetector = { name: "waveSettings", lookup() { - try { - const globalStore = (window as any).globalStore; - const settingsAtom = (window as any).globalAtoms?.settingsAtom; + try { + const globalStore = window.globalStore; + const settingsAtom = window.globalAtoms?.settingsAtom; if (globalStore && settingsAtom) { const settings = globalStore.get(settingsAtom); return settings?.["app:language"] || null;frontend/app/modals/about.tsx (1)
13-13: Address static analysis warnings for empty interface and pattern.The static analyzer has identified two code quality issues:
AboutModalPropsis an empty interface (equivalent to{})- The component uses an empty object destructuring pattern
Apply this diff to address both issues:
-interface AboutModalProps {} - -const AboutModal = ({}: AboutModalProps) => { +const AboutModal = () => {If you anticipate adding props in the future, you can keep the interface but remove the destructuring:
interface AboutModalProps {} -const AboutModal = ({}: AboutModalProps) => { +const AboutModal = (_props: AboutModalProps) => {Also applies to: 15-15
frontend/app/i18n/resources.ts (1)
1-53: LGTM! Well-structured i18n resources with good type safety.The resource structure is well-organized:
- Clear separation of English and Chinese imports
- All 10 namespaces consistently defined for both locales
- Proper use of
as constfor type inference and immutability- Structure aligns with i18next requirements
One minor suggestion: translate the Chinese comments to English for consistency:
-// 英文翻译 +// English translations import aiEN from "@/locales/en/ai.json"; // ... other imports -// 中文翻译 +// Chinese translations import aiZH from "@/locales/zh-CN/ai.json";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
go.sumis excluded by!**/*.sumpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (50)
.claude/plan/i18n-internationalization.md(1 hunks)frontend/app/aipanel/aifeedbackbuttons.tsx(3 hunks)frontend/app/aipanel/aimessage.tsx(4 hunks)frontend/app/aipanel/aipanel.tsx(2 hunks)frontend/app/aipanel/aipanelheader.tsx(4 hunks)frontend/app/aipanel/aipanelinput.tsx(4 hunks)frontend/app/aipanel/byokannouncement.tsx(3 hunks)frontend/app/aipanel/telemetryrequired.tsx(3 hunks)frontend/app/app.tsx(4 hunks)frontend/app/i18n/config.ts(1 hunks)frontend/app/i18n/hooks.ts(1 hunks)frontend/app/i18n/resources.ts(1 hunks)frontend/app/i18n/types.ts(1 hunks)frontend/app/modals/about.tsx(3 hunks)frontend/app/modals/modal.tsx(4 hunks)frontend/app/onboarding/onboarding.tsx(10 hunks)frontend/app/tab/tab.tsx(6 hunks)frontend/app/tab/tabbar.tsx(5 hunks)frontend/app/tab/tabcontent.tsx(2 hunks)frontend/app/tab/workspaceeditor.tsx(3 hunks)frontend/app/tab/workspaceswitcher.tsx(7 hunks)frontend/app/view/waveconfig/waveconfig.tsx(3 hunks)frontend/locales/en/ai.json(1 hunks)frontend/locales/en/common.json(1 hunks)frontend/locales/en/editor.json(1 hunks)frontend/locales/en/errors.json(1 hunks)frontend/locales/en/help.json(1 hunks)frontend/locales/en/modals.json(1 hunks)frontend/locales/en/notifications.json(1 hunks)frontend/locales/en/onboarding.json(1 hunks)frontend/locales/en/settings.json(1 hunks)frontend/locales/en/terminal.json(1 hunks)frontend/locales/zh-CN/ai.json(1 hunks)frontend/locales/zh-CN/common.json(1 hunks)frontend/locales/zh-CN/editor.json(1 hunks)frontend/locales/zh-CN/errors.json(1 hunks)frontend/locales/zh-CN/help.json(1 hunks)frontend/locales/zh-CN/modals.json(1 hunks)frontend/locales/zh-CN/notifications.json(1 hunks)frontend/locales/zh-CN/onboarding.json(1 hunks)frontend/locales/zh-CN/settings.json(1 hunks)frontend/locales/zh-CN/terminal.json(1 hunks)frontend/types/gotypes.d.ts(3 hunks)frontend/wave.ts(1 hunks)go.mod(0 hunks)package.json(4 hunks)pkg/wconfig/metaconsts.go(1 hunks)pkg/wconfig/settingsconfig.go(1 hunks)schema/settings.json(1 hunks)tsconfig.json(1 hunks)
💤 Files with no reviewable changes (1)
- go.mod
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-01T00:57:23.025Z
Learnt from: sawka
Repo: wavetermdev/waveterm PR: 2504
File: frontend/app/aipanel/aipanel-contextmenu.ts:15-16
Timestamp: 2025-11-01T00:57:23.025Z
Learning: In the waveterm codebase, types defined in custom.d.ts are globally available and do not require explicit imports. Backend types defined in gotypes.d.ts are also globally available.
Applied to files:
frontend/app/i18n/types.tsfrontend/wave.ts
📚 Learning: 2025-10-14T06:30:54.763Z
Learnt from: sawka
Repo: wavetermdev/waveterm PR: 2430
File: frontend/app/aipanel/aimessage.tsx:137-144
Timestamp: 2025-10-14T06:30:54.763Z
Learning: In `frontend/app/aipanel/aimessage.tsx`, the `AIToolUseGroup` component splits file operation tool calls into separate batches (`fileOpsNeedApproval` and `fileOpsNoApproval`) based on their approval state before passing them to `AIToolUseBatch`. This ensures each batch has homogeneous approval states, making group-level approval handling valid.
Applied to files:
frontend/app/aipanel/aipanelheader.tsxfrontend/app/aipanel/aifeedbackbuttons.tsxfrontend/app/aipanel/aipanel.tsxfrontend/app/aipanel/aipanelinput.tsxfrontend/app/aipanel/aimessage.tsx
📚 Learning: 2025-10-21T05:09:26.916Z
Learnt from: sawka
Repo: wavetermdev/waveterm PR: 2465
File: frontend/app/onboarding/onboarding-upgrade.tsx:13-21
Timestamp: 2025-10-21T05:09:26.916Z
Learning: In the waveterm codebase, clientData is loaded and awaited in wave.ts before React runs, ensuring it is always available when components mount. This means atoms.client will have data on first render.
Applied to files:
frontend/app/tab/tabcontent.tsxfrontend/app/app.tsxfrontend/app/tab/tab.tsx
🧬 Code graph analysis (5)
frontend/app/i18n/types.ts (1)
frontend/app/i18n/resources.ts (1)
resources(28-53)
frontend/app/i18n/hooks.ts (1)
frontend/app/store/global.ts (1)
atoms(836-836)
frontend/app/aipanel/aifeedbackbuttons.tsx (1)
frontend/util/util.ts (2)
makeIconClass(517-517)cn(502-502)
frontend/app/aipanel/aipanelinput.tsx (2)
frontend/util/util.ts (1)
cn(502-502)frontend/app/element/tooltip.tsx (1)
Tooltip(143-176)
frontend/app/app.tsx (1)
frontend/app/i18n/hooks.ts (1)
useLanguageSync(13-23)
🪛 Biome (2.1.2)
frontend/app/modals/about.tsx
[error] 12-13: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
[error] 15-15: Unexpected empty object pattern.
(lint/correctness/noEmptyPattern)
🪛 LanguageTool
.claude/plan/i18n-internationalization.md
[uncategorized] ~321-~321: 数词与名词之间一般应存在量词,可能缺少量词。
Context: ...助" } } ``` 预期结果: - ✅ 10个命名空间文件 × 2语言 = 20个JSON文件 - ✅ 文件结构一致,key路径对齐 - ✅ 英文文件...
(wa5)
🪛 markdownlint-cli2 (0.18.1)
.claude/plan/i18n-internationalization.md
52-52: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
487-487: Tables should be surrounded by blank lines
(MD058, blanks-around-tables)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: merge-gatekeeper
🔇 Additional comments (39)
pkg/wconfig/metaconsts.go (1)
8-18: NewConfigKey_AppLanguageconstant is consistent with existing config-key conventions.frontend/locales/en/ai.json (1)
1-59: English AI namespace file looks consistent and complete for the referenced keys.tsconfig.json (1)
17-27: Alias@/locales/*is properly configured and actively used. The bundler (electron-vite) correctly mirrors the TypeScript path configuration via thevite-tsconfig-pathsplugin, which is configured in all three build targets (main, preload, renderer). The alias is actively resolving locale imports infrontend/app/i18n/resources.tswith no module-not-found errors.frontend/types/gotypes.d.ts (1)
1053-1062: No action needed: telemetry property naming is intentional and consistent. The telemetry code atcmd/server/main-server.go:330correctly reads thewindow:transparentsetting and emits it assettings:transparentin telemetry. This follows a consistent pattern where all settings metrics in telemetry use the"settings:"prefix (e.g.,"settings:customwidgets","settings:customaimodes","settings:secretscount"), regardless of their actual config key namespace. The separation is by design: config keys use domain-specific prefixes, while telemetry metrics group all settings under a unified namespace.frontend/app/aipanel/telemetryrequired.tsx (1)
8-74: i18n implementation is correct. All translation keys exist in both en/ai.json and zh-CN/ai.json, and react-i18next 16.4.1 is compatible with React 19.2.0 (currently in use). TheuseTranslation("ai")namespace scoping is properly implemented.package.json (1)
30-152: The review comment's core claim cannot be verified. No PR description text is provided to establish the alleged version mismatch, and no references to the mentioned older versions (^23.17.0, ^14.1.0) exist in the codebase. The specified dependency versions (i18next 25.7.2, react-i18next 16.4.1, Electron 38.7.2) are compatible with React 19.2—the i18next initialization code uses only stable APIs, and tsconfig.json already has skipLibCheck: true to handle any TypeScript typing concerns with React 19..claude/plan/i18n-internationalization.md (1)
52-79: Add language specifier to code block and fix relative path.Line 52: Add
```textas the language for the directory tree code block.Line 637: Change
../CONTRIBUTING.mdto../../CONTRIBUTING.md(the correct relative path from.claude/plan/).frontend/wave.ts (1)
4-4: LGTM! Correct i18n initialization placement.The i18n config import is correctly placed at the top of the entry file, ensuring translations are initialized before React components mount. The side-effect import pattern is appropriate for this initialization.
frontend/app/tab/tabcontent.tsx (4)
14-14: LGTM! Correct i18n hook import.The react-i18next import is appropriate for adding translation support to this component.
55-55: LGTM! Loading message internationalized.The hardcoded loading text is correctly replaced with a translatable key.
57-57: LGTM! Not found message internationalized.The hardcoded error text is correctly replaced with a translatable key.
22-22: No action required — translation keys are properly defined.Both
tab.loadingandtab.notFoundkeys exist in the common namespace across all required locale files. The component's use ofuseTranslation("common")correctly references these keys which are defined in bothfrontend/locales/en/common.jsonandfrontend/locales/zh-CN/common.json.frontend/app/view/waveconfig/waveconfig.tsx (4)
12-12: LGTM! Correct i18n hook import.The react-i18next import is appropriate for adding translation support.
34-34: LGTM! Title internationalized correctly.The "Config Files" title is properly replaced with a translatable key.
77-77: LGTM! Deprecated label internationalized correctly.The "deprecated" label is properly replaced with a translatable key.
20-20: Translation keys for configFiles already exist in common namespace.Both
configFiles.titleandconfigFiles.deprecatedare already defined in both locale files (en/common.json and zh-CN/common.json) with appropriate translations.frontend/app/aipanel/aipanel.tsx (1)
17-18: Good i18n scoping for drag overlay strings.
UsinguseTranslation("ai")withdragDrop.*keys is consistent and keeps this component self-contained.Also applies to: 54-68
frontend/locales/zh-CN/modals.json (1)
1-13: Looks consistent with expected modal/footer key structure (placeholders preserved).frontend/app/app.tsx (1)
4-5: Verify i18n is initialized beforeuseLanguageSync()runs (avoid no-op sync / missing resources).
SinceuseLanguageSync()depends on the i18n instance being set up, make sure@/app/i18n/configis imported at app startup (entrypoint or a top-level side-effect import) rather than only via the context menu’s dynamic import.Also applies to: 87-126, 281-289
frontend/app/i18n/types.ts (1)
4-12: Good: react-i18next typing pins defaultNS + resource shape for key safety.frontend/app/tab/workspaceeditor.tsx (1)
4-4: No changes needed—the i18n implementation is correct.The code correctly uses
useTranslation("common")witht("workspace.delete")becausecommon.jsoncontains a nestedworkspaceobject with adeletekey. React-i18next supports dot notation for nested keys within a namespace, so the current implementation follows the expected pattern.frontend/app/tab/tab.tsx (3)
13-13: LGTM!The
useTranslationhook is correctly imported and initialized with the"common"namespace at the component level. This follows react-i18next best practices.Also applies to: 58-58
166-214: LGTM!The context menu labels are properly internationalized, and the
tfunction is correctly added to theuseCallbackdependency array (Line 213), ensuring the menu re-renders when the language changes.
242-262: LGTM!Button titles are properly internationalized using the same translation keys (
tab.unpinTab,tab.closeTab) as the context menu, ensuring consistency.frontend/app/tab/tabbar.tsx (3)
14-14: LGTM!The
useTranslationhook is correctly imported and initialized with the"common"namespace for theTabBarcomponent.Also applies to: 201-201
681-686: LGTM!The
addtabButtonDecltitle is correctly internationalized using thetab.newTabtranslation key.
694-703: LGTM!The app menu button title is properly internationalized with
tab.appMenu.frontend/app/modals/modal.tsx (3)
8-8: LGTM!The
useTranslationhook is correctly imported and initialized with the"common"namespace.Also applies to: 42-42
94-120: LGTM!The
ModalFootercorrectly provides fallback labels using translations whencancelLabelorokLabelprops are not provided. The nullish coalescing (??) ensures custom labels take precedence.
53-53: No action needed; translation key structure is consistent.The keys
"common.closeEsc"(line 53) and"actions.cancel"/"actions.ok"(lines 103-104) both follow the same pattern: they reference nested objects within thecommon.jsontranslation file. TheuseTranslation("common")hook loads the entire file, and both key formats access nested properties (common.closeEsc,actions.cancel,actions.ok) within that structure. This is the intended and consistent usage throughout the file.frontend/app/aipanel/byokannouncement.tsx (2)
6-6: LGTM!The
useTranslationhook is correctly imported and initialized with the"ai"namespace, which is appropriate for this AI panel component.Also applies to: 10-10
40-67: LGTM!The BYOK announcement content is properly internationalized with consistent translation keys (
byok.title,byok.description,byok.configure,byok.viewDocs). The component structure and event handlers remain unchanged.frontend/app/onboarding/onboarding.tsx (2)
12-33: Good i18n wiring forInitPage(namespace + keys look consistent).Also applies to: 57-142
150-198: Good i18n wiring forNoTelemetryStarPage; behavior unchanged.pkg/wconfig/settingsconfig.go (1)
55-65:AppLanguageaddition looks safe and works with existing typed settings plumbing.If
""is intended to mean “auto”,omitemptywill effectively treat it as “unset” (which might be perfect)—just sanity-check that behavior is what you want.frontend/app/tab/workspaceswitcher.tsx (1)
19-40: Nice cleanup: workspace switcher strings now consistently come fromcommon.workspace.*.Dependency versions are compatible:
react-i18next@^16.4.1works withReact@^19.2.0andi18next@^25.7.2without breaking changes. Runtime compatibility is confirmed; no issues detected.Also applies to: 112-137, 152-196
frontend/app/modals/about.tsx (1)
10-10: LGTM! Proper i18n implementation.The translation integration is well-implemented:
- Correct use of
useTranslationhook with the "common" namespace- Proper interpolation of dynamic values (version, buildTime, channel, year)
- Translation keys follow a logical structure
Also applies to: 16-16, 26-40, 49-49, 58-58, 67-67, 71-71
frontend/app/aipanel/aifeedbackbuttons.tsx (1)
6-6: LGTM! Clean i18n integration with improved conditional rendering.The internationalization implementation is well done:
- Correct use of
useTranslation("ai")hook- Proper translation keys for button titles (
message.goodResponse,message.badResponse,message.copyMessage)- Good addition of conditional rendering for the copy button (
messageText?.trim()) to prevent showing it for empty messagesThe className changes appear to be formatting consolidation without logic changes.
Also applies to: 14-14, 53-53, 63-63, 67-78
frontend/app/i18n/config.ts (1)
69-71: Translate the Chinese comment to English for consistency.The comment explaining the
useSuspense: falseconfiguration is in Chinese. Translate it to English to match the codebase convention:react: { - useSuspense: false, // 避免Electron环境下的Suspense问题 + useSuspense: false, // Avoid Suspense issues in Electron environment },The
useSuspense: falsesetting itself is appropriate for Electron applications—it's a documented best practice to preload translations and avoid async Suspense boundaries during render, which can cause flicker and hydration issues in Electron.
修复中文翻译文件的标点符号和格式问题: - 统一使用中文标点符号(,。:)替代英文标点(, . :) - 使用全角括号()替代半角括号( ) - 修正 Github → GitHub 大小写 - Copy TabId → Copy Tab ID - deprecated → Deprecated - 移除括号前的多余空格 - 确保中文排版规范一致 受影响文件: - frontend/locales/zh-CN/common.json - frontend/locales/zh-CN/onboarding.json - frontend/locales/zh-CN/ai.json - frontend/locales/en/common.json
**代码质量改进:** 1. hooks.ts - 增强语言切换验证: - 验证settingsLang是否在supportedLngs中 - 添加changeLanguage的错误处理(.catch) - 优化依赖数组为[settingsLang, i18n]仅监听语言变化 2. config.ts - 清理未使用导入: - 移除未使用的LanguageDetector导入 - 添加supportedLngs配置明确支持的语言 3. aimessage.tsx - 修复翻译key使用: - 将message改为messageKey作为返回值 - 确保传递翻译key而非原始文本 - 更新getThinkingMessage返回类型 **遵循原则:** - 错误处理完善 - 类型安全改进 - 代码清晰度提升
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
frontend/app/i18n/config.ts (2)
4-4: Unused import:getApi.The
getApiimport is not referenced anywhere in this file. The custom detector accessesglobalStoreandglobalAtomsdirectly viawindowcasts instead.Apply this diff to remove the unused import:
-import { getApi } from "@/store/global"; import i18n from "i18next";
9-27: Consider stronger typing for global object access.The detector casts
windowtoanyto accessglobalStoreandglobalAtoms, which bypasses TypeScript's type safety. While the try-catch guards against runtime errors, consider augmenting theWindowinterface or importing these from@/store/globalfor better type checking.Example augmentation approach:
declare global { interface Window { globalStore?: any; globalAtoms?: { settingsAtom?: any }; } }Or retrieve via the imported (but currently unused)
getApi()if that API exposes these objects.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
frontend/app/aipanel/aimessage.tsx(5 hunks)frontend/app/i18n/config.ts(1 hunks)frontend/app/i18n/hooks.ts(1 hunks)frontend/locales/en/common.json(1 hunks)frontend/locales/zh-CN/ai.json(1 hunks)frontend/locales/zh-CN/common.json(1 hunks)frontend/locales/zh-CN/onboarding.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- frontend/locales/zh-CN/onboarding.json
- frontend/locales/zh-CN/ai.json
- frontend/locales/en/common.json
- frontend/app/aipanel/aimessage.tsx
- frontend/locales/zh-CN/common.json
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/app/i18n/hooks.ts (1)
frontend/app/store/global.ts (1)
atoms(836-836)
🔇 Additional comments (3)
frontend/app/i18n/config.ts (1)
29-72: LGTM! Well-structured i18n initialization.The custom language detector correctly implements the priority chain (Wave settings → localStorage → system language), and the i18n configuration is comprehensive with appropriate fallback settings, namespace organization, and React integration. Disabling Suspense for Electron compatibility is the right call.
frontend/app/i18n/hooks.ts (2)
4-12: LGTM! Clean imports and clear documentation.The imports are appropriate and the JSDoc clearly explains the hook's purpose.
13-17: LGTM! Proper hook setup.Extracting
settingsLangoutside the effect is good practice and makes the dependency array more precise.
增强useLanguageSync中的语言验证: - 过滤i18next特殊代码(cimode, dev等) - 确保只有真实的用户语言代码被接受 - 防止调试模式被误用为语言设置
Summary
Implements comprehensive i18n system for Wave Terminal with Chinese (Simplified) language support.
Key Features
app:languagein settings.jsonWhat's Internationalized
Core Components (20+):
Translation Files:
Usage
Switch to Chinese:
Or edit
~/.config/waveterm/settings.json:{ "app:language": "zh-CN" }Switch back to English:
Technical Details
Dependencies Added:
Backend Changes:
app:languageto SettingsType (pkg/wconfig/settingsconfig.go)Architecture:
Test Plan
Screenshots
(Add screenshots showing Chinese UI if needed)
Future Work
Breaking Changes
None. Fully backward compatible.
Progress: ~45% complete
Files Changed: 53
Components Internationalized: 20+
Translation Entries: 140+