Cómo internacionalizar los textos de tu app Flutter paso a paso

abr. 1, 2025

Este artículo forma parte de una serie:

Cuando desarrollamos una aplicación, solemos enfocarnos primero en las funcionalidades, el diseño y la experiencia de usuario. Sin embargo, hay un aspecto que muchas veces dejamos para el final —o peor aún, ignoramos por completo—: la internacionalización de los textos, o lo que comúnmente se conoce como i18n (abreviatura de internationalization).

¿Qué es la internacionalización y por qué deberías tenerla en cuenta desde el inicio?

La internacionalización es el proceso de preparar nuestra aplicación para que pueda adaptarse fácilmente a diferentes idiomas y regiones sin necesidad de reescribir el código base. En el caso de Flutter, este proceso es más sencillo de lo que parece, gracias al soporte integrado que ofrece el framework para i18n a través de paquetes como flutter_localizations y intl.

Pero ¿por qué deberíamos preocuparnos por esto?

  • Alcance global: Si tu aplicación está en una tienda como Google Play o App Store, es accesible desde cualquier parte del mundo. Limitarla a un solo idioma es limitar su alcance. Eso sí, traducirla a múltiples idiomas conlleva un esfuerzo adicional y mayor mantenimiento, no en todos los casos es necesario traducir la app a todos los idiomas, dependerá del público objetivo y del mercado al que se dirija.
  • Mejor experiencia de usuario: Los usuarios se sienten más cómodos y valorados cuando una app habla su idioma. Esto mejora la retención y la percepción general del producto.
  • Escalabilidad del producto: Internacionalizar desde el principio hace que sea más fácil y rápido añadir nuevos idiomas más adelante, sin tener que rehacer toda la estructura de la app.

Internacionalizar no es traducir (solamente)

Es importante entender que internacionalizar no es simplemente traducir los textos. Es crear una estructura que permita que esos textos puedan cambiar dinámicamente según el idioma del dispositivo o la preferencia del usuario. Además, se deben considerar aspectos como:

  • El formato de fechas, horas y números, que varía entre regiones.
  • La dirección del texto, ya que algunos idiomas se escriben de derecha a izquierda (como el árabe o el hebreo).
  • Las unidades de medida y monedas, en caso de que nuestra app las utilice.
  • La longitud de los textos, que puede variar considerablemente entre idiomas, y que puede afectar el diseño y el layout de nuestra interfaz si no se ha tenido en cuenta desde el inicio.

Internacionalización en Flutter

Flutter nos proporciona herramientas muy eficaces para implementar una estrategia de internacionalización robusta y mantenible. Gracias al paquete intl, podemos cargar diferentes archivos de traducción, y acceder a los textos desde cualquier parte de nuestra app.

En este artículo veremos paso a paso cómo aplicar internacionalización de textos en una aplicación Flutter, terminando con un ejemplo práctico que te servirá como base para implementarlo en tus propios proyectos.

Antes de comenzar con la configuración, es importante entender cómo se organiza el proyecto para implementar la internacionalización correctamente. A continuación te mostramos la estructura básica que utilizaremos:

  
  lib/
  ├── main.dart               // Punto de entrada de la aplicación
  ├── home_page.dart          // Página principal con los textos localizados
  ├── l10n/                   // Carpeta donde guardamos los archivos de traducción
  │   ├── app_en.arb          // Traducciones en inglés
  │   ├── app_es.arb          // Traducciones en español
  │   └── app_fr.arb          // Traducciones en francés
  l10n.yaml                   // Configuración para generación de localizaciones
  pubspec.yaml                // Declaración de dependencias y configuración del proyecto
  

Paso 1: Configuración inicial

Para empezar, asegúrate de tener un proyecto Flutter creado. Si no lo tienes, puedes ver nuestro artículo sobre Flutter. Una vez creado, abre el archivo pubspec.yaml y añade las siguientes dependencias:


  name: greeting_app
  description: A simple Flutter app with internationalization
  version: 1.0.0+1
  
  environment:
    sdk: ">=3.0.0 <4.0.0"
  
  dependencies:
    flutter:
      sdk: flutter
    flutter_localizations:
      sdk: flutter
    intl: ^0.19.0
  
  flutter:
    uses-material-design: true
    generate: true
  

Luego, ejecuta el siguiente comando para instalar las dependencias:

  
  flutter pub get
  

