Skip to content

Conversation

@jsrcode
Copy link

@jsrcode jsrcode commented Dec 12, 2025

Summary

Implements comprehensive i18n system for Wave Terminal with Chinese (Simplified) language support.

Key Features

  • Settings-based language management - Language controlled via app:language in settings.json
  • Dynamic language switching - No restart required
  • Modular translation files - 10 namespaces organized by feature
  • TypeScript type safety - Full type support for translation keys
  • Auto language detection - Priority: Wave settings > localStorage > system language

What's Internationalized

Core Components (20+):

  • Modal system (buttons, defaults)
  • About dialog (complete)
  • Context menus (Cut/Copy/Paste)
  • Onboarding flow (complete)
  • Workspace switcher (all menus)
  • Tab system (right-click menu, buttons)
  • AI Panel (8 components: header, input, messages, feedback, telemetry, BYOK, drag-drop)
  • Config error messages

Translation Files:

  • ✅ common.json - Complete (80+ entries)
  • ✅ modals.json - Complete
  • ✅ onboarding.json - Complete
  • ✅ ai.json - Complete (40+ entries)
  • ⚪ 6 other namespaces - Skeleton only (for future expansion)

Usage

Switch to Chinese:

wsh setconfig app:language zh-CN

Or edit ~/.config/waveterm/settings.json:

{
  "app:language": "zh-CN"
}

Switch back to English:

wsh setconfig app:language en

Technical Details

Dependencies Added:

  • i18next@^23.17.0
  • react-i18next@^14.1.0
  • i18next-browser-languagedetector@^8.0.0

Backend Changes:

  • Added app:language to SettingsType (pkg/wconfig/settingsconfig.go)
  • Updated TypeScript types (frontend/types/gotypes.d.ts)

Architecture:

frontend/
├── app/i18n/          # i18n config, resources, types, hooks
├── locales/           # Translation files (en, zh-CN)

Test Plan

  • Translations display correctly in Chinese
  • Language switching works without restart
  • Settings persistence works
  • TypeScript types compile
  • No console errors
  • UI layouts adapt to text length
  • All components render properly

Screenshots

(Add screenshots showing Chinese UI if needed)

Future Work

  • Complete translations for editor, terminal, settings, notifications namespaces
  • Add more languages (Japanese, Korean, etc.)
  • Language picker in Settings UI
  • Translation management tools

Breaking Changes

None. Fully backward compatible.


Progress: ~45% complete
Files Changed: 53
Components Internationalized: 20+
Translation Entries: 140+

本次提交实现了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个组件)
@CLAassistant
Copy link

CLAassistant commented Dec 12, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 12, 2025

Walkthrough

