Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский by gy212 · Pull Request #33 · op7418/CodePilot · GitHub
Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский by gy212 · Pull Request #33 · op7418/CodePilot · GitHub
Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский by gy212 · Pull Request #33 · op7418/CodePilot · GitHub
Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский by gy212 · Pull Request #33 · op7418/CodePilot · GitHub
Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский by gy212 · Pull Request #33 · op7418/CodePilot · GitHub
Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский by gy212 · Pull Request #33 · op7418/CodePilot · GitHub
Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский by gy212 · Pull Request #33 · op7418/CodePilot · GitHub
Skip to content

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский - #33

Closed
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en
Closed

feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、Русский#33
gy212 wants to merge 2 commits into
op7418:mainfrom
gy212:feat/i18n-zh-en

Conversation

@gy212

@gy212gy212 commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

概述

基于 React Context + 自定义 Hook 实现完整的中英文国际化系统(零外部依赖)。用户可在设置页面切换 English / 中文 (简体),语言偏好持久化到 SQLite。

架构

layout.tsx → ThemeProvider → I18nProvider → AppShell → 所有组件通过 useTranslation() 获取 t()
  • 翻译文件:扁平 key-value 对象,dot-notation 命名空间(如 nav.newChatsettings.title
  • 语言偏好:通过现有 /api/settings/app 存储到 SQLite(ALLOWED_KEYS 中添加 locale
  • 参数插值:t('key', { count: 5 }) → 替换 {count} 占位符
  • 回退机制:中文缺失时回退到英文

新建文件(5 个)

文件说明
src/i18n/en.ts英文翻译字典(295 个 key)
src/i18n/zh.ts中文翻译字典(295 个 key)
src/i18n/index.ts类型导出 + 翻译查找工具函数
src/components/layout/I18nProvider.tsxReact Context Provider,管理 locale 状态、持久化、提供 t()
src/hooks/useTranslation.tsuseContext(I18nContext) 的封装 Hook

修改文件(27 个)

覆盖全部模块:聊天、布局、设置、扩展、插件、项目组件。

特殊处理

  • 模块级常量数组(如 BUILT_IN_COMMANDSMODE_OPTIONS):保持原定义不变,在组件渲染时用 t() 覆盖 description/label
  • <html lang>:在 I18nProvider 的 useEffect 中通过 document.documentElement.lang = locale 动态更新
  • 相对时间formatRelativeTime() 改为接受 t 函数参数
  • 语言名称:选择器中 "English" 和 "中文 (简体)" 始终用原文显示
  • 专业术语:API、SDK、MCP、JSON、Claude 等保持不翻译
  • 语言选择器:使用 shadcn Select 组件,与应用整体风格统一

@Angelahanshuang

Copy link
Copy Markdown
Contributor

好家伙,我就晚提交了一步

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

好家伙,我就晚提交了一步

今天凌晨1点就干完了,只是我睡着了没提交。刚才又review修了一些安全问题才提上来

@Angelahanshuang

Copy link
Copy Markdown
Contributor

不过还是老兄你写的完善

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good i18n architecture, but a few issues:

  1. Merge conflicts: PR has CONFLICTING status, please rebase onto latest main
  2. Scope: Touches 27+ files, very high conflict risk with other active PRs. Consider splitting into smaller PRs (core i18n infra first, then page-by-page translations)
  3. Internal error messages: Error messages in throw new Error() and internal logging shouldn't be translated - only user-facing UI text should use t()
  4. Dependency arrays: Adding t to useEffect dependency arrays may cause unnecessary re-renders when language changes mid-session

Please rebase and address these issues. Thanks for the work on i18n support!

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

基本完成了0.6.1版本的翻译。

@gy212
gy212 requested a review from op7418February 9, 2026 10:28
@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

已修复 lint 报错(当前仅剩 warnings)。

@gy212

gy212 commented Feb 9, 2026

Copy link
Copy Markdown
ContributorAuthor

适配了0.6.4
@op7418 哥,你先审查一下,你迭代太快了。

@op7418

Copy link
Copy Markdown
Owner

装备了0.6.4 @op7418 哥,你先审查一下,你迭代太快了。

哈哈好

@gy212

Copy link
Copy Markdown
ContributorAuthor

适配了0.7

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the i18n implementation! The zero-dependency approach with React Context + typed translation keys is clean and well-suited for a 2-locale app. Covering 295 keys across all UI modules is impressive.

A few things to address:

Medium — please fix:

  1. Error message regression in ChatView.tsx — The original error instanceof Error ? error.message : 'Unknown error' is replaced with just t('chat.failedToSend'), losing the actual server error message. Please preserve the original error detail, e.g. t('chat.failedToSend') + ': ' + (error instanceof Error ? error.message : '').

  2. chat.helpContent is a ~700-char markdown string — This massive block is not maintainable as a translation key. Since it references CLI commands that are always in English, consider keeping it untranslated or splitting it into structured pieces.

Low — nice to have:

  1. Unrelated changes bundled — The PR includes several non-i18n improvements (require→import conversions, code-block highlight fix, shimmer component refactor, Header hydration simplification, McpServerEditor key prop fix, etc.). These are all fine individually but make the PR harder to review and bisect. Consider splitting them into a separate PR.

  2. t() stability concernt uses useCallback with empty deps + localeRef. Components that only destructure { t } without subscribing to locale may not re-render on locale switch. This works in practice because most components use context, but it's fragile.

  3. Duplicate formatRelativeTime — Same function exists in both ChatListPanel.tsx and ImportSessionDialog.tsx. Should be extracted to a shared utility.

  4. Brand names in translations — "Anthropic", "OpenRouter", "AWS Bedrock", "Google Vertex" are brand names and don't need to be in translation files.

No security concerns. The locale validation is properly scoped to 'en' | 'zh'. Architecture is solid — looking forward to the revised version!

@gy212
gy212force-pushed the feat/i18n-zh-en branch 2 times, most recently from 7cd6361 to bf94c71CompareFebruary 10, 2026 07:14
@gy212

Copy link
Copy Markdown
ContributorAuthor

@op7418 绝大部分问题都修了,我本地一切完好。

@gy212
gy212 requested a review from op7418February 10, 2026 10:06
@gy212

Copy link
Copy Markdown
ContributorAuthor

已根据 review 完成修复并推送到 eat/i18n-zh-en(commit: 24aad56)。\n\n本次修复点:\n- 修复 i18n 参数插值中 $ 被 String.replace 误解释的问题:改为函数式替换,并对参数名做正则转义(src/i18n/index.ts)。\n- 已保证语言切换后聊天内即时文案可实时更新:ChatView 的 sendMessage/handleCommand 回调依赖已覆盖 与消息上下文(该部分此前已在分支上的 d931bc4 处理,本次确认保留)。\n- 修复内置命令 badge 描述的国际化:对 built-in command 记录并渲染 descriptionKey,避免固定英文描述。\n- 修复文件-only 发送兜底文案的语言切换闭包问题:handleSubmit 依赖包含 。\n\n本地校验:\n-
px eslint src/components/chat/ChatView.tsx src/components/chat/MessageInput.tsx src/i18n/index.ts\n- 结果:0 error(仅剩 2 条既有 warning,未在本次变更范围内)。

@gy212gy212 changed the title feat: 添加中英文国际化支持feat: 国际化支持拓展至中文、英文、繁體中文、日本語、Español、Português-Brasil、Deutsch、Français、РусскийFeb 11, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

语言拓展至 9 种语言

在原有中文、英文基础上,新增以下 7 种语言支持:

  • 繁體中文(zh-TW)
  • 日本語(ja)
  • Español(es)
  • Português-Brasil(pt-BR)
  • Deutsch(de)
  • Français(fr)
  • Русский(ru)

校验情况

每种语言均通过逐 key 深度校验,主要修复内容:

  • 变音符号修复 — es、pt-BR、fr、de 四个文件存在系统性变音符号/Umlaute 缺失,已全部补齐
  • 未翻译项修复 — 所有文件中 docPreview.sourcedocPreview.previewdocPreview.htmlPreview 等 key 已翻译
  • 翻译质量改进 — ru 的 chat.turns 用词优化,es 动词变位修正,fr 用词改进
  • TypeScript 编译通过npx tsc --noEmit 无翻译文件相关错误

@op7418op7418 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The i18n architecture itself is well-designed (zero-dep Context + hook, type-safe keys, secure interpolation). However:

  1. Please split non-i18n changes into separate PRs — `mcp-config.ts`, mcp-cli-parser tests, session-parser test changes, and settings route changes should not be in the i18n PR. This overlaps with PR #43 and makes review very difficult at 5000+ lines
  2. Don't translate internal error messages — `throw new Error(t(...))` should remain in English for debugging. Only translate user-facing UI text
  3. Consider phased language rollout — Ship en/zh first (well-tested), add other languages in follow-up PRs after native speaker review. 442 keys × 7 AI-generated languages is hard to verify
  4. Rebase instead of merge — The 19-file merge commit creates messy history and conflict resolutions are hard to verify

Add internationalization support with useTranslation hook, I18nProvider,
and language files for: zh, en, zh-TW, ja, es, pt-BR, de, fr, ru
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gy212

Copy link
Copy Markdown
ContributorAuthor

Review 修复已完成

1. 错误消息不再翻译

throw new Error(t(...)) 已全部改为英文字符串,方便调试:

  • throw new Error('Failed to load messages')
  • throw new Error('Failed to create session')
  • throw new Error('Failed to send message')
  • throw new Error('No response stream')

catch 块中用户可见的错误统一使用 t() 翻译显示,不再依赖 err.message

2. Rebase 替代 Merge

已用 rebase 重建为基于 main 的单个干净 commit,移除了之前的 merge commit。

  • tsc --noEmit 零错误
  • throw new Error() 中不再有 t() 调用

@op7418

Copy link
Copy Markdown
Owner

你好 @gy212,感谢你提交这个国际化方案!工作量很大,架构设计也很清晰。

经过检查,主分支目前还没有国际化的实现,这个功能对项目的国际化推广很有意义。

不过有几点需要讨论:

  1. 这个 PR 改动量较大(+4870/-434, 49 files),需要仔细评估对现有代码的影响
  2. 目前 PR 状态是 Changes Requested,之前的 review 意见可能需要先处理
  3. 如果存在冲突,需要 rebase 到最新的 main 分支

我们会在后续详细评估这个 PR 的合并方案。再次感谢你的贡献!

@op7418op7418 mentioned this pull request Feb 23, 2026
@gy212

Copy link
Copy Markdown
ContributorAuthor

此 PR 已拆分为多个独立 PR,便于逐语言审核和合并:

@gy212gy212 closed this Feb 23, 2026
youcho2 pushed a commit to youcho2/CodePilot that referenced this pull request Aug 11, 2026
…18#31)
Codex review second round caught two real P1 inconsistencies introduced by
the Dashboard/CLI split slice plus non-blocking contract drift.
P1.1 — Dashboard injection gate ≠ route auth gate.
runtime.ts injected the dashboard read/write MCPs whenever prompt + working
directory + dashboard keyword matched, but the route's `authorize` requires
`sameRealPath(workspacePath, assistant_workspace_path)`. Mismatch → the model
sees the tool and Codex 403s at call time. Fix: dashboard injection mirrors
memory's gate exactly (same sameRealPath check, same `assistantWorkspacePath`
passed as `workspacePath`) so "inject" and "route-authorize" never disagree.
CLI tools don't need this (no workspace scope).
P1.2 — Matrix promoted only for codex_account; runtime injects for ALL
codex_runtime providers.
The runtime didn't gate injection by provider, so under a CodePilot proxy
provider the dashboard/cli MCPs WERE injected (callable), but the matrix
returned `perception_only` for non-codex_account — the opposite drift from
P1.1 ("model says yes, Settings says no"). Fix per Codex's preferred option:
move the promotion into `capabilityMatrixForRuntime` so it applies to ALL
codex_runtime providers; `capabilityMatrixForRuntimeProvider` now only adds
codex_account-specific overrides (native notes + image/media demotion).
`buildCapabilityMatrix` delegates to `capabilityMatrixForRuntime` so every
matrix entry point stays aligned.
Non-blocking op7418#1 — contract text drift.
capability-contract.ts dashboard/cli `deferredReason` + `codex_proxy.notes`
rewritten — explicit that the LEGACY provider-proxy bridge is unsupported
(true), and that the codex_runtime path now ships via the mutation-level MCP
split + matrix-layer promotion. No schema changes (`kind: 'unsupported'`
stays accurate for the legacy bridge surface); the existing matrix invariant
test gets a `MATRIX_LAYER_PROMOTIONS` exception list documenting why the two
promoted cells are allowed to be executable despite `kind: 'unsupported'`.
Schema cleanup (introduce a new `mcp_server_split` kind, drop the exception
list) tracked as tech-debt op7418#33.
Non-blocking op7418#2 — elicitation policy pins.
codex-mcp-events.test.ts now pins all 4 new server names:
codepilot_{dashboard,cli_tools}_read → auto_accept,
codepilot_{dashboard,cli_tools}_write → user_approval.
Also added a regression guard: `codex_runtime + non-codex_account provider`
must STILL show dashboard/cli_tools executable with mixed trust + the right
noteKey. Updated the two pre-existing tests that asserted the OLD behaviour
(dashboard/cli perception_only on codex_runtime) — they now assert the
promoted state. Also synced the static `CAPABILITY_EXECUTABLE_RUNTIMES` map.
Per Codex review's explicit ask: the "待真账号 smoke" wording stays in the
op7418#31 capability table — this commit fixes the inconsistencies, but the
real-account end-to-end smoke for natural-conversation triggering + write
approval card + Deny blocking is still owed by the user.
Full unit suite 3045/3045. Live route: bad workspace still 403 (auth gate
intact); tools/list subsets unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@gy212@Angelahanshuang@op7418