发布时间:2026/9/1 23:28:38
HarmonyOS 应用开发之多语言国际化:zh_CN/en_US 限定词与 string.json 资源体系详解 多语言国际化zh_CN/en_US 限定词与 string.json 资源体系一、引言国际化i18n是多设备短视频应用走向更多用户的基本功。一个覆盖直板机、平板与 PC 的应用若把文案硬编码在代码里每一次文案调整、每新增一种语言都要翻遍全部源码——这既是维护负担也是质量隐患。HarmonyOS 提供了一套与深色模式同构的资源限定词机制文案声明在string.json中通过zh_CN、en_US等语言限定词目录提供多语言版本代码中一律用$r(app.string.xxx)引用系统按设备语言环境自动匹配切换语言零代码。multi-short-video 工程在五个产品模块、四个特性模块与公共模块中全面落地了这一机制。本文以首页products/default、评论multishortvideocomment、个人作品页multishortvideoindividual三处真实文案为例讲解 string.json 的资源定义、$r引用、格式化占位符与兜底策略。二、zh_CN/en_US 限定词目录与 string.json 资源定义国际化的载体是语言限定词目录。以评论模块为例其资源目录结构为features/multishortvideocomment/src/main/resources/ ├── base/element/string.json # 默认文案兜底中文 ├── zh_CN/element/string.json # 简体中文 ├── en_US/element/string.json # 美式英语 ├── dark/element/color.json # 深色颜色与语言正交 └── base/media/ # 图标等媒体资源base目录承担兜底职责当设备语言不匹配任何限定词目录时系统取base中的取值。因此工程把base的文案定义为中文zh_CN与base内容一致en_US提供英文——即便未来新增小语种未覆盖的文案也能正确回退到中文。限定词之间用中划线连接可组合例如dark/zh_CN同时限定主题与语言本文与深色模式文章51可以互相印证。string.json 的格式为name value数组。name 是编译期键必须与语言无关推荐英文下划线风格value 是展示文案。评论模块的中英文定义如下// features/multishortvideocomment/src/main/resources/zh_CN/element/string.json节选 { string: [ { name: leave_comment, value: 写评论 }, { name: author, value: 作者 }, { name: reply, value: 回复 }, { name: view_all_reply, value: 查看全部回复 }, { name: nothing_more, value: 暂时没有更多了 } ] }// features/multishortvideocomment/src/main/resources/en_US/element/string.json节选 { string: [ { name: leave_comment, value: leave a comment }, { name: author, value: author }, { name: view_all_reply, value: view all replies }, { name: nothing_more, value: Theres nothing more for now } ] }注意en_US中可以省略reply——未定义时自动回退base的中文回复。工程保留它是因为英文文案与中文不同故显式声明。限定词目录只写差异、base 兜底是控制多语言维护成本的关键。base与zh_CN内容一致的约定还有一个工程理由IDE 与构建系统在资源冲突时会有提示但不会阻止两份文件内容漂移例如某次需求只改了 base 忘记同步 zh_CN。工程建议通过脚本或 lint 规则强制二者 key 集合一致把兜底目录真正变成默认语言的备份而不是放任它成为第二事实源。同理dark颜色目录与base颜色目录的 key 集合也应保持一致任何新增颜色都要双份声明——这与第 51 篇文章中深色资源的治理纪律完全同构。三、$r(app.string.xxx) 引用方式UI 层引用文案统一使用$r(app.string.资源名)。$r返回一个Resource对象可传递给 Text 组件的文本参数、TextInput 的 placeholder、Tabs 的标题等。评论页features/multishortvideocomment/src/main/ets/view/Comment.ets中的真实引用Text($r(app.string.author)) // 作者徽标 Text($r(app.string.reply)) // 回复按钮 Text($r(app.string.view_all_reply)) // 查看全部回复 Text($r(app.string.nothing_more)) // 列表底部暂时没有更多了 TextInput({ text: this.commentInput!!, placeholder: $r(app.string.leave_comment), // 输入框占位文案 controller: this.controller })个人作品页features/multishortvideoindividual/.../components/Individual.ets同样统一引用$r(app.string.author_id)国家地理/National Geographic、$r(app.string.likes)获赞/likes、$r(app.string.search_placeholder)搜索/Search、$r(app.string.introduction)点击添加介绍…等页签标题通过 ViewModel 注入IndividualTabsViewModel.etsthis.individualTabsData.push(new MSVDataModel(works, $r(app.string.ind_work))); // 作品/work this.individualTabsData.push(new MSVDataModel(privacy, $r(app.string.ind_private))); // 私密/private this.individualTabsData.push(new MSVDataModel(collection, $r(app.string.ind_collection))); // 收藏/collection this.individualTabsData.push(new MSVDataModel(like, $r(app.string.ind_like))); // 喜欢/like首页 TabBar 文案定义在products/default/.../viewmodel/MainTabsViewModel.ets中中英文对照如下资源名zh_CNen_UShome_title首页Homefriend_title朋友Friendmessage_title消息Messagerecommend_title推荐Recommendfollow_title关注Follow这里有个重要观察$r引用是跨模块的——评论模块、个人页模块、公共模块的文案都通过各自模块的 string.json 定义引用路径统一为app.string.*系统按当前模块资源 → AppScope 全局资源的顺序解析。这也要求各模块资源名全局不冲突是第 55 篇文章代码规范强调资源命名纪律的原因之一。四、格式化字符串与占位符评论数、点赞数这类数字 文案的场景不能简单拼接字符串——不同语言对数字与名词的顺序、复数形式要求各异。正确做法是在 string.json 中声明带占位符的模板用$r(app.string.xxx, 参数)在引用时注入。视频模块的评论标题即为此范例features/multishortvideoadaptivevideo/src/main/resources/zh_CN/element/string.json{ name: comment_title, value: 评论(%d) }// features/multishortvideoadaptivevideo/src/main/resources/en_US/element/string.json { name: comment_title, value: comment(%d) }播放器控件层引用时注入数值features/multishortvideoadaptivevideo/.../view/AdaptiveVideo.ets第 322 行// bindSheet 半模态标题显示评论(5) title: { title: $r(app.string.comment_title, 5) }%d是十进制整数占位符系统按当前语言环境格式化后替换。这样中英文环境下数字与文案的相对位置、标点都由各语言自己的模板决定翻译时可以自由调整结构而不影响代码。除了%d鸿蒙资源还支持%s字符串、%f浮点数等占位符多参数按序对应。选择整句翻译还是模板占位符取决于数字与文案的排列关系是否跨语言稳定。以视频模块的发布时间为例中英文的时间表达差异明显2小时前 vs two hours ago工程选择整句翻译——release_time资源直接声明整句避免数字单位跨语言排列错位只有当数字与文案顺序在所有语言中都一致时才使用占位符。判断标准很简单把翻译交给译者时模板中保留的占位符越少出错概率越低。五、运行时语言切换与兜底策略运行时语言切换完全由系统承担用户在系统设置中修改语言后应用进程内资源引用自动指向新语言目录无需重启应用或手动刷新——前提是所有文案都通过$r引用且没有把字符串缓存在普通变量中。工程中Comment.ets、Individual.ets等组件每次 build 时都实时求值$r(app.string.xxx)天然支持热切换。兜底策略则要回答语言不齐时怎么办。限定词匹配的完整规则是先按限定词匹配程度排序匹配项越多越优先全部不匹配时回退base。因此base必须完整且兜底可用工程中 base 即中文能覆盖全部文案en_US等语言目录允许缺项缺项回退 base但缺项会造成半中半英的混排体验。工程中products/default/.../resources/en_US/element/string.json的mine_title值仍为我的中文未翻译就是一个需要排查的真实案例——en_US存在同名键但值未翻译系统不会回退到其他目录只能靠审查发现。这正是国际化质量治理的切入点要么该语言目录完整覆盖要么干脆不建目录靠 base 兜底最怕建了目录却不翻全。从实现层面看语言资源还影响module.json5中的应用名与 Ability 标签products/default的DefaultAbility_label、module_desc也走了$r(app.string.xxx)国际化系统桌面、任务卡片上展示的应用名会随语言变化。也就是说国际化不是页面文案的局部工程而是从桌面图标、任务卡片到页面内容的全链路统一。做国际化自查时除了页面遍历还要把桌面名称、通知栏文案、权限弹窗文案一并纳入检查范围。六、多模块文案的协同管理工程有五个产品模块、四个特性模块加一个公共模块每个模块维护自己的base/zh_CN/en_US三份 string.json跨模块文案的协同由此成为治理重点。工程的实际分工是公共文案放 common业务文案放所属特性模块产品定制文案放产品模块。公共模块common/multishortvideobase只声明了一条empty_text暂无内容/No content供各特性模块的空态组件复用评论、个人页、视频页的文案各自收口在本模块内leave_comment、ind_work、comment_title等首页 TabBar 的文案则因各产品形态不同而放在产品模块——default 的home_title/recommend_title即是如此tv 产品若有差异化文案只需在自己的资源目录覆盖。这种就近声明避免了公共资源命名空间的膨胀也符合products → features → common三层架构的职责边界。协同管理还需处理两个跨模块细节。其一是资源命名空间的唯一性$r(app.string.xxx)在运行时按当前模块 → AppScope顺序解析两个模块声明同名 key 时当前模块内的引用优先命中自己那份——这既是能力也是陷阱若想跨模块复用公共文案应引用公共模块明确暴露的资源而不是碰运气。其二是资源表与代码的同步新增文案后要同步检查zh_CN/en_US两份文件CI 可加脚本比对 key 集合发现缺项即失败对应前文目录完整性纪律代码审查时也可用$r(app.string.)的全局搜索快速核对每个引用点都有对应资源。对于需要按设备能力裁剪文案的场景工程还可以组合限定词与断点同一 key 在不同形态产品模块中给出不同 value配合WidthBreakpointType的代码分支做到文案与布局、交互同步适配。总之多模块国际化的本质是把文案即代码的观念升级为文案即资源定义在资源层、引用在代码层、差异由系统层解决。七、总结与最佳实践多语言国际化在本工程中沉淀为四条最佳实践文案零硬编码所有展示文案进string.json代码一律$r(app.string.xxx)引用占位符场景用$r(app.string.comment_title, 5)注入参数不手工拼接。base 兜底 语言目录只写差异base 放默认语言本工程为中文zh_CN/en_US按需声明新语言目录未覆盖的文案自动回退控制维护成本。name 与语言无关资源名统一英文下划线风格leave_commentvalue 才允许写中文避免把语言写进编译期键。目录完整性审查语言目录要么建全、要么不建对同名键值未翻译如 en_US 中mine_title残留中文这类隐患做专项排查可借助资源比对脚本在 CI 中拦截。遵循这四条新增页面时只需建资源 → 写引用两步多语言与多设备第 05 篇文章的资源规范共同构成工程化文案管理的地基。

