Flutter - интернационализация

В настоящее время мобильные приложения используются клиентами из разных стран, и, как следствие, приложения должны отображать контент на разных языках. Включение приложения для работы на нескольких языках называется интернационализацией приложения.

Чтобы приложение работало на разных языках, оно должно сначала найти текущий языковой стандарт системы, в которой работает приложение, а затем показать его содержимое в этом конкретном языковом стандарте, и этот процесс называется локализацией.

Фреймворк Flutter предоставляет три базовых класса для локализации и обширные служебные классы, производные от базовых классов, для локализации приложения.

Базовые классы следующие -

  • Locale - Locale - это класс, используемый для определения языка пользователя. Например, en-us определяет американский английский, и его можно создать как.

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

Здесь первый аргумент - это код языка, а второй аргумент - код страны. Другой пример создания аргентинского испанского (es-ar) языкового стандарта:

Locale es_locale = Locale('es', 'AR')
  • Локализации - Локализации - это общий виджет, используемый для установки языкового стандарта и локализованных ресурсов его дочернего элемента.

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 - это новый настраиваемый класс, созданный специально для получения определенного локализованного содержимого (заголовка и сообщения) для виджета. of использует класс Localizations для возврата нового класса CustomLocalizations.

  • LocalizationsDelegate <T> - LocalizationsDelegate <T> - это фабричный класс, через который загружается виджет Localizations. У него есть три метода преодоления -

    • isSupported - принимает языковой стандарт и возвращает, поддерживается ли указанный языковой стандарт или нет.

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

      Здесь делегат работает только для en и es locale.

    • load - принимает языковой стандарт и начинает загрузку ресурсов для указанного языкового стандарта.

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

      Здесь метод загрузки возвращает CustomLocalizations. Возвращенные CustomLocalizations можно использовать для получения значений заголовка и сообщения на английском и испанском языках.

    • shouldReload - указывает, требуется ли перезагрузка CustomLocalizations при перестройке его виджета Localizations.

@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 основаны на двух виджетах корневого уровня: MaterialApp или WidgetsApp. Flutter предоставляет готовую локализацию для обоих виджетов, это MaterialLocalizations и WidgetsLocalizations. Кроме того, Flutter также предоставляет делегатов для загрузки MaterialLocalizations и WidgetsLocalizations, и это соответственно GlobalMaterialLocalizations.delegate и GlobalWidgetsLocalizations.delegate.

Давайте создадим простое приложение с возможностью интернационализации, чтобы протестировать и понять концепцию.

  • Создайте новое приложение флаттера, flutter_localization_app.

  • Flutter поддерживает интернационализацию с помощью эксклюзивного пакета flutter flutter_localizations. Идея состоит в том, чтобы отделить локализованный контент от основного SDK. Откройте pubspec.yaml и добавьте ниже код, чтобы включить пакет интернационализации -

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations:
      sdk: flutter
  • Студия Android отобразит следующее предупреждение об обновлении pubspec.yaml.

  • Щелкните параметр Получить зависимости. Студия Android получит пакет из Интернета и правильно настроит его для приложения.

  • Импортируйте пакет flutter_localizations в main.dart следующим образом:

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, WidgetsApp и CustomLocalization, используя свойства MaterialApp, localizationsDelegates и supportedLocales, как указано ниже -

localizationsDelegates: [
   const CustomLocalizationsDelegate(),   
   GlobalMaterialLocalizations.delegate, 
   GlobalWidgetsLocalizations.delegate, 
], 
supportedLocales: [
   const Locale('en', ''),
   const Locale('es', ''), 
],
  • Используйте метод CustomLocalizations, чтобы получить локализованное значение заголовка и сообщения и использовать его в соответствующем месте, как указано ниже -

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 для получения заголовка и сообщения.

  • Скомпилируйте и запустите приложение. Приложение покажет свое содержимое на английском языке.

  • Закройте приложение. Идти кSettings → System → Languages and Input → Languages*.

  • Щелкните Добавить язык и выберите Испанский. Это установит испанский язык, а затем укажет его как один из вариантов.

  • Выберите испанский и переместите его над английским. Будет установлен испанский как первый язык, и все будет изменено на испанский текст.

  • Теперь перезапустите приложение интернационализации, и вы увидите заголовок и сообщение на испанском языке.

  • Мы можем вернуть язык к английскому, переместив английский вариант выше испанского в настройках.

  • Результат приложения (на испанском языке) показан на скриншоте ниже -

Использование пакета 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 отобразит предупреждение, как показано ниже, сообщающее об обновлении pubspec.yaml.

  • Щелкните параметр Получить зависимости. Студия Android получит пакет из Интернета и правильно настроит его для приложения.

  • Скопируйте файл main.dart из предыдущего примера, flutter_internationalization_app.

  • Импортируйте intl pacakge, как показано ниже -

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.