给应用接入一个第三方 ArkUI 组件时,中文界面能跑通,往往只说明默认语言资源存在。切换到英文,某个确认按钮可能仍显示中文;再切回中文,问题又消失了。把这类现象归结成“翻译漏了”不够准确,因为有些键本来就允许回退到基础目录,有些键却承担删除确认、放弃修改等风险提示,不能用基础文案蒙混过关。这一篇只做发布前可以复制的小检查:扫描可访问源码中的 resources/base/element/string.json 与 resources/en_US/element/string.json,把“允许系统回退的普通键”和“项目要求必须翻译的关键键”分开。示例工程叫 LocaleGate,检查批次 LG-210。基础资源有 12 个名称,英文覆盖 10 个;缺少的两个分别是 discard_warning 与 tool_tip_extra。其中前者在应用定义的关键键名单里,所以审计状态为 BLOCKED;后者可以使用基础资源回退,只给提醒。请注意:这是针对供应方可检查源码的 Node.js 静态门禁,不是声称对每个安装的 .har 文件都能直接读到相同目录,更不是华为工具链会按这个自定义名单拒绝构建。真实的 HAR 可能以不同的源码或字节码形式分发;访问不到资源源码时,这个脚本只能报告 NOT_INSPECTED,必须转向供应方产物说明和目标包实际验证。## 一、先定义哪些“回退”属于设计,而不是缺陷HarmonyOS 的资源目录可以包含基础资源和带限定词的语言资源。匹配当前设备条件的限定目录不存在对应资源时,框架会根据资源匹配规则回退查找基础目录;这能让应用避免因为少一条次要翻译就崩溃。但资源回退不是翻译完整性的商业验收结论。比如帮助页角落的说明文案可以临时沿用中文,危险操作按钮的说明却可能不能接受。示例故意保留两个缺口:tool_tip_extra 代表普通帮助气泡,允许回退;discard_warning 是放弃批注时提醒可能丢失未保存内容的文案,在该项目中被归入强制覆盖名单。这个清单不是系统预置,也不暗示官方上架审核把某个字段定义为敏感项。它是产品团队根据自身风险设定的明确准则,换一个项目就要重新评审。目录先限定为组件供应方签入仓库的一个快照 vendor-ui/resources。不去改安装缓存,也不从复杂的 .har 二进制结构里猜文件。扫描入口只接受两个显式传入的文件路径,方便 CI 把这份检查固定到某个提交。若对方提供 JSON5 或已打包且无法直接 JSON.parse 的数据,就不使用正则硬剥注释;先按实际格式另写可靠解析适配层。第一个代码段解决“读取与重复定义如何判定”的问题。假设资源遵守常见 string.json 结构,根节点的 string 是 [{ name, value }] 数组;读取失败、结构不对或键名在同文件内重复,都直接抛错。不能拿一次读取异常当“翻译缺失”,因为这两类故障的责任人完全不同。jsimport { readFileSync } from 'node:fs';function readCatalog(filePath) { const doc = JSON.parse(readFileSync(filePath, 'utf8')); if (!doc || !Array.isArray(doc.string)) { throw new Error(`BAD_FORMAT: ${filePath}`); } const table = new Map(); for (const row of doc.string) { if (!row || typeof row.name !== 'string' || typeof row.value !== 'string' || !row.name) { throw new Error(`BAD_ENTRY: ${filePath}`); } if (table.has(row.name)) { throw new Error(`DUPLICATE_KEY: ${row.name}`); } table.set(row.name, row.value); } return table;}````Map` 在这里只保存资源键与可读值,不执行语言选择,更不模拟系统运行时的完整资源匹配优先级。严格检查重复键,是因为同一文件内后写的相同名称很容易被脚本误认为自然覆盖,导致交付报告与编译行为无法对应。对于同名但不同限定目录的两个条目则不应该报警,它们本就是不同语言的候选值。## 二、12 对 10 的差分,不能只算一个百分比只给翻译覆盖率 `10/12`,会丢掉最重要的信息:缺失的到底是哪两个键。覆盖率为 83.3% 的资源包,有可能因为缺少两个不重要的说明仍可按项目标准放行,也可能因为一条核心确认文案缺失必须被拦下来。把数字变成可执行决策,前提是清单公开、分层明确、能解释给审阅者听。第二段负责差分。关键键名单显式写在源码里,便于代码审查。除了缺失项,还要检查英文资源里有没有**基础文件没有**的额外键;额外键本身暂不拦截,但值得提示供应方检查是否存在拼写错误或未同步的旧键。一个完全凭字符串总数判断的脚本会忽略这类差异。jsconst requiredKeys = new Set([ ‘submit_label’, ‘discard_warning’, ‘resume_hint’]);function auditCatalog(base, locale) { const missing = […base.keys()].filter(key => !locale.has(key)); const criticalMissing = missing.filter(key => requiredKeys.has(key)); const fallbackAllowed = missing.filter(key => !requiredKeys.has(key)); const orphan = […locale.keys()].filter(key => !base.has(key)); return { baseCount: base.size, localeCount: locale.size, criticalMissing, fallbackAllowed, orphan, gate: criticalMissing.length > 0 ? ‘BLOCKED’ : ‘REVIEW’ };}````gate不是华为规定的状态枚举,它只是我们的 CI 输出。这里没有在“无关键缺失”时直接写PASS,而写 REVIEW,原因是静态键差分还不包含界面截断、占位符格式、动态资源拼接、右到左排版、可访问性朗读或真实语言切换。即便脚本返回 REVIEW,开发者还必须用设备或预览环境查看实际页面。还有一个容易被忽略的非对称风险:当供应商更新 base,新增了键,却忘了更新英文资源,缺口数量会自动增加;当供应商只改英文,删掉基础键,所谓“多出来”的键也应被记录。这让差分成为版本升级验收的一份证据,而不是每次靠 QA 逐页回想哪个弹窗少了一句话。![](https://i-blog.csdnimg.cn/direct/99c8cdb879e24b6c98f8542c80a7156a.png)## 三、命令行必须让错误有明确出口很多工具脚本在本地打印一堆文字,CI 却仍然显示绿色,这是因为进程退出码始终是 0。第三段把前面的函数变成可以调用的命令行入口。推荐把这三段按照顺序合并进同一个 audit-locale.mjs;Node.js 标准库 API 即可完成,不依赖未经核验的 HarmonyOS 额外脚手架接口。```jsconst [baseFile, localeFile] = process.argv.slice(2);if (!baseFile || !localeFile) { console.error('用法: node audit-locale.mjs <base> <en_US>'); process.exitCode = 2;} else { try { const result = auditCatalog( readCatalog(baseFile), readCatalog(localeFile) ); console.log(JSON.stringify({ task: 'LG-210', ...result }, null, 2)); process.exitCode = result.gate === 'BLOCKED' ? 1 : 0; } catch (err) { console.error('NOT_INSPECTED:', String(err)); process.exitCode = 2; }}```如果资源可读,构造数据应输出 LG-210、baseCount=12、localeCount=10、criticalMissing=[discard_warning]、fallbackAllowed=[tool_tip_extra]和BLOCKED。约定退出码 1 表示项目规定的关键资源缺口,2 表示未能完成检查。这是工具自己的协议,不是 ohpm、Hvigor 或 DevEco Studio 的官方退出码约定。若将脚本并入流水线,最好同时记录被检查的第三方组件提交摘要、运行环境和两个输入路径,避免日后有人拿“脚本跑过”去证明另一个版本的包也没有问题。对于源码目录之外生成的资源,还应确认实际打包路径与源目录之间没有二次改写。可以另建一个小型合成样本做回归:预期 12/10、1 条关键缺失、1 条允许回退;然后人为补齐 discard_warning,确认脚本不再返回 BLOCKED。## 四、报告给人的应是“具体键”,不是一张红灯图演示的手机页面并不表示某次真实 HarmonyOS 系统已完成语言切换。它把内部诊断做成可读卡片:LG-210、基础键 12、英文键 10、关键缺失 1、允许回退 1、状态 BLOCKED。点开关键缺失后能看到 discard_warning;普通差分是 tool_tip_extra。这张图展示的是业务质检面板,而不是 DevEco 的编译器错误列表。![](https://i-blog.csdnimg.cn/direct/5bad628acd7b4993a6d2f0313fb5d97b.png)真实回归最该看三件事。第一,脚本读取的源码快照确实是当前准备集成的供应包,而不是某个复制后忘记更新的样例文件。第二,切换语言后关键页面显示的语句是否语义完整,尤其不要因为单词较长把“取消”“放弃”的操作含义挤到看不见。第三,组件升级后默认语言与英语资源应作为一个整体复核,不能只看到修改了 string.json就认定界面已经本地化成功。这里还能进一步细分出两种错误:**资源缺失**与**资源被引用却不再存在**。本文只检查两个清单之间的覆盖关系,不扫描 ArkTS 中所有$r(‘app.string.xxx’)` 访问表达式;静态引用、动态拼接、代码生成引用可能需要单独的分析器。不要把没有扫描的范围写成“已通过”。同理,一个键即使存在,译文为空字符串也可能存在体验问题;是否把空值纳入阻断,需要与产品约定后再扩展,而不是在脚本里偷偷塞进一套未公开规则。从工程产出看,关键不在于写了多少遍“国际化很重要”,而在于把一句“英文按钮有时是中文”拆成可追踪的差分记录。资源回退是平台能力,关键键门禁是应用策略,真实页面的语言效果则需要另行验证。三者相互配合,才能让三方组件的本地化问题在构建前被准确描述,而不是在上架临门一脚时才凭一张截图争论。参考资料与限制:华为资源分类与访问说明(基础资源、限定词目录及回退规则):https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V2/resource-categories-and-access-0000001544463977-V2 ;官方 HAR 构建及包含资源的产物说明:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-v5/ide-hvigor-build-har-V5 ;最新依赖管理说明:https://developer.huawei.com/consumer/cn/doc/HarmonyOS-Guides/ide-hmos-hvigor-dependencies 。此例未固定 DevEco SDK 构建号,没有声称真实 SDK 编译、应用商店审核或供应商缺陷确认。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