Flutter 國際化

2020-08-27 14:47 更新

設(shè)置一個國際化的應(yīng)用程序: the flutter_localizations package

默認(rèn)情況下,F(xiàn)lutter僅提供美國英語本地化。要添加對其他語言的支持,應(yīng)用程序必須指定其他MaterialApp屬性,并包含一個名為的單獨(dú)包-“flutter_localizations”。 截至2017年10月,該軟件包支持15種語言。

要使用flutter_localizations,請將該包作為依賴項添加到您的pubspec.yaml文件中:

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

接下來,導(dǎo)入flutter_localizations庫,并指定MaterialApp的localizationsDelegates和supportedLocales:

import 'package:flutter_localizations/flutter_localizations.dart';

new MaterialApp(
 localizationsDelegates: [
   // ... app-specific localization delegate[s] here
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', 'US'), // English
    const Locale('he', 'IL'), // Hebrew
    // ... other locales the app supports
  ],
  // ...
)

基于WidgetsApp的應(yīng)用程序類似,只是不需要GlobalMaterialLocalizations.delegate。

localizationsDelegates列表中的元素是生成本地化值集合的工廠。GlobalMaterialLocalizations.delegate 為Material Components庫提供了本地化的字符串和其他值。 GlobalWidgetsLocalizations.delegate定義widget默認(rèn)的文本方向,從左到右或從右到左。

有關(guān)這些應(yīng)用程序?qū)傩缘母嘈畔?,它們所依賴的類型以及如何國際化Flutter應(yīng)用程序,這些都可以在下面找到。


跟蹤區(qū)域設(shè)置: Locale類和Localizations widget

Locale類是用來識別用戶的語言環(huán)境。 移動設(shè)備支持通過系統(tǒng)設(shè)置菜單為所有應(yīng)用程序設(shè)置區(qū)域。國際化應(yīng)用程序通過顯示區(qū)域設(shè)置特定的值進(jìn)行響應(yīng)。 例如,如果用戶將設(shè)備的語言環(huán)境從英語切換到法語,則顯示“Hello World”的文本widget將用“Bonjour le monde”重建。

Localizations小部件定義其子項的區(qū)域設(shè)置以及子項依賴的本地化資源。 如果系統(tǒng)的語言環(huán)境發(fā)生變化,WidgetsApp將創(chuàng)建一個Localizations widget并重建它。

您始終可以通過以下方式查找應(yīng)用的當(dāng)前區(qū)域設(shè)置:

Locale myLocale = Localizations.localeOf(context);


加載和獲取本地化的值

Localizations widget用于加載和查找包含本地化值的集合的對象。應(yīng)用程序通過Localizations.of(context,type)來引用這些對象。 如果設(shè)備的區(qū)域設(shè)置發(fā)生更改,則Localizations widget會自動加載新區(qū)域設(shè)置的值,然后重新構(gòu)建使用它們的widget。 發(fā)生這種情況是因為Localizations像InheritedWidget一樣工作 。 當(dāng)build函數(shù)引用了繼承的widget時,會創(chuàng)建對繼承的widget的隱式依賴關(guān)系。當(dāng)繼承的widget發(fā)生更改(Localizations widget的區(qū)域設(shè)置發(fā)生更改時),將重建其依賴的上下文。

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

在大型應(yīng)用程序中,不同的模塊或軟件包可能會與自己的本地化捆綁在一起。 這就是Localizations widget管理對象表的原因,每個LocalizationsDelegate都有一個(對象表)。 要檢索由LocalizationsDelegateload方法之一產(chǎn)生的對象,可以指定一個BuildContext和對象的類型。

例如,Material Component widgets的本地化字符串由MaterialLocalizations類定義。 此類的實(shí)例由MaterialApp類提供的LocalizationDelegate創(chuàng)建。 它們可以通過Localizations.of被獲取到:

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

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

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

/// References to the localized values defined by MaterialLocalizations
/// are typically written like this:

tooltip: MaterialLocalizations.of(context).backButtonTooltip,


使用打包好的LocalizationsDelegates

為了盡可能小而且簡單,flutter軟件包中僅提供美國英語值的MaterialLocalizations和WidgetsLocalizations接口的實(shí)現(xiàn)。 這些實(shí)現(xiàn)類分別稱為DefaultMaterialLocalizations和DefaultWidgetsLocalizations。 除非與應(yīng)用程序的localizationsDelegates參數(shù)指定了相同基本類型的不同delegate,否則它們會自動包含 。

flutter_localizations軟件包包含稱為GlobalMaterialLocalizations和GlobalWidgetsLocalizations的本地化接口的多語言實(shí)現(xiàn)。 國際化的應(yīng)用程序必須按照設(shè)置國際化應(yīng)用程序中的說明為這些類指定本地化代理 。

import 'package:flutter_localizations/flutter_localizations.dart';

new MaterialApp(
 localizationsDelegates: [
   // ... app-specific localization delegate[s] here
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', 'US'), // English
    const Locale('fr', 'CA'), // canadian French
    // ... other locales the app supports
  ],
  // ...
)

全局本地化delegates構(gòu)造相應(yīng)類的特定于語言環(huán)境的實(shí)例。例如,GlobalMaterialLocalizations.delegate是一個產(chǎn)生GlobalMaterialLocalizations實(shí)例的LocalizationsDelegate。

