目录

  • 引言
  • 系统控件的多语言配置
    • yaml文件的配置
    • app增加多语言配置
    • 对app的改写
  • 自定义文本的多语言配置

引言

国际化(Localization)对于app来说是一个非常常见的需求。得益于flutter的StatefulWidge,实时切换app的语言环境是非常简单的。

flutter的Localization包含两个部分,预设控件的Localization配置以及自定义文本的Localization配置。

系统控件的多语言配置

flutter自带很多预设的控件,这些控件使用到的文本是可以根据app设定的语言环境来展示相应的语言文本的。默认的情况下,这些控件使用的是英文文案,即使你的手机系统是中文环境,flutter的控件仍然展示的是英文文案。

举个例子,我们使用flutter的DatePicker来演示一下:

import 'package:flutter/material.dart';
import 'widget/DemoWidget.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(// ignore: non_constant_identifier_namestitle: "test",theme: ThemeData(// This is the theme of your application.//// Try running your application with "flutter run". You'll see the// application has a blue toolbar. Then, without quitting the app, try// changing the primarySwatch below to Colors.green and then invoke// "hot reload" (press "r" in the console where you ran "flutter run",// or simply save your changes to "hot reload" in a Flutter IDE).// Notice that the counter didn't reset back to zero; the application// is not restarted.primarySwatch: Colors.blue,),home: DemoWidget(),);}
}

main.dart

import 'package:flutter/material.dart';class DemoWidget extends StatelessWidget {@overrideWidget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: new Text('Demo页面'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Text(Localizations.localeOf(context).toString()),MaterialButton(child: Text('选择时间'),color: Colors.grey,onPressed: () {showDatePicker(context: context,initialDate: DateTime.now(),firstDate: DateTime(2018),lastDate: DateTime(2030));},),],),),);}
}

demoWidget.dart

我们先确认一下系统的语言设置确实是中文的:

然后我们看一下运行结果:


可以看见,即使系统的语言是中文的,由于没有在flutter app中配置多语言支持,预设控件使用的语言仍然默认为英文。

要使预设控件使用的语言与系统的语言保持一致,我们需要进行如下配置:

yaml文件的配置

首先我们需要在pubspec.yaml文件中的dependencies下,增加flutter_localizations的配置,修改之后在terminal执行一下flutter packages get,或者在android studio的yaml文件右上角直接点击Packages get按钮。

denpendencies:flutter:sdk: flutter# 以下是新增部分flutter_loclizations:sdk: flutter

app增加多语言配置

在main.dart中增加import项

import 'package:flutter_localizations/flutter_localizations.dart';

并且为MaterialApp的构造函数增加localizationsDelegatessupportedLocales参数的赋值。

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';import 'widget/demoWidget.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(// ignore: non_constant_identifier_namestitle: "test",theme: ThemeData(// This is the theme of your application.//// Try running your application with "flutter run". You'll see the// application has a blue toolbar. Then, without quitting the app, try// changing the primarySwatch below to Colors.green and then invoke// "hot reload" (press "r" in the console where you ran "flutter run",// or simply save your changes to "hot reload" in a Flutter IDE).// Notice that the counter didn't reset back to zero; the application// is not restarted.primarySwatch: Colors.blue,),home: DemoWidget(),/*=====以下为新增部分========*/localizationsDelegates: [GlobalMaterialLocalizations.delegate,GlobalWidgetsLocalizations.delegate,],supportedLocales: [Locale('zh', 'CH'), Locale('en', 'US')],/*=====以上为新增部分========*/);}
}

supportedLocales这个参数很好理解,我们看一下localizationsDelegates这个参数的注释:

  /// Internationalized apps that require translations for one of the locales/// listed in [GlobalMaterialLocalizations] should specify this paramter/// and list the [supportedLocales] that the application can handle.

意思是说国际化的(在GlobalMaterialLocalization支持的语言范围内的)的app需要指定这个参数,并且需要同时指定supportedLocales这个参数。

跟踪localizationsDelegates这个参数,发现它一路传递到了Localizations这个类里。

MaterialApp#localizationsDelegate
_MaterialAppState#_localizationsDelegates
WidgetApp#localizationsDelegates
_WidgetsAppState#_localizationsDelegates
Localizations#delegates

