Orca 的 UI 本地化覆盖审计:用 AST 扫描器、覆盖契约与允许列表守住 i18n 迁移底线

发布时间:2026/9/7 23:52:29

Orca 的 UI 本地化覆盖审计:用 AST 扫描器、覆盖契约与允许列表守住 i18n 迁移底线
Orca 的 UI 本地化覆盖审计:用 AST 扫描器、覆盖契约与允许列表守住 i18n 迁移底线【免费下载链接】orcaOrca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.项目地址: https://gitcode.com/GitHub_Trending/orca48/orcaOrca 正在将全桌面端界面迁移到 i18next 本地化层,其前置产物 config/localization-audit.md 定义了一套覆盖率可复现的审计机制:每一个被检测到的面向用户的字符串,要么迁移到本地化层,要么带着明确理由被显式排除。读完本文,你将掌握如何运行 Orca 的本地化候选清单扫描与覆盖门禁、理解覆盖契约中算/不算本地化目标的边界,以及目录同步、运行时英文子集、源码提取校验这三条维护链路的实现原理。一、审计文档在项目中的定位Orca 的本地化不是一个孤立任务。被接受的翻译源架构与分阶段迁移计划记录在 config/i18n-translation-source.md(gettext PO 作为规范双语翻译源、稀疏目标目录、运行时英文回退)。而 config/localization-audit.md 是该迁移的前置工件(pre-work artifact),它解决一个更基础的问题:在逐波迁移 PR 落地之前,如何让哪些字符串还需要处理这件事变得可重复验证。核心目标是文档原文所述:让覆盖成为可复现的:每一个被检测到(匹配审计范围)的面向用户字符串,要么迁移到本地化层之后,要么带着理由被显式排除。这套机制在 package.json 中固化为五个 npm 脚本,并且全部挂入了lint聚合脚本(即每次 lint 都会跑完四条本地化校验链):verify:localization-catalog/sync:localization-catalog:目录键校验与同步(带--fix);verify:localization-runtime-catalog/sync:localization-runtime-catalog:运行时必需英文子集的校验与重新生成;verify:localization-extraction:源码提取校验;verify:localization-coverage/audit:localization:覆盖率门禁与候选审计。二、覆盖契约:什么算本地化候选,什么不算config/localization-audit.md 定义了覆盖的含义:所有匹配以下审计范围的字符串都必须被accounted for(归入某个迁移状态):必须覆盖的范围:渲染器中渲染的 JSX 文本;可访问性与表单属性,如aria-label、ariaLabel、alt、placeholder、title、label、description、subtitle、tooltip;面向用户的对象元数据,如设置搜索的title、description、keywords,以及 labels、badges、helper text、tooltips;面向用户的调用,如toast.success(...)、toast.error(...),浏览器alert(...)、confirm(...)、prompt(...)。有意不计为本地化缺失的范围(除非直接作为 UI 文案呈现):终端输出、agent 输出、git 输出、provider API 错误、shell 命令;文件路径、URL、环境变量、遥测事件名、ID、协议名;开发者日志、内部诊断、测试夹具、快照;应当保持原样的品牌、provider、模型、命令和产品名。这一契约在扫描器 config/scripts/audit-localization-coverage.mjs 中落地为具体的 AST 规则。该脚本基于 TypeScript 语言服务 API 解析源码,而不是正则匹配:JSX 属性白名单 audit-localization-coverage.mjs#L15-L32 比文档列出的范围更宽,还包含aria-description、emptyText、helperText、keywords、message、text、toggleDescription;对象键白名单 audit-localization-coverage.mjs#L33-L48 额外覆盖badge、error、message、toggleDescription;用户可见调用 audit-localization-coverage.mjs#L49-L65 识别alert/confirm/prompt/showError/showToast,以及toast.error/info/loading/message/promise/success/warning方法;模板字符串(\...${...})会被拆分为片段并标记为dynamic 候选。脚本还实现了几个防止误报的工程细节,值得参考:跳过测试与生成物:.d.ts、.test./.spec.、__tests__/、-test-harness/-fixtures类文件以及.git、dist、node_modules、out、__snapshots__、assets目录一律跳过(audit-localization-coverage.mjs#L79-L91);只在保留文案的二元运算符内继续识别:仅、??、||、被视为保留比较操作数的运算符,其他算术/比较表达式会终止向上追溯,避免把纯代码逻辑误判为文案;已处于t(...)/translate(...)内部的字符串不再报告,避免重复计入已迁移的调用;人类语言过滤hasHumanLanguageText要求文本长度不小于 2、包含字母(拉丁、中日韩),从而天然过滤掉纯数字、协议名、路径等排除类内容——这正是覆盖契约不算列表在扫描器层面的第一道实现。每条候选被归类为jsx-text、jsx-attribute:name、jsx-expression、object-property:key、user-visible-call之一,并携带文件路径、行列号、文本与dynamic标志——这个四元组就是后续门禁的比对签名。三、清单命令:生成机器可读与人工可审阅的候选清单文档给出的三条基础命令:# 生成机器可读清单(JSON) node config/scripts/audit-localization-coverage.mjs --json --output tmp/localization-candidates.json # 生成可审阅的 Markdown 清单 node config/scripts/audit-localization-coverage.mjs --markdown --output tmp/localization-candidates.md # 运行维护中的覆盖门禁 pnpm run verify:localization-coverage从 parseArgs 可以看到完整参数面:参数作用--json/--markdown输出格式;缺省为按 area 汇总的 summary--output path将结果写入文件(自动创建目录)--check门禁模式,与允许列表比对,发现新候选则以退出码 1 失败--allowlist path允许列表路径,默认config/localization-coverage-allowlist.json--source-root dir扫描根目录,默认src/renderer/src扫描范围与文档的说明一致:默认扫描src/renderer/src(主要 UI 表面);检查渲染器邻近的共享文案时可用--source-root src做更宽审计,但文档特别提醒非渲染器发现需要谨慎分类——很多属于诊断信息或外部工具文本。Markdown 清单(formatMarkdownReport)按area(如renderer/components/settings)分组,先给出每个区域的候选数与文件数汇总,再逐条列出文件:行:列 kind: 文本,可以直接作为迁移 PR 的任务清单使用。四、覆盖门禁:签名比对与允许列表门禁模式的核心逻辑在 findNewCandidates:每条候选生成签名(见 candidateSignature):{ filePath: ..., kind: object-property:title, text: Nightly #1, dynamic: false }允许列表中的每个条目额外携带count(同一签名允许出现的次数)。当某个签名在当前扫描中出现的次数超过允许列表记录次数时,超出的实例即为新候选,check 分支会打印失败信息并退出:New unlocalized renderer strings were found. Localize them or add a reviewed exclusion to the localization allowlist.即:新候选直接让检查失败,必须在同一次变更中完成本地化,或带着审阅过的理由加入允许列表。当前提交的允许列表 config/localization-coverage-allowlist.json 非常小,全部 13 条条目集中在三类审阅过的例外上,与文档描述的类别一致(文档写作时为 10 条,现仓库快照为 13 条,原则未变):测试夹具标题,如automations-page-fixtures.ts中的Nightly #1、Hermes;五个非英文语言一词的搜索关键词:语言、語言、언어、言語、Idioma、Langue(来自 [appearance-search.ts] 对应路径,这些词本身必须保持原语言才能在多语言搜索中命中);产品名搜索关键词:Ghostty/ghostty(出现在两处终端设置搜索元数据中)。可以看到允许列表不是技术债藏身处,而是一份每条都有明确理由、数量受控的豁免清单。五、目录同步:只动英文,绝不改目标目录添加或删除translate(...)调用后,文档要求运行:pnpm run sync:localization-catalog其实现 config/scripts/verify-localization-catalog.mjs 的行为与文档一一对应:补全缺失的en.json条目:从每个调用点的字符串 fallback(即translate(key, English default)的第二个字面量参数)中提取,AST 收集t/translate/translateMain/translateSearchKeyword的调用键(verify-localization-catalog.mjs#L93-L135);从不编辑目标目录:缺失的目标语言值保持缺失,运行时走既有英文回退;占位符不匹配是硬失败:已存在的目标条目若插值变量({{...}})与英文不一致,验证失败,直到本地化 PR 修复或退休该条目;扫描根为src/renderer/src与src/main(LOCALIZATION_SOURCE_ROOTS),主进程中的用户可见文案同样受约束。这一只写英文、冻结目标的同步模型,正是 i18n-translation-source.md 中 PR A 决策特性 PR 只改英文的落地形态:特性开发不再需要维持各语言目录的键对齐,未翻译键由运行时回退兜底。六、运行时必需英文子集:为什么只打包一小部分 en.json渲染器启动时急切打包的英文目录并不是完整的 en.json,而是 src/renderer/src/i18n/en-runtime-required.json。文档解释了原因:因为translate(key, fallback)总是提供默认值,且en在键缺失时会解析该默认值,所以这个子集只保留默认值无法复现的条目:带复数后缀的键(i18next 从目录而非 defaultValue 解析复数);目录值与内联默认值不同的键;没有任何调用点以字面默认值引用的键(动态键、动态默认值)。生成逻辑在 config/scripts/generate-runtime-required-english-catalog.mjs 中:复数后缀识别 PLURAL_SUFFIX_RE 覆盖_(zero|one|two|few|many|other),注释明确说明 i18next 绝不会从defaultValue推导复数形式,所以带后缀条目只能来自目录;collectRuntimeRequiredKeys 按上述三类规则收集必需键,再构建嵌套 JSON。校验模式(pnpm run verify:localization-runtime-catalog)区分两类失败与一类提示:missing:必需条目未打包——失败;contradicting:已打包条目与en.json文本不一致——失败;superfluous:不再需要的条目仍然在包中——不失败,仅提示 sync 可清除。注释(generate-runtime-required-english-catalog.mjs#L119-L128)点出了设计意图:不做字节级比较,因为子集只需安全(覆盖全部必需条目且不与en.json矛盾),过期的多余条目只是死重而不是错误字符串,因此一个无关 PR 新增普通键不会使其他分支上该文件的副本失效。与运行时的对应关系见 src/renderer/src/i18n/i18n.ts:英文目录随启动包急切载入,而es/ja/ko/zh四个目录通过 懒加载后端 动态import(),注释说明这避免了约 2MB 目录在每次冷启动被解析;translate()函数(i18n.ts#L76-L79)在伪本地化语言下还会套一层pseudoLocalizeString,为文档验收策略中的伪本地化冒烟测试提供运行时基础。七、源码提取校验:不提交第二份英文目录pnpm run verify:localization-extraction对应 config/scripts/verify-localization-extraction.mjs。它通过 i18next-cli 按 config/i18next.config.ts(提取t、*.t、translate、translateMain、translateSearchKeyword,忽略测试与快照)把静态可提取的键输出到临时目录——注释明确提取输出是本次检查的证据,不是第二份被提交的目录——然后与en.json比对:硬失败:静态提取出的键缺失于en.json,或内联默认值与目录值占位符不兼容;仅报告为迁移债(migration debt):已存在的未被引用的英文键(孤儿键)、以及仅措辞漂移(fallback drift,占位符一致但文本不同)的条目。文档对此的解释是:永久的双语翻译源(i18n-translation-source.md 决策的 gettext PO)将负责调和这些债务,而不是现在维护一个大型处置数据库;已审阅与陈旧的翻译状态同样延迟到该翻译源,而不是从 Git 历史永久推断。文档还特别指出:遗留的免费端点引导脚本与全目录修复脚本有意没有 package-script 入口——普通产品与本地化工作不得调用可以覆盖整个目标目录的工具。仓库中这些脚本(config/scripts/ 下的bootstrap-*、repair-locale-catalog.mjs、各类locale-*-overrides工具)仅作为被 PO 方案取代前的历史资产存在。八、迁移状态机:每个候选的三种终态文档规定每个候选应终结于以下状态之一:localized:组件从语言目录读取字符串;excluded:字符串有意不本地化,理由来自覆盖契约(如品牌名、终端输出);deferred:字符串面向用户但属于后续 PR 波次。关键约束:deferred只可用于规划,不能用于覆盖率门禁——门禁只认已本地化 允许列表豁免两种通过路径,这保证每次合并后的代码库都满足完整覆盖。九、PR 波次:推荐的迁移顺序文档给出的分波次计划,本质上是按风险与依赖排序的:基础设施:英文目录、语言设置项、语言选择器;设置壳层:设置搜索元数据、外观(Appearance);应用壳层:侧边栏、标题栏、状态栏、命令面板面、全局对话框/toast;业务页面:任务页、源码控制、hosted review、provider 专属 UI;剩余次要表面:终端 chrome、onboarding、功能提示、移动端、浏览器。第一波(基础设施)在当前仓库已经落地:支持语言解析(src/renderer/src/i18n/supported-languages.ts)、五个目录文件(en/es/ja/ko/zh,见 src/renderer/src/i18n/locales/)、语言设置搜索元数据(允许列表中的appearance-search.ts条目即出自第二波)。十、验收策略:三道检查 扫描器为准文档Proof Strategy要求最终门禁组合三项检查:扫描器覆盖:不存在未分类的可本地化候选——即本文第三、四节的--check门禁;目录正确性:现有翻译的插值变量匹配;缺失的目标条目报告而非拒绝(与第六节的缺失走英文回退一致);运行时覆盖:伪本地化(pseudo-localization)与真实语言冒烟测试,核心屏面无明显英文残留与布局裁切——运行时支撑即 i18n.ts#L76-L79 的pseudoLocalizeString分支。最后一条原则值得强调:子代理或人工审阅负责确认模糊的排除项,但扫描器是覆盖的唯一事实来源——人工判断不进入门禁,门禁由可重复运行的 AST 扫描决定。小结:一套可直接借鉴的 i18n 治理清单Orca 这套本地化审计机制的可复制要点:契约先行:先写清楚什么算候选、什么不算,再用 AST 扫描器把契约变成机器可执行规则,正则做不到这种精度;签名 计数的允许列表:豁免以文件 类别 文本 动态标志 次数精确到实例,数量受控且每条有审阅理由;英文与目标目录解耦:同步只补英文,目标缺失由运行时回退兜底,特性 PR 不碰翻译;最小运行时子集:按默认值能否复现剪枝启动包,校验只查安全性而非字节一致性;债务显式报告、不硬卡:孤儿键与措辞漂移作为迁移债交给后续双语翻译源调和,避免为历史遗留建立永久例外数据库;门禁进 lint 聚合脚本:四条校验全部挂入lint,从引入 PR 起就在 CI 中强制运行。【免费下载链接】orcaOrca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.项目地址: https://gitcode.com/GitHub_Trending/orca48/orca创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

