使用Intl包不仅可以非常轻松的实现国际化,而且可以将字符串文本分离成单独的文件,方便开发和翻译分工协作。
添加依赖:
dependencies:
#...省略无关项
intl: ^0.18.1
dev_dependencies:
#...省略无关项
intl_generator: ^0.4.1
intl_generator包主要包含了一些工具,在开发阶段主要作用是从代码中提取国际化的字符串到单独的arb文件和根据arb文件生成对应语言的dart代码,而intl包主要是引用和加载intl_generator生成后的代码。 需要注意的是,这里的版本如果和安装的插件Intl不一致可能会有冲突,最好和插件保持一致,插件的使用会更加的便捷。
创建必要目录
首先,在项目根目录创建一个I10n-arb目录,该目录保存接下来通过intl_generator命令生成的arb文件。样例如下:
{
"@@last_modified": "2018-12-10T15:46:20.897228",
"@@locale":"zh_CH",
"title": "Flutter应用",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
}
}
根据"@@locale"字段可以看出arb对应的中文件简体的翻译,里面的title字段对应的是应用标题的中文简体翻译。@title字段是对title的一些描述信息。
接下来,在lib目录下创建一个I10n目录,用于保存从arb文件生成的dart代码目录。
实现Localizations和Delegate类
使用intl包的一些方法实现Localizations和Delegate类。
class DemoLocalizations {
static Future<DemoLocalizations> load(Locale locale) {
final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
//2
return initializeMessages(localeName).then((b) {
Intl.defaultLocale = localeName;
return DemoLocalizations();
});
}
static DemoLocalizations of(BuildContext context) {
return Localizations.of<DemoLocalizations>(context, DemoLocalizations);
}
String get title {
return Intl.message(
'Flutter APP',
name: 'title',
desc: 'Title for the Demo application',
);
}
}
//Locale代理类
class DemoLocalizationsDelegate extends LocalizationsDelegate<DemoLocalizations> {
const DemoLocalizationsDelegate();
//是否支持某个Local
@override
bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode);
// Flutter会调用此类加载相应的Locale资源类
@override
Future<DemoLocalizations> load(Locale locale) {
//3
return DemoLocalizations.load(locale);
}
// 当Localizations Widget重新build时,是否调用load重新加载Locale资源.
@override
bool shouldReload(DemoLocalizationsDelegate old) => false;
}
- 注释1:messages_all.dart文件是通过intl_generator工具从arb文件生成的代码,刚开始并没有,运行命令后会生成,后面会介绍使用插件生成,注释2:initializaMessages函数也是生成的。
- 注释3:直接使用
DemoLocalizations.load()
即可。
添加国际化属性
Intl库提供了一些方法,这些方法可以帮助我们轻松实现不同语言的一些语法特性,比如复数语境。
intl_generator工具中来提取代码中的字符串到一个arb文件,运行如下命令:
flutter pub pub run intl_generator:extract_to_arb --output-dir=l10n-arb \ lib/l10n/localization_intl.dart
根据arb生成dart文件:
flutter pub pub run intl_generator:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/localization_intl.dart l10n-arb/intl_*.arb
可以将两个命令写进脚本中intl.sh 中,记得给脚本权限
//权限
chmod +x intl.sh
//脚本执行
./intl.sh
上面主要是讲述Intl的原理和一些实现思想,下面介绍,如何使用Intl插件来实现国际化:
- 打开Android Studio——》Preference——》Plugins——》Marketplace——》输入Intl,点击Install。
- 静待安装,安装好后,看下Installed中是否存在。
- 回到编码界面,选择——》Tools——》Flutter Intl——》Ininialize for the Project
- 静待界面中出现generated 和 I10n文件夹。
- 默认I10n文件中有intl_en.arb,在此文件中编写你想要添加的国家化字段,格式如下:
{
"@@last_modified": "2018-12-10T17:37:28.505088",
"title": "Flutter APP",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
},
//带变量字段
"remainingEmailsMessage": "{howMany,plural, =0{There are no emails left}=1{There is {howMany} email left}other{There are {howMany} emails left}}",
"@remainingEmailsMessage": {
"description": "How many emails remain after archiving.",
"type": "text",
"placeholders": {
"howMany": {
}
}
},
"Main_message": "Message",//常规字段
"Main_setting": "Setting",
"Main_home": "Home"
}
使用:
class SSLTestLocalizationsState extends State<SSLTestLocalizations>{
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: const Text("SSL Test Localization")
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: (){
Locale temLocal = Localizations.localeOf(context);//实际只能切换一次,因为系统语言没有改变,如果想内部随意切换应保存内部语言然后再切换
debugPrint("current ${temLocal.languageCode}");
if (temLocal.languageCode == "zh"){
temLocal = const Locale("en");
}else{
temLocal = const Locale("zh");
S.load(const Locale("zh"));
}
setState(() {
S.load(temLocal);
});
},
child: Text(S.of(context).Main_message)
),
Text(S.of(context).remainingEmailsMessage(10)),
Text(S.of(context).remainingEmailsMessage(1)),
Text(S.of(context).remainingEmailsMessage(2)),
Text(S.of(context).remainingEmailsMessage(0)),
],
),
),
);
}
}
效果: