Skip to content

PR:i18n settings 拆分与翻译质量门禁(含 messages no-emoji)#588

Merged
ding113 merged 65 commits intoding113:devfrom
YangQing-Lin:refactor/i18n-split-settings
Jan 11, 2026
Merged

PR:i18n settings 拆分与翻译质量门禁(含 messages no-emoji)#588
ding113 merged 65 commits intoding113:devfrom
YangQing-Lin:refactor/i18n-split-settings

Conversation

@YangQing-Lin
Copy link
Collaborator

@YangQing-Lin YangQing-Lin commented Jan 11, 2026

背景与目标

本 PR 以 settings / dashboard / myUsage 为主范围,完成 i18n 的结构拆分、翻译质量工程化门禁与多语言内容补齐,并补充中文对照文档与 PR 流程清单。当前分支已合并最新 dev,并处理了与 settings split 相关的冲突点,保证可回归。

主要变更

1) settings messages 拆分(替代 legacy settings.json)

  • 移除 messages/<locale>/settings.json,改为 messages/<locale>/settings/ 目录下小模块 JSON(递归结构)。
  • 运行时拼装:messages/<locale>/settings/index.ts 组装 settings namespace,并由 messages/<locale>/index.ts 引入,保证 key path 稳定。
  • 同步脚本升级:scripts/sync-settings-keys.js 支持 legacy 与 split 两种布局,使用 zh-CN 作为 canonical,同步所有 locale 的 key 集合并填充缺失项。

2) 翻译质量规则落地(R1/R2/R3/R4)与可执行门禁

  • 新增规则文档:docs/i18n-translation-quality.md(并提供中文对照版),定义 scope 与可执行规则:
    • R1:非 canonical locale 禁止出现 “与 zh-CN 相同且包含汉字” 的占位候选(支持 allowlist)。
    • R2:翻译更新不得破坏 placeholders/tokens(如 {count})。
    • R3:术语表(glossary)与术语一致性。
    • R4:messages/**/*.json 禁止 emoji(输出 codepoints,不直接打印 emoji 字符)。
  • 扫描/门禁脚本:
    • scripts/audit-settings-placeholders.js:支持 --scope=settings,dashboard,myUsage、TSV/JSON 输出与 --fail
    • scripts/audit-messages-no-emoji.js:可作为 CI fail gate(--fail),并修复跨平台路径分隔符问题。
    • scripts/audit-messages-emoji.js:用于清理前的命中清单与复现证据(mask 输出)。
  • 统一 bun 入口命令(写入 package.json scripts):
    • bun run i18n:audit-placeholders / bun run i18n:audit-placeholders:fail
    • bun run i18n:audit-messages-no-emoji / bun run i18n:audit-messages-no-emoji:fail

3) 翻译内容补齐与一致性修复(重点 ja / zh-TW)

  • 根据占位扫描清单,分模块补齐 ja / zh-TW 文案,减少误用 zh-CN 文案导致的 “占位候选”。
  • 固化括号规范(zh/zh-TW 用全角(),其他语言用半角 ()),并通过单测守护。
  • 同步更新 messages/*/settings/prices.json 等新增模块的翻译细节,确保通过 R1 与括号规范相关测试。

4) messages 去 emoji + 回归门禁

  • 清理 messages/** 中的 emoji(不改 key/结构,仅改 value 文案),例如 provider-chain.jsonsettings/data.json 的 warning/info 文案。
  • 增加 no-emoji 审计脚本 + 单测回归,避免后续引入。
  • 文档与 checklist 增补 “no-emoji 必跑项”。

5) 文档与协作流程补强(含中文对照)

  • 新增/补充:
    • docs/i18n-pr-checklist.md(及中文对照版):可执行命令 + 人工抽查最小集。
    • docs/i18n-settings-split.md(及中文对照版):拆分结构与验证方式。
    • docs/i18n-pr-evidence-2026-01-11.md:PR 证据模板(可复制到 PR 描述)。
  • CONTRIBUTING.md 补充 i18n 变更入口,方便贡献者按规则执行。

6) 同步最新 dev(已合并并解决冲突)

  • 本分支已 merge 最新 dev,并在冲突点上保持 settings split 的结构一致性:
    • dev 新增/调整的 settings.prices 文案落到 split 文件(messages/*/settings/prices.json)。
    • dev 新增的 prices UI 单测适配 split settings(新增测试侧 messages loader,避免依赖 legacy settings.json)。

