Flutter 鸿蒙插件适配实战:用 locale_plus 2.0.0 读取语言、地区与格式偏好

适配仓库: https://atomgit.com/oh-flutter/locale_plus

适配分支: feat/ohos_locale_plus_2.0.0

受测提交: 1387b3d8b3eadbb782c77c679a6446e50e9ebca0

一、最终效果与适配目标

国际化页面不只需要 zh_CN。金额输入要知道小数和分组符,日历要知道周首日,时间页需要 12/24 小时制、AM/PM 文本、IANA 时区及 UTC 偏移。locale_plus 2.0.0 已提供 13 个 Dart 查询接口,本次适配目标是保持接口和可空返回值不变,在 OHOS 上从系统国际化能力读取真实数据。

图 1:CHZ-AL00 / HarmonyOS 7.0.0.105 上读取到 zh、CN、Asia/Shanghai、28800 秒偏移、中文时段符号和公制偏好。

验证点 实测结果 证据
语言与地区 zh / CN,二者独立读取 图 1、图 6
时间信息 Asia/Shanghai、UTC 偏移 28800 秒、周首日 7 图 1、图 6
格式偏好 小数点、分组符、AM/PM、日期模式、12/24 小时制均返回 图 1
自动化与构建 15 Dart + 3 Widget + 15 ArkTS,共 33 项及 HAP 通过 图 4、图 5
验证边界 未修改系统语言、地区、历法或时区;其他 locale 由自动化覆盖 图 6

成果速览

项目 内容
上游基线 TAG v2.0.0,提交 9897037d81007432306825c3fb860c204efb853c,MIT
适配分支 feat/ohos_locale_plus_2.0.0
适配提交 1387b3d8b3eadbb782c77c679a6446e50e9ebca0
新增 OHOS 能力 13 项语言、地区、数字、日期、时区与单位偏好查询
保持不变的接口 LocalePlus 全部公开方法与 locale_plus 通道
真机结论 13 项基础读取通过;系统设置切换与其他设备未覆盖

二、实测环境与选库核对

组件 实测版本
Flutter OH 3.41.10-ohos-1.0.1
Dart 3.11.5
DevEco Studio 26.0.0 Release
HarmonyOS SDK API 26;示例兼容 API 18
真机 CHZ-AL00,HarmonyOS 7.0.0.105
插件 locale_plus 2.0.0

环境搭建参考 Flutter OH 环境搭建指南。本文使用已完整回归的稳定版 Flutter OH;3.44.9+ohos-0.0.1-canary1 是预览标签,不冒充本次实测版本。

2026 年 9 月 11 日,我核对 pub.dev 最新版 2.0.0、上游 TAG 与发布包,并对目标组织仓库做同名排查。没有发现可直接使用的 OHOS 实现后,才创建本次仓库。发布包 SHA 与上游来源均记录在适配批次证据中。

三、从上游基线建立 OHOS 分支

shell 复制代码
git clone https://atomgit.com/oh-flutter/locale_plus.git
cd locale_plus
git switch -c feat/ohos_locale_plus_2.0.0 v2.0.0
flutter create --template=plugin --platforms=ohos --no-pub .

我保留原 Dart、Android、iOS 和 Web 代码,只新增 OHOS HAR、示例宿主、双语说明与测试。模板生成后把插件类改为 LocalePlusPlugin,通道继续使用 locale_plus。

图 2:AtomGit origin、适配分支、完整 HEAD 与工作区状态。

四、先梳理 13 个接口的语义

公开接口都返回可空值,原生系统数据缺失时不应自行编造:

接口组 API 返回语义
locale getLanguageCode()、getRegionCode() 基础语言码和地区码
数字 getDecimalSeparator()、getGroupingSeparator() 当前 locale 的数字符号
时区 getTimeZoneIdentifier()、getSecondsFromGMT() IANA 标识和当前偏移秒数
时间/日期 is24HourTime()、getAmSymbol()、getPmSymbol()、getFirstDayOfWeek()、getDateFormatPattern() 系统格式偏好
其他 usesMetricSystem()、isUsingSamsungKeyboard() 单位策略与上游平台特定判断

语言和地区必须分开读。例如系统语言可能是 zh-Hans,基础语言码应解析为 zh;地区则来自独立的系统 region。UTC 偏移必须按"当前时刻"计算,才能包含夏令时,而不能写死时区的标准偏移。

五、用 LocalizationKit 实现格式查询

LocalePlusPlugin.ets 通过 i18n.System、i18n.getTimeZone() 和 systemDateTime 取得基础数据;数字、时段和日期格式通过 Intl 的 formatToParts() 拆解:

typescript 复制代码
case 'getRegionCode':
  return i18n.System.getSystemRegion();
case 'getLanguageCode':
  return new Intl.Locale(i18n.System.getSystemLanguage()).language;
case 'getTimeZoneIdentifier':
  return systemDateTime.getTimezoneSync();
case 'getSecondsFromGMT':
  return i18n.getTimeZone().getOffset(Date.now()) / 1000;

日期模式不能通过替换格式化后的数字猜测。实现用一个固定 UTC 日期拆出 year、month、day 和 literal,再按照字段宽度生成 yyyy/M/d、dd/MM/yyyy 等模式。字面量中如果有字母,需要加引号,防止被 intl.DateFormat 当成模式字符。

getFirstDayOfWeek() 保持系统返回的 ISO 1 到 7,不再把星期日改成 1。公制判断沿用上游 Android 的地区策略:US、LR、MM 返回 false,其他地区返回 true;它是地区规则,不是用户可单独修改的单位设置。Samsung 键盘是其他平台特定能力,OHOS 明确返回 false。

