前言
Intl是flutter中用于支持多语言操作的一个库,方便开发者通过arb文件来进行本地化操作,省去一些既定步骤的操作。
Flutter Intl则是针对Intl库开发的插件,主要功能为自动生成代码,简化前置操作,让开发者能更专注arb的编写;
Flutter Intl插件目前有VSCode版和IDEA/Android Studio版,使用步骤大致相同。
arb文件全称Application Resource Bundle(abbr. ARB)是一种本地化资源格式,遵循json规范,arb文件可以提供给翻译人员翻译完毕后,再另行导入。
Intl使用的是l10n标准(l10n即localization的缩写),库的目前版本为0.17.0,操作步骤可能与之前版本有所差异,注意鉴别。
本文就VSCode环境中演示一下Flutter Intl插件的使用,Flutter SDK版本为3.0.3,Dart版本为2.17.5。
插件的启用
安装插件
在扩展应用市场搜索"Intl",选择“Flutter Intl"安装:
启用插件
安装完成后,Ctrl+Shift+P打开包命令窗口,选择“Flutter Intl:初始化”:
自动生成相关文件
插件会在flutter工程目录下自动生成以下目录及文件:
--lib
--l10n
--intl_en.arb
--generated
--l10n.dart
--intl
--messages_all.dart
--messages_en.dart
intl_en.arb即对应的英文翻译文档;
l10n.dart中自动生成了本地化相关的类,类名默认为S;
messages_en.dart映射了intl_en.arb的对应字段;
messages_all.dart编写了管理messages_en.dart以及其他对应地区的messages_xx.dart的工厂类;
可以简单把调用链理解为:
l10n.dart <--messages_all.dart <--message_xx.dart <--intl_xx.arb
除了生成对应文件以外,插件也会在pubspec.yaml文件末尾自动添加intl的启用标识:
flutter_intl:
enabled: true
本地化配置
添加依赖
本地化的依赖需要自行在pubspec.yaml中添加:
dependencies:
flutter_localizations:
sdk: flutter
添加在dependencies节点或dev_dependencies节点视情况而定,dependencies意为项目依赖,dev_dependencies意为开发环境依赖;
这里依照官方的Flutter本地化应用介绍添加在dependencies节点下;
Intl库的依赖在插件的作用下已经添加到pubspec.lock文件中:
intl:
dependency: transitive
description:
name: intl
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.17.0"
但考虑到pubspec.lock官方不建议作为项目提交文件,因此在pubspec.yaml文件再进行直接依赖也是极好的,最终依赖是这样的:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: ^0.17.0
(添加依赖后理应执行pub get packages命令远程导入相关库,不过大多智能IDE都自行执行了这一过程)
添加中文支持
Ctrl+Shift+P打开包命令,选择"Add Locale":
填入对应区域代码"zh":
执行后会自动生成intl_zh.arb和messages_zh.dart文件,目录结构变为:
--lib
--l10n
--intl_en.arb
--intl_zh.arb
--generated
--l10n.dart
--intl
--messages_all.dart
--messages_en.dart
--messages_zh.dart
arb文件操作
在intl_en.arb文件中添加需要映射的字段,如下:
{
"home": "Home",
"about": "About",
"greet": "Hi, {name}",
"askChoice": "There are two choices:{one}? or {two}",
"@askChoice": {
"description": "Give someone two choice and wait for selection",
"placeHolder": {
"one": {
},
"two": {
}
}
},
"customDateFormat": "current date: {date}",
"@customDateFormat": {
"placeholders": {
"date": {
"type": "DateTime",
"format": "EEE, MM/dd/yyyy",
"isCustomDateFormat": "true"
}
}
}
}
并在intl_zh.arb添加对应的字段,如下:
{
"home": "首页",
"about": "关于",
"greet": "你好, {name}",
"askChoice": "这里有两个选择:{one}?或是 {two}",
"@askChoice": {
"description": "给某人两个选择,然后等待他的选择",
"placeHolder": {
"one": {
},
"two": {
}
}
},
"customDateFormat": "当前日期: {date}",
"@customDateFormat": {
"placeholders": {
"date": {
"type": "DateTime",
"format": "EEE, MM/dd/yyyy",
"isCustomDateFormat": "true"
}
}
}
}
普通的字段就相当于【资源引用符】,而以"@”符号开头的字段代表着规则与注释;
每次更新intl_xx.arb文件后,对应的messages_xx.dart以及l10n.dart中的S类就会自动更新相应的字段方法,也因此最终调用S类的方法即可获取映射字段;
本地化入口配置
要在程序入口或者说UI顶层,一般是MaterialApp或WidgetsApp的入口处配置本地化的字段;
即localizationsDelegates和supportedLocales两个字段;
前者为代理,可以理解处理字段映射的委托,后者为区域,即支持的区域代码列表;
上文提到过l10n.dart中生成的默认本地化相关类S,就是在这里使用的:
return MaterialApp(
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
//...其他代码
}
关于ios的本地化配置,同样可以参考官方文档的Flutter本地化应用中iOS 本地化:更新 iOS app bundle一小节的介绍。
使用
不同语言环境的输出
最终调用S.current或S.of(context)的对应arb字段即可:
print(S.current.about);
print(S.current.greet("老哥"));
print(S.current.askChoice("确定", "取消"));
print(S.current.customDateFormat(DateTime.now()));
中文环境下输出:
关于
你好, 老哥
这里有两个选择:确定?或是 取消
当前日期: 周五, 07/15/2022
英文环境下输出:
About
Hi, 老哥
There are two choices:确定? or 取消
current date: Fri, 07/15/2022
当然,以上输出中的“确定”“取消”等字段最好也在arb文件中提前定义。
以上例举的均是对应着Intl库中message方法的使用,更多其他用法可以参考Intl API。
手动指定语言环境
程序会根据系统的设置选择Locale,也可以自行指定;
比如可建立全局类,指定Intl的defaultLocale属性来改变语言环境:
class Application {
static Future init() async {
Intl.defaultLocale = 'en';
}
}
然后在程序入口处包裹:
Application.init().then((value) => runApp(MyApp()));
Intl.defaultLocale可能在某些平台下无法生效,可以尝试localeResolutionCallback强行指定默认的语言环境(这种方法相较稳定一些);
return MaterialApp(
localeResolutionCallback:
(Locale? locale, Iterable<Locale> supportedLocales) {
var result = supportedLocales
.where((element) => element.languageCode == locale?.languageCode);
if (result.isNotEmpty) {
print(locale?.languageCode);
// return locale;
return Locale('en');
}
return Locale('en');
},
//...其他
}
转载:https://blog.csdn.net/ifmylove2011/article/details/125797598