Skip to content

🌐 Cover chrome.i18n messages.json and Monaco editor langs for pt-BR / tr-TR#1605

Merged
CodFrm merged 3 commits into
mainfrom
i18n/pt-br-tr-l10n-coverage
Jul 18, 2026
Merged

🌐 Cover chrome.i18n messages.json and Monaco editor langs for pt-BR / tr-TR#1605
CodFrm merged 3 commits into
mainfrom
i18n/pt-br-tr-l10n-coverage

Conversation

@CodFrm

@CodFrm CodFrm commented Jul 17, 2026

Copy link
Copy Markdown
Member

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

背景

PR #1587 的 pt-BR 翻译遗漏了两处本地化面(见 评论反馈):

  • src/assets/_locales/ 下没有 pt_BR/messages.json(chrome.i18n 的扩展名称/商店描述),其余 8 个语言都有;
  • Monaco 编辑器语言包 editorLangs 没有 pt-BR 条目(编辑器 metadata 悬浮提示、@grant 权限说明、快速修复文案),缺失时静默回退英文。

排查中发现 tr-TR 存在同类缺口_locales/tr 已有,但 editorLangs 同样缺失土耳其语条目,一并补齐。

本次改动

  • 新增 src/assets/_locales/pt_BR/messages.json,商店描述沿用 pt-BR 语言包既有措辞(gerenciador de scripts de usuário)。
  • editorLangs 新增 pt-BRtr-TR 完整条目(各约 90 条),分别遵循 docs/references/terminology-pt-BR.mdterminology-tr-TR.md 的术语规范(如 pt-BR 用 entre origens 而非 origem cruzadaAbalink de afiliado;tr-TR 用 betikSekme、保留 GM API@ 标识符)。
  • 重构:原 langs.ts 单文件已含 9 种语言约 1300 行,按语言拆分为 src/pkg/utils/monaco-editor/langs/<locale>.ts + index.ts,导入路径 ./langs 不变。拆分为纯机械搬移,已用临时深度对比测试验证拆分前后 editorLangs 内容完全一致。
  • 新增两个守卫测试,防止后续新增语言再漏配:
    • src/pkg/utils/monaco-editor/langs.test.tseditorLangssrc/locales/ 注册的 UI 语言一一对应,且各条目键结构与 en-US 一致;
    • src/locales/chrome-locales.test.ts:每个 UI 语言都有对应的 _locales 目录,且各 messages.json 键与 en 一致。

已知限制

对其余翻译面做了完整盘点,运行时侧无其他缺口(各 locale 的 *.json 键与 en-US 完全对齐、语言下拉框与相对时间格式化均为动态派生、chrome.i18n.getMessage 无代码调用)。唯一剩余缺口在文档层:本地化 README 仅有 zh-CN / zh-TW / ja / RU 四种,de / vi / tr / pt-BR 尚无,留待后续单独处理。

建议审查重点

  • pt-BR / tr-TR 译文的自然度与术语选择(母语者视角),尤其 crontabantifeatureunwrap 等长文案。

关联

验证

  • 按 TDD 先写守卫测试并确认失败(pt-BR / tr-TR 缺失时各自命中),补齐后通过。
  • 拆分等价性:临时测试将拆分后的 editorLangs 与拆分前(git show HEAD 版本)深度对比,完全一致后移除。
  • pnpm lint:prettier / tsc / eslint 全部通过。
  • npx vitest run(与 lint 顺序执行):306 文件 / 3370 用例全部通过。此前并行跑 lint 与测试时曾出现偶发超时失败,失败集在多次运行间完全不同且单独重跑全过,确认为满载并发下 340ms 超时抖动,与本次改动无关。

CodFrm added 3 commits July 18, 2026 01:52
PR #1587 的 pt-BR 翻译遗漏了 src/assets/_locales/(商店/清单文案)与
src/pkg/utils/monaco-editor/langs.ts(编辑器 metadata 提示与快速修复文案,
缺失时回退英文)。补齐两处,并新增语言覆盖守卫测试。
土耳其语翻译当时同样遗漏了 editorLangs(_locales/tr 已存在)。补齐后
将守卫测试收紧为 editorLangs 与注册的 UI 语言一一对应。
langs.ts 已含 9 种语言约 1300 行,拆为 langs/<locale>.ts + index.ts,
导入路径 ./langs 不变。拆分为纯机械搬移,已用临时深度对比测试验证
拆分前后 editorLangs 内容完全一致。
@cyfung1031

This comment was marked as outdated.

@CodFrm
CodFrm marked this pull request as draft July 17, 2026 18:16
@CodFrm

This comment was marked as outdated.

cyfung1031 added a commit to cyfung1031/scriptcat that referenced this pull request Jul 17, 2026
用 PR scriptscat#1605 实测时发现:check-i18n.mjs 硬编码了单文件 src/pkg/utils/monaco-editor/langs.ts
路径,一旦该文件被拆分为 langs/<locale>.ts + langs/index.ts(如 scriptscat#1605 所做),检查会误报
"文件缺失"。改为先探测 langs/index.ts 是否存在,再退回单文件路径;并将 key 展开逻辑改为
按模块解析(parseModule/flattenNode),支持跨文件解析 import 绑定(如 index.ts 里
"pt-BR": ptBR 指向 ./pt-BR.ts 的 default export)与同文件 shorthand 属性
(如 pt-BR.ts 内的 grantValuePrompts,)。

已用 scriptscat#1605 的实际分支验证:新结构下 0 误报,人为在拆分后的 pt-BR.ts 中删除顶层 key 与
grantValuePrompts 子 key 均能正确报出具体路径。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cyfung1031

Copy link
Copy Markdown
Collaborator

#1606 里新增的机械检查脚本(scripts/check-i18n.mjs / pnpm run check:i18n)对本 PR 的 head commit(1f15ac7)做了实测,结果:全部通过,0 error / 0 warning

✅ i18n check passed: all locales match the en-US / en reference key sets.

具体覆盖到的点:

  • src/assets/_locales/pt_BR/messages.jsonen/messages.json key 完全一致(目录名是脚本扫描 _locales/ 实际内容解析出来的,不依赖写死的映射表)。
  • src/pkg/utils/monaco-editor/langs/index.ts 里的 editorLangs["pt-BR"]editorLangs["tr-TR"]en-US key 结构完全一致,包括嵌套的 prompt.* 和引用自 grantValuePrompts 常量的键。
  • src/locales/pt-BR/*.jsonsrc/locales/tr-TR/*.json 各命名空间与 index.ts 导出均无缺失/多余。
  • docs/references/terminology-pt-BR.mdterminology-tr-TR.md 均存在。

一个说明:本 PR 把 langs.ts 单文件拆分成了 langs/<locale>.ts + langs/index.ts。我原本的检查脚本硬编码了旧的单文件路径,第一次跑在这个 PR 上会误报"文件缺失"——这是脚本自身的问题,不是本 PR 的问题。已经修好(改为自动探测 langs/index.ts 是否存在,并支持跨文件解析 import 绑定),上面贴的是修好之后的结果,已经在 #1606 里更新。

另外发现本 PR 新增的 src/pkg/utils/monaco-editor/langs.test.tssrc/locales/chrome-locales.test.ts 这两个 vitest 守卫测试,和 #1606 的机械检查在设计目的上是重叠的(都是防止后续新增语言时再漏配)。两者可以并存,不算冲突,仅供参考。

@cyfung1031

Copy link
Copy Markdown
Collaborator

#1606 里新增的机械检查脚本(scripts/check-i18n.mjs / pnpm run check:i18n)对本 PR 的 head commit(1f15ac7)做了实测,结果:全部通过,0 error / 0 warning

@CodFrm ok了

@cyfung1031
cyfung1031 marked this pull request as ready for review July 17, 2026 18:39
@cyfung1031 cyfung1031 added the P0 🚑 需要紧急处理的内容 label Jul 18, 2026
@cyfung1031 cyfung1031 added this to the 2026七月 Milestone milestone Jul 18, 2026
@CodFrm
CodFrm merged commit 82546b1 into main Jul 18, 2026
9 of 10 checks passed
@cyfung1031
cyfung1031 deleted the i18n/pt-br-tr-l10n-coverage branch July 19, 2026 23:06
CodFrm added a commit that referenced this pull request Jul 20, 2026
* 🌐 添加翻译完整性机械检查 (check:i18n)

PR #1587 (pt-BR) 合并后发现 messages.json 与 monaco 编辑器语言遗漏,且当时无机制拦截;
本次新增 scripts/check-i18n.mjs 并接入 pnpm lint / lint:ci,机械校验:

- src/locales/<locale>/*.json 各命名空间 key 是否与 en-US 一一对应(缺失/多余均报错)
- src/locales/<locale>/index.ts 是否导出全部命名空间
- src/assets/_locales/<chrome-locale>/messages.json 与 en/messages.json 的 key 是否一致
  (尚未创建该目录时仅提示,不阻塞)
- docs/references/terminology-<locale>.md 是否存在(每个 locale 必须有,缺失即报错)
- src/pkg/utils/monaco-editor/langs.ts 中 editorLangs 各 locale 的 key 是否与 en-US 一致
  (尚未创建该 locale 条目时仅提示;已创建则 key 必须对齐)

已用 scriptscat/scriptcat 官方仓库的 PR #1568(韩语)与 #1587(pt-BR)实际验证:
正确通过完整、正确的翻译提交,也能在人为剔除 key / 文件时正确报错。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* 🔧 支持拆分后的 monaco-editor langs 模块结构

用 PR #1605 实测时发现:check-i18n.mjs 硬编码了单文件 src/pkg/utils/monaco-editor/langs.ts
路径,一旦该文件被拆分为 langs/<locale>.ts + langs/index.ts(如 #1605 所做),检查会误报
"文件缺失"。改为先探测 langs/index.ts 是否存在,再退回单文件路径;并将 key 展开逻辑改为
按模块解析(parseModule/flattenNode),支持跨文件解析 import 绑定(如 index.ts 里
"pt-BR": ptBR 指向 ./pt-BR.ts 的 default export)与同文件 shorthand 属性
(如 pt-BR.ts 内的 grantValuePrompts,)。

已用 #1605 的实际分支验证:新结构下 0 误报,人为在拆分后的 pt-BR.ts 中删除顶层 key 与
grantValuePrompts 子 key 均能正确报出具体路径。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* 🔒 pre-commit 阶段强制翻译完整性检查

CI 的 lint:ci 已经跑 check:i18n,但那只在 push/PR 之后才会看到红叉。
本次让本地 pre-commit 钩子在暂存区涉及翻译相关路径
(src/locales/、src/assets/_locales/、docs/references/terminology-*.md、
src/pkg/utils/monaco-editor/langs.ts 或 langs/ 拆分文件)时,
提前跑一遍 pnpm run check:i18n,不通过则直接拒绝提交,
不需要等到推送后在 CI 里才发现。

真正能拦住"不通过就不许合并"的还有一层:仓库 main 分支的
branch protection 需要把 Lint 设为 required status check,
这一步需要 scriptscat/scriptcat 的仓库管理员在 GitHub 设置里配置,
不是贡献者这边能做的。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* 🔧 pre-commit 机械检查范围收窄为仅 json 文件改动

之前的触发范围包含 terminology-*.md、langs.ts/langs/* 等非 json 文件,
导致本 PR 自身改动 .husky/pre-commit、scripts/check-i18n.mjs 这类非
翻译内容的提交也可能被牵连(虽然本次未命中,但范围过宽)。收窄为只在
暂存区包含 src/locales/**/*.json 或 src/assets/_locales/**/*.json 时才
触发 pnpm run check:i18n,其余改动(含本 PR 自身)不受影响,仍可正常
提交推送。CI 侧的 lint:ci 不受影响,仍覆盖全部 5 类检查。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* 🐛 修复 check:i18n 的多处 fail-open 漏洞并补齐回归测试

CodFrm 在 PR #1606 review 中指出: pre-commit 的 check:i18n 校验的是工作区而非
Git 暂存快照(暂存坏版本、工作区改回好版本可绕过检查,删除操作也不触发);
check-i18n.mjs 从未与 src/locales/locales.ts 的实际注册(NS/resources/import)
交叉核对,index.ts 导出检查只是子串匹配可被注释字符串骗过;Monaco 自定义 AST
evaluator 对 spread、计算属性、循环别名等无法解析的结构会静默折叠为空/叶子键集
而非报错;Chrome _locales 与 Monaco 覆盖面缺失只是 warning。

本次改动:
- scripts/git-staged-snapshot.mjs: 用 `git checkout-index` 直接从索引物化暂存
  快照,.husky/pre-commit 改为对该快照跑 check:i18n(--diff-filter 补上 D)。
- scripts/check-i18n.mjs: 新增 locales.ts 双向一致性检查(NS 数组 vs 命名空间
  文件、import/resources vs 磁盘目录);index.ts 导出改用真实 AST 解析;Monaco
  AST evaluator 对 spread/计算属性/不支持的表达式/循环引用/语法错误一律报错
  (fail-closed);Chrome _locales 与 Monaco 覆盖面缺失由 warning 升级为 error。
- 新增 scripts/check-i18n.test.mjs、scripts/git-staged-snapshot.test.mjs 覆盖
  上述所有可复现场景。
- docs/translation.md 同步更新为当前 fail-closed 行为。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* 🐛 修复 check:i18n 入口守卫在特殊路径下静默失效

check-i18n.mjs 与 git-staged-snapshot.mjs 都用
`import.meta.url === \`file://${process.argv[1]}\`` 判断是否被直接执行。
这个比较在两种情况下永不成立,main() / CLI 分支不执行,进程零输出 exit 0:

- `import.meta.url` 是 percent-encoded 的,而 argv[1] 是原始路径:仓库路径含
  空格或非 ASCII 字符(如 ~/我的项目/scriptcat)时两者不等;
- `import.meta.url` 会解析软链而 argv[1] 不会:macOS 的 /tmp、/var 即是软链。

后果是本 PR 建立的机制整体失效且毫无迹象——`pnpm lint` / `lint:ci` 里这一格
永远绿,pre-commit 中两个脚本以 `&&` 串联、一起放行坏提交。实测在
~/…/中文目录/ 下删掉 zh-CN/common.json 的一个 key 后 `git commit` 直接落库,
而同样的破坏在 ASCII 路径下会被正确拦截。这恰好是脚本自身
"fail-closed by design" 承诺要杜绝的失败模式。

改为两边都归一化成真实文件路径再比对,同时覆盖编码与软链两种情形。

补充 CLI 入口回归测试:原有用例都直接调 runCheck(),绕过了 CLI 入口,
覆盖不到"脚本到底有没有被执行"这一层。新用例把脚本复制到含空格 /
非 ASCII 字符的目录下真实 spawn,断言干净树输出通过信息、缺 key 时
exit 1。因需拉起 node 子进程(实测 300ms+),显式放宽这些用例的超时,
不套用 vitest.config.ts 给单元测试定的 340ms 预算。

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: 王一之 <yz@ggnb.top>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P0 🚑 需要紧急处理的内容

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants