Flutter 从 0 开始设计独立 APP | 第二篇:完整的国际化语言支持

鉴于 Flutter 高性能渲染和跨平台的优势,闪点清单在移动端 APP 上,使用了完整的 Flutter 框架来开发。既然是完整 APP,架构搭建完全不受历史 Native APP 的影响,没有历史包袱的沉淀,设计也能更灵活和健壮。

国际化语言的支持,是很多 APP 都有的一个强需求,APP 无论大小,只要还不想放弃国外的客户,一般就需要支持国际化。

flutter 国际化

官方支持

Flutter 官方方案提供了国际化的基础支持,如 Flutter 内置组件的国际化、语言代理、Widget 使用语言包、语言设置回调等,并支持自定义第三方类来扩展,可以参考 Flutter 国际化文档。 官方支持代码示例:

class DemoLocalizations {
  DemoLocalizations(this.locale);

final Locale locale;

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

static Map<String, Map<String, String>> _localizedValues = { ‘en’: { ‘title’: ‘Hello World’, }, ‘es’: { ‘title’: ‘Hola Mundo’, }, };

String get title { return _localizedValues[locale.languageCode][‘title’]; } }

官方方案的缺陷

官方的支持有几个缺陷:

  1. 依赖于 BuildContext 对象,在非 Widget 中调用时,需要层层传递 BuildContext 对象,或存储全局 BuildContext 对象。
  2. 在 MaterialApp 初始化前无法使用国际化(原因也是依赖于 BuildContext 对象)。
  3. 语言包定义推荐使用 Map 方式,无法利用静态语言的优势(语法提示、错误检查等);而为语言包每个属性自定义类和类字段,成本较高、使用和更新灵活性差。

i18n 介绍

鉴于 Flutter 官方支持的缺陷,我们调研了很多第三方库,最终发现了 i18n,并在此基础上、结合 Flutter 官方支持和自身封装,实现了更灵活易用的方案。

flutter 国际化

基础使用

i18n 使用 yaml 格式来定义语言包,同时提供构建脚本一键生成 Dart 语言包 Class 。如下:

lib/messages.i18n.yaml

button: save: Save load: Load users: welcome(String name): “Hello $name!” logout: Logout

该配置会生成几个 Class:Messages 、ButtonMessages 、UserMessages,生成后的 Dart 文件使用方式如下:

Messages m = Messages();
debugPrint(m.users.logout);
debugPrint(m.users.welcome('World'));

生成的 Dart 文件预览(开发时无需关心):

class Messages {
    const Messages();
    ButtonMessages get button => ButtonExampleMessages(this);
    UsersMessages get users => UsersExampleMessages(this);
}
class ButtonMessages {
    final Messages _parent;
    const ButtonMessages(this._parent);
    String get save => "Save";
    String get load => "Load";
}
class UsersMessages {
    final Messages _parent;
    const UsersMessages(this._parent);
    String get logout => "Logout";
    String welcome(String name) => "Hello $name!";
}

进阶功能

下面讲解一些进阶用法。

函数定义

i18n 支持函数定义,并支持传参,如上述的welcome函数:

debugPrint(m.users.welcome('World'));

参数定义基本没有限制,可以随意定义参数个数和类型。

内置函数

i18n 支持了一些内置函数,用于做不同语言解析的体验优化,如:plural 、cardinal 、ordinal 。具体规则和使用,可以参考这里: http://cldr.unicode.org/index/cldr-spec/plural-rules

使用 Dart 字符串模板

Dart 字符串模板是非常强大的,而在 i18n 中,你可以使用字符串模板(这点非常赞),如:

count(int cnt): "You have created $cnt ${_plural(cnt, one:'invoice', many:'invoices')}."

前置编译

i18n 依然依赖了 Dart 官方提供的 builder_runner 工具,来从 yaml 文件生成 Dart 文件,使用方式: flutter pub run build_runner build

flutter 国际化

语言包使用