Localizations是一个StatefulWidget,我们可以在_LocalizationsStatevoid load(Locale locale)方法中看到这个类对Delegates的初始化和使用。

  @overridevoid initState() {super.initState();load(widget.locale);}@overridevoid didUpdateWidget(Localizations old) {super.didUpdateWidget(old);if (widget.locale != old.locale|| (widget.delegates == null && old.delegates != null)|| (widget.delegates != null && old.delegates == null)|| (widget.delegates != null && _anyDelegatesShouldReload(old)))load(widget.locale);}void load(Locale locale) {final Iterable<LocalizationsDelegate<dynamic>> delegates = widget.delegates;if (delegates == null || delegates.isEmpty) {_locale = locale;return;}Map<Type, dynamic> typeToResources;final Future<Map<Type, dynamic>> typeToResourcesFuture = _loadAll(locale, delegates).then<Map<Type, dynamic>>((Map<Type, dynamic> value) {return typeToResources = value;});if (typeToResources != null) {// All of the delegates' resources loaded synchronously._typeToResources = typeToResources;_locale = locale;} else {// - Don't rebuild the dependent widgets until the resources for the new locale// have finished loading. Until then the old locale will continue to be used.// - If we're running at app startup time then defer reporting the first// "useful" frame until after the async load has completed.WidgetsBinding.instance.deferFirstFrameReport();typeToResourcesFuture.then<void>((Map<Type, dynamic> value) {WidgetsBinding.instance.allowFirstFrameReport();if (!mounted)return;setState(() {_typeToResources = value;_locale = locale;});});}}

结合我们对StatefulWidget生命周期的理解,至此我们已经知道flutter是如何去初始化Delegates和更新他的locale的了。具体如何去绑定资源的我们不再深入去看。

GlobalMaterialLocalizations这个类点进去看,可以知道它是提供了一些预设控件的多语言文案,而GlobalWidgetsLocalizations点进去看,则可以看到它是对文本排列是从左到右还是从右到左作了支持。由于文本排列从右到左的语言只有阿拉伯语、希伯来语、波斯语、普图什语和乌尔都语,如果你的app不支持这些语言的话,这个参数可以不添加也没关系。

对app的改写

由于我们需要对app的语言环境进行切换,也就意味着app是要保存当前选择的语言状态的,所以我们的app应该使用StatefulWidget来保存以及更新它的状态。

main.dart中找到你的app类,将你的app类改为继承自StatefulWidget,并且创建它的State类:

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';import 'widget/demoWidget.dart';void main() => runApp(MyApp());class MyApp extends StatefulWidget {@overrideState<StatefulWidget> createState() {return AppState();}
}class AppState extends State<MyApp> {Locale _locale;List<Locale> supportedLocales = [Locale('zh', 'CH'), Locale('en', 'US')];void changeLocale(Locale locale) {if (supportedLocales.map((locale) {return locale.languageCode;}).toSet().contains(locale?.languageCode)) {setState(() {_locale = locale;});}}@overrideWidget build(BuildContext context) {return MaterialApp(// ignore: non_constant_identifier_namestitle: "myApp",locale: _locale,theme: ThemeData(// This is the theme of your application.//// Try running your application with "flutter run". You'll see the// application has a blue toolbar. Then, without quitting the app, try// changing the primarySwatch below to Colors.green and then invoke// "hot reload" (press "r" in the console where you ran "flutter run",// or simply save your changes to "hot reload" in a Flutter IDE).// Notice that the counter didn't reset back to zero; the application// is not restarted.primarySwatch: Colors.blue,),home: DemoWidget(),localizationsDelegates: [GlobalMaterialLocalizations.delegate,GlobalWidgetsLocalizations.delegate,],supportedLocales: supportedLocales,);}
}

这样一来,每当我们调用app的changeLocale方法,更新MaterialApplocale属性,app就会将其语言更新为新的语言并且更新整个widget树。

自定义文本的多语言配置

通过上面的步骤我们可以知道,每当我们通过setState方法改变MaterialApplocale,会触发Widget的更新。因此我们可以写一个我们自己的LocalizationsDelegate,将其赋值到MaterialApplocalizationsDelegates参数中即可。下面我们来按照GlobalWidgetsLocalizations仿写一下。

class GlobalWidgetsLocalizations implements WidgetsLocalizations {/// Creates an object that provides localized resource values for the/// lowest levels of the Flutter framework.////// This method is typically used to create a [LocalizationsDelegate]./// The [WidgetsApp] does so by default.static Future<WidgetsLocalizations> load(Locale locale) {return SynchronousFuture<WidgetsLocalizations>(GlobalWidgetsLocalizations(locale));}......static const LocalizationsDelegate<WidgetsLocalizations> delegate = _WidgetsLocalizationsDelegate();
}
class _WidgetsLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {const _WidgetsLocalizationsDelegate();@overridebool isSupported(Locale locale) => true;@overrideFuture<WidgetsLocalizations> load(Locale locale) => GlobalWidgetsLocalizations.load(locale);@overridebool shouldReload(_WidgetsLocalizationsDelegate old) => false;@overrideString toString() => 'GlobalWidgetsLocalizations.delegate(all locales)';
}

参照GlobalWidgetsLocalizations,我们新建一个Translations.dart,在内声明Translations类和_TranslationsDelegate类,

import 'dart:async';import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';class Translations {Locale _locale;// 多语言文本资源,为了演示上的方便,将文本资源放到这个map里。// 实际工程中可以将资源放到本地的文件中,通过rootBundle去加载。// 也可以将资源放到服务器上,通过网络请求加载。Map<String, Map<String, String>> _resourceMap = {'zh': {'btnTextZh': '中文文案','pageTitle': '演示页面','btnTextEn': '英文文案'},'en': {'btnTextZh': 'lang:zh','pageTitle': 'demo page','btnTextEn': 'lang:en'},};Translations(this._locale);String text(textKey) {return _resourceMap[_locale.languageCode][textKey];}static Translations of(BuildContext context) {return Localizations.of<Translations>(context, Translations);}// 加载资源的方式。// 可以看到这个方法返回的类型是一个Future// 因为我们可以将多语言文本资源放到服务端或者本地文件里,// 因此加载多文本资源可能是耗时的,所以这里返回的类型是Future// 这里为了演示上的方便,将文本资源直接硬编码到代码里了。static Future<Translations> load(Locale locale) async {return SynchronousFuture<Translations>(Translations(locale));}static const _TranslationDelegate delegate = _TranslationDelegate();
}class _TranslationDelegate extends LocalizationsDelegate<Translations> {const _TranslationDelegate();@overridebool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode);@overrideFuture<Translations> load(Locale locale) => Translations.load(locale);@overridebool shouldReload(LocalizationsDelegate<Translations> old) => false;
}

在使用的地方,我们可以通过Translations类的of方法获取Translations类的实例。为了方便我们修改AppStateLocale,我们在AppState中设置一个static的变量供我们使用。当然,这只是为了演示上的方便,实际工程中我们可以使用单例,或者使用flutter-redux来保存app的状态。

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';import 'localization/translations.dart';
import 'widget/demoWidget.dart';void main() => runApp(MyApp());class MyApp extends StatefulWidget {@overrideState<StatefulWidget> createState() {return AppState();}
}class AppState extends State<MyApp> {// 供外部使用的_AppSetting实例,用于修改app的状态static _AppSetting setting = _AppSetting();@overridevoid initState() {super.initState();setting.changeLocale = (Locale locale) {if (setting.supportedLocales.map((locale) {return locale.languageCode;}).toSet().contains(locale?.languageCode)) {setState(() {setting._locale = locale;});}};}@overrideWidget build(BuildContext context) {return MaterialApp(// ignore: non_constant_identifier_namestitle: "myApp",locale: setting._locale,theme: ThemeData(// This is the theme of your application.//// Try running your application with "flutter run". You'll see the// application has a blue toolbar. Then, without quitting the app, try// changing the primarySwatch below to Colors.green and then invoke// "hot reload" (press "r" in the console where you ran "flutter run",// or simply save your changes to "hot reload" in a Flutter IDE).// Notice that the counter didn't reset back to zero; the application// is not restarted.primarySwatch: Colors.blue,),home: DemoWidget(),localizationsDelegates: [// 不要忘了将Translates.delegate添加到localizationsDelegates的列表中Translations.delegate,GlobalMaterialLocalizations.delegate,GlobalWidgetsLocalizations.delegate,],supportedLocales: setting._supportedLocales,);}
}class _AppSetting {_AppSetting();Null Function(Locale locale) changeLocale;Locale _locale;List<Locale> _supportedLocales = [Locale('zh', 'CH'), Locale('en', 'US')];
}

此外我们再新建一个演示页面来演示app内的语言环境切换:

import 'package:demoApp/localization/translations.dart';
import 'package:demoApp/main.dart';
import 'package:flutter/material.dart';class DemoWidget extends StatelessWidget {@overrideWidget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text(Translations.of(context).text("pageTitle")),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [MaterialButton(child: Text(Translations.of(context).text('btnTextZh')),color: Colors.grey,onPressed: () {AppState.setting.changeLocale(Locale('zh'));}),MaterialButton(child: Text(Translations.of(context).text('btnTextEn')),color: Colors.grey,onPressed: () {AppState.setting.changeLocale(Locale('en'));})],),),);}
}


至此我们已经完成了flutter app的国际化配置。

Flutter的国际化方式相关推荐

  1. Flutter 语言国际化状态管理

    Flutter语言国际化,手动切换App语言 1.配置字体文件:custom_localization.dart import 'dart:async';import 'package:flutter ...

  2. Flutter - International 国际化,Localization 本地化, 使用Intl

    新建项目,得到一个示例工程.本例中使用intl包来管理文字资源. 项目地址: https://github.com/RustFisher/localization_demo 步骤: 添加依赖项 - i ...

  3. Flutter网络请求方式总结

    转载于:https://www.jianshu.com/p/59fc5ed37453 前言 编写一个 App,最离不开的就是网络请求了.在Android 原生中,网络请求库一直在更新,网络请求库甚多: ...

  4. 浅谈Flutter跨平台调用方式MethodChannel

    Flutter是目前非常流行的跨平台方案,由于它的性能接近于原生应用,因而被越来越多的开发者所采用.既然是跨平台方案,那么久必然存在调用系统功能的需求,在Flutter中,Flutter层与nativ ...

  5. flutter 关于国际化l10n失效问题

    前言 在flutter开发过程中,可能下载他人的demo,而demo中有做国际化,在第一次运行的时候可能发现l10n不生效的问题: import 'package:flutter_learning/g ...

  6. Flutter之国际化多语言

    1.用多个文件来配各个国家的语言: 在lib 文件夹中创建新文件夹名为locale,目前文件配置支持中文和美文: lib/locale/i18n_zh.json lib/locale/i18n_en. ...

  7. 国际象棋ai下载_国际象棋AI的解剖

    国际象棋ai下载 Chess-playing programs made their grand debut in the 50's. They were unsurprisingly fairly ...

  8. Flutter实践:深入探索 flutter 中的状态管理方式(1)

    利用 Flutter 内置的许多控件我们可以打造出一款不仅漂亮而且完美跨平台的 App 外壳,我利用其特性完成了类似知乎App的UI界面,然而一款完整的应用程序显然不止有外壳这么简单.填充在外壳里面的 ...

  9. flutter 全选_Flutter ios 国际化(复制粘贴 中英文切换等问题)

    前提 在做flutter ios 国际化的时候遇到长按文本框崩溃的问题,然后google到一堆写法是重写cupertinoLocalization的奇怪做法,然后还千篇一律都是这么改的,其实不用那么麻 ...