相关新闻

2026/9/1 23:28:38

驱动模型匹配:从 driver_register 到bus->match/probe 的绑定路径

设备在 /sys 里看得见却不 probe、compatible 对了仍不绑驱动:根因常在 bus/device/driver 三件套的匹配与绑定,而不是 probe 函数体本身。本文沿 driver_register → bus_add_driver → driver_attach → bus->match → probe 走通一次绑定&#xff…

2026/9/1 23:28:38

C++项目实战:从环境搭建到开源推广的完整工程实践指南

1. 先想清楚:涨粉和写C代码,到底有什么关系?“彭于晏们我想涨1000粉(C语言)”这个标题,乍一看有点无厘头,但背后反映了一个非常真实的需求:很多C学习者或开发者,在掌握了…

2026/9/1 23:38:40

面齿轮建模全流程:从Matlab齿面计算到TCA验证

简介:本资源面向机械设计、齿轮传动系统开发及CAD/CAE仿真领域的工程师与高校研究者,聚焦面齿轮这一特殊盘形齿轮的高精度参数化建模难题。针对传统CAD软件难以直接生成复杂齿廓曲线的痛点,提供MATLAB编程驱动Pro/E(Creo&#xff…

2026/9/1 23:38:40

基于YOLOv8的交通违法车窗抛物抓拍系统详解与实战

简介:本资源是一套基于YOLOv8实现的交通违法车窗抛物智能识别系统,面向计算机、人工智能、自动化等专业本科生及初学者,解决城市交通监管中动态抛物行为自动抓拍与取证的技术难点,适用于毕业设计、课程设计、大作业及项目原型验证…

2026/9/1 23:38:40

std::numeric_limits<float>:一段深夜调试的浮点数探险

上周在折腾一个数值计算的小项目&#xff0c;需要用到浮点数的极值判断。一开始想当然地用FLT_MAX和FLT_MIN&#xff0c;后来翻cppreference才发现C11之后有更规范的std::numeric_limits<float>。正好手头有台阿贝云的免费云服务器&#xff0c;想着干脆在这上面写个测试程…

2026/9/1 23:38:40

车载音响体验指南:从硬件调校到音质评估的完整方法论

这次我们来看一个汽车音响系统的体验项目&#xff0c;它聚焦于岚图追光S这款车型搭载的音响系统&#xff0c;并以经典歌曲《枉凝眉》的龚玥演唱版本作为测试素材。对于关注汽车智能化、座舱娱乐体验&#xff0c;特别是对车载音响音质有要求的用户来说&#xff0c;这是一个非常具…

2026/9/1 23:38:40

游戏开发进阶:活用矩阵与数组思维,构建清晰高效的游戏逻辑

你是不是也遇到过这种情况&#xff1a;想写个小游戏练练手&#xff0c;或者优化一下某个功能&#xff0c;结果一上来就被各种坐标变换、状态管理、碰撞检测绕得晕头转向&#xff1f;代码写着写着就变成了一团乱麻&#xff0c;维护起来比重新写一遍还痛苦。很多人会把问题归结为…

2026/9/1 23:33:38

Brave邮箱别名创建指南

Brave浏览器创建邮件别名的具体步骤 Brave浏览器提供了一项隐私保护功能&#xff0c;允许用户创建虚假地址&#xff08;即邮件别名&#xff09;用于注册服务。以下是具体操作步骤&#xff1a; 1. 登录Brave账户 打开Brave浏览器&#xff0c;点击右上角的个人资料图标。选择*…

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出&#xff0c;第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器&#xff0c;出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台&#xff0c;直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/1 8:27:47

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流&#xff1a;为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历&#xff1a;明明传感器本身性能很好&#xff0c;信号输出却一塌糊涂——噪声大、漂移明显、重复性差&#xff0c;怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/1 7:04:43

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起&#xff0c;其实就是嵌入式开发里最常遇到的一类需求&#xff1a;用一块不算贵的 MCU&#xff0c;同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控&#xff0c;主频…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…