Flutter - Internacionalização

Hoje em dia, os aplicativos móveis são usados ​​por clientes de diferentes países e, como resultado, os aplicativos são obrigados a exibir o conteúdo em diferentes idiomas. Habilitar um aplicativo para funcionar em vários idiomas é denominado Internacionalizar o aplicativo.

Para que um aplicativo funcione em diferentes idiomas, ele deve primeiro encontrar o local atual do sistema no qual o aplicativo está sendo executado e, em seguida, mostrar seu conteúdo naquele local específico, e esse processo é chamado de localização.

A estrutura Flutter fornece três classes básicas para localização e classes de utilitários abrangentes derivadas de classes básicas para localizar um aplicativo.

As classes básicas são as seguintes -

  • Locale - Locale é uma classe usada para identificar o idioma do usuário. Por exemplo, en-us identifica o inglês americano e pode ser criado como.

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

Aqui, o primeiro argumento é o código do idioma e o segundo argumento é o código do país. Outro exemplo de criação de localidade Argentina espanhol (es-ar) é o seguinte -

Locale es_locale = Locale('es', 'AR')
  • Localizations - Localizations é um widget genérico usado para definir o Locale e os recursos localizados de seu filho.

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']; 
   } 
}
  • Aqui, CustomLocalizations é uma nova classe personalizada criada especificamente para obter determinado conteúdo localizado (título e mensagem) para o widget. do método usa a classe Localizations para retornar a nova classe CustomLocalizations.

  • LocalizationsDelegate <T> - LocalizationsDelegate <T> é uma classe de fábrica por meio da qual o widget Localizations é carregado. Tem três métodos de over-ridable -

    • isSupported - Aceita uma localidade e retorna se a localidade especificada é compatível ou não.

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

      Aqui, o delegado trabalha para en e es locale apenas.

    • load - Aceita uma localidade e começa a carregar os recursos para a localidade especificada.

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

      Aqui, o método load retorna CustomLocalizations. As CustomLocalizations retornadas podem ser usadas para obter valores de título e mensagem em inglês e espanhol

    • shouldReload - especifica se o recarregamento de CustomLocalizations é necessário quando seu widget Localizations é reconstruído.

@override 
bool shouldReload(CustomLocalizationsDelegate old) => false;
  • O código completo de CustomLocalizationDelegate é o seguinte -

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

Em geral, os aplicativos Flutter são baseados em dois widgets de nível raiz, MaterialApp ou WidgetsApp. Flutter fornece localização pronta para ambos os widgets e eles são MaterialLocalizations e WidgetsLocaliations. Além disso, o Flutter também fornece delegados para carregar MaterialLocalizations e WidgetsLocaliations e são GlobalMaterialLocalizations.delegate e GlobalWidgetsLocalizations.delegate, respectivamente.

Vamos criar um aplicativo habilitado para internacionalização simples para testar e entender o conceito.

  • Crie um novo aplicativo de flutter, flutter_localization_app.

  • Flutter apóia a internacionalização usando o pacote flutter exclusivo, flutter_localizations. A ideia é separar o conteúdo localizado do SDK principal. Abra o pubspec.yaml e adicione o código abaixo para habilitar o pacote de internacionalização -

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations:
      sdk: flutter
  • O Android Studio exibirá o seguinte alerta de que o pubspec.yaml está atualizado.

  • Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará corretamente para o aplicativo.

  • Importe o pacote flutter_localizations no main.dart da seguinte forma -

import 'package:flutter_localizations/flutter_localizations.dart'; 
import 'package:flutter/foundation.dart' show SynchronousFuture;
  • Aqui, o objetivo do SynchronousFuture é carregar as localizações personalizadas de forma síncrona.

  • Crie localizações personalizadas e seu delegado correspondente conforme especificado abaixo -

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; 
}
  • Aqui, CustomLocalizations é criado para oferecer suporte à localização de título e mensagem no aplicativo e CustomLocalizationsDelegate é usado para carregar CustomLocalizations.

  • Adicione delegados para MaterialApp, WidgetsApp e CustomLocalization usando as propriedades MaterialApp, localizationsDelegates e supportedLocales conforme especificado abaixo -

