Flutter: ¿Cómo agregar soporte para múltiples idiomas en tu aplicación?
En un mundo globalizado, las aplicaciones móviles necesitan romper las barreras del idioma para llegar a una audiencia más amplia. Flutter, con su enfoque multiplataforma, facilita la internacionalización y la localización de tu app, permitiéndote ofrecer una experiencia personalizada a usuarios de diferentes idiomas.
1. Configuración del Proyecto Flutter
Para comenzar a utilizar flutter_localizations
, necesitas agregar el paquete como una dependencia en tu archivo pubspec.yaml
, junto con el paquete intl
. Para hacerlo, ejecuta los siguientes comandos en tu terminal:
flutter pub add flutter_localizations --sdk=flutter
flutter pub add intl:any
Esto agregará las siguientes entradas a tu archivo pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
2. Crear Archivo de Recursos de Localización
Dentro de la carpeta lib
, crea una subcarpeta llamada l10n
. Dentro de esta carpeta, crea un archivo llamado app_en.arb
para almacenar tus recursos de localización en inglés.
3. Configurar Archivo de Configuración de Localización
Agrega un nuevo archivo YAML al directorio raíz del proyecto Flutter y nómbralo l10n.yaml
. Dentro de este archivo, incluye el siguiente contenido para configurar la generación de archivos de localización:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
4. Habilitar Generación Automática
Abre el archivo pubspec.yaml
y habilita el indicador de generación para permitir la generación automática de archivos de localización:
flutter:
generate: true # Agrega esta línea
5. Agregar Contenido al Archivo de Recursos en Inglés
Dentro de ${FLUTTER_PROJECT}/lib/l10n
, agrega el siguiente contenido al archivo app_en.arb
:
{
"testMedium": "Test for Medium"
}
6. Agregar Archivo de Recursos en Español
Agrega otro archivo llamado app_es.arb
en el mismo directorio. En este archivo, añade la traducción al español del mismo mensaje:
{
"testMedium": "Prueba para Medium"
}
7. Generar Archivos Automáticamente
Luego, ejecuta flutter pub get
o flutter run
en tu terminal. El generador de código realizará automáticamente la generación de archivos de localización. Puedes encontrar los archivos generados en ${FLUTTER_PROJECT}/.dart_tool/flutter_gen/gen_l10n
.
8. Integrar la Localización en el Archivo Main
Dentro del archivo main.dart
, asegúrate de importar las bibliotecas necesarias y de configurar la localización en el constructor de MaterialApp
:
import 'package:flutter/material.dart';
import 'package:multilang_app/screens/my_app.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
locale: Locale("EN"), //// Establece el idioma predeterminado a inglés
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: AppLocalizations.localizationsDelegates,
home: MyApp(),
);
}
}
9. Integración de Flutter Bloc para Manejar el Estado del Locale
Comencemos instalando las dependencias necesarias:
flutter pub add flutter_bloc
flutter pub add equatable
10. Definición del Archivo de Idiomas
Antes de crear el bloc, crearemos un archivo language.dart
en una carpeta utils
con la siguiente estructura:
import 'dart:ui';
enum Language { english, spanish }
extension LanguageExtension on Language {
String get locale {
switch (this) {
case Language.english:
return 'en';
case Language.spanish:
return 'es';
default:
return 'en';
}
}
String get name {
switch (this) {
case Language.english:
return 'English';
case Language.spanish:
return 'Español';
default:
return 'English';
}
}
String get flag {
switch (this) {
case Language.english:
return '🇺🇸';
case Language.spanish:
return '🇪🇸';
default:
return '🇺🇸';
}
}
Locale get localeValue {
switch (this) {
case Language.english:
return const Locale('en', "US");
case Language.spanish:
return const Locale('es', "ES");
default:
return const Locale('en', "US");
}
}
}
11. Estructura del Bloc de Localización
Crea la carpeta locale_bloc
y dentro de ella los siguientes archivos:
locale_bloc.dart
locale_event.dart
locale_state.dart
12. Definición de Estados del Bloc de Localización
Dentro del archivo locale_state.dart
, añade el siguiente contenido para definir los estados del bloque de localización. Inicializamos el idioma como inglés por defecto:
part of 'locale_bloc.dart';
sealed class LocaleState extends Equatable {
final Language selectedLanguage;
const LocaleState({Language? language})
: selectedLanguage = language ?? Language.english;
@override
List<Object> get props => [selectedLanguage];
}
final class LocaleInitial extends LocaleState {}
final class LocaleChanged extends LocaleState {
const LocaleChanged({super.language});
}
13. Definición de Eventos del Bloc de Localización
Dentro del archivo locale_event.dart
, añade el siguiente contenido para definir los eventos del bloque de localización, específicamente el evento para cambiar el idioma:
part of 'locale_bloc.dart';
sealed class LocaleEvent extends Equatable {
const LocaleEvent();
@override
List<Object> get props => [];
}
class ChangeLanguage extends LocaleEvent {
final Language selectedLanguage;
const ChangeLanguage(this.selectedLanguage);
@override
List<Object> get props => [selectedLanguage];
}
14. Implementación del Bloc de Localización
En el archivo locale_bloc.dart
, agrega el siguiente contenido para implementar el bloque de localización, incluyendo la lógica para manejar el evento de cambio de idioma:
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:multilang_app/infrastructure/utils/language.dart';
part 'locale_event.dart';
part 'locale_state.dart';
class LocaleBloc extends Bloc<LocaleEvent, LocaleState> {
LocaleBloc() : super(LocaleInitial()) {
on<ChangeLanguage>(_onChangeLanguage);
}
_onChangeLanguage(ChangeLanguage event, Emitter<LocaleState> emit) {
emit(LocaleChanged(language: event.selectedLanguage));
}
}
15. Integración del LocaleBloc en main.dart
En el archivo main.dart
, utilizamos MultiBlocProvider
para proporcionar el LocaleBloc
a toda la aplicación. Luego, en el BlocBuilder
, configuramos el idioma de la aplicación según el estado inicial del LocaleBloc
, que es inglés:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'presentation/blocs/locale_bloc/locale_bloc.dart';
import 'package:multilang_app/infrastructure/utils/language.dart';
import 'package:multilang_app/presentation/screens/my_app.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<LocaleBloc>(create: (_) => LocaleBloc()),
],
child: BlocBuilder<LocaleBloc, LocaleState>(
builder: (context, state) {
return MaterialApp(
debugShowCheckedModeBanner: false,
locale: state.selectedLanguage.localeValue,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: AppLocalizations.localizationsDelegates,
home: const MyApp(),
);
},
),
);
}
}
16. Utilización de AppLocalizations en MyApp
En la clase MyApp
, importamos AppLocalizations
y creamos la variable l10n
para acceder a los textos localizados. Luego, utilizamos esta variable para mostrar el texto localizado en la interfaz de usuario:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:multilang_app/infrastructure/utils/language.dart';
import 'package:multilang_app/presentation/blocs/locale_bloc/locale_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: const Text('Multilang App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
BlocBuilder<LocaleBloc, LocaleState>(
builder: (context, state) {
return _buildLanguageSwitch(
context,
Theme.of(context),
state,
);
},
),
Text(
l10n.testMedium,
style: const TextStyle(fontSize: 25),
),
],
),
),
);
}
}
17. Creación del Widget buildLanguageSwitch
Creamos el widget buildLanguageSwitch
que nos permite alternar entre los idiomas español e inglés en nuestra aplicación:
Widget _buildLanguageSwitch(
BuildContext context,
ThemeData theme,
LocaleState state,
) {
return TextButton(
onPressed: () {
context.read<LocaleBloc>().add(
ChangeLanguage(
state.selectedLanguage == Language.english
? Language.spanish
: Language.english,
),
);
},
child: RichText(
text: TextSpan(children: [
TextSpan(
text: "EN",
style: TextStyle(
fontSize: 18,
color: state.selectedLanguage == Language.english
? Colors.blue
: Colors.black,
),
),
const TextSpan(
text: " | ",
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
TextSpan(
text: "ES",
style: TextStyle(
fontSize: 18,
color: state.selectedLanguage == Language.spanish
? Colors.blue
: Colors.black,
),
),
]),
),
);
}
En este proceso, hemos explorado paso a paso cómo implementar la internacionalización y localización en una aplicación Flutter de manera eficiente y organizada. Desde la configuración inicial del proyecto hasta la integración de Flutter Bloc para gestionar el estado del locale y la implementación de la alternancia entre idiomas en la interfaz de usuario, hemos demostrado cómo crear una aplicación multilingüe con facilidad.
Recursos:
El código fuente del proyecto está disponible en GitHub:
Gracias por leer!