This 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 app:language; backend settings structs and schema updated. Package dependencies for i18n were added and Electron devDependency bumped; an indirect Go module was removed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Files/areas to focus:
    • frontend/app/i18n/config.ts — custom detector, initialization options, namespaces, Suspense disabled
    • frontend/app/i18n/hooks.ts — language sync logic and supportedLngs validation
    • frontend/app/i18n/types.ts — react-i18next module augmentation correctness
    • frontend/app/i18n/resources.ts and frontend/locales/* — namespace keys, interpolations, parity between en and zh-CN
    • Component edits (~20+) adding useTranslation — verify correct namespace usage and no missing keys (ai, common, modals, onboarding, tab, workspace, etc.)
    • frontend/app/modals/modal.tsx — ModalFooter fallback label behavior
    • tsconfig.json — new "@/locales/*" path alias correctness
    • package.json — new i18n dependencies and electron devDependency bump
    • pkg/wconfig/metaconsts.go, pkg/wconfig/settingsconfig.go, schema/settings.json, frontend/types/gotypes.d.ts — propagation and JSON tag/name consistency for app:language
    • frontend/wave.ts — intentional side-effect import of i18n
    • go.mod — removal of indirect dependency verification

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding i18n internationalization support with Chinese language to Wave Terminal.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing implementation features, internationalized components, technical changes, usage examples, and test plans.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5468e7 and fc346af.

📒 Files selected for processing (1)
  • frontend/app/i18n/hooks.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/app/i18n/hooks.ts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 localized aria-label to 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: Remove modals. prefix from translation keys.

With useTranslation("modals"), the namespace is already scoped to modals. The translation file keys are titleClean, title, noErrors, singleError, and configErrors (not prefixed with modals.). 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 _meta section 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 _meta to make missing keys obvious.

frontend/locales/zh-CN/notifications.json (1)

1-3: Optional: avoid placeholder translations.
Consider {} / _meta for 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 to ai translations; consider localizing the ON/OFF toggle text too.
Keeping title={...} 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 access globalStore and globalAtoms, 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:

  1. AboutModalProps is an empty interface (equivalent to {})
  2. 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 const for 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

📥 Commits

Reviewing files that changed from the base of the PR and between a5599e9 and a7c2e34.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • package-lock.json is 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.ts
  • frontend/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.tsx
  • frontend/app/aipanel/aifeedbackbuttons.tsx
  • frontend/app/aipanel/aipanel.tsx
  • frontend/app/aipanel/aipanelinput.tsx
  • frontend/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.tsx
  • frontend/app/app.tsx
  • frontend/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: New ConfigKey_AppLanguage constant 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 the vite-tsconfig-paths plugin, which is configured in all three build targets (main, preload, renderer). The alias is actively resolving locale imports in frontend/app/i18n/resources.ts with 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 at cmd/server/main-server.go:330 correctly reads the window:transparent setting and emits it as settings:transparent in 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). The useTranslation("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 ```text as the language for the directory tree code block.

Line 637: Change ../CONTRIBUTING.md to ../../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.loading and tab.notFound keys exist in the common namespace across all required locale files. The component's use of useTranslation("common") correctly references these keys which are defined in both frontend/locales/en/common.json and frontend/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.title and configFiles.deprecated are 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.
Using useTranslation("ai") with dragDrop.* 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 before useLanguageSync() runs (avoid no-op sync / missing resources).
Since useLanguageSync() depends on the i18n instance being set up, make sure @/app/i18n/config is 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") with t("workspace.delete") because common.json contains a nested workspace object with a delete key. 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 useTranslation hook 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 t function is correctly added to the useCallback dependency 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 useTranslation hook is correctly imported and initialized with the "common" namespace for the TabBar component.

Also applies to: 201-201


681-686: LGTM!

The addtabButtonDecl title is correctly internationalized using the tab.newTab translation 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 useTranslation hook is correctly imported and initialized with the "common" namespace.

Also applies to: 42-42


94-120: LGTM!

The ModalFooter correctly provides fallback labels using translations when cancelLabel or okLabel props 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 the common.json translation file. The useTranslation("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 useTranslation hook 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 for InitPage (namespace + keys look consistent).

Also applies to: 57-142


150-198: Good i18n wiring for NoTelemetryStarPage; behavior unchanged.

pkg/wconfig/settingsconfig.go (1)

55-65: AppLanguage addition looks safe and works with existing typed settings plumbing.

If "" is intended to mean “auto”, omitempty will 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 from common.workspace.*.

Dependency versions are compatible: react-i18next@^16.4.1 works with React@^19.2.0 and i18next@^25.7.2 without 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 useTranslation hook 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 messages

The 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: false configuration 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: false setting 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返回类型

**遵循原则:**
- 错误处理完善
- 类型安全改进
- 代码清晰度提升
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 getApi import is not referenced anywhere in this file. The custom detector accesses globalStore and globalAtoms directly via window casts 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 window to any to access globalStore and globalAtoms, which bypasses TypeScript's type safety. While the try-catch guards against runtime errors, consider augmenting the Window interface or importing these from @/store/global for 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

📥 Commits

Reviewing files that changed from the base of the PR and between a7c2e34 and f5468e7.

📒 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 settingsLang outside the effect is good practice and makes the dependency array more precise.

增强useLanguageSync中的语言验证:
- 过滤i18next特殊代码(cimode, dev等)
- 确保只有真实的用户语言代码被接受
- 防止调试模式被误用为语言设置
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants