Flutter - 国际化



如今,移动应用程序被来自不同国家的客户使用,因此,应用程序需要以不同的语言显示内容。使应用程序能够以多种语言工作称为应用程序的国际化。

为了使应用程序能够以不同的语言工作,它首先应该找到运行应用程序的系统的当前区域设置,然后需要以该特定区域设置显示其内容,此过程称为本地化。

Flutter 框架为本地化提供了三个基础类和从基础类派生的广泛实用程序类,以本地化应用程序。

基础类如下所示:

  • Locale - Locale 是一个用于识别用户语言的类。例如,en-us 表示美式英语,可以创建如下所示:

Locale en_locale = Locale('en', 'US')

这里,第一个参数是语言代码,第二个参数是国家/地区代码。创建阿根廷西班牙语 (es-ar)区域设置的另一个示例如下所示:

Locale es_locale = Locale('es', 'AR')
  • Localizations - Localizations 是一个通用 Widget,用于设置其子级的区域设置和本地化资源。

class CustomLocalizations { 
   CustomLocalizations(this.locale); 
   final Locale locale; 
   static CustomLocalizations of(BuildContext context) { 
      return Localizations.of<CustomLocalizations>(context, CustomLocalizations); 
   } 
   static Map<String, Map<String, String>> _resources = {
      'en': {
         'title': 'Demo', 
         'message': 'Hello World' 
      }, 
      'es': {
         'title': 'Manifestación', 
         'message': 'Hola Mundo', 
      }, 
   }; 
   String get title { 
      return _resources[locale.languageCode]['title']; 
   }
   String get message { 
      return _resources[locale.languageCode]['message']; 
   } 
}
  • 这里,CustomLocalizations 是一个专门为 Widget 获取某些本地化内容(标题和消息)而创建的新自定义类。of 方法使用 Localizations 类返回新的 CustomLocalizations 类。

  • LocalizationsDelegate<T> - LocalizationsDelegate<T> 是一个工厂类,通过它加载 Localizations Widget。它有三个可覆盖的方法:

    • isSupported - 接受一个区域设置并返回指定的区域设置是否受支持。

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

      这里,委托仅适用于 en 和 es 区域设置。

    • load - 接受一个区域设置并开始加载指定区域设置的资源。

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

      这里,load 方法返回 CustomLocalizations。返回的 CustomLocalizations 可用于获取英语和西班牙语中标题和消息的值

    • shouldReload - 指定当 Localizations Widget 重建时是否需要重新加载 CustomLocalizations。

@override 
bool shouldReload(CustomLocalizationsDelegate old) => false;
  • CustomLocalizationDelegate 的完整代码如下所示:

class CustomLocalizationsDelegate extends 
LocalizationsDelegate<CustomLocalizations> { 
   const CustomLocalizationsDelegate(); 
   @override 
   bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode);
   @override 
   Future<CustomLocalizations> load(Locale locale) { 
      return SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale));
   } 
   @override bool shouldReload(CustomLocalizationsDelegate old) => false; 
}

通常,Flutter 应用程序基于两个根级 Widget,MaterialApp 或 WidgetsApp。Flutter 为这两个 Widget 提供了现成的本地化,它们是 MaterialLocalizations 和 WidgetsLocaliations。此外,Flutter 还提供了委托来加载 MaterialLocalizations 和 WidgetsLocaliations,它们分别是 GlobalMaterialLocalizations.delegate 和 GlobalWidgetsLocalizations.delegate。

让我们创建一个简单的启用国际化的应用程序来测试和理解这个概念。

  • 创建一个新的 flutter 应用程序,flutter_localization_app。

  • Flutter 使用专用的 flutter 包 flutter_localizations 支持国际化。其理念是从主 SDK 中分离本地化内容。打开 pubspec.yaml 并添加以下代码以启用国际化包:

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations:
      sdk: flutter
  • Android studio 将显示以下警报,提示 pubspec.yaml 已更新。

Alert
  • 单击获取依赖项选项。Android studio 将从 Internet 获取包并为应用程序正确配置它。

  • 在 main.dart 中导入 flutter_localizations 包,如下所示:

import 'package:flutter_localizations/flutter_localizations.dart'; 
import 'package:flutter/foundation.dart' show SynchronousFuture;
  • 这里,SynchronousFuture 的目的是同步加载自定义本地化。

  • 创建自定义本地化及其相应的委托,如下所示:

class CustomLocalizations { 
   CustomLocalizations(this.locale); 
   final Locale locale; 
   static CustomLocalizations of(BuildContext context) {
      return Localizations.of<CustomLocalizations>(context, CustomLocalizations); 
   }
   static Map<String, Map<String, String>> _resources = {
      'en': {
         'title': 'Demo', 
         'message': 'Hello World' 
      }, 
      'es': { 
         'title': 'Manifestación', 
         'message': 'Hola Mundo', 
      }, 
   }; 
   String get title { 
      return _resources[locale.languageCode]['title']; 
   } 
   String get message { 
      return _resources[locale.languageCode]['message']; 
   } 
}
class CustomLocalizationsDelegate extends
LocalizationsDelegate<CustomLocalizations> {
   const CustomLocalizationsDelegate();
   
   @override 
   bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode); 
   
   @override 
   Future<CustomLocalizations> load(Locale locale) { 
      return SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale)); 
   } 
   @override bool shouldReload(CustomLocalizationsDelegate old) => false; 
}
  • 这里,创建 CustomLocalizations 以支持应用程序中标题和消息的本地化,并使用 CustomLocalizationsDelegate 来加载 CustomLocalizations。

  • 使用 MaterialApp 属性 localizationsDelegates 和 supportedLocales 添加 MaterialApp、WidgetsApp 和 CustomLocalization 的委托,如下所示:

localizationsDelegates: [
   const CustomLocalizationsDelegate(),   
   GlobalMaterialLocalizations.delegate, 
   GlobalWidgetsLocalizations.delegate, 
], 
supportedLocales: [
   const Locale('en', ''),
   const Locale('es', ''), 
],
  • 使用 CustomLocalizations 方法 of 获取标题和消息的本地化值,并在适当的位置使用它,如下所示:

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(CustomLocalizations .of(context) .title), ), 
         body: Center(
            child: Column(
               mainAxisAlignment: MainAxisAlignment.center, 
               children: <Widget>[ 
                  Text( CustomLocalizations .of(context) .message, ), 
               ], 
            ), 
         ),
      );
   }
}
  • 这里,为了简化起见,我们将 MyHomePage 类从 StatefulWidget 修改为 StatelessWidget,并使用 CustomLocalizations 获取标题和消息。

  • 编译并运行应用程序。应用程序将以英语显示其内容。

  • 关闭应用程序。转到设置 → 系统 → 语言和输入 → 语言*

  • 单击添加语言选项并选择西班牙语。这将安装西班牙语并将其列为选项之一。

  • 选择西班牙语并将其移到英语上方。这将把西班牙语设置为第一语言,并且所有内容都将更改为西班牙语文本。

  • 现在重新启动国际化应用程序,您将看到标题和消息以西班牙语显示。

  • 我们可以通过在设置中将英语选项移到西班牙语选项上方来将语言恢复为英语。

  • 应用程序(西班牙语)的结果显示在下面给出的屏幕截图中:

Manifestacion

使用 intl 包

Flutter 提供了 intl 包来进一步简化本地化移动应用程序的开发。intl 包提供了特殊方法和工具来半自动生成特定于语言的消息。

让我们使用 intl 包创建一个新的本地化应用程序,并了解这个概念。

  • 创建一个新的 flutter 应用程序,flutter_intl_app。

  • 打开 pubspec.yaml 并添加包详细信息。

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations: 
      sdk: flutter 
   intl: ^0.15.7 
   intl_translation: ^0.17.3
  • Android studio 将显示如下所示的警报,通知 pubspec.yaml 已更新。