图 3:13 个方法的路由,以及语言、地区、时区和格式数据来源。

该插件只读取公开系统 locale 数据,无需新增权限,也不会修改系统设置。Engine 解绑后清除 handler;系统异常返回 locale_query_failed,未知方法返回 notImplemented。

六、测试和 HAP 构建

shell 复制代码
flutter pub get
flutter analyze
flutter test
node --test ohos/test/locale_plus.test.cjs
cd example
flutter analyze
flutter test
flutter build hap --debug --no-codesign

15 项 Dart、3 项 Widget 和 15 项 ArkTS,共 33 项通过。原生测试覆盖英语、德语、法语、阿拉伯语、印地语数字符号,正负及半小时时区偏移,中英文 AM/PM,四种日期顺序,地区公制规则、错误恢复和 Engine 重绑。

图 4:静态分析、33 项功能测试和示例回归结果。

图 5:无签名 HAP 元数据及远程 Git 依赖锁定口径。

七、固定提交接入与真机验证

yaml 复制代码
dependencies:
  locale_plus:
    git:
      url: https://atomgit.com/oh-flutter/locale_plus.git
      ref: 1387b3d8b3eadbb782c77c679a6446e50e9ebca0

隔离宿主的 pubspec.lock 解析到同一 SHA,签名 HAP 构建和覆盖安装通过。真机逐项读取 13 个接口,并用 Dart 本地时区偏移对照 28800 秒,全部通过。页面结果包括 zh、CN、Asia/Shanghai、小数点、分组符、中文上午/下午、12 小时制、周首日 7、yyyy/M/d 和公制。

图 6:13 项真机读取结论及未修改系统设置的验证边界。

本轮没有切换语言、地区、历法和时区,因此不能声称所有组合都已真机验收。自动化覆盖不同 locale 的算法分支,但它和真实设备切换是两类证据。

应用内真实截图:刷新后的格式信息

图 7:页面上半段展示语言、地区、时区、UTC 偏移及数字分隔符。

图 8:刷新后第 2 次读取,日期模式、周首日、24 小时制和公制偏好仍保持一致。

八、FAQ

Q1:为什么语言码和地区码不能从同一个字符串截取

  • 现象: 脚本假定 locale 总是 language_REGION,遇到脚本码或缺少地区时解析错误。
  • 原因: 系统语言和地区是独立设置,语言标签也可能包含 script。
  • 解决方法: 分别读取 system language 与 system region,语言再交给 Intl.Locale 解析。
  • 验证结果: 自动化用 zh-Hans 与 GB 的组合确认返回 zh / GB。

Q2:UTC 偏移为什么不能写成时区常量

  • 现象: 夏令时地区在不同日期返回值会变化。
  • 原因: IANA 时区标识不等于固定偏移,偏移与当前时间有关。
  • 解决方法: 调用 getOffset(Date.now()) 并从毫秒换算为秒。
  • 验证结果: 测试覆盖负偏移、零偏移和半小时偏移,真机与 Dart 当前偏移一致。

Q3:usesMetricSystem 是否读取用户偏好

  • 现象: 调用方以为它代表系统设置页中的自定义单位。
  • 原因: 上游 API 按地区规则推断,OHOS 适配保持同一语义。
  • 解决方法: 将它用于默认值;用户明确选择的单位仍应保存在业务配置中。
  • 验证结果: US/LR/MM 与 CN/GB 的规则由 ArkTS 测试覆盖。

九、总结

locale_plus 2.0.0 已在 OHOS 上补齐全部 13 项系统 locale 查询,并保留可空返回值和原通道契约。33 项自动化、HAP 构建和 API 26 真机基础读取通过,且没有申请权限或修改系统设置。

正式项目应锁定受测 SHA,把这些结果当作格式默认值,并为系统数据缺失保留降级显示。语言与地区切换、其他历法和更多设备仍需按业务覆盖。

十、参考链接

欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter

相关推荐
事圆则缓1 小时前
Flutter 开发鸿蒙实战:从 OpenHarmony 适配版到 HAP 构建与插件接入
flutter·华为·harmonyos
传奇开心果编程1 小时前
【ArkUI进阶练中学】第9课:分布式能力与多设备协同
学习·ui·华为·harmonyos
李游Leo2 小时前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 输入帧内参与位姿的版本一致性门禁【鸿蒙心迹】
c++·3d·harmonyos
tsqtsqtsq03092 小时前
Account Kit 华为账号服务介绍
华为·harmonyos
天空之城--2 小时前
Android一周动态:Android 18首次官宣、Compose Material3 1.4转正(5趋势+5资讯)
android·人工智能·flutter·架构·android jetpack
恋猫de小郭2 小时前
Meta 分享怎么用 AI 迁移 Compose 项目不烧心
android·前端·flutter
EatFan2 小时前
Flutter 鸿蒙适配实践 2026:从环境搭建、混合渲染到 OpenTelemetry 性能基建
flutter·华为·harmonyos·openharmony·opentelemetry·鸿蒙适配·impeller
m0_738185822 小时前
Flutter 鸿蒙化实战:flutter_secure_storage 适配 OpenHarmony,敏感数据安全存储
安全·flutter·华为·harmonyos·鸿蒙
李游Leo2 小时前
HarmonyOS 7 HiAppEvent + AppGallery Connect:审核复现链路的脱敏日志切片与证据校验【鸿蒙心迹】
华为·harmonyos
李游Leo2 小时前
HarmonyOS 7 + Core Vision Kit:文搜图索引代际切换与模型升级回滚【鸿蒙心迹】
华为·harmonyos