截至2017年10月,國際化代理的類支持約15種語言


為應(yīng)用的本地化資源定義一個類

將所有這些放在一起用于國際化應(yīng)用程序通常從封裝應(yīng)用程序本地化值的類開始。下面的例子是這些類的典型例子。

這個示例的完整源代碼

本示例基于intl包提供的API和工具 。指定本地化資源的另一個類描述了一個不依賴于intl包的示例。

DemoLocalizations類包含應(yīng)用程序的字符串(僅用于示例),該字符串被翻譯為應(yīng)用程序支持的語言環(huán)境。 使用Dart的intl 包生成的函數(shù)initializeMessages()來加載翻譯的字符串,并使用Intl.message()查找它們。

class DemoLocalizations {
  static Future<DemoLocalizations> load(Locale locale) {
    final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);
    return initializeMessages(localeName).then((Null _) {
      Intl.defaultLocale = localeName;
      return new DemoLocalizations();
    });
  }

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

  String get title {
    return Intl.message(
      'Hello World',
      name: 'title',
      desc: 'Title for the Demo application',
    );
  }
}

基于intl包的類導(dǎo)入生成的message目錄,該目錄提供initializeMessages()函數(shù)和每個語言環(huán)境的后備存儲Intl.message()。 message目錄由一個intl工具生成,該工具分析包含Intl.message()調(diào)用的類的源代碼。在這個示例中,這是DemoLocalizations類。


指定應(yīng)用程序的supportedLocales參數(shù)

雖然Flutter的Material Components library包含對大約16種語言的支持,但默認(rèn)情況下僅提供英文。 開發(fā)人員需要決定支持哪種語言,因為工具庫支持與應(yīng)用程序不同的一組語言環(huán)境是沒有意義的。

MaterialAppsupportedLocales參數(shù)限制語言環(huán)境更改。 當(dāng)用戶更改其設(shè)備上的區(qū)域設(shè)置時,新區(qū)域如果是列表的成員,則應(yīng)用程序的Localizations widget 就適用于該區(qū)域。如 果找不到設(shè)備區(qū)域設(shè)置的精確匹配項(譯者語:指語言和地區(qū)同時匹配,如中文,中國),則使用第一個匹配區(qū)域設(shè)置languageCode(譯者語:只設(shè)置語言,而不指定地區(qū))。 如果失敗,則supportedLocales使用列表的第一個元素 。

就之前的DemoApp示例而言,該應(yīng)用只接受美國英語或加拿大法語語言環(huán)境,并將美國英語(列表中的第一個語言環(huán)境)替換為其他任何內(nèi)容。

可以提供一個localeResolutionCallback,在應(yīng)用獲取用戶設(shè)置的語言區(qū)域時會被回調(diào)。 例如,要讓您的應(yīng)用程序無條件接受用戶選擇的任何區(qū)域設(shè)置:

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
       localeResolutionCallback(Locale locale, Iterable<Locale> supportedLocales) {
         return locale;
       }
       // ...
    );
  }
}


指定本地化資源的另一個類

之前的DemoApp示例是根據(jù)Dartintl包定義的。為了簡單起見,開發(fā)人員可以選擇自己的方法來管理本地化值,也可以與不同的i18n框架進(jìn)行集成。 這個示例的完整源代碼

在此版本的DemoApp中,包含應(yīng)用程序本地化的類DemoLocalizations將直接在每種語言Map中包含其所有的翻譯:

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'];
  }
}

簡單的國際化應(yīng)用中, DemoLocalizationsDelegate略有不同。它的load方法返回一個SynchronousFuture, 因為不需要進(jìn)行異步加載。

class DemoLocalizationsDelegate extends LocalizationsDelegate<DemoLocalizations> {
  const DemoLocalizationsDelegate();

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

  @override
  Future<DemoLocalizations> load(Locale locale) {
    return new SynchronousFuture<DemoLocalizations>(new DemoLocalizations(locale));
  }

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


附錄: 使用Dart intl工具

在使用Dart intl包構(gòu)建API之前, 您需要查看intl包的文檔。以下是根據(jù)intl軟件包本地化應(yīng)用程序的過程摘要。

示例程序依賴于一個生成的源文件l10n/messages_all.dart ,它定義了應(yīng)用程序使用的所有本地化字符串。

重新構(gòu)建 l10n/messages_all.dart 需要兩個步驟.

  1. 將應(yīng)用程序的根目錄作為當(dāng)前目錄,從lib/main.dart生成l10n/intl_messages.arb
    $ flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/i10n lib/main.dart

    該intl_messages.arb文件是一個JSON格式的map,擁有一個在main.dart中定義的Intl.message()函數(shù)入口。 此文件作為英語和西班牙語翻譯的一個模板,intl_en.arb和intl_es.arb。這些翻譯是由您,開發(fā)人員創(chuàng)建的。

  2. 使用應(yīng)用程序的根目錄作為當(dāng)前目錄,為每個intl_<locale>.arb文件生成intl_messages_<locale>.dart,并在intl_messages_all.dart中導(dǎo)入所有message文件:

    $ flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n \
       --no-use-deferred-loading lib/main.dart lib/l10n/intl_*.arb

    DemoLocalizations類使用生成的initializeMessages() 函數(shù)(定義在intl_messages_all.dart)來加載本地化的message并使用Intl.message()來查找它們。

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號