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

发布于 1周前 作者 h691938207 来自 Flutter

鉴于 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实现完整的国际化语言支持,满足全球用户的需求。

回到顶部