localizationsDelegates: [
   const CustomLocalizationsDelegate(),   
   GlobalMaterialLocalizations.delegate, 
   GlobalWidgetsLocalizations.delegate, 
], 
supportedLocales: [
   const Locale('en', ''),
   const Locale('es', ''), 
],
  • Use o método CustomLocalizations, de para obter o valor localizado do título e da mensagem e use-o no local apropriado, conforme especificado abaixo -

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, ), 
               ], 
            ), 
         ),
      );
   }
}
  • Aqui, modificamos a classe MyHomePage de StatefulWidget para StatelessWidget por motivos de simplicidade e usamos CustomLocalizations para obter o título e a mensagem.

  • Compile e execute o aplicativo. O aplicativo exibirá seu conteúdo em inglês.

  • Feche o aplicativo. Vamos paraSettings → System → Languages and Input → Languages*.

  • Clique em Adicionar uma opção de idioma e selecione Espanhol. Isso instalará o idioma espanhol e o listará como uma das opções.

  • Selecione Espanhol e mova-o acima de Inglês. Isso será definido como espanhol como primeiro idioma e tudo será alterado para o texto em espanhol.

  • Agora reinicie o aplicativo de internacionalização e você verá o título e a mensagem em espanhol.

  • Podemos reverter o idioma para o inglês movendo a opção Inglês acima da opção Espanhol na configuração.

  • O resultado da aplicação (em espanhol) é mostrado na imagem abaixo -

Usando pacote intl

O Flutter fornece o pacote internacional para simplificar ainda mais o desenvolvimento de aplicativos móveis localizados. O pacote intl fornece métodos e ferramentas especiais para a geração semi-automática de mensagens específicas de idioma.

Vamos criar um novo aplicativo localizado usando o pacote intl e entender o conceito.

  • Crie um novo aplicativo de flutter, flutter_intl_app.

  • Abra pubspec.yaml e adicione os detalhes do pacote.

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations: 
      sdk: flutter 
   intl: ^0.15.7 
   intl_translation: ^0.17.3
  • O Android Studio exibirá o alerta, conforme mostrado abaixo, informando que o pubspec.yaml está atualizado.

  • Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará corretamente para o aplicativo.

  • Copie main.dart do exemplo anterior, flutter_internationalization_app.

  • Importe o pacote internacional conforme mostrado abaixo -

import 'package:intl/intl.dart';
  • Atualize a classe CustomLocalization conforme mostrado no código fornecido abaixo -

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; 
}
  • Aqui, usamos três métodos do pacote intl em vez de métodos personalizados. Caso contrário, os conceitos são os mesmos.

    • Intl.canonicalizedLocale - Usado para obter o nome de localidade correto.

    • Intl.defaultLocale - usado para definir a localidade atual

    • Intl.message - Usado para definir novas mensagens.

  • importar l10n/messages_all.dartArquivo. Iremos gerar este arquivo em breve

import 'l10n/messages_all.dart';
  • Agora, crie uma pasta, lib / l10n

  • Abra um prompt de comando e vá para o diretório raiz do aplicativo (onde pubspec.yaml está disponível) e execute o seguinte comando -

flutter packages pub run intl_translation:extract_to_arb --output-
   dir=lib/l10n lib/main.dart
  • Aqui, o comando irá gerar, arquivo intl_message.arb, um modelo para criar mensagem em localidade diferente. O conteúdo do arquivo é o seguinte -

{
   "@@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": {} 
   }
}
  • Copie intl_message.arb e crie um novo arquivo, intl_en.arb.

  • Copie intl_message.arb e crie um novo arquivo, intl_es.arb e altere o conteúdo para o idioma espanhol como mostrado abaixo -

{
   "@@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": {} 
   } 
}
  • Agora, execute o seguinte comando para criar o arquivo de mensagem final, 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
  • Compile e execute o aplicativo. Ele funcionará de forma semelhante ao aplicativo acima, flutter_localization_app.