Informing Updation
  • 单击获取依赖项选项。Android studio 将从 Internet 获取包并为应用程序正确配置它。

  • 复制上一个示例 flutter_internationalization_app 中的 main.dart。

  • 导入 intl 包,如下所示:

import 'package:intl/intl.dart';
  • 更新 CustomLocalization 类,如以下代码所示:

class CustomLocalizations { 
   static Future<CustomLocalizations> load(Locale locale) {
      final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString(); 
      final String localeName = Intl.canonicalizedLocale(name); 
      
      return initializeMessages(localeName).then((_) {
         Intl.defaultLocale = localeName; 
         return CustomLocalizations(); 
      }); 
   } 
   static CustomLocalizations of(BuildContext context) { 
      return Localizations.of<CustomLocalizations>(context, CustomLocalizations); 
   } 
   String get title {
      return Intl.message( 
         'Demo', 
         name: 'title', 
         desc: 'Title for the Demo application', 
      ); 
   }
   String get message{
      return Intl.message(
         'Hello World', 
         name: 'message', 
         desc: 'Message for the Demo application', 
      ); 
   }
}
class CustomLocalizationsDelegate extends 
LocalizationsDelegate<CustomLocalizations> {
   const CustomLocalizationsDelegate();
   
   @override
   bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode); 
   @override 
   Future<CustomLocalizations> load(Locale locale) { 
      return CustomLocalizations.load(locale); 
   } 
   @override 
   bool shouldReload(CustomLocalizationsDelegate old) => false; 
}
  • 这里,我们使用了 intl 包中的三个方法,而不是自定义方法。否则,概念相同。

    • Intl.canonicalizedLocale - 用于获取正确的区域设置名称。

    • Intl.defaultLocale - 用于设置当前区域设置

    • Intl.message - 用于定义新消息。

  • 导入l10n/messages_all.dart文件。我们很快就会生成此文件

import 'l10n/messages_all.dart';
  • 现在,创建一个文件夹,lib/l10n

  • 打开命令提示符并转到应用程序根目录(其中 pubspec.yaml 可用)并运行以下命令:

flutter packages pub run intl_translation:extract_to_arb --output-
   dir=lib/l10n lib/main.dart
  • 这里,该命令将生成 intl_message.arb 文件,这是一个在不同区域设置中创建消息的模板。文件内容如下所示:

{
   "@@last_modified": "2019-04-19T02:04:09.627551", 
   "title": "Demo", 
   "@title": {
      "description": "Title for the Demo application", 
      "type": "text", 
      "placeholders": {} 
   }, 
   "message": "Hello World", 
   "@message": {
      "description": "Message for the Demo 
      application", 
      "type": "text", 
      "placeholders": {} 
   }
}
  • 复制 intl_message.arb 并创建新文件 intl_en.arb。

  • 复制 intl_message.arb 并创建新文件 intl_es.arb,并将内容更改为西班牙语,如下所示:

{
   "@@last_modified": "2019-04-19T02:04:09.627551",  
   "title": "Manifestación", 
   "@title": {
      "description": "Title for the Demo application", 
      "type": "text", 
      "placeholders": {} 
   },
   "message": "Hola Mundo",
   "@message": {
      "description": "Message for the Demo application", 
      "type": "text", 
      "placeholders": {} 
   } 
}
  • 现在,运行以下命令以创建最终消息文件 messages_all.dart。

flutter packages pub run intl_translation:generate_from_arb 
--output-dir=lib\l10n --no-use-deferred-loading 
lib\main.dart lib\l10n\intl_en.arb lib\l10n\intl_es.arb
  • 编译并运行应用程序。它将与上面的应用程序 flutter_localization_app 类似。

广告