在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、引言

随着应用的全球化发展,国际化(i18n)成为应用开发的重要组成部分。一个优秀的国际化方案能让应用支持多种语言、适应不同地区的文化习惯、正确显示日期时间和货币格式。HarmonyOS 提供了完善的国际化能力,包括资源文件管理、i18n 模块和 Intl 模块。

本文将以一个多彩渐变风格的国际演示页面为主线,深入讲解 HarmonyOS 国际化的核心概念和实战技巧,帮助读者掌握多语言开发的技能。

二、国际化基础概念

2.1 什么是国际化

国际化(Internationalization,缩写 i18n)是指设计和开发应用时,使其能够适应不同语言和地区的技术过程。核心目标:

  1. 多语言支持:界面文字可以切换多种语言。
  2. 地区适应:日期、时间、货币、数字格式随地区变化。
  3. 资源分离:文本资源与代码分离,便于翻译和维护。

2.2 语言与地区

  • 语言:如中文、英文、日文。
  • 地区:如中国大陆(CN)、美国(US)、日本(JP)。
  • Locale:语言和地区的组合,如 zh_CN(简体中文-中国)、en_US(英语-美国)、ja_JP(日语-日本)。

三、资源文件管理

3.1 资源目录结构

HarmonyOS 通过资源目录实现多语言支持:

entry/src/main/resources/
├── base/           # 默认资源(兜底)
│   ├── element/    # 字符串、颜色等
│   └── media/      # 图片等
├── zh_CN/          # 简体中文资源
│   └── element/
│       └── string.json
├── en_US/          # 英语资源
│   └── element/
│       └── string.json
└── ja_JP/          # 日语资源
    └── element/
        └── string.json

3.2 定义字符串资源

base/element/string.json 中定义默认字符串:

{
  "string": [
    {
      "name": "app_title",
      "value": "My Application"
    },
    {
      "name": "app_hello",
      "value": "Hello, World"
    }
  ]
}

zh_CN/element/string.json 中定义中文翻译:

{
  "string": [
    {
      "name": "app_title",
      "value": "我的应用"
    },
    {
      "name": "app_hello",
      "value": "你好,世界"
    }
  ]
}

3.3 在代码中使用资源

// 使用字符串资源
Text($r('app.string.app_title'))

// 带参数
Text($r('app.string.welcome', '张三'))

代码说明:

  • $r('app.string.xxx') 引用字符串资源。
  • 系统会根据当前语言自动选择对应语言目录中的资源。
  • 支持带参数格式化。

四、i18n 模块

4.1 系统语言管理

import { i18n } from '@kit.LocalizationKit';

// 获取系统语言
const lang = i18n.System.getSystemLanguage();
console.info(`系统语言: ${lang}`);

// 设置系统语言
i18n.System.setSystemLanguage('zh_CN');

4.2 获取系统区域

// 获取系统区域
const region = i18n.System.getSystemRegion();
console.info(`系统区域: ${region}`);

// 获取系统时区
const timezone = i18n.System.getSystemTimezone();
console.info(`系统时区: ${timezone}`);

4.3 判断语言方向

// 判断是否 RTL(从右到左)语言
const isRTL = i18n.isRTL('ar');
console.info(`阿拉伯语是否 RTL: ${isRTL}`);

五、Intl 模块

Intl 模块用于国际化格式化,包括日期、时间、数字、货币等。

5.1 日期格式化

import { Intl } from '@kit.LocalizationKit';

// 创建日期格式化器
const dateFmt = new Intl.DateTimeFormat('zh-CN', {
  dateStyle: 'full',
  timeStyle: 'medium'
});

// 格式化日期
const dateStr = dateFmt.format(new Date());
console.info(`格式化日期: ${dateStr}`);

5.2 数字格式化

// 创建数字格式化器
const numFmt = new Intl.NumberFormat('zh-CN', {
  style: 'decimal',
  minimumFractionDigits: 2
});

// 格式化数字
const numStr = numFmt.format(1234.567);
console.info(`格式化数字: ${numStr}`);  // 1,234.57

5.3 货币格式化

// 创建货币格式化器
const currencyFmt = new Intl.NumberFormat('zh-CN', {
  style: 'currency',
  currency: 'CNY'
});

// 格式化货币
const moneyStr = currencyFmt.format(99.9);
console.info(`格式化货币: ${moneyStr}`);  // ¥99.90

六、实战代码:多语言演示页面

下面我们实现一个多彩渐变风格的国际演示页面,包含语言切换、多语言对照表。

6.1 定义数据结构

interface I18nRow {
  key: string;
  zh: string;
  en: string;
  ja: string;
}

代码说明:

I18nRow 接口描述多语言对照表中的一行数据,包含资源键和三种语言的翻译。

6.2 组件状态定义