验证与门禁(本地已通过)

  • bun run lint
  • bun run typecheck
  • bun run test
  • bun run build
  • bun run i18n:audit-placeholders:fail
  • bun run i18n:audit-messages-no-emoji:fail

影响范围与迁移说明

  • 后续修改 settings 文案请直接改 messages/<locale>/settings/**.json;不要再编辑 messages/<locale>/settings.json(已移除)。
  • 新增 key 或调整结构后,建议:
    1. node scripts/sync-settings-keys.js 保证各 locale key 集一致;
    2. bun run i18n:audit-placeholders / :fail 检查占位候选;
    3. bun run i18n:audit-messages-no-emoji:fail 避免 messages emoji 回归。

风险与建议抽查

  • 这是一次大范围 i18n 结构与文案变更,建议按 docs/i18n-pr-checklist.mdjazh-TWsettings/dashboard/myUsage 做最小人工 spot-check(截图/路径留证)。
  • bun run build 通过,但 Next/Turbopack 对部分 Edge Runtime 路径存在 Node.js API 警告(不影响本 PR 目标;如需后续治理可单独开任务)。

YangQing-Lin and others added 30 commits January 10, 2026 22:41
…n/claude-code-hub into refactor/i18n-split-settings
@coderabbitai
Copy link

coderabbitai bot commented Jan 11, 2026

Important

Review skipped

Too many files!

136 files out of 286 files are above the max files limit of 150.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@greptile-apps
Copy link

greptile-apps bot commented Jan 11, 2026

Too many files changed for review. (286 files found, 100 file limit)

@github-actions github-actions bot added enhancement New feature or request area:i18n area:docs size/XL Extra Large PR (> 1000 lines) labels Jan 11, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @YangQing-Lin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

本次拉取请求旨在全面提升项目的国际化(i18n)管理水平,通过对 settingsdashboardmyUsage 模块的 i18n 结构进行拆分,引入自动化翻译质量门禁,并补齐多语言内容,以确保翻译的准确性、一致性和可维护性。同时,还完善了相关文档和协作流程,为未来的 i18n 贡献提供了清晰的指导和保障。

Highlights

  • i18n 设置拆分: 将 settings.json 拆分为 messages/<locale>/settings/ 目录下的模块化 JSON 文件,并由 index.ts 运行时组装,替代了旧的单一文件结构。
  • 翻译质量门禁: 引入了 R1-R4 翻译质量规则,包括禁止非规范语言出现中文占位符、保留占位符/token、术语一致性及消息 JSON 禁止 emoji,并提供了可执行的审计脚本进行自动化检查。
  • 翻译内容补齐与规范化: 针对 jazh-TW 语言,根据占位符扫描结果补齐了翻译内容,并统一了括号规范(中文全角,其他语言半角)。
  • 移除消息 Emoji: 清理了 messages/** 中的 emoji 字符,并增加了 no-emoji 审计脚本及单测回归,以避免后续引入。
  • 文档与协作流程完善: 新增了 i18n PR 检查清单、settings 拆分结构说明、PR 证据模板等文档,并更新了 CONTRIBUTING.md,以提供清晰的贡献指导。
  • 与最新 dev 分支合并: 已合并最新 dev 分支,并处理了 settings 拆分相关的冲突点,确保了代码的可回归性。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

这是一个非常出色且全面的拉取请求。它系统性地重构了 i18n 的 settings 结构,引入了强大的质量保障机制,并完成了大量的翻译工作。变更内容非常清晰,文档齐全,新增的自动化检查脚本和单元测试将极大地提升未来国际化工作的质量和可维护性。

我详细审查了代码变更、新脚本、测试和文档,没有发现明显的问题。逻辑严谨,实现扎实。对细节的关注,例如统一括号用法和移除表情符号,值得称赞。

这是一次高质量的提交,显著提升了项目的工程化水平。做得非常棒!

Comment on lines 7 to 84
function loadJson(p) {
return JSON.parse(fs.readFileSync(p, "utf8"));
}

function normalizeLocales(messagesRoot, locales) {
if (typeof locales === "string") return normalizeLocales(messagesRoot, [locales]);
if (Array.isArray(locales) && locales.length > 0) {
return locales
.flatMap((s) => String(s).split(","))
.map((s) => s.trim())
.filter(Boolean);
}

const dirs = fs.readdirSync(messagesRoot, { withFileTypes: true });
return dirs
.filter((d) => d.isDirectory() && !d.name.startsWith("."))
.map((d) => d.name)
.sort((a, b) => a.localeCompare(b));
}

function toCodepoint(cp) {
const hex = cp.toString(16).toUpperCase();
return `U+${hex.padStart(4, "0")}`;
}

function listEmojiCodepoints(value) {
EMOJI_RE.lastIndex = 0;
const out = [];
for (const m of value.matchAll(EMOJI_RE)) {
const cp = m[0].codePointAt(0);
if (typeof cp === "number") out.push(toCodepoint(cp));
}
return out;
}

function findMessagesEmojiMatches({ messagesDir, locales }) {
const root = messagesDir || path.join(process.cwd(), "messages");
const targets = normalizeLocales(root, locales);
const rows = [];

for (const locale of targets) {
const localeDir = path.join(root, locale);
if (!fs.existsSync(localeDir) || !fs.statSync(localeDir).isDirectory()) continue;

const files = emojiAudit.listJsonFiles(localeDir);
for (const file of files) {
const relFileNative = path.relative(localeDir, file);
const relFilePosix = relFileNative.replaceAll(path.sep, "/");
const keyPrefix = emojiAudit.fileToKeyPrefix(relFileNative);
const obj = loadJson(file);

for (const leaf of emojiAudit.flattenLeafStrings(obj)) {
if (typeof leaf.value !== "string") continue;
const emojiCount = emojiAudit.countEmojiCodepoints(leaf.value);
if (emojiCount === 0) continue;

const fullKey = keyPrefix
? leaf.key
? `${keyPrefix}.${leaf.key}`
: keyPrefix
: leaf.key;

const codepoints = Array.from(new Set(listEmojiCodepoints(leaf.value))).sort((a, b) =>
a.localeCompare(b)
);

rows.push({
file: path.posix.join("messages", locale, relFilePosix),
key: fullKey,
emojiCount,
codepoints,
});
}
}
}

return rows.sort((a, b) => a.file.localeCompare(b.file) || a.key.localeCompare(b.key));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

这个 PR 引入了多个新的 i18n 审计脚本,例如 audit-messages-no-emoji.jsaudit-messages-emoji.jsaudit-settings-placeholders.js。这些脚本极大地提升了翻译质量的保障。

我注意到这些脚本之间存在一些重复的代码,主要是一些辅助函数和文件遍历逻辑。例如:

  • normalizeLocales
  • loadJson
  • listJsonFiles
  • flattenLeafStrings / flatten
  • 遍历 messages 目录下各 locale 和 JSON 文件的逻辑

为了提高代码的可维护性并遵循 DRY (Don't Repeat Yourself) 原则,建议将这些通用的辅助函数和遍历逻辑提取到一个共享的工具文件中(例如 scripts/i18n-utils.js)。

这样可以:

  1. 减少重复代码:避免在多个文件中维护相同的逻辑。
  2. 简化未来更新:当需要修改 locale 的发现逻辑或文件处理方式时,只需在一个地方修改。
  3. 提高脚本清晰度:每个审计脚本可以更专注于其核心的检查逻辑,而不是文件系统操作。

例如,可以创建一个通用的 forEachMessageLeaf 函数,它接收一个回调函数,在每个消息的叶子节点上执行特定的检查。

这是一个重构建议,可以使这套优秀的审计工具更加健壮和易于维护。

const path = require("node:path");
const emojiAudit = require("./audit-messages-emoji.js");

const EMOJI_RE = /\p{Extended_Pictographic}/gu;
Copy link
Contributor

Choose a reason for hiding this comment

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

[High] [LOGIC-BUG] Emoji audit misses keycap/flag sequences (false negatives)

Why this is a problem: scripts/audit-messages-no-emoji.js:5 uses const EMOJI_RE = /\p{Extended_Pictographic}/gu;, which does not match common emoji sequences like keycaps ([0-9#*]\uFE0F?\u20E3) or flags (\p{Regional_Indicator}{2}). This means bun run i18n:audit-messages-no-emoji:fail can report OK even when messages/**/*.json contains those emoji.

