Flutter實戰(zhàn) 讓App支持多語言

2021-03-09 14:19 更新

如果我們的應(yīng)用要支持多種語言,那么我們需要“國際化”它。這意味著我們在開發(fā)時需要為應(yīng)用程序支持的每種語言環(huán)境設(shè)置“本地化”的一些值,如文本和布局。Flutter SDK 已經(jīng)提供了一些組件和類來幫助我們實現(xiàn)國際化,下面我們來介紹一下 Flutter 中實現(xiàn)國際化的步驟。

接下來我們以MaterialApp類為入口的應(yīng)用來說明如何支持國際化。

大多數(shù)應(yīng)用程序都是通過MaterialApp為入口,但根據(jù)低級別的WidgetsApp類為入口編寫的應(yīng)用程序也可以使用相同的類和邏輯進行國際化。MaterialApp實際上也是WidgetsApp的一個包裝。

注意,”本地化的值和資源“是指我們針對不同語言準備的不同資源,這些資源一般是指文案(字符串),當然也會有一些其他的資源會根據(jù)不同語言地區(qū)而不同,比如我們需要顯示一個APP上架地的國旗圖片,那么不同 Locale 區(qū)域我們就需要提供不同的的國旗圖片。

#支持國際化

默認情況下,F(xiàn)lutter SDK 中的組件僅提供美國英語本地化資源(主要是文本)。要添加對其他語言的支持,應(yīng)用程序須添加一個名為“flutter_localizations”的包依賴,然后還需要在MaterialApp中進行一些配置。 要使用flutter_localizations包,首先需要添加依賴到pubspec.yaml文件中:

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

接下來,下載flutter_localizations庫,然后指定MaterialApplocalizationsDelegatessupportedLocales

import 'package:flutter_localizations/flutter_localizations.dart';


new MaterialApp(
 localizationsDelegates: [
   // 本地化的代理類
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', 'US'), // 美國英語
    const Locale('zh', 'CN'), // 中文簡體
    //其它Locales
  ],
  // ...
)

MaterialApp類為入口的應(yīng)用不同, 對基于WidgetsApp類為入口的應(yīng)用程序進行國際化時,不需要GlobalMaterialLocalizations.delegate

localizationsDelegates列表中的元素是生成本地化值集合的工廠。GlobalMaterialLocalizations.delegate 為 Material 組件庫提供的本地化的字符串和其他值,它可以使 Material 組件支持多語言。 GlobalWidgetsLocalizations.delegate定義組件默認的文本方向,從左到右或從右到左,這是因為有些語言的閱讀習慣并不是從左到右,比如如阿拉伯語就是從右向左的。

supportedLocales也接收一個 Locale 數(shù)組,表示我們的應(yīng)用支持的語言列表,在本例中我們的應(yīng)用只支持美國英語和中文簡體兩種語言。

#獲取當前區(qū)域Locale

Locale (opens new window)類是用來標識用戶的語言環(huán)境的,它包括語言和國家兩個標志如:

const Locale('zh', 'CN') // 中文簡體

我們始終可以通過以下方式來獲取應(yīng)用的當前區(qū)域 Locale:

Locale myLocale = Localizations.localeOf(context);

Localizations (opens new window)組件一般位于 widget 樹中其它業(yè)務(wù)組件的頂部,它的作用是定義區(qū)域 Locale 以及設(shè)置子樹依賴的本地化資源。 如果系統(tǒng)的語言環(huán)境發(fā)生變化,WidgetsApp (opens new window)將創(chuàng)建一個新的 Localizations 組件并重建它,這樣子樹中通過Localizations.localeOf(context) 獲取的 Locale 就會更新。

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

當我們更改系統(tǒng)語言設(shè)置時,APP 中的 Localizations 組件會重新構(gòu)建,Localizations.localeOf(context) 獲取的 Locale 就會更新,最終界面會重新 build 達到切換語言的效果。但是這個過程是隱式完成的,我們并沒有主動去監(jiān)聽系統(tǒng)語言切換,但是有時我們需要在系統(tǒng)語言發(fā)生改變時做一些事,比如系統(tǒng)語言切換為一種我們 APP 不支持的語言時,我們需要設(shè)置一個默認的語言,這時我們就需要監(jiān)聽 locale 改變事件。

我們可以通過localeResolutionCallbacklocaleListResolutionCallback回調(diào)來監(jiān)聽 locale 改變的事件,我們先看看localeResolutionCallback的回調(diào)函數(shù)簽名:

