Flutter - Internacionalización

Hoy en día, las aplicaciones móviles son utilizadas por clientes de diferentes países y, como resultado, se requieren aplicaciones para mostrar el contenido en diferentes idiomas. Habilitar una aplicación para que funcione en varios idiomas se denomina internacionalización de la aplicación.

Para que una aplicación funcione en diferentes idiomas, primero debe encontrar la configuración regional actual del sistema en el que se está ejecutando la aplicación y luego debe mostrar su contenido en esa configuración regional en particular, y este proceso se llama Localización.

El marco Flutter proporciona tres clases base para la localización y amplias clases de utilidad derivadas de las clases base para localizar una aplicación.

Las clases base son las siguientes:

  • Locale : Locale es una clase que se usa para identificar el idioma del usuario. Por ejemplo, en-us identifica el inglés americano y se puede crear como.

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

Aquí, el primer argumento es el código de idioma y el segundo argumento es el código de país. Otro ejemplo de creación de la configuración regional en español de Argentina (es-ar) es el siguiente:

Locale es_locale = Locale('es', 'AR')
  • Localizaciones : las localizaciones son un widget genérico que se utiliza para configurar la configuración regional y los recursos localizados de su hijo.

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']; 
   } 
}
  • Aquí, CustomLocalizations es una nueva clase personalizada creada específicamente para obtener cierto contenido localizado (título y mensaje) para el widget. of usa la clase Localizations para devolver una nueva clase CustomLocalizations.

  • LocalizationsDelegate <T>: LocalizationsDelegate <T> es una clase de fábrica a través de la cual se carga el widget de Localizaciones. Tiene tres métodos anulables:

    • isSupported: acepta una configuración regional y devuelve si la configuración regional especificada es compatible o no.

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

      Aquí, el delegado trabaja solo para la configuración regional en y es.

    • load: acepta una configuración regional y comienza a cargar los recursos para la configuración regional especificada.

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

      Aquí, el método de carga devuelve CustomLocalizations. Las localizaciones personalizadas devueltas se pueden usar para obtener valores de título y mensaje tanto en inglés como en español

    • shouldReload: especifica si la recarga de CustomLocalizations es necesaria cuando se reconstruye su widget de Localizaciones.

@override 
bool shouldReload(CustomLocalizationsDelegate old) => false;
  • El código completo de CustomLocalizationDelegate es el siguiente:

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

En general, las aplicaciones de Flutter se basan en dos widgets de nivel raíz, MaterialApp o WidgetsApp. Flutter proporciona localización lista para usar para ambos widgets y son MaterialLocalizations y WidgetsLocaliations. Además, Flutter también proporciona delegados para cargar MaterialLocalizations y WidgetsLocaliations y son GlobalMaterialLocalizations.delegate y GlobalWidgetsLocalizations.delegate respectivamente.

Creemos una aplicación sencilla habilitada para la internacionalización para probar y comprender el concepto.

  • Cree una nueva aplicación de flutter, flutter_localization_app.

  • Flutter apoya la internacionalización utilizando el paquete flutter exclusivo, flutter_localizations. La idea es separar el contenido localizado del SDK principal. Abra pubspec.yaml y agregue el siguiente código para habilitar el paquete de internacionalización:

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations:
      sdk: flutter
  • Android Studio mostrará la siguiente alerta de que pubspec.yaml está actualizado.

  • Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo configurará correctamente para la aplicación.

  • Importe el paquete flutter_localizations en main.dart de la siguiente manera:

import 'package:flutter_localizations/flutter_localizations.dart'; 
import 'package:flutter/foundation.dart' show SynchronousFuture;
  • Aquí, el propósito de SynchronousFuture es cargar las localizaciones personalizadas de forma sincrónica.

  • Cree una localización personalizada y su delegado correspondiente como se especifica a continuación:

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; 
}
  • Aquí, CustomLocalizations se crea para admitir la localización del título y el mensaje en la aplicación y CustomLocalizationsDelegate se utiliza para cargar CustomLocalizations.

  • Agregue delegados para MaterialApp, WidgetsApp y CustomLocalization usando las propiedades de MaterialApp, localizationsDelegates y supportedLocales como se especifica a continuación:

