Flutter, por defecto, sólo proporciona localizaciones para inglés de Estados Unidos. Por lo tanto, si queremos que nuestra aplicación esté localizada en castellano, vamos a tener que indicárselo. Veamos cómo.
Configurando nuestra aplicación
Lo primero que debemos hacer es añadir en nuestro fichero pubspec.yaml el paquete flutter_localizations. Lo correcto es que esté justo debajo del sdk:flutter o también podemos instalarlo desde la consola con la siguiente línea de comando: flutter pub add flutter_localizations --sdk=flutter
Nuestro fichero pubspec.yaml debería quedar así:
dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter
Esto nos dará acceso a todo lo necesario para continuar internacionalizando nuestra aplicación. Entre estas cosas, el paquete nos da acceso a los delegados que controlan las traducciones necesarias para los widgets de Android o de iOS que utilicemos, así cómo las traducciones de otros widgets genéricos de Flutter.
Estos delegados respectivamente son:
GlobalMaterialLocalizations.delegate GlobalCupertinoLocalizations.delegate GlobalWidgetsLocalizations.delegate
Para usarlos en nuestra aplicación, deberemos añadirlos en el constructor de nuestra MaterialApp como localizationsDelegates
return const MaterialApp( localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate ]);
Mas adelante veremos cómo crear nuestro propio delegado para traducir cadenas de textos, pero por ahora, sigamos configurando la aplicación.
Lo siguiente que debemos hacer es indicarle qué idiomas vamos a soportar. Para ello debemos seguir modificando el constructor de nuestra MaterialApp. En el ejemplo, vamos a soportar el español de España e inglés genérico, sin código de país.
return const MaterialApp( localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate ], supportedLocales: const [ Locale('es', 'ES'), //Español de españa Locale('en'), //Inglés, cualquier país ],);
Una vez añadidos los idiomas que vamos a soportar, ya podríamos arrancar nuestra aplicación y, por ejemplo, si colocamos un CalendarDatePicker
en nuestra página principal y cambiamos el idioma de nuestro teléfono de Español a Inglés, veremos cómo el primer día de la semana del calendario cambia de lunes a domingo y viceversa.
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Column( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ CalendarDatePicker( initialDate: DateTime.now(), firstDate: DateTime(1900), lastDate: DateTime(2100), onDateChanged: (value) {}), ], ), ); } }
Construyendo nuestro propio delegado
Ahora veamos cómo hacer para traducir nuestras propias cadenas de texto. Como ya hemos dicho, vamos a necesitar crear un delegado. Lo bueno es que, de la parte de «crear el delegado» se va encargar el generador de código de Flutter. Nosotros sólo tenemos que crear un fichero de configuración con formato .yaml, los ficheros de recursos con formato .arb y habilitar el generador de código de Flutter
Comencemos por el fichero de configuración. Este fichero lo colocamos en la raíz del proyecto y, como estamos hablando de localizar nuestra aplicación, lo podemos llamar l10n.yaml.
El contenido del fichero será el siguiente:
l10n.yaml
arb-dir: lib/l10n template-arb-file: strings_es.arb output-localization-file: app_localizations.dart untranslated-messages-file: untranslated.txt
- arb-dir: Indica la carpeta donde vamos a colocar los ficheros con las traducciones.
- template-arb-file: Indica el fichero de traducciones por defecto de nuestra aplicación. Este fichero deberá estar incluido en la carpeta que hemos escrito en la opción anterior ( arb-dir ) y como ya sabemos, tendrá el formato .arb que básicamente es muy parecido a un fichero .json y en su contenido tendremos una serie de identificadores de las cadenas a traducir, su traducción y una breve descripción. Más adelante veremos esto con detalle. En este ejemplo, el fichero lo he llamado strings_es.arb, pero podría llamarse papa_es.arb. Lo importante es entender que este será el fichero plantilla para la generación del código, es decir, los identificadores de las cadenas de texto que no estén en este fichero, pero sí puedan estar en otros, no se tendrán en cuenta para la generación.
- output-localization-file: Indica el nombre del fichero que Flutter debe generar con el delegado para soportar los diferentes lenguajes que utilicemos. Lo podemos llamar como queramos, pero la clase que generará se llamará AppLocalizations con lo que por convención el archivo lo llamamos app_localizations.dart
- untranslated-messages-file: Este apartado no es obligatorio, pero, en mi opinión, es realmente útil al indicarlo y poner un nombre de fichero con extensión .txt. El proceso de generación nos escribirá en él los posibles errores durante el proceso de generación, identificadores de cadenas que no existen en un fichero u otro por ejemplo, con lo que facilita el mantenimiento de nuestras traducciones.
Este sería el contenido básico del fichero de configuración para la generación de nuestro delegado. Hay muchas mas opciones que puedes consultar aquí.
Añadiendo nuestras traducciones
Nuestro siguiente paso es generar los ficheros con las traducciones, como ya hemos visto. Estos ficheros deberán estar en la carpeta lib/l10n. Recordemos que tendremos tantos ficheros como idiomas queramos soportar.
En el fichero de configuración hemos decidido que los ficheros se van a llamar strings<código de idiona>.arb, por lo que en nuestro ejemplo, deberíamos terminar con dos ficheros:
En su forma mas sencilla, el contenido de los ficheros será el siguiente:
strings_en.arb
{
"titleApp": "Traducciones",
"@titleApp": {
"description": "El título de la aplicación"
},
"helloWorld": "Hola Mundo!",
"@helloWorld": {
"description": "El saludo convencional del programador novato."
}
}
Y por lo tanto el contenido del fichero strings_en.arb deberá ser:
{
"titleApp": "Translations!",
"@titleApp": {
"description": "The title of the app"
},
"helloWorld": "Hello World!",
"@helloWorld": {
"description": "The conventional newborn programmer greeting"
}
}
- Identificador de la cadena: El identificador de la cadena debe ser único y estará acompañado del valor traducido. En el ejemplo estamos viendo el fichero en español. Este identificativo deberá existir igual en el fichero strings_en.arb, pero con la traducción de la palabra Traducciones al idioma inglés.
- Referencia al indicador: La generación del código podemos controlarla gracias al formato .arb. Con este formato podemos añadir descripciones para la cadena e incluso operaciones más complejas, como configurar placeholders, la pluralización o sustitución de valores dentro de la cadena traducida, etc. Para más información sobre cómo controlar la generación puedes consultarla aquí.
Activando la generación de código
Ya por último, sólo nos queda habilitar la generación de código de Flutter. Para ello, volvemos al fichero pubspec.yaml y buscamos la parte de Flutter, ahí añadimos generate: true.
El fichero debería quedar de la siguiente manera:
flutter: generate: true
Ahora, desde el terminal, debemos realizar un flutter clean
y un flutter pub get
. Si todo ha ido bien, que sí, Flutter nos habrá generado en nuestra carpeta de proyecto la siguiente estructura:
Vemos que tenemos los ficheros app_localizations_en.dart, app_localizations_**_es**.dart y app_localizations.dart. Este último es el delegado que controlará nuestras traducciones, y si lo abrimos, ya nos explica los siguientes pasos que debemos seguir para añadir el delegado en la aplicación.
Añadiendo nuestro delegado
Como último paso, debemos añadir nuestro delegado en la lista de delegados para la localización. Esta lista la añadimos en MaterialApp casi al principio de este tutorial.
Para poder configurarlo, primero debemos importar el fichero en nuestro main.dart o donde estemos inicializando MaterialApp
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Y luego ya podemos añadir el delegado
return const MaterialApp( localizationsDelegates: [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate ], supportedLocales: const [ Locale('es', 'ES'), //Español de españa Locale('en'), //Inglés, cualquier país ],);
Ya podemos usar nuestras cadenas de texto y ver cómo son traducidas, para ello basta con invocarlas de la siguiente manera:
AppLocalizations.of(context)!.helloWorld
Podemos hacerlo dentro de cualquier widget, por ejemplo, añadamos un widget de texto debajo del calendario
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Column( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ CalendarDatePicker( initialDate: DateTime.now(), firstDate: DateTime(1900), lastDate: DateTime(2100), onDateChanged: (value) {}), Text(AppLocalizations.of(context)!.helloWorld), ], ), ); } }
Ahora, si ejecutamos la aplicación y cambiamos el idioma, veremos cómo nuestro widget de texto, con el texto Hola Mundo! será traducido al idioma seleccionado.
Y voilà, hemos terminado de localizar nuestra aplicación de Flutter, por lo menos en cuanto a las cadenas de texto y los controles por defecto… porque, existe otro paquete que nos ayudará también a localizar nuestra aplicación dándonos herramientas para el formato numérico, el formato de las fechas e incluso para trabajar mejor con nuestros ficheros .arb. Ese paquete es intl, pero ese, será otro post 😉
Tienes el código de ejemplo en este enlace.