Flutter-多语言国际化

315 阅读5分钟

支持国际化

默认情况下,Flutter SDK中的组件仅提供美国英语本地化资源(主要是文本),要添加对其他语言的支持,应用程序必须添加一个名为"flutter_localiztions"的包依赖,然后还要在MaterialApp中进行一些配置。要使用flutter_localizations包,首先需要添加依赖到pubspec.yaml文件中:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

接下来,下载flutter_localiztions库,然后指定MaterialApp的localizationsDelegates和supportedLocals:

MaterialApp(
 localizationsDelegates: [
   // 本地化的代理类
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', 'US'), // 美国英语
    const Locale('zh', 'CN'), // 中文简体
    //其他Locales
  ],
  // ...
)

与MaterialApp类为入口的应用不同,对基于WidgetsApp类入口的应用程序进行国际化时,不需要GlobalMaterialLocalizations.delegate。

localizationsDelegates列表中的元素是本地化值集合的工厂类。 GlobalMaterialLocalizations.delegate为Material组件库提供的本地化的字符和其它值,它可以使Material组件支持多语言。GlobalWidgetsLocalizations.delegate定义组件默认的文本向,从左到右或从右到左,这是因为有些语言的阅读习惯不是从左到右,比如:阿拉伯、希伯来。

supportedLocales也接收一个Locale数组,表示应用支持的语言列表。

获取当前区域Locale

local类是用来标识用户的语言环境,包括语言和国家两个标识:

const Locale('zh', 'CN') // 中文简体

可以通过以下方式来获取应用的当前区域Locale:

Locale myLocale = Localizations.localeOf(context);

Localizations组件一般位于widget树中其它业务组件的顶部,它的作用是定义区域Locale以及设置子树依赖的本地化资源。如果系统语言环境发生变化,则会使用对应的本地化资源。

监听系统语言切换

当更改系统语言设置时,APP中的Localizations组件会重新构建, Localizations.localeOf(context)获取的Locale就会更新,最终界面会重新build达到切换语言的效果,但是这个过程是隐式完成的,并没有主动去监听系统语言切换,但是有时候需要在系统语言发生改变时做一些事情,比如系统语言切换为一种APP不支持的语言时,需要设置一个默认的语言,这时需要监听locale改变事件:

可以通过licaleResolutionCallback或localeListResolutionCallback回调来监听locale改变的事件,localeResolutionCallback的回调函数签名:

Locale Function(Locale locale, Iterable<Locale> supportedLocales)
  • local:当前的系统语言设置,当应用启动时或用户动态改变语言设置时,此locale即为系统的当前locale。当开发者手动置顶APP的locale时,那么此locale参数代表开发者指定的locale,此时将忽略系统locale如:
MaterialApp(
 ...
 locale: const Locale('en', 'US'), //手动指定locale
 ...
)

此时手动指定了应用locale为美国英语,指定后即使设备当前语言是中文简体,应用中locale也依然是美国英语。如果locale为null,则表示Flutter未能获取到设备的locale信息,所以在使用locale前需要判空。

  • supportedLocales为当前应用支持的locale列表,是开发者在MaterialApp中通过supportedLocales属性注册的
  • 返回值是一个locale,此locale为Flutter APP最终使用的locale,通常在不支持的语言区域时返回一个默认的Locale。

localeListResolutionCallback和localeResolutionCallback唯一的不同在第一个参数类型,前者接收一个locale列表,后者接收耽搁Locale

Locale Function(List<Locale> locales, Iterable<Locale> supportedLocales)

在Flutter中,应该优先使用localeListResolutionCallback,当然不必担心Android系统的差异性,如果在低版本的Android系统中,Flutter会自动处理这种情况,此时Locale列表只会包含一项。

Localization 组件

Localizations组件用于加载和查找应用当前语言下的本地化值或资源,应用程序通过Localizations.of(context, type)来引用这些对象。如果设备的Locale区域设置发生更改,则Localizations组件会自动加载新区域的Locale值,然后重新build使用(依赖)了它们的组件,原因是Localizations内部使用了InheritedWidget:当子组件的build函数引用了InheritedWidget时,会创建对InheritedWidget的隐式依赖关系,因此,当InheritedWidget发生更改时,即Localizations的Locale设置发生更改,将重新构建所有依赖它的子组件。

本地化值由Localizations的LocalizationsDelegates列表加载。每个委托必须定义一个异步的load()函数,以生成封装了一系列本地化值的对象。

在大型应用程序中,不同模块或Package可能会与自己的本地化值捆绑在一起,这就是为什么需要用Localizations管理对象表的原因。要使用由LocalizationsDelegate的load方法之一产生的对象,可以指定一个buildContext和对象的类型来找到它,Material组件库的本地化字符串由MaterialLocalizations类定义,此类的实例由MaterialApp类提供的LocalizationDelegate创建:

Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);

这个特殊的Localizations.of()表达式会经常使用,所以MaterialLocalizations类提供了一个便捷方法:

static MaterialLocalizations of(BuildContext context) {
  return Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);
}

// 可以直接调用便捷方法
tooltip: MaterialLocalizations.of(context).backButtonTooltip,

使用打包好的LocalizationsDelegates

为了尽可能小而简单,flutter软件包中仅提供美国英文值的MaterialLocalizations和WidgetsLocalizations接口的实现。这些实现类分别称为DefaultMaterialLocalizations和DefaultWidgetsLocalizations。flutter_localizations包含GlobalMaterialLocalizations和GlobalWidgetsLocalizations的本地化接口的多语言实现,国际化应用程序必须按照开头所说为这些类指定本地化代理。

GlobalMaterialLocalizations和GlobalWidgetsLocalizations只是Material组件库的本地化实现,如果要支持多语言,那么需要实现自己的Localizations。