当前位置: 首页 > news >正文

ReactNative项目OpenHarmony三方库集成实战:react-native-localize

欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

📋 前言

国际化(i18n)和本地化(l10n)是移动应用走向全球市场的关键步骤。无论是多语言支持、货币格式化、日期时间显示,还是度量单位转换,都需要获取用户设备的本地化设置。react-native-localize是一个强大的本地化工具库,提供了丰富的 API 来获取设备的语言、地区、货币、时区等本地化信息,帮助开发者轻松实现应用的国际化适配。

🎯 库简介

基本信息

为什么需要本地化库?

特性手动获取react-native-localize
语言列表⚠️ 需调用原生API✅ 统一接口获取
货币代码❌ 需自行推断✅ 直接获取用户偏好
时区信息⚠️ 需原生模块✅ 跨平台一致API
数字格式❌ 需手动处理✅ 获取格式设置
最佳语言匹配❌ 需自行实现✅ 内置匹配算法
HarmonyOS 支持❌ 无✅ 完善适配

核心功能

功能说明HarmonyOS 支持
getLocales()获取用户首选语言列表
getCurrencies()获取用户首选货币代码
getCountry()获取用户所在国家代码
getCalendar()获取日历格式
getTimeZone()获取时区信息
uses24HourClock()判断是否使用24小时制
getNumberFormatSettings()获取数字格式设置
findBestLanguageTag()查找最佳匹配语言
getTemperatureUnit()获取温度单位
usesMetricSystem()判断是否使用公制

兼容性验证

在以下环境验证通过:

📦 安装步骤

1. 安装依赖

请到三方库的 Releases 发布地址查看配套的版本信息:

三方库版本发布信息支持 RN 版本
3.1.0@react-native-ohos/react-native-localize0.72
3.4.2@react-native-ohos/react-native-localize0.77
3.6.2@react-native-ohos/react-native-localize0.82

# RN 0.72 版本npminstall@react-native-ohos/react-native-localize@3.1.1-rc.1# RN 0.77 版本npminstall@react-native-ohos/react-native-localize@3.4.2# RN 0.82 版本npminstall@react-native-ohos/react-native-localize@3.6.2# 或者使用 yarnyarnadd@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按钮,或者在终端执行:

cdharmony/entry ohpminstall

3. 配置 CMakeLists 和引入 RNLocalizePackage(仅 0.77 需要)

打开harmony/entry/src/main/cpp/CMakeLists.txt,添加:

project(rnapp)cmake_minimum_required(VERSION3.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"usingnamespacernoh;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,添加:

importtype{RNPackageContext,RNPackage}from'rnoh/ts';+import{RNLocalizePackage}from'@react-native-ohos/react-native-localize/ts';exportfunctioncreateRNPackages(ctx:RNPackageContext):RNPackage[]{return[+newRNLocalizePackage(ctx),];}

🚀 同步并运行

点击 DevEco Studio 右上角的sync按钮,或者在终端执行:

cdharmony/entry ohpminstall

然后编译、运行即可。

📖 API 详解

getLocales() - 获取用户首选语言列表

返回用户首选的语言环境列表,按优先级排列。这是实现应用多语言支持的核心 API,通过获取用户的语言偏好来决定应用显示的语言版本。

返回值类型Locale[]

Locale 对象结构

属性类型说明示例值
languageCodestringISO 639-1 语言代码“zh”, “en”, “ja”
countryCodestringISO 3166-1 国家代码“CN”, “US”, “JP”
languageTagstring完整的 BCP 47 语言标签“zh-Hans-CN”, “en-US”
isRTLboolean是否为从右到左的语言false, true

使用场景

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

返回对象结构

属性类型说明中国示例美国示例
decimalSeparatorstring小数分隔符“.”“.”
groupingSeparatorstring千位分隔符“,”“,”

💡提示:不同地区的数字格式差异较大,如欧洲部分地区使用逗号作为小数分隔符。

使用场景

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。

参数

返回值类型{ languageTag: string; isRTL: boolean } | undefined

匹配规则

  1. 首先尝试完全匹配(如 “zh-Hans-CN”)
  2. 其次尝试语言+脚本匹配(如 “zh-Hans”)
  3. 最后尝试仅语言匹配(如 “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 方式会在本地化设置变化时触发组件重新渲染。


📋 完整示例

importReact,{useMemo}from"react";import{SafeAreaView,ScrollView,StyleSheet,Text,View,}from"react-native";import*asRNLocalizefrom"react-native-localize";consttranslations:Record<string,Record<string,string>>={en:{welcome:"Welcome",language:"Language",currency:"Currency",timezone:"Timezone"},zh:{welcome:"欢迎",language:"语言",currency:"货币",timezone:"时区"},ja:{welcome:"ようこそ",language:"言語",currency:"通貨",timezone:"タイムゾーン"},};constApp:React.FC=()=>{constlocales=RNLocalize.getLocales();constcurrencies=RNLocalize.getCurrencies();constcountry=RNLocalize.getCountry();consttimeZone=RNLocalize.getTimeZone();constuses24Hour=RNLocalize.uses24HourClock();constnumberSettings=RNLocalize.getNumberFormatSettings();constbestMatch=RNLocalize.findBestLanguageTag(["en","zh","ja"]);constcurrentLang=(bestMatch?.languageTag.split("-")[0]askeyoftypeoftranslations)||"en";constt=translations[currentLang]||translations.en;constformatNumber=(num:number):string=>{constparts=num.toFixed(2).split(".");constintPart=parts[0].replace(/\B(?=(\d{3})+(?!\d))/g,numberSettings.groupingSeparator);returnintPart+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>);};conststyles=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},});exportdefaultApp;