Necesitamos crear también un fichero l10n.yaml en la raíz del proyecto. Este archivo es donde configuraremos la localización de nuestra app.


  arb-dir: lib/l10n
  template-arb-file: app_en.arb
  output-localization-file: app_localizations.dart
  

Esto le dice a Flutter que busque los archivos .arb en la carpeta lib/l10n, que el archivo de plantilla es app_en.arb y que el archivo de salida para las clases de localización generadas será app_localizations.dart.

A continuación, crea una carpeta llamada l10n dentro de la carpeta lib. En esta carpeta, crearás los archivos .arb que contendrán las traducciones de los textos de tu aplicación. Por ejemplo, puedes crear un archivo llamado app_en.arb para el inglés, app_es.arb para el español y app_fr.arb para el francés. Estos serían los diferentes archivos:

app_en.arb


  {
    "@@locale": "en",
    "greeting": "Hello, {name}!",
    "showDate": "Show Date",
    "todayIs": "Today is {date}"
  }
  

app_es.arb

  
  {
    "@@locale": "es",
    "greeting": "¡Hola, {name}!",
    "showDate": "Mostrar fecha",
    "todayIs": "Hoy es {date}"
  }
  

app_fr.arb


  {
    "@@locale": "fr",
    "greeting": "Bonjour, {name} !",
    "showDate": "Afficher la date",
    "todayIs": "Nous sommes le {date}"
  }
  

Paso 2: Configuración de MaterialApp

Abre el archivo main.dart y configura tu MaterialApp para que soporte la localización. Aquí es donde especificarás los idiomas que tu aplicación soportará y los archivos de localización que utilizarás.

  
  import 'package:flutter/material.dart';
  import 'package:flutter_localizations/flutter_localizations.dart';
  import 'package:flutter_gen/gen_l10n/app_localizations.dart';
  import 'home_page.dart';
  
  void main() {
    runApp(const GreetingApp());
  }
  
  class GreetingApp extends StatefulWidget {
    const GreetingApp({super.key});
  
    @override
    State<GreetingApp> createState() => _GreetingAppState();
  }
  
  class _GreetingAppState extends State<GreetingApp> {
    Locale? _locale;
  
    void setLocale(Locale locale) {
      setState(() {
        _locale = locale;
      });
    }
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Greeting App',
        debugShowCheckedModeBanner: false,
        locale: _locale,
        supportedLocales: const [
          Locale('en'),
          Locale('es'),
          Locale('fr'),
        ],
        localizationsDelegates: const [
          AppLocalizations.delegate,
          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
        ],
        home: HomePage(onLocaleChange: setLocale),
      );
    }
  }
  

Los delegates son responsables de cargar las traducciones y formatear los textos según el idioma seleccionado. En este caso, estamos usando AppLocalizations.delegate para cargar nuestras traducciones personalizadas, y los delegados globales de Flutter para manejar la localización de widgets y materiales.

Paso 3: Crear la página principal

Ahora, creamos un archivo llamado home_page.dart en la carpeta lib y añade el siguiente código:


  import 'package:flutter/material.dart';
  import 'package:intl/intl.dart';
  import 'package:flutter_gen/gen_l10n/app_localizations.dart';
  
  class HomePage extends StatefulWidget {
    final void Function(Locale) onLocaleChange;
  
    const HomePage({super.key, required this.onLocaleChange});
  
    @override
    State<HomePage> createState() => _HomePageState();
  }
  
  class _HomePageState extends State<HomePage> {
    String? _formattedDate;
  
    void _showDate() {
      final now = DateTime.now();
      final localeName = Localizations.localeOf(context).languageCode;
      final formatted = DateFormat.yMMMMd(localeName).format(now);
  
      setState(() {
        _formattedDate = AppLocalizations.of(context)!.todayIs(formatted);
      });
    }
  
    void _changeLanguage(String languageCode) {
      final newLocale = Locale(languageCode);
      widget.onLocaleChange(newLocale);
    }
  
    @override
    Widget build(BuildContext context) {
      final loc = AppLocalizations.of(context)!;
  
      return Scaffold(
        appBar: AppBar(
          title: const Text('Greeting App'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(24.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                loc.greeting('John'),
                style: Theme.of(context).textTheme.headlineMedium,
              ),
              const SizedBox(height: 24),
              ElevatedButton(
                onPressed: _showDate,
                child: Text(loc.showDate),
              ),
              if (_formattedDate != null) ...[
                const SizedBox(height: 16),
                Text(
                  _formattedDate!,
                  style: Theme.of(context).textTheme.bodyLarge,
                ),
              ],
              const Spacer(),
              Text('Change Language:'),
              Row(
                children: [
                  TextButton(
                    onPressed: () => _changeLanguage('en'),
                    child: const Text('English'),
                  ),
                  TextButton(
                    onPressed: () => _changeLanguage('es'),
                    child: const Text('Español'),
                  ),
                  TextButton(
                    onPressed: () => _changeLanguage('fr'),
                    child: const Text('Français'),
                  ),
                ],
              ),
            ],
          ),
        ),
      );
    }
  }
    

Paso 4: Generar las clases de localización

Una vez que tenemos todos los archivos .arb creados y configurado el fichero l10n.yaml, es momento de generar las clases de localización que usaremos en nuestro proyecto.

Flutter incluye una herramienta llamada gen-l10n que se encarga de analizar nuestros archivos .arb y generar automáticamente el archivo app_localizations.dart.

Puedes ejecutar la generación de forma manual con el siguiente comando:

  
  flutter gen-l10n
  

Esto generará el archivo app_localizations.dart en la carpeta .dart_tool/flutter_gen/gen_l10n/ de la raíz del proyecto, que contendrá las clases necesarias para acceder a las traducciones de tu aplicación, esta carpeta es auto generada (como su nombre bien indica) y no ha de ser modificada. Llegados a este punto, ya puedes ejecutar tu aplicación y ver cómo se muestran los textos dependiendo del idioma que tenga configurado tu dispositivo, también, te permite cambiar de idioma directamente desde la app sin tener que cambiar la configuración del dispositivo.

Ahora ya estamos listos para ejecutar nuestra aplicación con el siguiente comando:

  
  flutter run
  

Conclusión

En este pequeño ejemplo práctico hemos creado una aplicación Flutter muy sencilla pero funcional, donde los textos cambian automáticamente en función del idioma del dispositivo. Veamos un breve resumen de los archivos clave y su propósito:

  • pubspec.yaml: Añadimos las dependencias necesarias para usar flutter_localizations y intl, además de habilitar la generación automática de código de localización.
  • l10n.yaml: Archivo de configuración donde le indicamos a Flutter dónde están los archivos .arb con las traducciones y cómo debe generar el código necesario.
  • Carpeta lib/l10n/ con los .arb: Aquí centralizamos todas las traducciones. Estos archivos permiten escalar fácilmente a nuevos idiomas en el futuro sin tocar el código fuente.
  • main.dart: Configuramos MaterialApp para soportar múltiples idiomas y delegados de localización.
  • home_page.dart: Creamos la interfaz principal con un saludo personalizado y un botón que muestra la fecha formateada correctamente según el idioma seleccionado.

Este ejemplo nos ayuda a entender cómo organizar un proyecto Flutter con soporte multilingüe desde el principio, siguiendo una estructura limpia y escalable. Internacionalizar una aplicación Flutter no es tan complejo como puede parecer, y los beneficios que nos aporta son enormes. Desde mejorar la experiencia del usuario hasta permitir que nuestra app crezca en nuevos mercados, preparar nuestra app para múltiples idiomas es una inversión inteligente a medio y largo plazo.

Además, Flutter pone a nuestra disposición herramientas potentes y bien integradas que nos facilitan mucho el proceso, permitiéndonos mantener un proyecto limpio, organizado y preparado para escalar.

Cabe mencionar que al lanzar la aplicación nos aparece un mensaje de advertencia hablando sobre que la librería flutter_gen será eliminada en futuras versiones de Flutter, por lo que es recomendable, para versiones creadas ahora, seguir las recomendaciones de uso de la documentación oficial.

Ya sea para proyectos personales, productos en producción o MVPs, tener una estructura de internacionalización lista desde el inicio te ahorrará dolores de cabeza en el futuro. Deja un comentario abajo si tienes alguna duda o crees que hay algo que se nos haya pasado por alto.

Happy Coding!

comments powered by Disqus

Artículos relacionados

Quizá te puedan interesar

September 15, 2024

Asincronía en Flutter

Introducción a la Asincronía en Programación En el mundo de la programación, uno de los mayores …

leer más