@Entry
@Component
struct I18nPage {
  @State currentLang: string = 'zh_CN';
  @State rows: I18nRow[] = [
    { key: 'app.title', zh: 'HarmonyOS 应用', en: 'HarmonyOS App', ja: 'ハーモニーOSアプリ' },
    { key: 'app.hello', zh: '你好,世界', en: 'Hello, World', ja: 'こんにちは、世界' },
    { key: 'app.welcome', zh: '欢迎使用', en: 'Welcome', ja: 'ようこそ' },
    { key: 'app.confirm', zh: '确定', en: 'OK', ja: '決定' },
    { key: 'app.cancel', zh: '取消', en: 'Cancel', ja: 'キャンセル' }
  ];
  @State tabIndex: number = 0;

代码说明:

  • @State currentLang:当前语言。
  • @State rows:多语言对照表数据,每种语言三列。
  • @State tabIndex:Tabs 分页索引。

6.3 获取当前语言文本

getText(row: I18nRow): string {
  if (this.currentLang === 'zh_CN') {
    return row.zh;
  } else if (this.currentLang === 'en_US') {
    return row.en;
  }
  return row.ja;
}

代码说明:

getText 根据当前语言返回对应的文本:

  • zh_CN 返回中文。
  • en_US 返回英文。
  • 其他(ja_JP)返回日文。

6.4 切换语言

switchLang(lang: string): void {
  this.currentLang = lang;
  try {
    i18n.System.setSystemLanguage(lang);
  } catch (e) {
    // 模拟环境无法切换系统语言,仅切换界面文案
  }
  promptAction.showToast({ message: `已切换语言: ${lang}` });
}

代码说明:

switchLang 切换语言:

  1. 更新状态this.currentLang = lang 更新界面语言,触发 UI 刷新。
  2. 尝试切换系统语言:调用 i18n.System.setSystemLanguage,在真机上会改变系统语言。模拟环境中可能失败,用 try...catch 捕获。
  3. 提示反馈:Toast 提示切换结果。

6.5 构建 UI

build() {
  Column() {
    // 顶部多彩渐变标题
    Column() {
      Text('I18N')
        .fontSize(12)
        .fontColor('#FFFFFFCC')
        .letterSpacing(8)
      Text('国际化与多语言')
        .fontSize(26)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .margin({ top: 6 })
      Text('i18n · 资源文件 · 多语言切换')
        .fontSize(12)
        .fontColor('#FFFFFFCC')
        .margin({ top: 6 })
    }
    .width('100%')
    .padding({ top: 48, bottom: 28 })
    .linearGradient({
      angle: 120,
      colors: [['#EE5A24', 0], ['#FFA502', 0.4], ['#2ED573', 0.7], ['#18DCFF', 1]]
    })

    // 语言切换按钮组
    Row({ space: 10 }) {
      Button('中文')
        .height(40)
        .layoutWeight(1)
        .fontSize(13)
        .fontColor(this.currentLang === 'zh_CN' ? Color.White : '#EE5A24')
        .backgroundColor(this.currentLang === 'zh_CN' ? '#EE5A24' : '#FFFFFF')
        .borderRadius(20)
        .border({ width: 1, color: '#EE5A24' })
        .onClick(() => { this.switchLang('zh_CN'); })
      Button('English')
        .height(40)
        .layoutWeight(1)
        .fontSize(13)
        .fontColor(this.currentLang === 'en_US' ? Color.White : '#18DCFF')
        .backgroundColor(this.currentLang === 'en_US' ? '#18DCFF' : '#FFFFFF')
        .borderRadius(20)
        .border({ width: 1, color: '#18DCFF' })
        .onClick(() => { this.switchLang('en_US'); })
      Button('日本語')
        .height(40)
        .layoutWeight(1)
        .fontSize(13)
        .fontColor(this.currentLang === 'ja_JP' ? Color.White : '#FFA502')
        .backgroundColor(this.currentLang === 'ja_JP' ? '#FFA502' : '#FFFFFF')
        .borderRadius(20)
        .border({ width: 1, color: '#FFA502' })
        .onClick(() => { this.switchLang('ja_JP'); })
    }
    .width('100%')
    .padding(16)

代码说明:

语言切换按钮组:

  • 三个按钮分别对应中文、英文、日文。
  • 每个按钮使用不同的主题色:中文=橙色(#EE5A24)、英文=青色(#18DCFF)、日文=橙色(#FFA502)。
  • 选中按钮使用实心主题色背景、白色文字;未选中使用白色背景、彩色文字和描边。
  • 通过条件判断 this.currentLang === 'zh_CN' 控制选中态样式。
    // Tabs 分页展示
    Tabs({ barPosition: BarPosition.Start, index: this.tabIndex }) {
      TabContent() {
        Column({ space: 10 }) {
          ForEach(this.rows, (row: I18nRow) => {
            Row({ space: 12 }) {
              Text(row.key)
                .fontSize(12)
                .fontColor('#999999')
                .fontFamily('monospace')
                .width(90)
              Text(this.getText(row))
                .fontSize(16)
                .fontWeight(FontWeight.Medium)
                .fontColor('#2F3542')
                .layoutWeight(1)
            }
            .width('100%')
            .padding(14)
            .backgroundColor(Color.White)
            .borderRadius(12)
            .shadow({ radius: 4, color: '#11000000', offsetY: 2 })
          })
        }
        .width('100%')
        .padding(16)
      }
      .tabBar('当前语言')
    }
    .width('100%')
    .layoutWeight(1)

代码说明:

Tabs 分页展示当前语言下的文本:

  • 每行显示资源键(等宽灰色字体)和当前语言的翻译文本。
  • this.getText(row) 根据当前语言动态返回对应文本。
  • 切换语言时,由于 currentLang@State,UI 自动刷新,所有文本立即更新。
    // 多语言对照表
    Column() {
      Text('多语言对照表')
        .fontSize(14)
        .fontWeight(FontWeight.Bold)
        .fontColor('#EE5A24')
        .alignSelf(ItemAlign.Start)
        .margin({ bottom: 8 })
      Row() {
        Text('键').layoutWeight(1).fontSize(11).fontColor('#EE5A24')
        Text('中文').layoutWeight(1).fontSize(11).fontColor('#EE5A24')
        Text('English').layoutWeight(1).fontSize(11).fontColor('#18DCFF')
        Text('日本語').layoutWeight(1).fontSize(11).fontColor('#FFA502')
      }
      .width('100%')
      .padding(8)
      .backgroundColor('#FFF0E6')

      Scroll() {
        ForEach(this.rows, (row: I18nRow) => {
          Row() {
            Text(row.key).layoutWeight(1).fontSize(10).fontColor('#999999').fontFamily('monospace')
            Text(row.zh).layoutWeight(1).fontSize(11).fontColor('#2F3542')
            Text(row.en).layoutWeight(1).fontSize(11).fontColor('#2F3542')
            Text(row.ja).layoutWeight(1).fontSize(11).fontColor('#2F3542')
          }
          .width('100%')
          .padding(8)
          .border({ width: { bottom: 1 }, color: '#FFF0E6' })
        })
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height(220)
    .padding(12)
    .backgroundColor('#FFFBF7')
    .borderRadius(14)
    .border({ width: 1, color: '#FFE0C8' })

    Button('返回首页')
      .width('100%')
      .height(46)
      .fontSize(15)
      .fontColor(Color.White)
      .backgroundColor('#EE5A24')
      .borderRadius(23)
      .onClick(() => { router.back(); })
  }
  .width('100%')
  .height('100%')
  .backgroundColor('#FFF8F0')
}

代码说明:

多语言对照表是四列表格:

  • 表头:键、中文、English、日本語,每种语言使用对应主题色。
  • 数据行:每行展示同一资源键在三种语言下的翻译,方便对比。
  • 表格支持滚动查看。

七、国际化最佳实践

7.1 资源分离

所有界面文字都应放在资源文件中,避免硬编码在代码里。这样翻译时只需修改资源文件,无需改动代码。

7.2 语言目录规划

为每个支持的语言创建独立目录,base 目录作为兜底默认值:

resources/
├── base/
├── zh_CN/
├── en_US/
└── ja_JP/

7.3 占位符使用

使用带参数的字符串资源,避免字符串拼接:

{
  "string": [
    {
      "name": "welcome_user",
      "value": "欢迎,%s!"
    }
  ]
}
Text($r('app.string.welcome_user', '张三'))

7.4 日期时间本地化

使用 Intl 模块格式化日期、时间、数字、货币,确保符合当地习惯。

7.5 文本长度适配

不同语言的文本长度差异很大(如德语较长),UI 设计时需考虑文本溢出,使用 maxLinestextOverflow 处理。

八、常见问题

8.1 切换语言不生效

原因:只修改了界面状态,没有更新系统语言,或资源文件缺失。

解决:调用 i18n.System.setSystemLanguage,确保对应语言目录存在。

8.2 中文乱码

原因:文件编码问题。

解决:确保资源文件使用 UTF-8 编码。

8.3 文本溢出

原因:不同语言文本长度差异大。

解决:使用 maxLinestextOverflow、自适应布局。

九、总结

本文深入讲解了 HarmonyOS 国际化技术,通过一个多彩渐变风格的国际演示页面实战演示了多语言切换、资源管理和文本本地化等核心能力。

核心要点回顾:

  1. 国际化让应用支持多种语言和地区。
  2. 资源目录结构:base 兜底 + 各语言目录。
  3. $r() 引用字符串资源,系统自动选择语言。
  4. i18n 模块管理系统语言、区域、时区。
  5. Intl 模块格式化日期、时间、数字、货币。
  6. 资源分离、占位符、文本适配是最佳实践。

国际化是应用走向全球市场的关键能力,掌握它能构建真正国际化的应用。至此,我们的 16 篇技术专题博客已全部完成,覆盖了 HarmonyOS 开发的各个核心方向。

Logo

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

更多推荐