編寫國際化Flutter App

本文介紹了如何對Flutter應用進行國際化和多語言支持如果您的應用可能會給另一種語言的用戶使用,那么您需要“國際化”它。這意味著您在編寫應用程序時需要為應用程序支持的每種語言環境...

你將會學到什么:
1. 如何跟蹤設備的區域(locale)設置(用戶的首選語言)
2. 如何管理特定于區域環境(locale)的應用程序值.
3. 如何使應用程序支持多區域環境

如果您的應用可能會給另一種語言的用戶使用,那么您需要“國際化”它。這意味著您在編寫應用程序時需要為應用程序支持的每種語言環境, 設置“本地化”的一些值,如文本和布局。Flutter提供一些widgets和類,以幫助實現國際化,而Flutter的庫本身也是國際化的。

接下來的教程主要是根據Flutter MaterialApp類編寫的,因為大多數應用程序都是這樣編寫的。根據較低級別的WidgetsApp類編寫的應用程序也可以使用相同的類和邏輯進行國際化。

內容

國際化APP的例子:如果您想通過閱讀國際化Flutter應用程序的代碼開始,下面是兩個小例子。第一個旨在盡可能簡單,第二個使用intl包提供的API和工具。 如果您沒用過Dart的intl包,請參閱使用Dart intl 工具

設置一個國際化的應用程序: the flutter_localizations package

默認情況下,Flutter僅提供美國英語本地化。要添加對其他語言的支持,應用程序必須指定其他MaterialApp屬性,并包含一個名為的單獨包-"flutter_localizations"。 截至2017年10月,該軟件包支持15種語言。

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

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

接下來,導入flutter_localizations庫,并指定MaterialApp的localizationsDelegatessupportedLocales

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的應用程序類似,只是不需要GlobalMaterialLocalizations.delegate

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

有關這些應用程序屬性的更多信息,它們所依賴的類型以及如何國際化Flutter應用程序,這些都可以在下面找到。

跟蹤區域設置: Locale類和Localizations widget

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

Localizations小部件定義其子項的區域設置以及子項依賴的本地化資源。 如果系統的語言環境發生變化,WidgetsApp將創建一個Localizations widget并重建它。

您始終可以通過以下方式查找應用的當前區域設置:

Locale myLocale = Localizations.localeOf(context);

加載和獲取本地化的值

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

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

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

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

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

這個特殊的Localizations.of()表達式經常使用,所以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接口的實現。 這些實現類分別稱為DefaultMaterialLocalizations和DefaultWidgetsLocalizations。 除非與應用程序的localizationsDelegates參數指定了相同基本類型的不同delegate,否則它們會自動包含 。

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

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構造相應類的特定于語言環境的實例。例如,GlobalMaterialLocalizations.delegate是一個產生GlobalMaterialLocalizations實例的LocalizationsDelegate。

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

為應用的本地化資源定義一個類

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

這個示例的完整源代碼

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

DemoLocalizations類包含應用程序的字符串(僅用于示例),該字符串被翻譯為應用程序支持的語言環境。 使用Dart的intl 包生成的函數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包的類導入生成的message目錄,該目錄提供initializeMessages()函數和每個語言環境的后備存儲Intl.message()。 message目錄由一個intl工具生成,該工具分析包含Intl.message()調用的類的源代碼。在這個示例中,這是DemoLocalizations類。

指定應用程序的supportedLocales參數

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

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

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

可以提供一個localeResolutionCallback,在應用獲取用戶設置的語言區域時會被回調。 例如,要讓您的應用程序無條件接受用戶選擇的任何區域設置:

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

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

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

在此版本的DemoApp中,包含應用程序本地化的類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'];
  }
}

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

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包構建API之前, 您需要查看intl包的文檔。以下是根據intl軟件包本地化應用程序的過程摘要。

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

重新構建 l10n/messages_all.dart 需要兩個步驟.

1.將應用程序的根目錄作為當前目錄,從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()函數入口。 此文件作為英語和西班牙語翻譯的一個模板,intl_en.arbintl_es.arb。這些翻譯是由您,開發人員創建的。

2.使用應用程序的根目錄作為當前目錄,為每個intl_<locale>.arb文件生成intl_messages_<locale>.dart,并在intl_messages_all.dart中導入所有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() 函數(定義在intl_messages_all.dart)來加載本地化的message并使用Intl.message()來查找它們。


所屬標簽

無標簽

官方入門指南

Flutter官方發布的入門指導,包括了如何在不同的平臺(Windows, Mac, Linux)上搭建開發環境,以及一些入門級的指導,以便您從零開始進入Flutter的世界,同時,一些Flutter的框架API,也是您開發時必不可少的工具書。

從這里進入


25选5玩法中奖