👋你好,欢迎来到我的博客!我是【菜鸟学鸿蒙】
我是一名在路上的移动端开发者,正从传统“小码农”转向鸿蒙原生开发的进阶之旅。为了把学习过的知识沉淀下来,也为了和更多同路人互相启发,我决定把探索 HarmonyOS 的过程都记录在这里。
🛠️主要方向:ArkTS 语言基础、HarmonyOS 原生应用(Stage 模型、UIAbility/ServiceAbility)、分布式能力与软总线、元服务/卡片、应用签名与上架、性能与内存优化、项目实战,以及 Android → 鸿蒙的迁移踩坑与复盘。
🧭内容节奏:从基础到实战——小示例拆解框架认知、专项优化手记、实战项目拆包、面试题思考与复盘,让每篇都有可落地的代码与方法论。
💡 我相信:写作是把知识内化的过程,分享是让生态更繁荣的方式。
如果你也想拥抱鸿蒙、热爱成长,欢迎关注我,一起交流进步!🚀
前言
做多语言适配时,一个很常见的误区是:中文页面已经完成,只要把“确定”“取消”“立即体验”翻译成英文,国际化就结束了。
真正开始切换语言后,问题往往才出现:中文四个字能放下的按钮,英文可能变成二十多个字符;某些语言的文本长度进一步增加;同一个数字在不同区域使用不同的小数点和分组符号;日期顺序也未必都是“年-月-日”。
所以,多语言适配不能只解决“翻译”,还要同时处理资源组织、系统匹配、回退策略、弹性布局以及区域格式化。
本文以一个最小的“设置页”为例,围绕 HarmonyOS 7 做一次完整拆解:把页面中的中文硬编码迁移到资源文件,准备中英文资源,让 ArkUI 根据语言环境加载对应内容,再处理英文文本变长后最容易出现的 UI 问题。
按照华为当前版本资料,HarmonyOS 7 对应 API 26.0.0;官方也建议面向 HarmonyOS 7 升级并适配 26.0.0 开发套件。
一、国际化为什么不能从“翻译字符串”开始
先看一种非常普通的 ArkTS 写法:
@Entry@Componentstruct SettingsPage{build(){Column({space:16}){Text('语言与地区').fontSize(24)Text('切换语言后,应用内容将自动更新')Button('立即体验')}.width('100%').padding(20)}}中文环境下,这段代码没有明显问题。
但一旦应用需要支持英语,开发者就很容易继续写成:
Text(isEnglish?'Language & Region':'语言与地区')页面少的时候似乎还能接受,随着业务增长,会迅速出现几个问题:
- UI 文案和业务逻辑混在一起;
- 新增语言需要不断修改 ArkTS;
- 同一个字符串可能散落在多个页面;
- 无法充分利用系统的资源匹配机制;
- 翻译人员也很难脱离代码维护语言内容。
华为官方国际化指南明确提出,UI 元素中的字符串、图片等本地化内容应该与代码逻辑分离,并放入应用资源中。这样新增地区版本时,主要调整资源,而不是重新修改业务代码。
这也是本文实践的第一个原则:
ArkTS 负责“页面做什么”,资源文件负责“页面说什么”。
二、先确认 HarmonyOS 7 下我们到底要用什么
本文场景只涉及本地应用资源、ArkUI 页面以及 Localization Kit 的本地化规则,不需要网络、相机、定位之类的系统权限。
需要关注的部分可以整理成下面这样:
| 项目 | 本文使用情况 |
|---|---|
| 系统背景 | HarmonyOS 7 |
| 对应版本 | API 26.0.0 |
| UI 框架 | ArkUI |
| 开发语言 | ArkTS |
| 本地化能力 | Localization Kit / 应用资源系统 |
| 字符串访问 | $r('app.string.xxx') |
| 资源位置 | src/main/resources |
| 运行时权限 | 本场景无额外权限 |
| 核心目标 | 多语言资源匹配、默认资源回退、UI 伸缩适配 |
HarmonyOS 当前官方文档仍将 Localization Kit 作为本地化相关能力入口,包含国际化、本地化、资源管理等内容。
需要特别区分一个版本问题:一些较早的官方国际化示例使用@ohos.intl下的NumberFormat、DateTimeFormat。HarmonyOS 后续版本的 API 变更记录已经对@ohos.intl中多项接口标记了废弃版本变化,因此面向 HarmonyOS 7 新工程时,不应该看到旧教程就直接照搬,而应该再次以 API 26 当前参考文档确认接口状态。
本文的核心 Demo 因此只采用已经能够明确核实的应用资源与 ArkUI 资源引用机制;日期、数字部分重点讲设计原则和 API 版本检查方法,不把历史接口伪装成 HarmonyOS 7 新推荐方案。
三、默认资源不是“可有可无”的兜底目录
一个典型的模块资源目录可以这样组织:
entry └── src └── main └── resources ├── base │ └── element │ └── string.json ├── zh_CN │ └── element │ └── string.json └── en_US └── element └── string.json这里有三个层次:
base:默认资源;zh_CN:简体中文、中国区域对应资源;en_US:英语、美国区域对应资源。
华为官方“提供多语言资源”文档说明,应用资源目录分为默认base目录和带限定词的目录。系统运行时会根据语言、地区等条件寻找最匹配资源;如果应用偏好语言以及系统语言都没有找到合适资源,最终会加载默认资源。因此默认目录必须准备完整。
当前华为官方场景示例的工程结构中,也仍可以看到base、en_US、zh_CN这类资源目录组织形式。
这个地方比较容易理解错:
base不是“中文版目录”的另一个名字。
它真正承担的是默认资源职责。
如果项目规定默认语言是中文,可以把完整中文资源放入base;也可以同时维护zh_CN,用于进一步区分语言/地区场景。但无论如何,不建议把base做成一个只有少数几个字符串的残缺目录。
四、搭一个最小的中英文资源示例
这次把页面定义成一个很小的设置卡片:
- 标题;
- 一行描述;
- 一个主要操作按钮;
- 一段比较长的提示文字。
这样既能验证资源匹配,也容易观察英文文本长度变化。
1. 默认资源
resources/base/element/string.json:
{"string":[{"name":"page_title","value":"语言与地区"},{"name":"page_description","value":"切换语言后,应用会使用对应的本地化资源"},{"name":"primary_action","value":"立即体验"},{"name":"language_tip","value":"界面设计需要同时考虑文本长度、日期、数字和单位等区域差异。"}]}2. 中文资源
resources/zh_CN/element/string.json:
{"string":[{"name":"page_title","value":"语言与地区"},{"name":"page_description","value":"切换语言后,应用会使用对应的本地化资源"},{"name":"primary_action","value":"立即体验"},{"name":"language_tip","value":"界面设计需要同时考虑文本长度、日期、数字和单位等区域差异。"}]}3. 英文资源
resources/en_US/element/string.json:
{"string":[{"name":"page_title","value":"Language & Region"},{"name":"page_description","value":"The app uses localized resources that match the selected language."},{"name":"primary_action","value":"Start Exploring"},{"name":"language_tip","value":"Layout design should also account for differences in text length, dates, numbers, and measurement units."}]}这里真正需要注意的是:三个目录中的资源名称保持一致,变化的是资源值。
ArkTS 不应该关心当前加载的是:
立即体验还是:
Start Exploring页面只需要请求primary_action。
五、页面不要再写字符串,用$r()引用资源
页面可以改成:
@Entry@Componentstruct SettingsPage{build(){Column({space:16}){Text($r('app.string.page_title')).fontSize(24).fontWeight(FontWeight.Bold).width('100%')Text($r('app.string.page_description')).fontSize(16).width('100%')Button($r('app.string.primary_action')).width('100%').padding({left:16,right:16,top:12,bottom:12})Text($r('app.string.language_tip')).fontSize(14).width('100%')}.width('100%').padding(20)}}这段代码解决的核心问题不是“让英文显示出来”,而是让页面代码与具体语言解耦。
$r('app.string.xxx')用来访问应用资源。ResourceManager 官方 API 文档也明确说明,可以通过类似$r('app.string.test')的资源地址访问应用资源,并可通过.id获得对应资源 ID。
这样再新增德语、法语时,页面通常不需要出现:
if(language==='de'){...}而是继续补充新的限定词资源目录。
六、系统到底怎样决定加载哪一份字符串
多语言资源并不是简单做一次:
当前语言 == en_US ?官方资源匹配机制会结合应用偏好语言列表以及应用已经提供的限定词资源进行选择。
对于字符串,可以把匹配过程理解成下面几步:
- 根据当前语言与应用资源限定词寻找相关目录;
- 按匹配程度对候选资源进行排序;
- 从匹配度最高的资源开始寻找目标字符串;
- 当前偏好语言没有找到时,再检查偏好语言列表里的其他语言;
- 如果依然没有合适资源,则使用
base默认资源。
因此资源目录的意义并不是让业务代码自己选语言,而是:
业务代码只请求资源,资源系统负责选择最匹配的实现。
这也是为什么不建议自己维护一个巨大的:
switch(language){case'zh':case'en':case'de':case'fr':}这种代码实际上是在重复实现资源系统已经提供的职责。
七、找不到目标语言时,为什么base很重要
假设后续应用只提供:
base zh_CN en_US某个用户的偏好语言并没有对应的完整资源目录。
此时真正保护页面不出现资源缺失问题的,就是默认资源。
官方明确要求默认资源目录需要完整填充,否则可能造成资源加载失败甚至编译相关问题。
因此整理多语言资源时,可以给自己定一条很实用的规则:
新增一个资源 key 时,先补base,再补各语言目录。
比如新增:
privacy_settings不要只在zh_CN中添加,然后等翻译完成再想起base。
比较稳妥的维护顺序是:
base ↓ zh_CN ↓ en_US ↓ 其他语言资源 key 一致性的检查,也应该进入发布前的本地化回归流程。
八、真正让页面“英文全乱”的,经常不是资源,而是布局
现在再看中文版:
立即体验英文:
Start Exploring字符串明显变长。
如果原来的设计是:
Button($r('app.string.primary_action')).width(100).height(40)那么中文显示正常,并不能证明这个布局合理。
问题在于我们实际上把三个条件写死了:
文本长度 按钮宽度 按钮高度只要语言发生变化,三者之间的关系就可能被破坏。
所以本文示例没有给按钮固定 100vp 宽度,而是:
Button($r('app.string.primary_action')).width('100%').padding({left:16,right:16,top:12,bottom:12})重点不是要求所有按钮都必须占满一行,而是尽量避免根据中文版文案反推组件固定尺寸。
同样,对于普通正文:
Text($r('app.string.language_tip')).width('100%')允许文本在可用宽度中自然排版,通常比直接假设“这一行永远只有十几个汉字”更可靠。
华为官方本地化测试内容也明确把“应用界面排版”作为本地化测试对象之一,而不只是检查有没有漏翻译。
九、如果换成德语,比英语还长怎么办
英文变长只是第一轮检查。
国际化页面设计不能把“英文版能放下”当作终点,因为其他语言的表达长度还可能继续增加。
这时候通常有三类处理方式。
1. 普通描述文本允许自然换行
正文、说明、卡片描述本身就适合多行展示。
不要为了保持中文页面的一行高度,把所有语言都强制压在一行里。
2. 操作按钮给文案留下弹性
按钮设计应该考虑:
内容宽度 + 左右内边距而不是:
中文四个字 ≈ 80vp如果产品视觉上必须限制按钮宽度,则需要在设计阶段明确超长文本策略,而不是上线前看到翻译结果再临时处理。
3. 截断应该是明确的产品选择
ArkUI 文本组件具有超长文本与行数控制相关能力,但“能显示省略号”并不代表应该默认把重要操作截断。
例如:
Delete all downloaded offline content如果最后只剩:
Delete all down...虽然布局没溢出,但操作含义可能已经不完整。
因此,多语言页面适配的目标不是“永远不换行”,而是让信息在不同语言环境下仍然可理解、可操作。
十、日期、数字和单位不要自己拼字符串
多语言开发还有一个比文本翻译更隐蔽的问题:
Text(year+'-'+month+'-'+day)以及:
Text(price+' USD')再比如:
Text(distance+' km')这些写法表面上没有中文,却仍然可能没有完成国际化。
官方国际化说明明确提醒,不能假设所有地区都使用相同的数字分组符、小数分隔符等文化习惯。
华为数字与度量衡国际化指南还举了非常直接的例子:同一个1000,不同文化环境中的分隔符含义可能不同,因此需要进行区域化格式处理,而不能把固定显示形式写死。
日期也是类似的。
不同地区可能在以下方面存在差异:
年/月/日顺序 12小时制 / 24小时制 月份显示方式 星期显示方式 时区因此应该把两个概念区分开:
原始数据 ↓ 本地化格式化 ↓ 页面展示字符串而不是:
原始数据 ↓ 手动 + "-" + "/" + "km" ↓ 展示HarmonyOS Localization Kit 提供日期、数字、度量衡、时区等国际化能力。
这里再强调一次版本问题:历史官方指南中可以看到:
import{intl}from'@kit.LocalizationKit';letformatter=newintl.NumberFormat(...);但 HarmonyOS 后续 API 变更资料已经标记了@ohos.intl多项 API 的废弃版本变化。面向 HarmonyOS 7 / API 26 新项目,在真正落地格式化代码前,应以当前 SDK API Reference 中的状态和替代接口为准,而不是直接复制旧版本示例。
这种地方宁可少写一段“看起来能运行”的代码,也不要把旧 API 包装成 HarmonyOS 7 推荐写法。
十一、语言切换之后,建议至少做一遍这样的回归
多语言页面测试不能只看“有没有变成英文”。
可以按下面的顺序检查。
1. 先检查资源完整性
重点确认:
base zh_CN en_US中的 key 是否一致。
如果新增了:
primary_action却漏掉了一个目录,应该优先修资源,而不是在 ArkTS 中加条件分支。
2. 再检查匹配与回退
测试至少应该包含:
中文 英文 一个没有提供专用资源的语言第三种情况主要用于检查默认资源是否能够正常承担回退职责。
3. 检查长文本
特别关注:
- Button;
- Tabs;
- 列表尾部操作;
- 对话框操作区;
- 单行标题;
- 横向 Row 中的多个文字组件。
很多中文 UI 的问题并不会在中文环境暴露出来。
4. 检查动态数据
不要只切语言检查静态标题,还要观察:
日期 时间 价格 百分比 文件大小 距离 温度 单位因为“字符串翻译正确”和“区域格式正确”是两个问题。
5. 检查业务代码中剩余的硬编码
可以重点搜索:
Text('Button(' title:message:不能简单认为这些位置全部有问题,但它们很适合作为人工检查入口。
华为官方当前仍提供本地化测试、伪本地化测试以及语言测试相关指导,这类测试本身就是完整本地化流程的一部分。
十二、几个容易理解错的地方
“有en_US就不用base了”
不对。
base是默认资源回退链的重要组成部分,应该准备完整资源。
“国际化就是所有中文翻译成英文”
不够。
官方国际化能力范围本身就覆盖语言、时间日期、数字、度量衡、时区等区域差异。
“英文放不下就统一缩小字体”
这通常只是在隐藏布局问题。
更应该先检查固定宽度、固定高度、横向空间分配以及是否允许合理换行。
“所有语言都用省略号就安全了”
布局可能不溢出了,但信息可能不完整。尤其是按钮、权限说明、支付信息等关键文本,不应该把“截断成功”当作适配完成。
“搜索到官方示例就可以直接复制”
还差一步:核对版本。
HarmonyOS 7 已进入 API 26.0.0 版本体系,而较早文档中的接口可能已经发生废弃或替代变化。官方升级指南也明确要求开发者评估 API 版本变化并完成适配。
十三、实际项目中可以按什么顺序排查
碰到“中文版正常,英文版布局错乱”,可以先不要急着改字体。
建议按这条链路检查:
字符串是不是仍然硬编码? ↓ 目标语言资源目录是否存在? ↓ 资源 key 是否完整且一致? ↓ base 默认资源是否完整? ↓ $r() 引用的资源名称是否正确? ↓ 组件是否使用了针对中文设计的固定尺寸? ↓ 长文本是否允许合理换行或伸缩? ↓ 日期、数字、单位是否仍在手动拼字符串? ↓ 最后做中文 / 英文 / 回退语言回归这样排查有一个好处:能够先区分到底是资源问题还是布局问题。
如果$r()已经拿到了正确英文,页面仍然溢出,就不应该继续折腾语言匹配,而应该回到 ArkUI 布局本身。
反过来,如果英文环境仍显示base的内容,那么应优先检查限定词资源与匹配关系,而不是改组件尺寸。
开发经验总结
这次最小实践虽然只有一个页面,但多语言适配真正值得带到项目里的有五点。
第一,不要把可见文案直接写进 ArkTS 业务代码。页面通过$r()请求资源,让不同语言资源与业务逻辑分离。
第二,base必须当作正式资源维护。它不是临时目录,而是资源匹配最终的默认回退。
第三,布局不能只按照中文字符串长度设计。按钮、标题、Row 横向布局都应该给翻译后的文本留下变化空间。
第四,日期、数字和单位也是本地化内容。没有中文字符,并不代表已经国际化。
第五,版本核对要放在复制代码之前。HarmonyOS 7 对应 API 26.0.0,旧版本 Localization Kit 示例中的 API 状态需要重新确认,尤其不能把已经进入废弃流程的历史接口直接写成新项目推荐方案。
如果正在整理一个已有的 HarmonyOS 项目,可以先做一个很小的动作:搜索所有直接出现在 ArkTS 里的用户可见字符串,再挑一个页面迁移到base + zh_CN + en_US资源结构。完成这一步以后,很多隐藏的固定宽度、字符串拼接和格式化问题会自然暴露出来。
📝 写在最后
如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 👍、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!
我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!
感谢你的阅读,我们下篇文章再见~👋
✍️ 作者:菜鸟不学编程
🧵 本文原创,转载请注明出处。