最新文章

  1. spring MVC做form提交Neither BindingResult nor plain target object for bean name 'command' available...
  2. spring中Converter如何注入的
  3. asp.net中此页的状态信息无效,可能已损坏的解决之道
  4. SQLServer之事务简介
  5. 第五章(1)Libgdx应用框架之生命周期
  6. pom.xml中依赖的optionaltrue/optional标签
  7. Linux 部分命令无法使用-bash: /usr/bin/*: Permission denied
  8. Docker:(四)docker网络模式
  9. 2年前端 杭州 面试 集合 面经 前端
  10. 计算机领域顶级会议列表
  11. gulp压缩html
  12. linux内top命令,Linux中的top命令的详细解释
  13. 请将磁盘插入“U盘(F)“
  14. 智禾教育:淘宝店铺的常见类型有哪些,智禾为你分享介绍
  15. 解密刷子是如何进行APP刷量的?
  16. 删除 Windows 的默认打开方式
  17. vue+高德地图实现地图搜索及点击定位
  18. linux生成随机数
  19. ch340c(cH340C与8266)
  20. 网站建设服务办理增值电信业务经营许可证

热门文章

  1. 正弦函数及其FFT变换(一)
  2. remove 删除文件
  3. 【小龙女陈妍希古装Win7主题】
  4. 查看飞信隐身是可以做到的。而且很简单。
  5. Python多线程多进程、异步、异常处理等高级用法
  6. FEMTO-ST轴承数据集(IEEE PHM 2012 Challenge)
  7. 基于Java日程表系统的设计与实现
  8. 计算机毕业设计 SSM驾校预约培训管理系统(源码+论文)
  9. 在系统启动时至少一个服务或驱动程序产生错误 hwinfo32
  10. 10kv电缆为什么要做耐压试验? 有什么意义吗?