定位 ClickHouse 无状态测试 CI 失败:Stateless/Fast test 产物(Artifacts)抓取与解压实战

定位 ClickHouse 无状态测试 CI 失败:Stateless/Fast test 产物(Artifacts)抓取与解压实战

2026/9/7 23:52:29

定位 ClickHouse 无状态测试 CI 失败:Stateless/Fast test 产物(Artifacts)抓取与解压实战 【免费下载链接】ClickHouse ClickHouse is a real-time analytics database management system 项目地址: https://gitcode.com/GitHub_Trending/…

工业4.0不会取代精益生产:数字化转型的底层逻辑与融合之道

工业4.0不会取代精益生产:数字化转型的底层逻辑与融合之道

2026/9/7 23:52:29

前两年帮一家汽配厂做数字化诊断,对方的CIO跟我说了一句让我印象特别深的话:“我们花了大几百万上MES,结果车间主任跟我说库存反而更乱了。”这不是个案。过去十年我见过太多企业,把工业4.0当成一剂万能药,上了系统、买…

ppt-master 的 AGENTS.md 详解:AI Agent 路由权威、命令速查与仓库执行纪律

ppt-master 的 AGENTS.md 详解:AI Agent 路由权威、命令速查与仓库执行纪律

2026/9/7 23:52:29

ppt-master 的 AGENTS.md 详解:AI Agent 路由权威、命令速查与仓库执行纪律 【免费下载链接】ppt-master AI turns documents or topics into real, native PowerPoint decks—with native shapes, transitions and animations, data-backed charts and tables on d…

新闻推荐系统全栈实战:从Selenium爬虫到Hadoop与大模型混合推荐

新闻推荐系统全栈实战:从Selenium爬虫到Hadoop与大模型混合推荐

2026/9/8 1:12:33

如果你最近在做大数据方向的课程设计或者毕设,大概率刷到过“新闻推荐系统”这个题目。热点新闻平台、爬虫、可视化、Hadoop、推荐算法,这几个词叠在一起确实很唬人,尤其是再加上“大模型”之后,几乎是答辩现场的“王炸”配置。但…

构网型逆变器小信号建模与稳定性分析实践

构网型逆变器小信号建模与稳定性分析实践

2026/9/8 1:12:33

1. 项目背景与核心价值构网型逆变器(Grid-Forming Inverter, GFMI)作为新能源发电系统的核心接口设备,其稳定性直接关系到电力系统的可靠运行。传统基于锁相环的跟网型控制策略在弱电网条件下表现不佳,而构网型控制通过模拟同步发电机特性,能…

tkinter网格布局重构:告别魔法数字,写出可维护的grid代码

tkinter网格布局重构:告别魔法数字,写出可维护的grid代码

2026/9/8 1:12:33

写tkinter桌面程序这么久,我最大的体会是:业务逻辑写得再漂亮,布局一团乱也会把整体观感拖下水。尤其是碰到一堆 grid(row4, column2, padx10, pady5) 这种裸奔式的网格调用,表面看程序能跑,等需求一变,真…

COMSOL 5.6瓦斯渗流多物理场耦合建模:从达西定律到工程应用

COMSOL 5.6瓦斯渗流多物理场耦合建模:从达西定律到工程应用

2026/9/8 1:12:33

这段时间我一直在整理自己手里的COMSOL 5.6瓦斯相关模型,起因很简单:项目里反复要处理煤层瓦斯渗流、钻孔抽采、采动影响下的渗透率变化这类问题,每次从头搭模型,结构相似但参数不同,改起来费时还容易出错。后来我把几…

ThinkPHP 6 + Vue 3 打造茶园茶农文化交流平台完整实践

ThinkPHP 6 + Vue 3 打造茶园茶农文化交流平台完整实践

2026/9/8 1:12:33

两年前一个做文旅的朋友找到我,说想给当地茶园和茶农做一个线上交流平台:茶叶资讯、茶文化文章、茶农之间的经验问答,顺带把茶叶和茶具卖起来。当时我脑子里迅速过了一遍技术栈,最后定下的方案就是标题里这套组合——ThinkPHP 6 L…