localizationsDelegates: [
   const CustomLocalizationsDelegate(),   
   GlobalMaterialLocalizations.delegate, 
   GlobalWidgetsLocalizations.delegate, 
], 
supportedLocales: [
   const Locale('en', ''),
   const Locale('es', ''), 
],
  • Utilice el método CustomLocalizations, de para obtener el valor localizado del título y el mensaje y utilícelo en el lugar apropiado como se especifica a continuación:

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, ), 
               ], 
            ), 
         ),
      );
   }
}
  • Aquí, hemos modificado la clase MyHomePage de StatefulWidget a StatelessWidget por razones de simplicidad y usamos CustomLocalizations para obtener el título y el mensaje.

  • Compila y ejecuta la aplicación. La aplicación mostrará su contenido en inglés.

  • Cierre la aplicación. IrSettings → System → Languages and Input → Languages*.

  • Haga clic en Agregar una opción de idioma y seleccione español. Esto instalará el idioma español y luego lo listará como una de las opciones.

  • Seleccione español y muévalo arriba de inglés. Esto se establecerá como español como primer idioma y todo se cambiará al texto en español.

  • Ahora reinicie la aplicación de internacionalización y verá el título y el mensaje en idioma español.

  • Podemos revertir el idioma a inglés moviendo la opción de inglés sobre la opción de español en la configuración.

  • El resultado de la aplicación (en español) se muestra en la captura de pantalla que se muestra a continuación:

Usando el paquete intl

Flutter proporciona un paquete internacional para simplificar aún más el desarrollo de aplicaciones móviles localizadas. El paquete intl proporciona métodos y herramientas especiales para generar mensajes específicos de idioma de forma semiautomática.

Creemos una nueva aplicación localizada utilizando el paquete intl y comprendamos el concepto.

  • Cree una nueva aplicación de flutter, flutter_intl_app.

  • Abra pubspec.yaml y agregue los detalles del paquete.

dependencies: 
   flutter: 
      sdk: flutter 
   flutter_localizations: 
      sdk: flutter 
   intl: ^0.15.7 
   intl_translation: ^0.17.3
  • Android Studio mostrará la alerta como se muestra a continuación, informando que pubspec.yaml está actualizado.

  • Haga clic en la opción Obtener dependencias. Android Studio obtendrá el paquete de Internet y lo configurará correctamente para la aplicación.

  • Copie el archivo main.dart del ejemplo anterior, flutter_internationalization_app.

  • Importe el paquete intl como se muestra a continuación:

import 'package:intl/intl.dart';
  • Actualice la clase CustomLocalization como se muestra en el código que se proporciona a continuación:

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; 
}
  • Aquí, hemos utilizado tres métodos del paquete intl en lugar de métodos personalizados. De lo contrario, los conceptos son los mismos.

    • Intl.canonicalizedLocale: se utiliza para obtener el nombre correcto de la configuración regional.

    • Intl.defaultLocale: se utiliza para establecer la configuración regional actual

    • Mensaje internacional: se utiliza para definir mensajes nuevos.

  • importar l10n/messages_all.dartarchivo. Generaremos este archivo en breve

import 'l10n/messages_all.dart';
  • Ahora, cree una carpeta, lib / l10n

  • Abra un símbolo del sistema y vaya al directorio raíz de la aplicación (donde pubspec.yaml está disponible) y ejecute el siguiente comando:

flutter packages pub run intl_translation:extract_to_arb --output-
   dir=lib/l10n lib/main.dart
  • Aquí, el comando generará, archivo intl_message.arb, una plantilla para crear un mensaje en diferentes configuraciones regionales. El contenido del archivo es el siguiente:

{
   "@@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 y cree un nuevo archivo, intl_en.arb.

  • Copie intl_message.arb y cree un nuevo archivo, intl_es.arb y cambie el contenido al idioma español como se muestra a continuación:

{
   "@@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": {} 
   } 
}
  • Ahora, ejecute el siguiente comando para crear el archivo de mensaje 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
  • Compila y ejecuta la aplicación. Funcionará de forma similar a la aplicación anterior, flutter_localization_app.