Suggested fix:

// Handle Extended_Pictographic + keycap + flag sequences
const EMOJI_RE =
  /(\p{Extended_Pictographic}|\p{Regional_Indicator}{2}|[0-9#*]\uFE0F?\u20E3)/gu;

// When listing codepoints, output full sequences (no emoji printed)
for (const m of value.matchAll(EMOJI_RE)) {
  const seq = Array.from(m[0])
    .map((ch) => ch.codePointAt(0))
    .filter((cp) => typeof cp === "number")
    .map((cp) => toCodepoint(cp))
    .join("+");
  if (seq) out.push(seq);
}

Also update scripts/audit-messages-emoji.js:4 so maskEmoji() / countEmojiCodepoints() stay consistent, and add a unit test case that includes a keycap and a flag sequence.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

已在 bfd982d 中修复

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

This PR is XL and spans messages content, new auditing scripts, new unit tests, and documentation updates, which increases merge risk and makes regression isolation difficult. One correctness gap was found in the no-emoji gate: the current emoji regex can miss keycap and flag sequences, allowing false negatives.

PR Size: XL

  • Lines changed: 25126
  • Files changed: 286
  • Split suggestion: Split into separate PRs for (1) settings messages split + runtime loader, (2) audit scripts + tests, (3) translation content updates (messages JSON only), (4) docs/checklists.

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 1 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Critical Issues (Must Fix)

  • None.

High Priority Issues (Should Fix)

  • (Confidence 90) scripts/audit-messages-no-emoji.js misses keycap/flag emoji sequences due to \p{Extended_Pictographic} only, weakening the intended no-emoji fail gate.

Review Coverage

  • Logic and correctness
  • Security (OWASP Top 10)
  • Error handling
  • Type safety
  • Documentation accuracy
  • Test coverage
  • Code clarity

Automated review by Codex AI

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

  • Identified PR #588 and applied the label size/XL (25126 lines changed across 286 files).
  • Posted an inline review comment on scripts/audit-messages-no-emoji.js:5 about the emoji regex missing keycap/flag sequences (false negatives), with a concrete regex + test suggestion.
  • Submitted the full review summary to the PR via gh pr review.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

This is a well-structured large PR that implements i18n settings splitting and translation quality gates. The code is clean, consistent across all locales, and includes comprehensive test coverage. No significant issues were identified.

PR Size: XL

  • Lines changed: 25,126 (+14,033 / -11,093)
  • Files changed: 288

Note for XL PRs: This PR makes a coordinated architectural change (i18n settings split), so while large, the changes are cohesive and would be difficult to split further without breaking the migration.

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Key Observations

Strengths identified (not listed as praise, but context):

  • All messages/<locale>/settings/index.ts files are byte-for-byte consistent in structure
  • New audit scripts (audit-messages-emoji.js, audit-messages-no-emoji.js, audit-settings-placeholders.js, sync-settings-keys.js) have proper module exports for testability
  • Test files cover edge cases including allowlist filtering, CLI flags, and output formats
  • Emoji removal from JSON files follows the correct pattern (replacing with text equivalents)

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Appropriate for build scripts (exceptions propagate to terminate)
  • Type safety - Clean (TypeScript index files properly typed)
  • Documentation accuracy - Clean
  • Test coverage - Adequate (14 new test files covering scripts and guards)
  • Code clarity - Good

Automated review by Claude AI

@ding113 ding113 merged commit 8637837 into ding113:dev Jan 11, 2026
9 of 10 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Jan 11, 2026
@github-actions github-actions bot mentioned this pull request Jan 12, 2026
ding113 added a commit that referenced this pull request Jan 12, 2026
* PR: 修复 Edge Runtime 下 `process.once` 构建告警(AsyncTaskManager 导入链) (#589)

* fix: skip async task manager init on edge

* fix: avoid static async task manager import

* test: cover edge runtime task scheduling

* chore: document edge runtime process.once fix

* chore: record edge runtime warning baseline

* fix: drop NEXT_PHASE and lazy-init async task manager

* test: isolate NEXT_RUNTIME in cloud price sync tests

* docs: stabilize edge process.once repro baseline

* docs: make rollback instructions hashless

* docs: add grep checklist for edge warning audit

* chore: run regression gate and align docs

* test: cover edge runtime guard on register

* Update src/lib/async-task-manager.ts

补充 NEXT_PHASE === "phase-production-build" 检查

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* chore: format code (fix-edge-runtime-process-once-bee7e19)

* PR:i18n settings 拆分与翻译质量门禁 (#588)

* refactor(i18n): split settings json into smaller files

* refactor(i18n): load settings from split module

* refactor(i18n): remove legacy settings.json

* chore(i18n): update sync-settings-keys for split layout

* test(i18n): add split settings guards

* chore: align biome schema version

* chore(i18n): document messages loading contract

* chore(i18n): add settings split verification notes

* chore: format code (refactor-i18n-split-settings-3f48fec)

* chore: fix i18n request formatting

* chore: format code (refactor-i18n-split-settings-a1eff62)

* fix: replace settings placeholder translations

* chore: verify settings sync script is idempotent

* test: run i18n settings split guards

* test: add audit for zh-CN placeholder settings strings

* chore: apply biome formatting

* chore: document manual i18n settings verification

* fix: translate all providers filter in ja

* fix: translate all providers filter in zh-TW

* fix: translate providers section copy in zh-TW

* fix: translate providers section copy in ja

* feat: extend placeholder audit output

* feat: add allowlist for placeholder audit

* docs: define i18n translation quality rules

* chore: add i18n audit fail commands

* docs: add i18n PR checklist

* chore: format i18n audit tests

* fix: translate dashboard placeholders

* fix: translate myUsage placeholders

* fix: enforce locale-specific parentheses

* fix: start translating provider form strings

* fix: translate provider form strings

* fix: translate provider guide content

* test: add ja dashboard parentheses guard

* test: add zh-TW dashboard parentheses guard

* test: add zh-TW myUsage parentheses guard

* chore: translate ja provider form strings

* chore: translate zh-TW provider form strings

* chore: translate ja providers guide

* chore: translate zh-TW providers guide

* chore: refine zh-TW dashboard strings

* chore: translate ja providers strings

* chore: translate zh-TW providers strings

* chore: refine zh-TW api test strings

* chore: translate zh-TW settings small modules

* chore: translate ja settings small modules

* chore: clear i18n placeholders in settings

* chore: format code (refactor-i18n-split-settings-2437d19)

* test: fix biome formatting in i18n test

* chore: verify Biome lint gate (I18NE-030)

* chore: add messages emoji audit script (I18NE-010)

* fix: remove emoji from messages warnings (I18NE-040)

* test: add messages no-emoji audit gate (I18NE-050)

* docs: add zh-CN i18n docs (I18NE-020)

* docs: add messages no-emoji rule (I18NE-060)

* chore: run full regression checks (I18NE-070)

* docs: add i18n PR evidence template (I18NE-080)

* fix: make messages no-emoji audit path-sep safe

* docs: add bun alias for messages no-emoji audit

* fix: detect keycap and flag emoji sequences in i18n message audits

* fix(provider): allow removing custom whitelisted models (#592) (#593)

* fix(rectifier): detect 'signature: Field required' error and trigger rectifier (#594)

- Extend detectThinkingSignatureRectifierTrigger to match 'signature: Field required'
- Add Rule 72 for friendly error message when signature field is missing
- Add comprehensive test cases for the new detection logic

This fixes an issue where switching from non-Anthropic to Anthropic channels
with thinking blocks missing signature fields would fail without proper handling.

* feat(users): increase provider group length to 200 (#591)

close #590

* feat(usage-doc): update OpenCode config example with GPT-5.2 and Gemini v1beta (#597)

- Add OpenAI GPT-5.2 model configuration with reasoningEffort options
- Add GPT-5.2-small variant using medium reasoning effort
- Fix Gemini baseURL to use /v1beta endpoint
- Update i18n strings to reflect different baseURLs per provider

* feat: auto-complete Codex session identifiers (#599)

* fix: Codex session completion must not inject metadata (#601)

* feat: auto-complete Codex session identifiers

* fix: avoid Codex metadata injection

---------

Co-authored-by: YangQing-Lin <56943790+YangQing-Lin@users.noreply.github.com>
Co-authored-by: Hwwwww-dev <47653238+Hwwwww-dev@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:docs area:i18n enhancement New feature or request size/XL Extra Large PR (> 1000 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants