Skip to content

Brazilian Portuguese/pt-BR Translation - #1587

Merged
CodFrm merged 20 commits into
scriptscat:mainfrom
Lucas559-noob:main
Jul 17, 2026
Merged

CodFrm merged 20 commits into
scriptscat:mainfrom
Lucas559-noob:main

Conversation

@Lucas559-noob

@Lucas559-noob Lucas559-noob commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Checklist / 检查清单

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

Description / 描述

Screenshots / 截图

@cyfung1031 cyfung1031 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Brazilian Portuguese (pt-BR) Translation Review

Verdict

Request changes before merge.

The translation is a useful and generally understandable first pass. The namespace files are structurally complete, the JSON is organized correctly, and most placeholders and technical identifiers are preserved. However, the PR is not ready to merge because:

  1. pt-BR is not imported or registered in src/locales/locales.ts, so the locale cannot be selected or loaded.
  2. Six links in guide.json were changed to unverified /pt-BR/ routes, contrary to the repository rule that URLs must be preserved.
  3. Several strings materially change the meaning of the English and Simplified Chinese sources.
  4. Product terminology is not consistent, especially for Subscribe/Subscription, Skill, Source, browser tabs, file monitoring, and technical API terms.
  5. The locale terminology document and documentation index entries are missing.

What is right

Structural and technical strengths

  • All 11 runtime namespaces are present and exported by src/locales/pt-BR/index.ts.
  • The Portuguese files follow the same object structure as the English and Simplified Chinese files.
  • i18next placeholders are generally preserved correctly, including:
    • {{count}}, {{selected}}, {{total}}
    • {{attempt}}, {{max}}
    • {{scriptName}}, {{subscribeName}}
    • ${dir}
  • HTML/React markup is retained in onboarding and popup strings.
  • Metadata and developer identifiers are mostly preserved:
    • @match, @exclude, @grant, @connect
    • @resource, @require
    • ESLint, VSCode, OPFS, MCP, TTFT
    • SKILL.md, SkillScript
  • The major script-type distinctions are mostly retained:
    • script de usuário
    • script de página
    • script em segundo plano
    • script agendado
  • Many full-sentence translations are natural and faithful, for example:
    • permission.cookie_warning_desc
    • editor.confirm_override_when_edit_conflict
    • install.perm_match_summary
    • agent.dom_permission_describe
    • settings.sync_delete_desc (apart from one grammatical coordination issue)
  • Product capitalization is usually correct as ScriptCat.
  • The popup strings correctly preserve the English documentation URLs; this is the correct behavior unless localized destinations are verified.

Good choices that should be retained

Concept Current pt-BR choice Assessment
Background Script Script em segundo plano Natural and clearly distinct from other script types.
Scheduled Script Script agendado Natural pt-BR product wording.
User Script Script de usuário Appropriate generic term.
Storage Armazenamento Natural for data storage and storage space.
Permissions Permissão / Autorização Mostly distinguishes capability from granting access.
ScriptCat ScriptCat Correct product spelling in most strings.
Cron expression Expressão cron Technically understandable and concise.
Metadata identifiers Preserved Correct and required.
Backup Backup Common and natural in Brazilian software.
Cloud Nuvem / na nuvem Natural when grammar and prepositions are adjusted by context.

Release-blocking issues

1. The locale is not registered

The PR adds src/locales/pt-BR/index.ts, but does not modify src/locales/locales.ts.

Required integration:

import * as ptBR from "./pt-BR";

and inside resources:

"pt-BR": { title: "Português (Brasil)", ...ptBR },

Without this change, the new files are not part of the i18next resource bundle and the language will not appear as an available runtime locale.

2. The required terminology and documentation entries are missing

The repository translation guide says a new language should have a per-locale terminology file and be registered in the terminology table.

Add:

  • docs/references/terminology-pt-BR.md
  • A row to docs/translation.md:
| `pt-BR` | Português (Brasil) | [terminology-pt-BR.md](./references/terminology-pt-BR.md) |
  • Update docs/README.md from 8 locale guidelines to 9 and include pt-BR.

A proposed terminology file accompanies this report.

3. guide.json changes protected URLs

The repository rules explicitly require URLs to be preserved. The Portuguese file changes six destinations to guessed /pt-BR/ routes:

  • installed_scripts
  • script_list_content (two links)
  • script_list_action_content
  • tools_backup_content
  • subscribe_content

No Portuguese routes should be introduced unless they are confirmed to exist and contain the intended content. Keep the English source destinations for now:

  • https://docs.scriptcat.org/en/...
  • https://scriptcat.org/en/search

This is especially important because src/locales/locales.ts currently routes every non-Chinese documentation path to /en.

Major meaning and functionality issues

Severity Namespace / key English meaning Simplified Chinese clarification Current pt-BR Recommended pt-BR Why
Blocker settings.blacklist_placeholder Prevent ScriptCat from running scripts on matching pages Explicitly says “禁止…运行脚本” Desative o ScriptCat para executar scripts... Impeça o ScriptCat de executar scripts em páginas como\nhttps://*.example.com Current text can be read as “disable ScriptCat in order to execute scripts,” reversing the intended behavior.
Blocker settings.migration_confirm_message Retrying migration will modify existing data Explicit cause/effect warning Tentar novamente ... para modificar dados existentes Tentar novamente a migração do mecanismo de armazenamento modificará os dados existentes. Confirme. Consulte: https://docs.scriptcat.org/docs/change/v0.17/ Current text turns a warning into an instruction whose purpose is to modify data.
Major editor.run_at / editor.run_in Execution timing vs execution environment 运行时机 vs 运行环境 Both are Executar Em Momento da execução / Ambiente de execução Two distinct fields become indistinguishable.
Major common.type_string Technical String data type Keeps string Texto String “Texto” is not equivalent to the JSON/programming data type.
Major editor.storage_api Storage API Terminology guide preserves the API term API de Armazenamento Storage API The repository terminology treats this as a technical API name.
Major editor.eslint_rules_reset Reset-completed state ESLint规则已重置 Redefinir Regras do ESLint Regras do ESLint redefinidas A result/status was changed into a command.
Major editor.editor_config_reset Reset-completed state 编辑器配置已重置 Redefinir Configuração do Editor Configuração do editor redefinida Same state/action error.
Major editor.editor_type_definition_reset Reset-completed state 编辑器类型定义已重置 Redefinir Definição de Tipo do Editor Definição de tipos do editor redefinida Same state/action error.
Major editor.only_background_scheduled_can_run Background or scheduled scripts Chinese corrects the bad English crontab scripts to 定时脚本 scripts de segundo plano/crontab Apenas scripts em segundo plano ou scripts agendados podem ser executados crontab is not the product script type.
Major Subscription action/object across files Subscribe is an action; Subscription is an object Chinese uses one form because Chinese does not require the same noun/verb distinction All forms use Inscrição Action: Assinar; object: Assinatura The current translation loses the noun/verb distinction and sounds like event registration.
Major Skill entity across agent, install, script Product entity Skill, tied to SKILL.md Chinese deliberately preserves Skill in entity labels Habilidade Use Skill for installed/imported product entities; use habilidade only generically Translating every product label makes SKILL.md, SkillScript, and the installed object look unrelated.
Major install.restore_settings_clear_all Deselect all Chinese: 全不选 Limpar tudo Desmarcar tudo “Clear all” sounds destructive in a restore/import screen.
Major install.unimportable_count Count of items that cannot be imported Chinese includes “items” {{count}} não podem ser importados {{count}} itens não podem ser importados The Portuguese sentence has no subject noun.
Major install.resource_import_failed Resources could not be imported Chinese uses a passive failure construction Os seguintes recursos falharam ao importar: Não foi possível importar os seguintes recursos: Current text says the resources themselves failed while importing.
Major install.warning_risk_antifeature Declares anti-features / @antifeature metadata Technical feature warning ele declara anti-recursos ele declara metadados @antifeature anti-recursos is not established userscript terminology.
Major script.homepage Script homepage Chinese explicitly says 脚本主页 Página Inicial Página do script “Página Inicial” normally means the application's home page.
Major settings.enable_background.description Generic browser background behavior Chinese deliberately says browser, not Chrome Ends with sair manualmente do Chrome ...até que você encerre manualmente o navegador. The English terminology guide already identifies browser-specific Chrome as a review defect.
Major permission.script_accessing_cross_origin_resource Cross-origin resource Chinese: cross-domain resource recurso de origem cruzada recurso entre origens “Entre origens” is the standard Brazilian web wording.
Major permission.permission_cors Cross-domain / CORS Keeps cors as identifier Domínio cruzado (cors) Entre origens (CORS) Use standard terminology and capitalization.
Major logs.live Real-time/live logs Chinese: 实时 Ao Vivo Em tempo real “Ao vivo” suggests broadcasting, not continuously updating logs.
Major logs.total_logs Total queried logs Chinese uses a direct count Um total de {{length}} logs foram consultados Foram encontrados {{length}} logs no total Current subject–verb agreement is incorrect.
Major popup.ext_update_notification ScriptCat extension updated Chinese preserves product name Extensão Scriptcat atualizada Extensão ScriptCat atualizada Product capitalization is wrong.
Major popup.develop_mode_guide, popup.allow_user_script_guide Desktop click instruction Chinese corrects source tap to 点击 toque para... clique para saber como ativar This is a desktop browser-extension control, not a touch-only UI.
Major install.updatepage.tap_to_expand Expand desktop row/control Chinese: 点击展开 Toque para expandir Clique para expandir Same desktop interaction problem.
Major agent.tasks_subtitle Run automatically on a cron schedule Chinese: run according to a Cron cycle em um cronograma cron Execute tarefas do agente automaticamente de acordo com uma expressão cron Current phrase is redundant and unnatural.
Major agent.tasks_never_run Task has never run Chinese: not run Nunca executado Ainda não executada The implied noun is feminine tarefa; current agreement is wrong.
Major script.import_done Import success/failure totals Chinese explicitly labels success and failure {{success}} com sucesso · {{fail}} falharam Importação concluída: {{success}} com êxito · {{fail}} com falha Current first count has no noun/status relation and the two halves are not parallel.

Important terminology and naturalness issues

Namespace / key or pattern Current pt-BR Recommended direction Notes
source / col_source Fonte Origem Fonte is better reserved for a font, source code, or a specifically named data source. For provenance/install origin, use Origem.
common.more_menu Mais menus Mais opções The source describes a single “more” menu, not multiple menus.
common.exclude_off Excluir a execução de $0 Impedir a execução em $0 “Excluir” sounds like deleting a run.
editor.bulk_values Valores em massa Valores em lote “Em lote” is standard software wording and matches Edição em lote.
editor.confirm_delete_exclude exclusão desta exclusão Excluir esta regra de exclusão? Avoid awkward repetition.
File watching Observar arquivo, Observando Monitorar arquivo, Monitorando, Parar monitoramento Better describes continuous filesystem monitoring.
guide.title Guia de integração Guia de primeiros passos Chinese clarifies that this is beginner onboarding, not system integration.
guide.tour_finish Concluído Concluir This appears to be an action/button.
logs.last_1_hour Última 1 Hora Última hora Current phrase is ungrammatical/redundant.
Log intervals 1m, 5m 1 min, 5 min m is ambiguous in Portuguese.
logs.time Hora Horário or Data e hora after UI check English/Chinese use the broader concept “time.”
Authorization duration Temporário Temporária Must agree with feminine Duração.
auto_close_in {{second}}s {{second}} s or a localized seconds label Add spacing; pluralization may require a future i18n plural rule.
popup.page_in_blacklist lista negra lista de bloqueio More precise and avoids an unnecessary literal calque.
Right-click menu menu de clique com o botão direito menu de contexto Standard, shorter Brazilian software wording.
badge_type_none Nenhum Não exibir Chinese clarifies this is display behavior, not a missing noun.
expand_count Contagem para Expandir Limite de itens visíveis Current phrase is literal and unclear.
script.background_script_tooltip Executa ... uma vez ativado É executado em segundo plano quando ativado Avoids reading “uma vez” as “one time.”
script.error_script_type_mismatch não podem ser convertidos não é possível converter entre scripts normais e scripts em segundo plano Current sentence omits the conversion relationship.
settings.blacklist_pages Página na Lista Negra Páginas bloqueadas The setting represents a collection, not one page.
settings.script_run_env.all Todos Todas as abas Chinese and the English terminology review identify these as browser tabs.
settings.blacklist_pages_desc comma splice Impedir que scripts sejam executados nas páginas especificadas, com suporte a curingas Fix grammar and make the capability explicit.
install.skill_secret Segredo Secreto This is a state/adjective parallel to Obrigatório.
install.skill_warning_desc ele injeta... a Skill injeta... or omit pronoun If habilidade is retained, agreement would need feminine ela.
install.referral_link_title Link de Referência Link de indicação or Link de afiliado after product check Current wording can mean a citation/reference link.
install.membership_title Recursos de Membro Recursos para membros Natural Brazilian phrasing.
tools.pulling_data_from_cloud Puxando Dados da Nuvem Obtendo dados da nuvem Avoid an English developer-jargon calque in user-facing UI.
agent.model_supports_vision Entrada de Visão Entrada de imagem or Entrada visual Current phrase is unnatural.
agent.skills_refresh Atualizar Recarregar Distinguish refresh from version update.
agent.skills_updates_available atualização(ões) disponível(is) Atualizações disponíveis Avoid parenthetical pseudo-plural forms in UI.
agent.chat_new / chat_delete Chat Prefer conversa consistently The same namespace otherwise uses conversa.
agent.chat_background_* Modo de fundo Execução em segundo plano More natural and consistent with script terminology.
agent.search_engine_desc fonte de recuperação fonte de busca usada pela ferramenta web_search “Recuperação” is an unnecessary retrieval-system calque.
agent.summary_model_desc volta para o padrão usa o modelo padrão se não estiver definido More precise and natural.

Systemic style issue: excessive title case

Many Portuguese labels capitalize almost every noun and adjective:

  • Nova Versão Disponível
  • Configurações de Execução
  • Falha na Verificação de Atualização
  • Regras do ESLint Salvas
  • Página Inválida

Brazilian Portuguese software interfaces normally use sentence case:

  • Nova versão disponível
  • Configurações de execução
  • Falha na verificação de atualização
  • Regras do ESLint salvas
  • Página inválida

This is not only cosmetic: sentence case makes labels easier to scan and avoids inconsistent capitalization between labels and notifications. The terminology file supplied with this review makes sentence case the default.

Source disagreements that need product confirmation

These are not simple Portuguese mistakes. English and Simplified Chinese disagree, so the maintainer should confirm intended behavior.

Key English Simplified Chinese Portuguese choice Recommendation
guide.setting_sync_content Mentions syncing deletions and updating the script version here Mentions deletion propagation to other devices; does not mention updating the version Follows English Confirm product behavior and then align all three locales.
script.latest_version Latest Version “Already the latest version” Última Versão Confirm whether this is a label or a status. If status, use Já está na versão mais recente.
install.background_script_description Runs automatically when the browser starts Explicitly says it runs once when the browser opens Follows English and omits “once” Confirm whether it runs once at startup or continuously.
script.apply_to_run_status Ambiguous combined label Also retains a combined concept Literal combined label Inspect the actual column/control before rewriting. It may need two labels.
agent.chat_tools_count Count of tools Count of tool calls Count of tools Confirm whether the number represents available tools or invocations.

Suggested patch checklist

  1. Register pt-BR in src/locales/locales.ts.
  2. Add docs/references/terminology-pt-BR.md.
  3. Add pt-BR to docs/translation.md.
  4. Update the terminology count/list in docs/README.md.
  5. Restore all six modified URLs in guide.json unless the localized destinations are verified.
  6. Fix all release-blocking and major rows in this report.
  7. Apply the terminology file consistently:
    • Assinar vs Assinatura
    • preserve product Skill
    • Origem, not generic Fonte
    • menu de contexto
    • aba for browser tab
    • entre origens (CORS)
    • Monitorar arquivo
    • sentence case
  8. Recheck placeholders and identifiers after editing.
  9. Build the extension and verify:
    • language selector shows Português (Brasil)
    • every namespace loads
    • long strings fit dialogs, tables, badges, and mobile layouts
    • split strings such as menu_expand_num_before / menu_expand_num_after form a grammatical sentence
  10. Ask a Brazilian Portuguese speaker to do a final in-product fluency pass after the semantic fixes.

Recommended review decision

Request changes, with the locale registration, URL restoration, and major semantic corrections required before approval. The contribution has a solid base and is worth continuing; it needs terminology normalization and a focused second pass rather than a full rewrite.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I chose to use "Criar Script de Segundo Plano" to translate Create Background Script due to the following semantic nuances in Portuguese:

  • "Script de Segundo Plano" (Recommended): The preposition "de" establishes a relationship of categorization/type. It correctly defines the nature of the script (a script that runs in the background), perfectly mapping the English meaning of "Background Script".
  • "Script em Segundo Plano" (Avoided): The preposition "em" introduces syntactic ambiguity. It wrongly implies that the action of creating the script will happen in the background (asynchronously) while the user does something else in the system.

I still didn't read the other stuff to fix, maybe this is in them too, was looking on the files before the comment.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please read all AI review comments

For good suggestions, apply them with commits.

For bad suggestions, reply with reasons why they are bad.

Afterwards, mark this PR as ready please.
Thanks

@Lucas559-noob
Lucas559-noob marked this pull request as ready for review July 16, 2026 21:30

cyfung1031 commented Jul 17, 2026 •

Copy link
Copy Markdown
Collaborator

Hi @Lucas559-noob,

Thank you for the translation work. I reviewed the remaining comments and prepared 6 small commits with the needed fixes.

Changes made:

  • Added pt-BR to the translation guide and documentation index.
  • Changed unclear labels to describe what the screen really shows.
  • Changed Latest Version to a status message: Already on the latest version.
  • Made the background-script wording consistent.
  • Used Skill consistently for the ScriptCat product feature.
  • Fixed More menus, blacklist, badge, and other terminology.
  • Changed many labels to normal Portuguese sentence case.
  • Improved the wording in the tools page.
  • Changed the Agent tool counter from tools to tool calls.
  • Fixed ATIVADO and DESATIVADO to ATIVADA and DESATIVADA.
  • Changed file-watching text from Observando to Monitorando.
  • Fixed remaining sentence-case and spacing inconsistencies.

Why these changes are needed:

  • Some old texts could be understood in the wrong way.
  • Some labels did not accurately describe what the interface shows.
  • Some product terms were not used consistently.
  • The Agent counter shows tool calls, not the number of tools.
  • The Portuguese word execução is feminine.
  • Brazilian Portuguese interfaces normally use sentence case.
  • The file-watching terminology should follow the new pt-BR guide.
  • The new language guide must be listed in the documentation index.

@cyfung1031 cyfung1031 left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@CodFrm please final check before merging.

Since the translation is not covering all, some parts shall still display as English (fallback).

@CodFrm
CodFrm merged commit 83f32cc into scriptscat:main Jul 17, 2026
9 of 10 checks passed
@cyfung1031

Copy link
Copy Markdown
Collaborator

remarks: translation in messages.json and monaco editor langs are not covered in this PR.

@CodFrm

CodFrm commented Jul 17, 2026

Copy link
Copy Markdown
Member

remarks: translation in messages.json and monaco editor langs are not covered in this PR.

Oops, missed those. I'll handle them in a separate PR.

@cyfung1031

Copy link
Copy Markdown
Collaborator

remarks: translation in messages.json and monaco editor langs are not covered in this PR.

Oops, missed those. I'll handle them in a separate PR.

Actually, we don't have a solid mechanism to prevent this, and it's difficult to guarantee translation quality.

So, ensuring that users can fall back to English should be enough.

We can't use AI to generate every translation.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants