【鸿蒙心迹】国际化 i18n 与多语言资源管理实战(HarmonyOS 7.x)

【鸿蒙心迹】国际化 i18n 与多语言资源管理实战(HarmonyOS 7.x)

摘要: 应用要出海,多语言不是"翻译几个字符串"------资源文件管理、动态切换语言、RTL 布局、日期/数字/货币格式化都要做。本文用涟漪睡眠 App 出海东南亚为案例,讲清 i18n 全链路与 5 个踩坑。

适用版本: HarmonyOS NEXT 7.x / API 14+(2026 年稳定版)

开篇:加了一门语言,界面先崩了一半

"应用要出海东南亚,泰语、越南语、马来语都加上。"

2026 年 8 月,涟漪睡眠 App 出海。我以为国际化就是翻译几个字符串,结果发现:资源文件要按 locale 分目录、动态切换语言要重渲染、RTL(阿拉伯语)布局要镜像、日期/数字/货币格式化要按 locale。这篇把 i18n 全链路讲透。


一、i18n 全链路

二、字符串资源管理

资源目录结构

text 复制代码
resources/
  base/                          # 默认(英语)
    element/
      string.json
  zh_CN/                         # 简体中文
    element/
      string.json
  th_TH/                         # 泰语
    element/
      string.json
  ar_SA/                         # 阿拉伯语(RTL)
    element/
      string.json
json 复制代码
// resources/base/element/string.json(英语)
{
  "string": [
    { "name": "app_name", "value": "NewsFlow" },
    { "name": "welcome", "value": "Welcome to NewsFlow" },
    { "name": "settings", "value": "Settings" }
  ]
}
json 复制代码
// resources/zh_CN/element/string.json(中文)
{
  "string": [
    { "name": "app_name", "value": "信息流" },
    { "name": "welcome", "value": "欢迎来到信息流" },
    { "name": "settings", "value": "设置" }
  ]
}
json 复制代码
// resources/th_TH/element/string.json(泰语)
{
  "string": [
    { "name": "app_name", "value": "NewsFlow" },
    { "name": "welcome", "value": "ยินดีต้อนรับสู่ NewsFlow" },
    { "name": "settings", "value": "การตั้งค่า" }
  ]
}

使用资源引用

typescript 复制代码
Text($r('app.string.welcome'))  // 自动按系统 locale 选

避坑 1 :base 目录是默认 fallback,必须完整。如果 th_TH 缺某个 key,会 fallback 到 base,不会崩。


三、动态切换语言

typescript 复制代码
import { i18n } from '@kit.LocalizationKit';
import { router } from '@kit.ArkUI';

async function switchLanguage(locale: string): Promise<void> {
  // 切换应用语言:只改资源查找方向,已渲染的组件树不会自动重建
  i18n.System.setAppPreferredLanguage(locale);  // 如 'th_TH'
  // 重载页面触发资源重查(路由用 @kit.ArkUI 的 router 单例)
  await router.replaceUrl({ url: 'pages/Home' });
}

避坑 2 :切换语言后页面不会自动重渲染,需要 replaceUrl 重新加载或用 @StorageLink 触发全局刷新。


四、RTL 布局(阿拉伯语)

检测 RTL

typescript 复制代码
import { i18n } from '@kit.LocalizationKit';

const isRTL = i18n.System.isRTL();  // 阿拉伯语/希伯来语返回 true

布局镜像

typescript 复制代码
import { i18n } from '@kit.LocalizationKit';

@Entry
@Component
struct NewsPage {
  @State isRTL: boolean = i18n.System.isRTL();
  build() {
    Row() {
      Image($r('app.media.avatar'))
      Text($r('app.string.welcome'))
    }
    .direction(this.isRTL ? Direction.Rtl : Direction.Ltr)  // 自动镜像
  }
}

避坑 3 :图标不要镜像------"返回箭头"在 RTL 下应该指向右,但"相机图标"不需要翻转。用 .matchTextDirection(false) 标记不跟随文字方向翻转的图标。


五、格式化:日期/数字/货币

日期格式化

typescript 复制代码
import { i18n } from '@kit.LocalizationKit';

// DateTimeFormat 是实例 API:先按 locale + 选项构造实例,再调用 format
function formatDate(date: Date, locale: string): string {
  const formatter = new i18n.DateTimeFormat(locale, {
    year: 'numeric', month: 'long', day: 'numeric',
  });
  return formatter.format(date);
}

formatDate(new Date(2026, 7, 12), 'en-US');  // "August 12, 2026"
formatDate(new Date(2026, 7, 12), 'zh-CN');  // "2026年8月12日"
formatDate(new Date(2026, 7, 12), 'th-TH');  // "12 สิงหาคม 2026"

数字/货币格式化

typescript 复制代码
import { i18n } from '@kit.LocalizationKit';

// NumberFormat 同样是实例 API(构造时传 locale + 选项),没有 format 静态方法
function formatNumber(value: number, locale: string): string {
  return new i18n.NumberFormat(locale, { style: 'decimal' }).format(value);
}

formatNumber(1234567.89, 'en-US');  // "1,234,567.89"
formatNumber(1234567.89, 'de-DE');  // "1.234.567,89"

// 货币用 style:'currency' + currency 选项,没有 formatCurrency 静态方法
const currencyFormatter = new i18n.NumberFormat('th-TH', {
  style: 'currency', currency: 'THB',
});
currencyFormatter.format(99.99);  // "฿99.99"

六、5 个 i18n 踩坑

1. 字符串拼接破坏语序

现象 :'欢迎' + name + '来到信息流',泰语语序不同,拼接后不通顺。

解决:用占位符:

json 复制代码
// resources/base/element/string.json(英语)
{ "string": [{ "name": "welcome", "value": "Welcome %s to NewsFlow" }] }
json 复制代码
// resources/zh_CN/element/string.json(中文)
{ "string": [{ "name": "welcome", "value": "欢迎 %s 来到信息流" }] }
json 复制代码
// resources/th_TH/element/string.json(泰语)
{ "string": [{ "name": "welcome", "value": "ยินดีต้อนรับ %s สู่ NewsFlow" }] }
typescript 复制代码
import { common } from '@kit.AbilityKit';

// getStringByName 把可变参数按 %s/%d 顺序填进译文,
// 占位符在译文里的位置由译者决定,不要求与中文语序一致。
function getWelcome(context: common.UIAbilityContext, name: string): string {
  return context.resourceManager.getStringByName('welcome', name);
}
// en: "Welcome 张三 to NewsFlow"
// th_TH: "ยินดีต้อนรับ 张三 สู่ NewsFlow"

2. 复数处理

现象 :'你有 ' + n + ' 条消息',英语要 "1 message" / "2 messages"。

解决 :用复数资源(plural.json 与 string.json 同级,用 app.plural.xxx 引用):

json 复制代码
// resources/base/element/plural.json
// 复数资源放 plural.json;base(英语)必须同时有 one / other 两个类别
{
  "plural": [
    { "name": "messages_one", "value": "You have %d message" },
    { "name": "messages_other", "value": "You have %d messages" }
  ]
}
typescript 复制代码
// 第二个参数是数量,系统按当前 locale 的 CLDR 类别选 one / other
Text($r('app.plural.messages', n))

3. RTL 布局图标翻转

解决 :见上文"避坑 3",用 .matchTextDirection(false) 标记不镜像图标。

4. 日期时区

现象:服务端返回 UTC 时间,本地显示差 8 小时。

解决 :用 i18n.DateTimeFormat 自动按本地时区格式化。

5. 资源文件体积

现象:支持 20 种语言,APK 体积暴涨。

解决:按需加载语言包,或用 AGC 动态下发语言资源。


