借助App Store与Google Play,全世界任何一个国家的使用者都可以使用我们开发的应用,不过由于应用的使用者来自不同国家,所以在应用正式上架之前需要让应用能够支持多种语言,即应用的国际化。
在Flutter开发中,应用的国际化主要涉及语言和地区差异性配置两个方面,它们是应用程序的组成部分之一。关于语言的国际化比较好理解,而地区差异性配置指的是根据国家风俗的不同进行的差异性配置。按照Flutter官方的适配方案,要在Flutter应用中实现语言的国际化,需要经过以下几步。
可以发现,如果直接按照官方提供的国际化方案来进行应用适配,不仅工作量大而且极易出错。为了达到快速适配,减少代码编写造成的错误,可以使用Android Studio提供的Flutter i18n国际化插件。如果还没有安装Flutter i18n插件,可以打开Android Studio,然后依次选择【Preference】→【Plugins】→【Marketplace】搜索Flutter i18n插件进行安装,如下图所示。
安装完成之后,重启Android Studio就可以使用它进行Flutter的国际化适配了。需要说明的是,由于最新版的Android Studio已经不支持使用应用市场的方式来安装Flutter i18n插件,所以需要先从Jetbrains官网下载后再从本地进行安装,如下图所示。
由于Flutter i18n插件需要依赖flutter_localizations插件包,所以执行国际化适配之前,还需要在pubspec.yaml文件中添加flutter_localizations依赖,如下所示。
dependencies: flutter_localizations: sdk: flutter
在命令行中使用flutter packages get命令拉取依赖。然后,在项目的根目录下会自动生成一个res文件夹,该文件夹默认会包含一个strings_en.arb文件,arb文件的格式如下。
{ "app_name": "Flutter App internationalization", "main_title": "Flutter i18n", "main_content" : "You have click the button many times" }
arb文件是JSON格式的配置文件,可以用来存放文案标识符和文案翻译的键值对。事实上,这种将字符串文本分离成单独文件的做法,可以方便开发人员和翻译人员分工协作,从而提高适配效率。
默认情况下,系统只会生成英文资源配置strings_en.arb文件,如果要支持中文,则需要使用手动的方式在values目录下增加一个strings_zh.arb文件。在res/values文件夹上右键,然后依次选择【New】→【Arb File】→【Choose language】创建一个名为strings_zh.arb的arb文件,并添加如下内容。
{ "app_name": "Flutter应用国际化", "main_title": "Flutter国际化", "main_content" : "点击按钮次数: $count" }
实际使用时,只需要修改res/values目录下的arb文件内容,i18n插件就会自动生成对应的Dart转换代码,如下图所示。
需要说明的是,由于i18n.dart文件的代码是由插件自动生成的,所以不要手动修改里面的内容。接下来,还需要在应用程序的入口,即MaterialApp中设置国际化所需的两个重要参数localizationsDelegates与supportedLocales,如下所示。
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate ], supportedLocales: S.delegate.supportedLocales, home: MyHomePage(title: '本地化'), ); } }
其中,localizationsDelegates表示应用程序的翻译回调,supportedLocales表示应用所支持的语言地区属性,而S.delegate则是Flutter i18n插件自动生成的类,包含Flutter所支持的语言地区属性以及对应的文案翻译映射。在上面的代码中,除了加入S.delegate外,还加入了GlobalMaterialLocalizations.delegate和GlobalWidgetsLocalizations.delegate这两个回调。
前者为Material组件库提供的本地化的字符串和其他值,它可以使组件支持多语言,而后者则是用于定义组件默认的文本方向,从左到右或从右到左。之所以要加入这两个回调,是因为Flutter提供的组件本身已经支持了国际化,所以没必要再适配一遍。而参数supportedLocales则用于表示应用所支持的语言地区,它的格式如下。
const Locale('zh', 'CN') //中文简体
其中,Locale类是用来标识用户语言环境的,它由语言和国家两个属性构成。在上面的代码中,我们将它设置成S.delegate.supportedLocales,即当前设备的语言。完成上述应用程序的国际化配置操作后,接下来就可以在程序中通过S.of(context)方式获取arb文件中的内容了。下面是使用S.of(context)方式获取arb文件中标题名字的例子,如下所示。
S.of(context).main_title //获取标题
需要说明的是,使用上面的方式获取翻译文案的内容需要在能获取到上下文的前提下才能生效,也就是说只能对MaterialApp的子组件才会生效。因此,如果要对应用的标题进行国际化配置,直接使用上面的方式是不行的,不过可以使用MaterialApp提供的onGenerateTitle回调方法来进行处理,如下所示。
onGenerateTitle: (context) { return S.of(context).app_name; },
对于应用界面文案的国际化则要相对简单许多,直接使用S.of(context)方式拿到arb文件中翻译文案,然后设置到界面即可。下面是对Flutter官方工程的国际化处理,代码如下。
Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(S.of(context).main_title), centerTitle: true, ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text(S.of(context).main_content), Text('$_counter', style: Theme.of(context).textTheme.display1), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); }
接下来,切换系统中的英文和中文,然后运行上面的代码,可以看到,应用的内容会随着系统的语言进行切换,效果下图所示。
不过,由于iOS应用程序有一套自建的语言环境管理机制,所以使用上面的方式适配国际化对于iOS应用程序是无效的。为了让iOS应用程序也能支持国际化,还需要在原生iOS工程中进行额外的配置。
使用Xcode打开Flutter项目的iOS原生工程,切换到工程面板,然后在Localization选项配置中添加中文支持,如下图所示。
完成上述iOS原生工程配置后,再次回到Flutter工程,选择iOS模拟器运行程序,就可以看到可以正常的支持国际化了,如下图所示。
可以发行,国际化的核心就是语言差异配置抽取。与Flutter的国际化处理方式不同,原生Android和iOS应用适配国际化只需要按照要求将国际化资源放到对应的文件夹目录,然后应用层代码访问国际化资源时就会自动根据语言地区进行适配。