Locale Function(Locale locale, Iterable<Locale> supportedLocales)

  • 參數(shù)locale的值為當前的當前的系統(tǒng)語言設(shè)置,當應(yīng)用啟動時或用戶動態(tài)改變系統(tǒng)語言設(shè)置時此 locale 即為系統(tǒng)的當前 locale。當開發(fā)者手動指定 APP 的 locale 時,那么此 locale 參數(shù)代表開發(fā)者指定的 locale,此時將忽略系統(tǒng) locale 如:

  MaterialApp(
   ...
   locale: const Locale('en', 'US'), //手動指定locale
   ...
  )

上面的例子中手動指定了應(yīng)用 locale 為美國英語,指定后即使設(shè)備當前語言是中文簡體,應(yīng)用中的 locale 也依然是美國英語。如果localenull,則表示 Flutter 未能獲取到設(shè)備的 Locale 信息,所以我們在使用locale之前一定要先判空。

  • supportedLocales 為當前應(yīng)用支持的 locale 列表,是開發(fā)者在 MaterialApp 中通過supportedLocales屬性注冊的。

  • 返回值是一個Locale,此Locale為 Flutter APP 最終使用的Locale。通常在不支持的語言區(qū)域時返回一個默認的Locale。

localeListResolutionCallbacklocaleResolutionCallback唯一的不同就在第一個參數(shù)類型,前者接收的是一個Locale列表,而后者接收的是單個Locale。

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

在較新的 Android 系統(tǒng)中,用戶可以設(shè)置一個語言列表,這樣一來,支持多語言的應(yīng)用就會得到這個列表,應(yīng)用通常的處理方式就是按照列表的順序依次嘗試加載相應(yīng)的 Locale,如果某一種語言加載成功則會停止。圖13-1是 Android 系統(tǒng)中設(shè)置語言列表的截圖:

設(shè)置語言列表

在 Flutter 中,應(yīng)該優(yōu)先使用localeListResolutionCallback,當然你不必擔心 Android 系統(tǒng)的差異性,如果在低版本的 Android 系統(tǒng)中,F(xiàn)lutter 會自動處理這種情況,這時 Locale 列表只會包含一項。

#Localization 組件

Localizations 組件用于加載和查找應(yīng)用當前語言下的本地化值或資源。應(yīng)用程序通過Localizations.of(context,type) (opens new window)來引用這些對象。 如果設(shè)備的 Locale 區(qū)域設(shè)置發(fā)生更改,則 Localizations 組件會自動加載新區(qū)域的 Locale 值,然后重新 build 使用(依賴)了它們的組件,之所以會這樣,是因為Localizations內(nèi)部使用了InheritedWidget (opens new window),我們在介紹該組件時講過:當子組件的build函數(shù)引用了InheritedWidget時,會創(chuàng)建對InheritedWidget的隱式依賴關(guān)系。因此,當InheritedWidget發(fā)生更改時,即Localizations的 Locale 設(shè)置發(fā)生更改時,將重建所有依賴它的子組件。

本地化值由LocalizationsLocalizationsDelegates (opens new window)列表加載 。 每個委托必須定義一個異步 load() 方法,以生成封裝了一系列本地化值的對象。通常這些對象為每個本地化值定義一個方法。

在大型應(yīng)用程序中,不同模塊或 Package 可能會與自己的本地化值捆綁在一起。 這就是為什么要用Localizations 管理對象表的原因。 要使用由LocalizationsDelegateload方法之一產(chǎn)生的對象,可以指定一個BuildContext和對象的類型來找到它。例如,Material 組件庫的本地化字符串由MaterialLocalizations (opens new window)類定義,此類的實例由 MaterialApp (opens new window)類提供的LocalizationDelegate創(chuàng)建, 它們可以如下方式獲取到:

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

這個特殊的Localizations.of()表達式會經(jīng)常使用,所以 MaterialLocalizations 類提供了一個便捷方法:

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


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

#使用打包好的LocalizationsDelegates

為了盡可能小而且簡單,flutter 軟件包中僅提供美國英語值的MaterialLocalizationsWidgetsLocalizations接口的實現(xiàn)。 這些實現(xiàn)類分別稱為DefaultMaterialLocalizationsDefaultWidgetsLocalizations。flutter_localizations 包包含GlobalMaterialLocalizationsGlobalWidgetsLocalizations的本地化接口的多語言實現(xiàn), 國際化的應(yīng)用程序必須按照本節(jié)開頭說明的那樣為這些類指定本地化 Delegate。

上述的GlobalMaterialLocalizationsGlobalWidgetsLocalizations只是 Material 組件庫的本地化實現(xiàn),如果我們要讓自己的布局支持多語言,那么就需要實現(xiàn)在即的Localizations,我們將在下一節(jié)介紹其具體的實現(xiàn)方式。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號