七、i18n 自查清单

  • base 目录字符串完整?
  • 各 locale 目录翻译齐全?
  • 字符串用占位符不拼接?
  • 复数用 one/other 资源?
  • RTL 布局用 Direction.Rtl?
  • 图标 matchTextDirection 标记?
  • 日期/数字/货币用 i18n 格式化?
  • 动态切换语言后重新加载页面?

实测数据(涟漪睡眠 App,Mate 60 Pro,HarmonyOS 7.x)

指标 优化前 优化后
适配语言数 2(中文/英语) 6(含泰语、越南语、马来语、阿拉伯语 RTL)
翻译条目 320 条,泰语缺 key 频繁回退 base 1200+ 条,各 locale 与 base key 100% 一致(构建期校验)
伪本地化测试发现问题数 47 处(拼接语序错乱、复数形态错误、图标误镜像) 3 处(占位符 + 复数资源 + matchTextDirection(false) 后回归通过)
日期/数字/货币格式化错误数 22 处(UTC 时区差 8 小时、货币符号硬编码) 0 处(统一走 i18n.DateTimeFormat / NumberFormat)
单语言适配工时 约 3 人日(含修 RTL 与格式化问题) 约 1 人日(占位符与校验脚本模板化后)

避坑要点

  1. 字符串用占位符:拼接破坏语序
  2. RTL 图标不镜像:用 matchTextDirection(false)
  3. base 是 fallback:必须完整

边界与已知限制

限制项 具体表现 规避方式
语言切换时机 系统语言切换后资源不会自动重载,部分场景需重启 Ability 监听语言变化并主动刷新页面
应用内切换 运行时改语言需重建 UI 才生效 提供重启提示,或改为重启后生效
复数规则 中文无复数、英语 2 种、阿拉伯语 6 种 用复数资源而非字符串拼接
RTL 布局 阿语/希伯来语需镜像布局,具象图标不该翻转 具象图标用 matchTextDirection(false)
日期与数字 时区、区域格式差异大 统一用系统格式化 API,不手写拼接
资源体积 语言越多包体越大 按区域拆分、按需下发
回退机制 缺失翻译回退 base,key 写错直接显示 key base 必须完整,构建期校验 key 一致性

小结

i18n 最容易低估的是语序与复数 :中文里"共 3 条"拼成 "共" + n + "条" 没问题,换成英语、阿语就可能语序错乱或复数形态不对。所有带变量的文案都必须走占位符 + 复数资源。

其次是 RTL:布局镜像是系统做的,但方向性图标(返回箭头、进度条)要单独声明不镜像,否则界面会"看起来对、用起来反"。

评论区交流: 你的应用支持几种语言?评论区交流 i18n 经验。

相关推荐
OH_TPC2 小时前
HarmonyOS APP开发---"云客服"远程视频客服App,需要用到这个库
harmonyos
weixin_468466852 小时前
视觉Transformer的“第二次革命”:ViT³如何用测试时训练重构注意力范式
人工智能·深度学习·机器学习·ai·重构·transformer·vit
逆回18 小时前
给鸿蒙手机做一只 3D 宠物:五个把我卡住的问题
harmonyos
寂寞的船19 小时前
【Unity知识速递】第5期 Unity 6.2 深度解析:AI Assistant 登场,World Space UI 与 Sentis 全面升级
人工智能·ui·unity
钉先生贾19 小时前
性能、体积与稳定性:怎样写出可信的适配结论
华为·harmonyos
秋名山小白1 天前
Playwright UI 自动化测试实战教程
python·ui
笑 总不会犯错1 天前
摆脱多端数据撕裂,鸿蒙分布式数据库同步与冲突合并
harmonyos
用户117910488331 天前
鸿蒙签名失败不是玄学:5 个证据点把 hapsigntool 一次排通 GitHub:swsgbl/hmharness
开源·ai编程·harmonyos
redtank20001 天前
纯血鸿蒙小工具三件套实测:弹幕手持、爱记录与仓库管理软件
学习·华为·智能手机·harmonyos