前置编译后,每个语言包会生成 N 个 Class (语言包的每一个分类或组合会生成一个 Class 文件),然后会生成一个根 Class,我们可以直接使用根 Class (当然也可以使用任何一个分类层级的 Class )。

比如两个语言包文件: AppMessages.i18n.yamlAppMessages_en.i18n.yaml(未加语言后缀的,会认为是默认语言包,因此 AppMessages.i18n.yaml 是默认语言包),会生成 2 个根 Dart Class: class AppMessagesclass AppMessages_en extends AppMessages

AppMessages_en自动继承自AppMessages,因此我们可以直接使用AppMessages类型来存储语言包,并在语言切换时重新为其实例化对应的子类:

AppMessages appMessages = new AppMessages();

resetLocalLang(String localeName) { switch (localeName) { case ‘en’: appMessages = AppMessages_en(); break; case ‘zh’: default: appMessages = AppMessages(); break; } }

然后你可以在任意地方使用语言包:

debugPrint('Load Button: ${appMessages.button.load}');

FlatButton( child: Text(appMessages.button.save), onPressed: () { /// 干点什么 }, )

Flutter 集成

集成到 Flutter,依然要依赖于官方的支持,在 MaterialApp 中设置和监听本地语言包:

[@override](/user/override)
Widget build(BuildContext context) {
  return MaterialApp(
    localeResolutionCallback:
        (Locale locale, Iterable<Locale> supportedLocales) {
      /// Local changed
    },
    localizationsDelegates: [
      GlobalMaterialLocalizations.delegate,
      GlobalWidgetsLocalizations.delegate,
    ],
    supportedLocales: ['zh', 'en']
        .map((loc) => new Locale(loc))
        .toList(growable: false),
    /// ...
  );
}

结尾

国际化支持,是一个移动端 APP 框架层的基础能力,设计原则应该是使用无感知、灵活易扩展;但维护成本是难免有增加的,比如每次改文案要所有语言包同时更改。

讲到这里,还并没有完成基础框架的搭建,后面我们会讲解更多的 Flutter 架构设计内容,比如:通知、分享、UI 设计等等。


持续分享闪点清单在 Flutter 上的开发经验。闪点清单,一款悬浮清单软件:

闪点清单,一款悬浮清单软件


Flutter 从 0 开始设计独立 APP | 第二篇:完整的国际化语言支持

更多关于Flutter 从 0 开始设计独立 APP | 第二篇:完整的国际化语言支持的实战教程也可以访问 https://www.itying.com/category-92-b0.html

6 回复

有意向来头条么? https://v2ex.com/t/684705,

更多关于Flutter 从 0 开始设计独立 APP | 第二篇:完整的国际化语言支持的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


阿拉伯语言,可以支持么?从右到左

支持的

可以的

暂时还没有哇🤩

针对帖子“Flutter 从 0 开始设计独立 APP | 第二篇:完整的国际化语言支持”,以下是从IT技术专业的角度给出的回复:

Flutter作为高性能渲染和跨平台的开发框架,为独立APP的国际化语言支持提供了强有力的支持。实现Flutter应用的国际化,关键在于合理利用Flutter官方方案和第三方库。

Flutter官方方案提供了基础支持,如内置组件的国际化、语言代理等,但存在依赖于BuildContext对象、在MaterialApp初始化前无法使用国际化等缺陷。因此,在实际开发中,可以考虑结合第三方库如i18n来实现更灵活易用的国际化方案。

i18n使用yaml格式来定义语言包,支持函数定义和传参,内置了plural、cardinal、ordinal等函数用于优化不同语言的解析体验。同时,i18n还支持Dart字符串模板,使得语言包的定义和使用更加便捷。

在实现国际化时,需要注意以下几点:

  1. 确保为应用提供完整的翻译资源,覆盖所有需要支持的语言和区域。
  2. 在MaterialApp中正确配置支持的语言和本地化委托。
  3. 合理使用第三方库,如i18n,来优化国际化方案。

综上所述,通过合理利用Flutter官方方案和第三方库,我们可以为Flutter独立APP实现完整的国际化语言支持,满足全球用户的需求。

回到顶部