Flutter - internacjonalizacja

W dzisiejszych czasach aplikacje mobilne są używane przez klientów z różnych krajów, w związku z czym aplikacje są wymagane do wyświetlania treści w różnych językach. Umożliwienie aplikacji pracy w wielu językach nazywa się internacjonalizacją aplikacji.

Aby aplikacja działała w różnych językach, powinna najpierw znaleźć aktualne ustawienie regionalne systemu, w którym działa aplikacja, a następnie wyświetlić jej zawartość w tym konkretnym języku, a proces ten nazywa się Lokalizacja.

Framework Flutter udostępnia trzy klasy bazowe do lokalizacji i rozbudowane klasy narzędziowe pochodzące z klas bazowych do lokalizacji aplikacji.

Podstawowe klasy są następujące -

  • Locale - Locale to klasa używana do identyfikacji języka użytkownika. Na przykład en-us identyfikuje amerykański angielski i można go utworzyć jako.

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

Tutaj pierwszy argument to kod języka, a drugi to kod kraju. Kolejny przykład tworzenia ustawień regionalnych dla Argentyny (es-ar) jest następujący -

Locale es_locale = Locale('es', 'AR')
  • Lokalizacje - lokalizacje to ogólny widget używany do ustawiania ustawień regionalnych i zlokalizowanych zasobów jego elementów podrzędnych.

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']; 
   } 
}
  • Tutaj CustomLocalizations to nowa klasa niestandardowa utworzona specjalnie w celu uzyskania określonej zlokalizowanej zawartości (tytułu i komunikatu) dla widżetu. of używa klasy Localizations, aby zwrócić nową klasę CustomLocalizations.

  • LocalizationsDelegate <T> - LocalizationsDelegate <T> to klasa fabryczna, za pośrednictwem której ładowany jest widget Localizations. Ma trzy metody do pokonania -

    • isSupported - akceptuje ustawienie regionalne i zwraca, czy określone ustawienie regionalne jest obsługiwane, czy nie.

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

      W tym przypadku delegat działa tylko w językach en i es.

    • load - akceptuje ustawienia regionalne i rozpoczyna ładowanie zasobów dla określonych ustawień regionalnych.

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

      Tutaj metoda load zwraca CustomLocalizations. Zwróconych CustomLocalizations można użyć do uzyskania wartości tytułu i komunikatu w języku angielskim i hiszpańskim

    • shouldReload - określa, czy ponowne wczytanie CustomLocalizations jest konieczne, gdy jego widget Localizations jest przebudowywany.

@override 
bool shouldReload(CustomLocalizationsDelegate old) => false;
  • Pełny kod CustomLocalizationDelegate jest następujący -

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

Ogólnie rzecz biorąc, aplikacje Flutter są oparte na dwóch widżetach poziomu głównego, MaterialApp lub WidgetsApp. Flutter zapewnia gotową lokalizację dla obu widżetów i są to MaterialLocalizations i WidgetsLocaliations. Ponadto Flutter zapewnia również delegatów do ładowania MaterialLocalizations i WidgetsLocaliations i są to odpowiednio GlobalMaterialLocalizations.delegate i GlobalWidgetsLocalizations.delegate.

Stwórzmy prostą aplikację z możliwością internacjonalizacji, aby przetestować i zrozumieć koncepcję.

  • Utwórz nową aplikację flutter, flutter_localization_app.

  • Flutter wspiera internacjonalizację przy użyciu ekskluzywnego pakietu flutter, flutter_localizations. Chodzi o to, aby oddzielić zlokalizowaną zawartość od głównego zestawu SDK. Otwórz pubspec.yaml i dodaj poniższy kod, aby włączyć pakiet internacjonalizacji -

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations:
      sdk: flutter
  • Studio Android wyświetli następujący alert informujący o zaktualizowaniu pliku pubspec.yaml.

  • Kliknij opcję Pobierz zależności. Studio Android pobierze pakiet z Internetu i odpowiednio skonfiguruje go dla aplikacji.

  • Zaimportuj pakiet flutter_localizations w main.dart w następujący sposób -

import 'package:flutter_localizations/flutter_localizations.dart'; 
import 'package:flutter/foundation.dart' show SynchronousFuture;
  • Tutaj celem SynchronousFuture jest synchroniczne ładowanie niestandardowych lokalizacji.

  • Utwórz niestandardowe lokalizacje i odpowiadającego im delegata, jak określono poniżej -

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; 
}
  • Tutaj CustomLocalizations jest tworzony w celu obsługi lokalizacji tytułu i komunikatu w aplikacji, a CustomLocalizationsDelegate jest używany do ładowania CustomLocalizations.

  • Dodaj delegatów dla MaterialApp, WidgetsApp i CustomLocalization przy użyciu właściwości MaterialApp, lokalizacjiDelegates i supportedLocales, jak określono poniżej -

localizationsDelegates: [
   const CustomLocalizationsDelegate(),   
   GlobalMaterialLocalizations.delegate, 
   GlobalWidgetsLocalizations.delegate, 
], 
supportedLocales: [
   const Locale('en', ''),
   const Locale('es', ''), 
],
  • Użyj metody CustomLocalizations of, aby uzyskać zlokalizowaną wartość tytułu i komunikatu i użyj go w odpowiednim miejscu, jak określono poniżej -

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, ), 
               ], 
            ), 
         ),
      );
   }
}
  • Tutaj zmodyfikowaliśmy klasę MyHomePage ze StatefulWidget do StatelessWidget ze względu na prostotę i użyliśmy CustomLocalizations, aby uzyskać tytuł i komunikat.

  • Skompiluj i uruchom aplikację. Aplikacja wyświetli zawartość w języku angielskim.

  • Zamknij aplikację. Iść doSettings → System → Languages and Input → Languages*.

  • Kliknij Dodaj opcję języka i wybierz hiszpański. Spowoduje to zainstalowanie języka hiszpańskiego, a następnie wyświetli go jako jedną z opcji.

  • Wybierz hiszpański i przenieś go nad angielski. Spowoduje to ustawienie hiszpańskiego jako pierwszego języka i wszystko zostanie zmienione na hiszpański.

  • Teraz ponownie uruchom aplikację do internacjonalizacji, a zobaczysz tytuł i komunikat w języku hiszpańskim.

  • Możemy przywrócić język angielski, przesuwając opcję angielski nad opcję hiszpańską w ustawieniach.

  • Wynik aplikacji (po hiszpańsku) pokazano na zrzucie ekranu podanym poniżej -

Korzystanie z pakietu intl

Flutter dostarcza pakiet intl, aby jeszcze bardziej uprościć tworzenie zlokalizowanych aplikacji mobilnych. Pakiet intl zapewnia specjalne metody i narzędzia do półautomatycznego generowania komunikatów specyficznych dla języka.

Stwórzmy nową zlokalizowaną aplikację przy użyciu pakietu intl i zrozummy koncepcję.

  • Utwórz nową aplikację flutter, flutter_intl_app.

  • Otwórz pubspec.yaml i dodaj szczegóły pakietu.

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations: 
      sdk: flutter 
   intl: ^0.15.7 
   intl_translation: ^0.17.3
  • Studio Android wyświetli alert, jak pokazano poniżej, informując, że plik pubspec.yaml został zaktualizowany.

  • Kliknij opcję Pobierz zależności. Studio Android pobierze pakiet z Internetu i odpowiednio skonfiguruje go dla aplikacji.

  • Skopiuj plik main.dart z poprzedniej próbki, flutter_internationalization_app.

  • Zaimportuj pakiet intl, jak pokazano poniżej -

import 'package:intl/intl.dart';
  • Zaktualizuj klasę CustomLocalization, jak pokazano w kodzie podanym poniżej -

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; 
}
  • Tutaj użyliśmy trzech metod z pakietu intl zamiast metod niestandardowych. W przeciwnym razie koncepcje są takie same.

    • Intl.canonicalizedLocale - służy do uzyskania poprawnej nazwy ustawień regionalnych.

    • Intl.defaultLocale - Służy do ustawiania bieżących ustawień regionalnych

    • Intl.message - służy do definiowania nowych wiadomości.

  • import l10n/messages_all.dartplik. Wkrótce wygenerujemy ten plik

import 'l10n/messages_all.dart';
  • Teraz utwórz folder lib / l10n

  • Otwórz wiersz polecenia i przejdź do katalogu głównego aplikacji (gdzie dostępny jest pubspec.yaml) i uruchom następujące polecenie -

flutter packages pub run intl_translation:extract_to_arb --output-
   dir=lib/l10n lib/main.dart
  • Tutaj polecenie wygeneruje plik intl_message.arb, szablon do tworzenia wiadomości w różnych lokalizacjach. Zawartość pliku jest następująca -

{
   "@@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": {} 
   }
}
  • Skopiuj intl_message.arb i utwórz nowy plik, intl_en.arb.

  • Skopiuj intl_message.arb i utwórz nowy plik, intl_es.arb i zmień zawartość na język hiszpański, jak pokazano poniżej -

{
   "@@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": {} 
   } 
}
  • Teraz uruchom następujące polecenie, aby utworzyć ostateczny plik komunikatów, 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
  • Skompiluj i uruchom aplikację. Będzie działać podobnie do powyższej aplikacji flutter_localization_app.