ReactNative项目OpenHarmony三方库集成实战:react-native-localize
国际化(i18n)和本地化(l10n)是移动应用走向全球市场的关键步骤。无论是多语言支持、货币格式化、日期时间显示,还是度量单位转换,都需要获取用户设备的本地化设置。是一个强大的本地化工具库,提供了丰富的 API 来获取设备的语言、地区、货币、时区等本地化信息,帮助开发者轻松实现应用的国际化适配。库名称版本信息3.1.0: 支持 RN 0.72 版本3.4.2: 支持 RN 0.77 版本3.6.
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

📋 前言
国际化(i18n)和本地化(l10n)是移动应用走向全球市场的关键步骤。无论是多语言支持、货币格式化、日期时间显示,还是度量单位转换,都需要获取用户设备的本地化设置。react-native-localize 是一个强大的本地化工具库,提供了丰富的 API 来获取设备的语言、地区、货币、时区等本地化信息,帮助开发者轻松实现应用的国际化适配。
🎯 库简介
基本信息
- 库名称:
react-native-localize - 版本信息:
3.1.0+@react-native-ohos/react-native-localize: 支持 RN 0.72 版本3.4.2+@react-native-ohos/react-native-localize: 支持 RN 0.77 版本3.6.2+@react-native-ohos/react-native-localize: 支持 RN 0.82 版本
- 官方仓库: https://github.com/zoontek/react-native-localize
- 鸿蒙仓库: https://atomgit.com/openharmony-sig/rntpc_react-native-localize
- 主要功能:
- 🌐 获取用户首选语言列表
- 💱 获取用户首选货币代码
- 📅 获取日历格式和时区
- 🔢 获取数字格式设置
- 🕐 判断是否使用24小时制
为什么需要本地化库?
| 特性 | 手动获取 | react-native-localize |
|---|---|---|
| 语言列表 | ⚠️ 需调用原生API | ✅ 统一接口获取 |
| 货币代码 | ❌ 需自行推断 | ✅ 直接获取用户偏好 |
| 时区信息 | ⚠️ 需原生模块 | ✅ 跨平台一致API |
| 数字格式 | ❌ 需手动处理 | ✅ 获取格式设置 |
| 最佳语言匹配 | ❌ 需自行实现 | ✅ 内置匹配算法 |
| HarmonyOS 支持 | ❌ 无 | ✅ 完善适配 |
核心功能
| 功能 | 说明 | HarmonyOS 支持 |
|---|---|---|
| getLocales() | 获取用户首选语言列表 | ✅ |
| getCurrencies() | 获取用户首选货币代码 | ✅ |
| getCountry() | 获取用户所在国家代码 | ✅ |
| getCalendar() | 获取日历格式 | ✅ |
| getTimeZone() | 获取时区信息 | ✅ |
| uses24HourClock() | 判断是否使用24小时制 | ✅ |
| getNumberFormatSettings() | 获取数字格式设置 | ✅ |
| findBestLanguageTag() | 查找最佳匹配语言 | ✅ |
| getTemperatureUnit() | 获取温度单位 | ❌ |
| usesMetricSystem() | 判断是否使用公制 | ❌ |
兼容性验证
在以下环境验证通过:
- RNOH: 0.72.90; SDK: HarmonyOS 6.0.0 (API Version 20); IDE: DevEco Studio 6.0.2; ROM: HarmonyOS 6.0.0
📦 安装步骤
1. 安装依赖
请到三方库的 Releases 发布地址查看配套的版本信息:
| 三方库版本 | 发布信息 | 支持 RN 版本 |
|---|---|---|
| 3.1.0 | @react-native-ohos/react-native-localize | 0.72 |
| 3.4.2 | @react-native-ohos/react-native-localize | 0.77 |
| 3.6.2 | @react-native-ohos/react-native-localize | 0.82 |

# RN 0.72 版本
npm install @react-native-ohos/react-native-localize@3.1.1-rc.1
# RN 0.77 版本
npm install @react-native-ohos/react-native-localize@3.4.2
# RN 0.82 版本
npm install @react-native-ohos/react-native-localize@3.6.2
# 或者使用 yarn
yarn add @react-native-ohos/react-native-localize
2. 验证安装
安装完成后,检查 package.json 文件:
{
"dependencies": {
"@react-native-ohos/react-native-localize": "^3.1.1-rc.1"
}
}
🔧 HarmonyOS 平台配置 ⭐
1. 在工程根目录的 oh-package.json5 添加 overrides 字段(看自己的版本是什么,在package.json中)
打开 harmony/oh-package.json5,添加以下配置:
{
// ... 其他配置
"overrides": {
"@rnoh/react-native-openharmony": "0.72.90"
}
}
2. 引入原生端代码
方式一:通过 HAR 包引入(推荐)
💡 提示:HAR 包位于三方库安装路径的
harmony文件夹下。
打开 harmony/entry/oh-package.json5,添加以下依赖:
"dependencies": {
"@react-native-ohos/react-native-localize": "file:../../node_modules/@react-native-ohos/react-native-localize/harmony/rn_localize.har"
}
点击右上角的 sync 按钮,或者在终端执行:
cd harmony/entry
ohpm install
3. 配置 CMakeLists 和引入 RNLocalizePackage(仅 0.77 需要)
打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加:
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
add_subdirectory("${RNOH_CPP_DIR}" ./rn)
# 添加 RNLocalize 模块
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-localize/src/main/cpp" ./rn_localize)
add_library(rnoh_app SHARED
"./PackageProvider.cpp"
"${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)
# 链接 RNLocalize 库
+ target_link_libraries(rnoh_app PUBLIC rnoh_localize)
打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:
#include "RNOH/PackageProvider.h"
+ #include "RNLocalizePackage.h"
using namespace rnoh;
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
return {
+ std::make_shared<RNLocalizePackage>(ctx),
};
}
4. 在 ArkTs 侧引入 RNLocalizePackage
打开 harmony/entry/src/main/ets/RNPackagesFactory.ts,添加:
import type { RNPackageContext, RNPackage } from 'rnoh/ts';
+ import { RNLocalizePackage } from '@react-native-ohos/react-native-localize/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
+ new RNLocalizePackage(ctx),
];
}
🚀 同步并运行
点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:
cd harmony/entry
ohpm install
然后编译、运行即可。
📖 API 详解
getLocales() - 获取用户首选语言列表
返回用户首选的语言环境列表,按优先级排列。这是实现应用多语言支持的核心 API,通过获取用户的语言偏好来决定应用显示的语言版本。
返回值类型:Locale[]
Locale 对象结构:
| 属性 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| languageCode | string | ISO 639-1 语言代码 | “zh”, “en”, “ja” |
| countryCode | string | ISO 3166-1 国家代码 | “CN”, “US”, “JP” |
| languageTag | string | 完整的 BCP 47 语言标签 | “zh-Hans-CN”, “en-US” |
| isRTL | boolean | 是否为从右到左的语言 | false, true |
使用场景:
- 应用启动时确定默认语言
- 多语言内容切换
- 判断是否需要 RTL 布局支持
import * as RNLocalize from 'react-native-localize';
const locales = RNLocalize.getLocales();
// 返回示例:
// [
// { languageCode: "zh", countryCode: "CN", languageTag: "zh-Hans-CN", isRTL: false },
// { languageCode: "en", countryCode: "US", languageTag: "en-US", isRTL: false }
// ]
// 实际应用:根据用户语言偏好加载对应的翻译文件
const primaryLocale = locales[0];
const languageCode = primaryLocale.languageCode; // "zh"
// 判断是否需要 RTL 布局
if (primaryLocale.isRTL) {
// 应用 RTL 样式,如 flexDirection: 'row-reverse'
}
getCurrencies() - 获取用户首选货币代码
返回用户设备设置的首选货币代码列表,按优先级排列。这对于电商、金融类应用尤为重要,可以自动显示用户熟悉的货币符号。
返回值类型:string[]
返回值说明:返回 ISO 4217 货币代码数组,如 [“CNY”, “USD”]
使用场景:
- 电商应用自动显示本地货币价格
- 金融应用默认货币选择
- 价格格式化显示
const currencies = RNLocalize.getCurrencies();
// 返回示例:["CNY", "USD"]
// 实际应用:根据货币代码格式化价格
const currencySymbols: Record<string, string> = {
CNY: '¥',
USD: '$',
EUR: '€',
JPY: '¥',
};
const formatPrice = (amount: number, currency: string) => {
const symbol = currencySymbols[currency] || currency;
return `${symbol}${amount.toFixed(2)}`;
};
const userCurrency = currencies[0]; // "CNY"
const displayPrice = formatPrice(99.99, userCurrency); // "¥99.99"
getCountry() - 获取用户所在国家代码
返回用户设备设置的国家/地区代码,用于判断用户的地理位置偏好。
返回值类型:string
返回值说明:返回 ISO 3166-1 alpha-2 国家代码,如 “CN”、“US”、“JP”
使用场景:
- 内容地区限制判断
- 默认配送地址设置
- 地区特定功能开关
const country = RNLocalize.getCountry();
// 返回示例:"CN"
// 实际应用:根据国家显示不同内容
const getAvailableFeatures = (countryCode: string) => {
const featuresByCountry: Record<string, string[]> = {
CN: ['wechat-pay', 'alipay', 'unionpay'],
US: ['apple-pay', 'google-pay', 'paypal'],
JP: ['line-pay', 'paypay'],
};
return featuresByCountry[countryCode] || ['credit-card'];
};
const availablePaymentMethods = getAvailableFeatures(country);
getCalendar() - 获取日历格式
返回用户设备设置的日历类型,用于日期相关的显示和计算。
返回值类型:string
常见返回值:
| 返回值 | 说明 | 主要使用地区 |
|---|---|---|
| “gregorian” | 公历(格里高利历) | 全球通用 |
| “chinese” | 农历 | 中国 |
| “japanese” | 日本年号历 | 日本 |
| “islamic” | 伊斯兰历 | 中东地区 |
使用场景:
- 日历应用日期显示
- 节假日判断
- 日期选择器本地化
const calendar = RNLocalize.getCalendar();
// 返回示例:"gregorian"
// 实际应用:根据日历类型调整日期显示
const formatDateByCalendar = (date: Date, calendarType: string) => {
switch (calendarType) {
case 'chinese':
// 返回农历日期(需要额外的农历转换库)
return convertToLunarDate(date);
case 'japanese':
// 返回日本年号日期
return formatJapaneseYear(date);
default:
return date.toLocaleDateString();
}
};
getTimeZone() - 获取时区信息
返回用户设备设置的时区标识符,用于时间相关的计算和显示。
返回值类型:string
返回值说明:返回 IANA 时区标识符,如 “Asia/Shanghai”、“America/New_York”
使用场景:
- 跨时区时间显示
- 日程安排和提醒
- 服务器时间同步
const timeZone = RNLocalize.getTimeZone();
// 返回示例:"Asia/Shanghai"
// 实际应用:将 UTC 时间转换为本地时间
const convertToLocalTime = (utcTime: Date, timeZone: string) => {
const options: Intl.DateTimeFormatOptions = {
timeZone,
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short',
};
return utcTime.toLocaleString('zh-CN', options);
};
const localTime = convertToLocalTime(new Date(), timeZone);
// 输出:"2024年1月15日 下午3:30 CST"
uses24HourClock() - 判断是否使用24小时制
判断用户设备是否使用 24 小时制时间格式,用于时间显示的本地化。
返回值类型:boolean
返回值说明:true 表示使用 24 小时制,false 表示使用 12 小时制(AM/PM)
使用场景:
- 时间选择器格式
- 时间显示格式
- 日程时间显示
const uses24Hour = RNLocalize.uses24HourClock();
// 返回示例:true
// 实际应用:根据用户偏好格式化时间
const formatTime = (hours: number, minutes: number, use24Hour: boolean) => {
if (use24Hour) {
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
} else {
const period = hours >= 12 ? 'PM' : 'AM';
const displayHours = hours % 12 || 12;
return `${displayHours}:${minutes.toString().padStart(2, '0')} ${period}`;
}
};
const timeString = formatTime(15, 30, uses24Hour);
// 24小时制输出:"15:30"
// 12小时制输出:"3:30 PM"
getNumberFormatSettings() - 获取数字格式设置
返回用户设备的数字格式化设置,包括小数分隔符和千位分隔符。
返回值类型:NumberFormatSettings
返回对象结构:
| 属性 | 类型 | 说明 | 中国示例 | 美国示例 |
|---|---|---|---|---|
| decimalSeparator | string | 小数分隔符 | “.” | “.” |
| groupingSeparator | string | 千位分隔符 | “,” | “,” |
💡 提示:不同地区的数字格式差异较大,如欧洲部分地区使用逗号作为小数分隔符。
使用场景:
- 数字输入框格式化
- 金额显示
- 数据报表展示
const settings = RNLocalize.getNumberFormatSettings();
// 返回示例:{ decimalSeparator: ".", groupingSeparator: "," }
// 实际应用:根据本地设置格式化数字
const formatNumber = (num: number, settings: typeof settings) => {
const parts = num.toFixed(2).split('.');
const intPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, settings.groupingSeparator);
return intPart + settings.decimalSeparator + parts[1];
};
// 中国/美国格式
formatNumber(1234567.89, { decimalSeparator: '.', groupingSeparator: ',' });
// 输出:"1,234,567.89"
// 欧洲部分国家格式
formatNumber(1234567.89, { decimalSeparator: ',', groupingSeparator: '.' });
// 输出:"1.234.567,89"
findBestLanguageTag() - 查找最佳匹配语言
从应用支持的语言列表中,找到与用户偏好最匹配的语言。这是实现应用多语言切换的关键 API。
参数:
languageTags: string[]- 应用支持的语言标签数组
返回值类型:{ languageTag: string; isRTL: boolean } | undefined
匹配规则:
- 首先尝试完全匹配(如 “zh-Hans-CN”)
- 其次尝试语言+脚本匹配(如 “zh-Hans”)
- 最后尝试仅语言匹配(如 “zh”)
使用场景:
- 应用启动时选择最佳语言
- 语言切换回退逻辑
- 多语言内容加载
const bestMatch = RNLocalize.findBestLanguageTag(['en-US', 'en', 'fr', 'zh']);
// 返回示例:{ languageTag: "zh", isRTL: false }
// 实际应用:选择最佳匹配语言加载翻译
const supportedLanguages = ['en', 'zh', 'ja', 'ko', 'es', 'fr'];
const bestLanguage = RNLocalize.findBestLanguageTag(supportedLanguages);
if (bestLanguage) {
// 加载匹配的语言包
const translations = require(`./locales/${bestLanguage.languageTag}.json`);
// 应用翻译
i18n.setTranslations(translations);
} else {
// 回退到默认语言
const fallbackTranslations = require('./locales/en.json');
i18n.setTranslations(fallbackTranslations);
}
useLocalize() - Hook 方式获取本地化信息
React Hook 方式获取本地化 API,适合在函数组件中使用。当本地化设置发生变化时,组件会自动重新渲染。
返回值:包含所有本地化方法的对象
使用场景:
- 函数组件中获取本地化信息
- 响应本地化设置变化
- 简化代码结构
import { useLocalize } from 'react-native-localize';
const MyComponent = () => {
const { getLocales, getCurrencies, getCountry, getTimeZone } = useLocalize();
// 每次调用都会获取最新值
const locales = getLocales();
const currencies = getCurrencies();
const country = getCountry();
const timeZone = getTimeZone();
return (
<View>
<Text>语言: {locales[0]?.languageTag}</Text>
<Text>货币: {currencies[0]}</Text>
<Text>国家: {country}</Text>
<Text>时区: {timeZone}</Text>
</View>
);
};
⚠️ 注意:与直接调用 API 不同,Hook 方式会在本地化设置变化时触发组件重新渲染。
📋 完整示例

