news 2026/9/1 23:28:00

HarmonyOS 应用开发之多语言国际化:zh_CN/en_US 限定词与 string.json 资源体系详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS 应用开发之多语言国际化:zh_CN/en_US 限定词与 string.json 资源体系详解

多语言国际化:zh_CN/en_US 限定词与 string.json 资源体系

一、引言

国际化(i18n)是"多设备短视频"应用走向更多用户的基本功。一个覆盖直板机、平板与 PC 的应用,若把文案硬编码在代码里,每一次文案调整、每新增一种语言,都要翻遍全部源码——这既是维护负担,也是质量隐患。HarmonyOS 提供了一套与深色模式同构的资源限定词机制:文案声明在string.json中,通过zh_CNen_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_CNbase内容一致,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": "There's nothing more for now!" } ] }

注意en_US中可以省略reply——未定义时自动回退base的中文"回复"。工程保留它是因为英文文案与中文不同,故显式声明。限定词目录只写差异、base 兜底,是控制多语言维护成本的关键。

basezh_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.ets):

this.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_US

home_title首页Home
friend_title朋友Friend
message_title消息Message
recommend_title推荐Recommend
follow_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.etsIndividual.ets等组件每次 build 时都实时求值$r('app.string.xxx'),天然支持热切换。

兜底策略则要回答"语言不齐时怎么办"。限定词匹配的完整规则是:先按限定词匹配程度排序(匹配项越多越优先),全部不匹配时回退base。因此:

  • base必须完整且兜底可用(工程中 base 即中文,能覆盖全部文案);
  • en_US等语言目录允许缺项,缺项回退 base;
  • 但缺项会造成"半中半英"的混排体验。工程中products/default/.../resources/en_US/element/string.jsonmine_title值仍为"我的"(中文未翻译),就是一个需要排查的真实案例——en_US存在同名键但值未翻译,系统不会回退到其他目录,只能靠审查发现。这正是国际化质量治理的切入点:要么该语言目录完整覆盖,要么干脆不建目录靠 base 兜底,最怕"建了目录却不翻全"。

从实现层面看,语言资源还影响module.json5中的应用名与 Ability 标签:products/defaultDefaultAbility_labelmodule_desc也走了$r('app.string.xxx')国际化,系统桌面、任务卡片上展示的应用名会随语言变化。也就是说,国际化不是"页面文案"的局部工程,而是从桌面图标、任务卡片到页面内容的全链路统一。做国际化自查时,除了页面遍历,还要把桌面名称、通知栏文案、权限弹窗文案一并纳入检查范围。

六、多模块文案的协同管理

工程有五个产品模块、四个特性模块加一个公共模块,每个模块维护自己的base/zh_CN/en_US三份 string.json,跨模块文案的协同由此成为治理重点。工程的实际分工是:公共文案放 common,业务文案放所属特性模块,产品定制文案放产品模块

公共模块common/multishortvideobase只声明了一条empty_text("暂无内容"/"No content"),供各特性模块的空态组件复用;评论、个人页、视频页的文案各自收口在本模块内(leave_commentind_workcomment_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_comment),value 才允许写中文,避免把"语言"写进编译期键。
  • 目录完整性审查:语言目录要么建全、要么不建;对"同名键值未翻译"(如 en_US 中mine_title残留中文)这类隐患做专项排查,可借助资源比对脚本在 CI 中拦截。

遵循这四条,新增页面时只需"建资源 → 写引用"两步,多语言与多设备(第 05 篇文章的资源规范)共同构成工程化文案管理的地基。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 23:25:14

HoRain云--CSS 属性 选择器

CSS 属性选择器用于根据元素的属性或属性值来选择 HTML 元素。属性选择器可以帮助你在不需要为元素添加类或 ID 的情况下对其进行样式化。注意:IE7 和 IE8 需声明 !DOCTYPE 才支持属性选择器!IE6 和更低的版本不支持属性选择器。以下是常见的 CSS 属性选…

作者头像 李华
网站建设 2026/9/1 23:23:06

南京矢量数据包全解析:SHP格式处理与坐标系转换实战

简介:这是一份覆盖南京市全域的GIS矢量数据资源包,内含市、区、县、镇、村多级行政边界,完整收录国道、省道、县道、高速、地铁轻轨、铁路及乡村道路等线状交通要素,同步整合水系、绿地、岛屿等自然地理底图,并集成公交…

作者头像 李华
网站建设 2026/9/1 23:18:33

生产计划管理有效方法揭秘:如何提升企业运营效率

一、引言:为什么生产计划管理决定企业运营效率生产计划管理是制造企业运营管理的核心环节,它连接销售需求、物料供应、设备产能和人员调配,直接决定企业能否按时交付、控制库存、降低成本。现实中,很多企业并非缺乏订单或技术能力…

作者头像 李华
网站建设 2026/9/1 23:17:43

ZYNQ双项目实战:FFT频谱分析与打地鼠游戏开发全流程复盘

简介:ZYNQ平台双项目实战包是一份面向高校数字系统设计、嵌入式FPGA综合实践及课程设计场景的完整参考案例。包内集合两套可运行的工程:基于FFT的频谱分析系统,以及趣味性强的打地鼠交互游戏。频谱分析项目采用Vivado IP核或HLS方式构建&…

作者头像 李华
网站建设 2026/9/1 23:10:50

用Claude Code Skill实现ASO自动化:从关键词调研到文案生成

做 App 推广的人,大概率都知道 ASO 这三个字母意味着什么:关键词排名、榜单、评论、转化率……但很少有人想到,ASO 的前半段调研工作,居然也能像写代码一样,交给 Claude Code 去批量处理。更让我注意的是,D…

作者头像 李华
网站建设 2026/9/1 23:09:18

AlphaGo Zero源码深度解析:从策略网络到自我对弈机制

简介:AlphaGo作为深度学习与强化学习在棋类AI领域的标志性成果,这份源码包面向想深入理解蒙特卡洛树搜索、策略网络与价值网络原理的AI学习者和研究者。压缩包共55个文件,以37个Python脚本为主,另有7个SGF棋谱、2个HDF5模型权重文…

作者头像 李华