<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Flutter 實(shí)戰(zhàn)】國際化及App 內(nèi)切換語言功能

          共 8726字,需瀏覽 18分鐘

           ·

          2020-11-23 13:24

          老孟導(dǎo)讀:本文介紹如何實(shí)現(xiàn)國際化以及實(shí)現(xiàn) App 內(nèi)切換語言功能。

          使App支持國際化

          當(dāng)應(yīng)用程序支持不同語言的時候,就需要對應(yīng)用程序進(jìn)行國際化,當(dāng)然國際化不僅僅指文字,也可以是布局圖片等。Flutter 已經(jīng)提供了組件來實(shí)現(xiàn)國際化,下面是實(shí)現(xiàn)國際化的步驟:

          MaterialApp.supportedLocales 中添加支持的語言:

          MaterialApp(
          ??title:?'Flutter?IntlApp',
          ??supportedLocales:?[
          ????const?Locale('zh'),
          ????const?Locale('en'),
          ??],
          ??...
          )

          比如上面的代碼中,只支持英文和中文。

          根據(jù)不同的語言獲取不同的資源:

          class?AppLocalizations?{
          ??final?Locale?locale;

          ??AppLocalizations(this.locale);

          ??static?AppLocalizations?of(BuildContext?context)?{
          ????return?Localizations.of(context,?AppLocalizations);
          ??}

          ??static?Map<String,?Map<String,?String>>?_localizedValues?=?{
          ????'en':?{
          ??????'title':?'Hello?World',
          ????},
          ????'zh':?{
          ??????'title':?'你好',
          ????},
          ??};

          ??String?get?title?{
          ????return?_localizedValues[locale.languageCode]['title'];
          ??}
          }

          這里只設(shè)置了一個文案,實(shí)際項(xiàng)目中建議不同語言存放在不同的文件中。

          設(shè)置用于加載語言的 Delegate

          class?AppLocalizationsDelegate?extends?LocalizationsDelegate<AppLocalizations>?{
          ??const?AppLocalizationsDelegate();

          ??@override
          ??bool?isSupported(Locale?locale)?=>?['en',?'zh'].contains(locale.languageCode);

          ??@override
          ??Future?load(Locale?locale)?{
          ????return?SynchronousFuture(AppLocalizations(locale));
          ??}

          ??@override
          ??bool?shouldReload(AppLocalizationsDelegate?old)?=>?false;
          }

          將此 Delegate 添加到 MaterialApp:

          MaterialApp(
          ??title:?'Flutter?IntlApp',
          ??localizationsDelegates:?[
          ????AppLocalizationsDelegate(),
          ??],
          ??supportedLocales:?[
          ????const?Locale('zh'),
          ????const?Locale('en'),
          ??],
          ??home:?_HomePage(),
          )

          使用:

          Scaffold(
          ??????body:?Column(
          ????????mainAxisAlignment:?MainAxisAlignment.center,
          ????????children:?[
          ??????????Text('國際化:${AppLocalizations.of(context).title}'),
          ?????????],
          ??????????),
          ????????],
          ??????),
          ????)

          注意:Scaffold 不要添加 AppBar 數(shù)據(jù),否則報錯,具體原因下面會給出。

          重點(diǎn)是這句:

          AppLocalizations.of(context).title

          此時,App會根據(jù)系統(tǒng)語言作為當(dāng)前的語言。

          系統(tǒng)是如何實(shí)現(xiàn)國際化的?

          Flutter 的國際化是通過 Localizations 組件實(shí)現(xiàn),上面沒有用到 Localizations 組件啊,是的,App 中并沒有直接使用,因?yàn)?MaterialApp 內(nèi)部封裝了此組件,通過 DevTools 可以查看:

          Localizations 組件用于加載本地化資源、獲取系統(tǒng)語言,Localizations 組件內(nèi)部使用了 InheritedWidget 組件,當(dāng)其屬性即 Locale 發(fā)生變化時,其子組件將重建。

          上面定義的 AppLocalizations 類內(nèi)部的 of 方法:

          static?AppLocalizations?of(BuildContext?context)?{
          ??return?Localizations.of(context,?AppLocalizations);
          }

          Localizations.of 源代碼:

          這段代碼是獲取 Type 類型(App 傳入的類型為 AppLocalizations)的資源,看一下 resourcesFor 的源代碼:

          關(guān)鍵在 _typeToResources :

          _typeToResources 是一個 Map 類型, _typeToResources 初始化數(shù)據(jù)的:

          widget.delegates 的類型是:

          ///?This?list?collectively?defines?the?localized?resources?objects?that?can
          ///?be?retrieved?with?[Localizations.of].
          final?Listdynamic>>?delegates;

          是否還記得 MaterialApp localizationsDelegates 屬性,此 delegates 就是在 MaterialApp 中設(shè)置的值,到此我們理解了

          Localizations.of(context,?AppLocalizations)

          這句是如何獲取 AppLocalizations 實(shí)例的,當(dāng)然中間還有一些其他的判斷,具體可自行查看源代碼。

          添加系統(tǒng)國際化支持

          前面說到 Scaffold 不要添加 AppBar 數(shù)據(jù),否則報錯,填上看其異常信息:

          Scaffold(
          ??????appBar:?AppBar(),
          ??????body:?Column(
          ????????mainAxisAlignment:?MainAxisAlignment.center,
          ????????children:?[
          ??????????Text('國際化:${AppLocalizations.of(context).title}'),
          ????????],
          ??????),
          ????)

          上面的異常效果不明顯,看控制臺的異常信息:

          提示 MaterialLocalizations 找不到,MaterialLocalizations 是什么呢?其實(shí)它是系統(tǒng)組件的國際化資源,所以修復(fù)以上異常的方法是引入 MaterialLocalizations,在pubspec.yaml文件中添加包依賴:

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

          MaterialApp 修改如下:

          MaterialApp(
          ??title:?'Flutter?IntlApp',
          ??localizationsDelegates:?[
          ????AppLocalizationsDelegate(),
          ????GlobalMaterialLocalizations.delegate,
          ????GlobalWidgetsLocalizations.delegate,
          ????GlobalCupertinoLocalizations.delegate,
          ??],
          ??supportedLocales:?[
          ????const?Locale('zh'),
          ????const?Locale('en'),
          ??],
          ??home:?_HomePage(),
          )

          flutter_localizations 99%的概率會引入,但我們要知道這個并不是必須的。

          添加應(yīng)用程序 title 國際化

          按照上面的方式國際化:

          MaterialApp(
          ??title:?'${AppLocalizations.of(context).title}',
          ??localizationsDelegates:?[
          ????AppLocalizationsDelegate(),
          ????GlobalMaterialLocalizations.delegate,
          ????GlobalWidgetsLocalizations.delegate,
          ????GlobalCupertinoLocalizations.delegate,
          ??],
          ??supportedLocales:?[
          ????const?Locale('zh'),
          ????const?Locale('en'),
          ??],
          ??home:?_HomePage(),
          )

          直接異常了,因?yàn)榇藭r使用的 context 是從 build 方法中傳入的,而 Localizations 從 context 開始向上查找,國際化資源是在 MaterialApp 組件中的,所以無法找到 AppLocalizations。

          修改方式是使用 onGenerateTitle:

          MaterialApp(
          ??onGenerateTitle:?(context)?{
          ????return?AppLocalizations.of(context).title;
          ??},
          ??localizationsDelegates:?[
          ????AppLocalizationsDelegate(),
          ????GlobalMaterialLocalizations.delegate,
          ????GlobalWidgetsLocalizations.delegate,
          ????GlobalCupertinoLocalizations.delegate,
          ??],
          ??supportedLocales:?[
          ????const?Locale('zh'),
          ????const?Locale('en'),
          ??],
          ??home:?_HomePage(),
          )

          系統(tǒng)語言為英文:

          系統(tǒng)語言為中文:

          此方法只在 Android 上有效,iOS 上沒有效果。

          設(shè)置默認(rèn)語言

          如果 App 僅支持英文和中文,其他系統(tǒng)的語言也默認(rèn)使用中文:

          MaterialApp(
          ??onGenerateTitle:?(context)?{
          ????return?AppLocalizations.of(context).title;
          ??},
          ??localeResolutionCallback:
          ??????(Locale?locale,?Iterable?supportedLocales)?{
          ????var?result?=?supportedLocales
          ????????.where((element)?=>?element.languageCode?==?locale.languageCode);
          ????if?(result.isNotEmpty)?{
          ??????return?locale;
          ????}
          ????return?Locale('zh');
          ??},
          ??localizationsDelegates:?[
          ????AppLocalizationsDelegate(),
          ????GlobalMaterialLocalizations.delegate,
          ????GlobalWidgetsLocalizations.delegate,
          ????GlobalCupertinoLocalizations.delegate,
          ??],
          ??supportedLocales:?[
          ????const?Locale('zh'),
          ????const?Locale('en'),
          ??],
          ??home:?_HomePage(),
          )

          localeResolutionCallback 回調(diào)中 locale 參數(shù)表示當(dāng)前系統(tǒng)語言,supportedLocales 表示支持的語言,即 MaterialApp.supportedLocales 設(shè)置的值。

          通過這兩個參數(shù)判斷當(dāng)然系統(tǒng)語言是否在支持的范圍內(nèi),如果支持則返回系統(tǒng)語言,不支持則返回默認(rèn)語言。

          使用此方法也可以實(shí)現(xiàn)所有英語區(qū)域的國家使用英語,而國內(nèi)、香港、澳門等使用中文。

          監(jiān)聽系統(tǒng)語言切換

          當(dāng)更改系統(tǒng)語言設(shè)置時,Localizations 組件將會重新 build,而用戶就看到了語言的切換,這個過程是系統(tǒng)完成的,代碼并不需要主動去監(jiān)聽語言切換,但如果想監(jiān)聽語言切換可以通過 localeResolutionCallback 或 localeListResolutionCallback 回調(diào)來監(jiān)聽。通常情況下,使用localeListResolutionCallback,localeListResolutionCallback有兩個參數(shù):List locales 和 Iterable supportedLocales,在較新的Android系統(tǒng)中可以設(shè)置語言列表,List locales就表示這個語言列表,

          supportedLocales為當(dāng)前應(yīng)用支持的locale列表,是在MaterialApp中設(shè)置supportedLocales的值。localeListResolutionCallback返回一個Locale,此Locale表示最終使用的Locale,一般情況下在App不支持當(dāng)前語言時返回一個默認(rèn)值。localeListResolutionCallback的用法如下:

          MaterialApp(
          ??????supportedLocales:?[
          ????????Locale('zh'),
          ????????Locale('en'),
          ??????],
          ??????localeListResolutionCallback:?(List?locales,?Iterable?supportLocales){
          ????????print('locales:$locales');
          ????????print('supportLocales:$supportLocales');
          ??????},?????
          )

          輸出如下:

          locales:[zh_Hans_CN,?ja_JP,?en_GB]
          supportLocales:[zh,?en]

          也可以通過如下代碼獲取當(dāng)前系統(tǒng)語言:

          Locale?myLocale?=?Localizations.localeOf(context);

          應(yīng)用程序內(nèi)切換語言

          應(yīng)用程序?qū)崿F(xiàn)切換語言功能只需將 MaterialApp 中 locale 屬性作為一個變量,切換不同的 Locale 即可達(dá)到切換語言的目的。代碼如下:

          class?IntlApp?extends?StatelessWidget?{
          ??@override
          ??Widget?build(BuildContext?context)?{
          ????return?MyApp();
          ??}
          }



          class?MyApp?extends?StatefulWidget?{

          ??@override
          ??MyAppState?createState()?=>?MyAppState();
          }

          class?MyAppState?extends?State<MyApp>?{

          ??static?_AppSetting?setting?=?_AppSetting();

          ??@override
          ??void?initState()?{
          ????super.initState();
          ????setting.changeLocale?=?(Locale?locale)?{
          ??????setState(()?{
          ????????setting._locale?=?locale;
          ??????});
          ????};
          ??}

          ??@override
          ??Widget?build(BuildContext?context)?{
          ????return?MaterialApp(
          ??????onGenerateTitle:?(context)?{
          ????????return?AppLocalizations.of(context).title;
          ??????},
          ??????localeResolutionCallback:
          ??????????(Locale?locale,?Iterable?supportedLocales)?{
          ????????var?result?=?supportedLocales
          ????????????.where((element)?=>?element.languageCode?==?locale.languageCode);
          ????????if?(result.isNotEmpty)?{
          ??????????return?locale;
          ????????}
          ????????return?Locale('zh');
          ??????},
          ??????locale:?setting._locale,
          ??????localizationsDelegates:?[
          ????????AppLocalizationsDelegate(),
          ????????GlobalMaterialLocalizations.delegate,
          ????????GlobalWidgetsLocalizations.delegate,
          ????????GlobalCupertinoLocalizations.delegate,
          ??????],
          ??????supportedLocales:?[
          ????????const?Locale('zh'),
          ????????const?Locale('en'),
          ??????],
          ??????home:?_HomePage(),
          ????);
          ??}
          }

          _HomePage 代碼:

          class?_HomePage?extends?StatefulWidget?{
          ??@override
          ??__HomePageState?createState()?=>?__HomePageState();
          }

          class?__HomePageState?extends?State<_HomePage>?{
          ??@override
          ??Widget?build(BuildContext?context)?{
          ????return?Scaffold(
          ??????appBar:?AppBar(),
          ??????body:?Column(
          ????????mainAxisAlignment:?MainAxisAlignment.center,
          ????????children:?[
          ??????????Text('${AppLocalizations.of(context).title}'),
          ??????????Row(
          ????????????mainAxisAlignment:?MainAxisAlignment.center,
          ????????????children:?[
          ??????????????RaisedButton(
          ????????????????child:?Text('中文'),
          ????????????????onPressed:?()?{
          ??????????????????MyAppState.setting.changeLocale(Locale('zh'));
          ????????????????},
          ??????????????),
          ??????????????RaisedButton(
          ????????????????child:?Text('英文'),
          ????????????????onPressed:?()?{
          ??????????????????MyAppState.setting.changeLocale(Locale('en'));
          ????????????????},
          ??????????????),
          ????????????],
          ??????????),
          ????????],
          ??????),
          ????);
          ??}
          }

          _AppSetting 代碼:

          class?_AppSetting?{
          ??_AppSetting();

          ??Null?Function(Locale?locale)?changeLocale;
          ??Locale?_locale;
          }


          你可能還喜歡


          關(guān)注「老孟Flutter」
          讓你每天進(jìn)步一點(diǎn)點(diǎn)


          瀏覽 105
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产极品艳情生活视频在线播放 | av人人操 | 狠狠撸视频| 一道本一区二区三区在线视频 | 大香蕉欧美伊人 |