⚠️ 遗留问题

http://www.cnnetsun.cn/news/1594448.html

相关文章:

  • 代理IP:按流量还是按IP/时长计费更划算?
  • Qwen3-0.6B-FP8应用场景:开发者测试LLM应用前端UI兼容性的沙盒环境
  • Play Integrity API Checker:Android设备安全检测的5个实战场景
  • Qwen-Image-Edit-2511-Unblur-Upscale:你的模糊图片修复神器
  • OFA图像描述模型作品集:AI生成的图片描述有多准确?
  • AI写的还是人写的?这个神器一眼识破AI痕迹!
  • 完全离线语音处理:基于AnythingLLM的本地化语音转文字开源方案
  • 多情景驱动的土地利用格局模拟与生态系统服务响应:基于PLUS-InVEST模型的AI全流程框架
  • ROS 实战指南:从 rosbag 高效提取 RGB 与深度图数据
  • Qwen3.5-9B效果展示:工业设备铭牌照片→型号识别+参数提取
  • Qwen2.5-7B应用案例:用vLLM加速推理,实现智能问答与数据格式化
  • OCR+NLP黑科技:火眼审阅如何实现扫描件合同的精准比对?
  • Vue2动态路由重复添加问题:从路由守卫到addRoute的解决方案
  • 云原生图书馆管理系统架构设计:基于SaaS的一站式解决方案与实战案例分析
  • 大模型时代,算力租用成为AI创新的核心支撑
  • 2026年3月可买断的房产中介房源管理系统
  • Palo Alto PAN-OS 12.1.5 VM-Series for ESXi, KVM - 基于机器学习的下一代防火墙操作系统
  • 别再死记硬背了!用‘约束传播’思想秒解八皇后,LeetCode 52题实战复盘
  • 解决Azure Databricks的Serverless SQL Warehouse访问问题
  • 组织通用治理-软考高项-知识点及考点预测
  • 幻境·流金技术深挖:BF16混合精度对生成质量与速度的影响
  • C# WinForm免注册调用大漠插件3.1233:Windows 10自动化开发实战
  • SAM 3多场景落地:电商主图自动抠图、教育课件图形提取、法律文书图示标注
  • Ostrakon-VL-8B GPU算力优化:8B模型在A10/A100上vLLM吞吐提升300%实测
  • SAP物料账期管理的3个冷知识:为什么MMPV必须逐月打开?虚拟机快速开期技巧
  • Ryujinx实战指南:用C打造Switch游戏PC模拟器
  • 告别复杂配置:Ostrakon-VL-8B零售多模态模型一键部署实战
  • CosyVoice高保真语音合成作品集:影视解说与有声书案例
  • Windows下Electron项目集成better-sqlite3全攻略:从编译失败到完美运行的避坑指南
  • S2-Pro模型成本控制实战:按需加载与请求合并优化