import React, { useMemo } from "react";
import {
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View,
} from "react-native";
import * as RNLocalize from "react-native-localize";
const translations: Record<string, Record<string, string>> = {
en: { welcome: "Welcome", language: "Language", currency: "Currency", timezone: "Timezone" },
zh: { welcome: "欢迎", language: "语言", currency: "货币", timezone: "时区" },
ja: { welcome: "ようこそ", language: "言語", currency: "通貨", timezone: "タイムゾーン" },
};
const App: React.FC = () => {
const locales = RNLocalize.getLocales();
const currencies = RNLocalize.getCurrencies();
const country = RNLocalize.getCountry();
const timeZone = RNLocalize.getTimeZone();
const uses24Hour = RNLocalize.uses24HourClock();
const numberSettings = RNLocalize.getNumberFormatSettings();
const bestMatch = RNLocalize.findBestLanguageTag(["en", "zh", "ja"]);
const currentLang = (bestMatch?.languageTag.split("-")[0] as keyof typeof translations) || "en";
const t = translations[currentLang] || translations.en;
const formatNumber = (num: number): string => {
const parts = num.toFixed(2).split(".");
const intPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, numberSettings.groupingSeparator);
return intPart + numberSettings.decimalSeparator + parts[1];
};
return (
<SafeAreaView style={styles.container}>
<ScrollView contentContainerStyle={styles.content}>
<Text style={styles.title}>{t.welcome}</Text>
<View style={styles.card}>
<Text style={styles.cardTitle}>本地化信息</Text>
<View style={styles.row}>
<Text style={styles.label}>{t.language}:</Text>
<Text style={styles.value}>{locales[0]?.languageTag}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>{t.currency}:</Text>
<Text style={styles.value}>{currencies[0]}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>{t.timezone}:</Text>
<Text style={styles.value}>{timeZone}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>国家:</Text>
<Text style={styles.value}>{country}</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>24小时制:</Text>
<Text style={styles.value}>{uses24Hour ? "是" : "否"}</Text>
</View>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>数字格式化示例</Text>
<Text style={styles.formatText}>1234.56 → {formatNumber(1234.56)}</Text>
<Text style={styles.formatText}>9876543.21 → {formatNumber(9876543.21)}</Text>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>支持的语言列表</Text>
{locales.map((locale, index) => (
<View key={index} style={styles.localeRow}>
<Text style={styles.localeText}>{locale.languageTag}</Text>
{locale.isRTL && <Text style={styles.rtlBadge}>RTL</Text>}
</View>
))}
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#F5F5F5" },
content: { padding: 16 },
title: { fontSize: 24, fontWeight: "bold", marginBottom: 20, color: "#333", textAlign: "center" },
card: { backgroundColor: "#FFF", borderRadius: 12, padding: 16, marginBottom: 16 },
cardTitle: { fontSize: 16, fontWeight: "600", marginBottom: 12, color: "#333" },
row: { flexDirection: "row", justifyContent: "space-between", paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: "#F0F0F0" },
label: { fontSize: 14, color: "#666" },
value: { fontSize: 14, fontWeight: "500", color: "#333" },
formatText: { fontSize: 14, color: "#007AFF", marginVertical: 4 },
localeRow: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingVertical: 8 },
localeText: { fontSize: 14, color: "#333" },
rtlBadge: { backgroundColor: "#FF9500", color: "#FFF", paddingHorizontal: 8, paddingVertical: 2, borderRadius: 4, fontSize: 12 },
});
export default App;
⚠️ 遗留问题
更多推荐


所有评论(0)