Cursor:AI代码编辑器的智能协作与实战应用

Cursor:AI代码编辑器的智能协作与实战应用

2026/9/8 1:02:33

1. Cursor:重新定义代码编辑器的智能协作体验第一次听说Cursor时,我以为这不过是又一个VS Code的衍生品。直到真正上手使用后,我才意识到这个"披着编辑器外衣的AI编程助手"正在悄然改变开发者的工作流。作为一款深度整合GPT-4的智能…

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

2026/9/7 20:21:46

本文首发于“生态学者”!从“湿地面积”到“土壤碳密度”:为什么需要重新认识潮汐湿地蓝碳变化?潮汐湿地位于陆地与海洋的交汇地带,包括红树林、盐沼和潮滩,是全球重要的蓝碳生态系统。其土壤能够长期储存大量有机碳&a…

adb抓包

adb抓包

2026/9/7 3:44:24

前言 本文介绍如何通过 tcpdump 在 Android 手机上抓取网络数据包,并在电脑端使用 Wireshark 进行分析。适用于需要排查 App 网络请求、分析接口调用或调试网络问题的开发与测试场景。1. 手机要有 root 权限2. 下载 tcpdump3. adb push C:\Users\zhangkuixun\Downlo…

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

2026/9/7 8:03:37

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战 在云原生基础设施中,容器镜像体积直接决定了服务的部署速度与弹性扩容敏捷度。对于传统的 Go / Java 微服务,镜像体积通常被严格控制在 50MB 到 200MB 以内,拉取镜像只…

芯片良率波动可视化:动画拆解工艺因果,重建客户信任

芯片良率波动可视化:动画拆解工艺因果,重建客户信任

2026/9/8 0:02:30

芯片这个行业有个不太被人摆到台面上、但几乎每天都在发生的场景:客户拿着一条良率曲线截图问你,这批货的良率怎么掉了三个点,是不是工艺出问题了,产生的不良会不会流到他们产线上去。你解释了半天,客户似懂非懂&#…

PyTorch DataLoader参数冲突:sampler与shuffle互斥的根源与正确写法

PyTorch DataLoader参数冲突:sampler与shuffle互斥的根源与正确写法

2026/9/8 0:02:30

ValueError: sampler option is mutually exclusive with shuffle,这个报错我在 PyTorch 的 DataLoader 上至少见过几十次了,而且很有意思的是,它经常不是新手专属——很多写了好几年模型的老手,在从单机改成自定义采样器&#xf…

中国车企再破谣言,GAC吉利零跑获欧盟安全五星

中国车企再破谣言,GAC吉利零跑获欧盟安全五星

2026/9/8 0:02:30

有人可能在网上开着皮卡拍视频,声称中国电动车不仅性能不如美国大排量车型,安全性也堪忧。然而事实恰恰相反,GAC、吉利和零跑最新推出的电动车型在极为严苛的欧盟新车安全评鉴(Euro NCAP)测试中全部斩获满分。就在特斯…

远程协作的工作台整理

远程协作的工作台整理

2026/9/7 3:38:07

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/4 7:42:10

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/6 23:21:51

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…