IntlPull
Tutorial
15 min read

Cómo Internacionalizar tu App Flutter con Archivos ARB: Tutorial Completo

Aprende a internacionalizar tu aplicación Flutter usando archivos ARB y el paquete Intl. Guía paso a paso que cubre configuración, plurales, formas de género, formato de fechas y flujos de trabajo optimizados con IntlPull CLI para aplicaciones multilingües listas para producción.

Equipo IntlPull
Equipo IntlPull
20 Feb 2026, 01:39 PM [PST]
On this page
Summary

Aprende a internacionalizar tu aplicación Flutter usando archivos ARB y el paquete Intl. Guía paso a paso que cubre configuración, plurales, formas de género, formato de fechas y flujos de trabajo optimizados con IntlPull CLI para aplicaciones multilingües listas para producción.

Construir una aplicación Flutter que llegue a usuarios de todo el mundo requiere una internacionalización (i18n) adecuada. Si bien Flutter proporciona un excelente soporte i18n desde el principio, comprender cómo usar efectivamente los archivos ARB (Application Resource Bundle) puede marcar la diferencia entre un flujo de trabajo de localización torpe y un sistema optimizado y mantenible. Este tutorial completo te guía a través de todo lo que necesitas saber sobre la internacionalización de tu aplicación Flutter con archivos ARB, desde la configuración básica hasta patrones avanzados y herramientas modernas con IntlPull.

¿Qué son los Archivos ARB y Por Qué Usarlos?

ARB (Application Resource Bundle) es un formato basado en JSON diseñado específicamente para almacenar recursos localizables. Originalmente creado por Google, los archivos ARB se han convertido en el estándar para la internacionalización de Flutter porque ofrecen varias ventajas clave:

Seguridad de Tipos: Los archivos ARB funcionan con la generación de código de Flutter para crear métodos de traducción con seguridad de tipos, detectando errores en tiempo de compilación en lugar de tiempo de ejecución.

Metadatos Enriquecidos: A diferencia del JSON simple, los archivos ARB admiten metadatos para cada traducción, incluidas descripciones, marcadores de posición y ejemplos que ayudan a los traductores a comprender el contexto.

Soporte de Formato de Mensaje ICU: Soporte integrado para reglas gramaticales complejas como plurales, formas de género y texto condicional.

Integración de Herramientas: Los archivos ARB se integran perfectamente con sistemas de gestión de traducción, facilitando la colaboración en equipo.

Así es como se ve un archivo ARB básico:

JSON
1{
2  "@@locale": "es",
3  "helloWorld": "¡Hola Mundo!",
4  "@helloWorld": {
5    "description": "El saludo convencional del programador novato"
6  }
7}

La clave @@locale identifica el idioma, helloWorld es tu clave de traducción, y @helloWorld contiene metadatos que ayudan a los traductores a comprender el contexto.

Configuración de la Internacionalización de Flutter

Construyamos una configuración completa de internacionalización desde cero. Crearemos una aplicación simple que demuestre todos los conceptos clave.

Paso 1: Agregar Dependencias Requeridas

Primero, actualiza tu pubspec.yaml para incluir los paquetes necesarios:

YAML
1dependencies:
2  flutter:
3    sdk: flutter
4  flutter_localizations:
5    sdk: flutter
6  intl: ^0.19.0
7
8flutter:
9  generate: true

El paquete flutter_localizations proporciona soporte de localización para widgets Material y Cupertino, mientras que intl maneja el formato de mensajes, fechas/horas y números.

Paso 2: Configurar la Generación de Código

Crea un archivo llamado l10n.yaml en la raíz de tu proyecto:

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

Esta configuración le dice a Flutter dónde encontrar tus archivos ARB y dónde generar el código de localización.

Paso 3: Crear tu Primer Archivo ARB

Crea el directorio lib/l10n y agrega tu archivo de plantilla app_en.arb:

JSON
1{
2  "@@locale": "en",
3  "appTitle": "Mi Aplicación Increíble",
4  "@appTitle": {
5    "description": "El título de la aplicación"
6  },
7  "welcomeMessage": "¡Bienvenido a nuestra aplicación!",
8  "@welcomeMessage": {
9    "description": "Mensaje mostrado en la pantalla de inicio"
10  },
11  "greeting": "¡Hola, {name}!",
12  "@greeting": {
13    "description": "Saludo personalizado",
14    "placeholders": {
15      "name": {
16        "type": "String",
17        "example": "Alicia"
18      }
19    }
20  }
21}

Paso 4: Agregar Idiomas Adicionales

Crea app_es.arb para español:

JSON
1{
2  "@@locale": "es",
3  "appTitle": "Mi Aplicación Increíble",
4  "welcomeMessage": "¡Bienvenido a nuestra aplicación!",
5  "greeting": "¡Hola, {name}!"
6}

Observa que solo necesitas incluir las traducciones, no los metadatos. Los metadatos del archivo de plantilla se usan automáticamente.

Paso 5: Generar Código de Localización

Ejecuta el comando de generación de código:

Terminal
flutter gen-l10n

Esto crea clases Dart con seguridad de tipos en .dart_tool/flutter_gen/gen_l10n/ que usarás para acceder a tus traducciones.

Paso 6: Configurar tu Aplicación

Actualiza tu main.dart para habilitar la localización:

DART
1import 'package:flutter/material.dart';
2import 'package:flutter_localizations/flutter_localizations.dart';
3import 'package:flutter_gen/gen_l10n/app_localizations.dart';
4
5void main() {
6  runApp(const MyApp());
7}
8
9class MyApp extends StatelessWidget {
10  const MyApp({super.key});
11
12  
13  Widget build(BuildContext context) {
14    return MaterialApp(
15      title: 'Demo i18n Flutter',
16      localizationsDelegates: const [
17        AppLocalizations.delegate,
18        GlobalMaterialLocalizations.delegate,
19        GlobalWidgetsLocalizations.delegate,
20        GlobalCupertinoLocalizations.delegate,
21      ],
22      supportedLocales: const [
23        Locale('en'),
24        Locale('es'),
25      ],
26      home: const HomeScreen(),
27    );
28  }
29}

Paso 7: Usar Traducciones en tus Widgets

Ahora puedes acceder a las traducciones en cualquier widget:

DART
1class HomeScreen extends StatelessWidget {
2  const HomeScreen({super.key});
3
4  
5  Widget build(BuildContext context) {
6    final l10n = AppLocalizations.of(context)!;
7
8    return Scaffold(
9      appBar: AppBar(
10        title: Text(l10n.appTitle),
11      ),
12      body: Center(
13        child: Column(
14          mainAxisAlignment: MainAxisAlignment.center,
15          children: [
16            Text(
17              l10n.welcomeMessage,
18              style: Theme.of(context).textTheme.headlineMedium,
19            ),
20            const SizedBox(height: 20),
21            Text(l10n.greeting('Alicia')),
22          ],
23        ),
24      ),
25    );
26  }
27}

¡Eso es todo! Tu aplicación ahora admite múltiples idiomas. La configuración regional del dispositivo determinará automáticamente qué idioma mostrar.

Manejo de Plurales y Formas de Género

Una de las características más poderosas de los archivos ARB es el soporte para el formato de mensaje ICU, que maneja reglas gramaticales complejas que varían entre idiomas.

Formas Plurales

Diferentes idiomas tienen diferentes reglas de plural. El inglés tiene dos formas (uno/otros), pero el polaco tiene tres y el árabe tiene seis. Los archivos ARB manejan esto automáticamente:

JSON
1{
2  "itemCount": "{count, plural, =0{Sin artículos} =1{Un artículo} other{{count} artículos}}",
3  "@itemCount": {
4    "description": "Número de artículos en el carrito",
5    "placeholders": {
6      "count": {
7        "type": "int"
8      }
9    }
10  }
11}

Uso en Dart:

DART
Text(l10n.itemCount(0)); // "Sin artículos"
Text(l10n.itemCount(1)); // "Un artículo"
Text(l10n.itemCount(5)); // "5 artículos"

Formas de Género

Algunos idiomas requieren texto diferente según el género:

JSON
1{
2  "replyMessage": "{gender, select, male{Él respondió a tu mensaje} female{Ella respondió a tu mensaje} other{Respondieron a tu mensaje}}",
3  "@replyMessage": {
4    "description": "Mensaje de notificación para respuestas",
5    "placeholders": {
6      "gender": {
7        "type": "String"
8      }
9    }
10  }
11}

Uso:

DART
Text(l10n.replyMessage('female')); // "Ella respondió a tu mensaje"

Combinación de Plurales y Género

Puedes anidar estos patrones para escenarios complejos:

JSON
1{
2  "friendRequest": "{count, plural, =1{{gender, select, male{Él} female{Ella} other{Te}} te envió una solicitud de amistad} other{{count} personas te enviaron solicitudes de amistad}}",
3  "@friendRequest": {
4    "placeholders": {
5      "count": {"type": "int"},
6      "gender": {"type": "String"}
7    }
8  }
9}

Formato de Fecha, Hora y Números

Los archivos ARB admiten formato consciente de la configuración regional para fechas, horas y números.

Formato de Fecha

JSON
1{
2  "lastSeen": "Última vez visto: {date}",
3  "@lastSeen": {
4    "placeholders": {
5      "date": {
6        "type": "DateTime",
7        "format": "yMMMd"
8      }
9    }
10  }
11}

Formatos de fecha comunes:

  • yMMMd: 12 feb 2026
  • yMMMMd: 12 de febrero de 2026
  • jm: 5:30 PM
  • yMd: 12/2/2026

Uso:

DART
Text(l10n.lastSeen(DateTime.now()));
// Español: "Última vez visto: 12 feb 2026"

Formato de Números y Moneda

JSON
1{
2  "price": "Precio: {amount}",
3  "@price": {
4    "placeholders": {
5      "amount": {
6        "type": "double",
7        "format": "currency",
8        "optionalParameters": {
9          "symbol": "$",
10          "decimalDigits": 2
11        }
12      }
13    }
14  },
15  "discount": "Ahorra {percent}%",
16  "@discount": {
17    "placeholders": {
18      "percent": {
19        "type": "int",
20        "format": "compact"
21      }
22    }
23  }
24}

Uso:

DART
Text(l10n.price(29.99)); // "Precio: $29.99"
Text(l10n.discount(15)); // "Ahorra 15%"

Organización de Archivos de Traducción Grandes

A medida que tu aplicación crece, gestionar las traducciones se vuelve más complejo. Aquí hay estrategias para mantener las cosas organizadas.

Espacio de Nombres por Característica

En lugar de un archivo ARB masivo, divide las traducciones por característica:

lib/l10n/
  ├── app_es.arb          # Cadenas globales
  ├── auth_es.arb         # Autenticación
  ├── profile_es.arb      # Perfil de usuario
  ├── settings_es.arb     # Configuración
  └── ...

Actualiza l10n.yaml:

YAML
1arb-dir: lib/l10n
2template-arb-file: app_en.arb
3output-localization-file: app_localizations.dart
4synthetic-package: false

Usar Nombres de Clave Descriptivos

Malo:

JSON
1{
2  "btn1": "Enviar",
3  "msg2": "Ocurrió un error"
4}

Bueno:

JSON
1{
2  "submitButton": "Enviar",
3  "networkErrorMessage": "Ocurrió un error"
4}

Agregar Contexto con Metadatos

Siempre incluye descripciones y ejemplos:

JSON
1{
2  "tapToEdit": "Toca para editar",
3  "@tapToEdit": {
4    "description": "Texto de sugerencia mostrado debajo de campos editables",
5    "context": "Usado en la pantalla de perfil para el campo de biografía"
6  }
7}

Esto ayuda a los traductores a comprender dónde y cómo se usa el texto, lo que lleva a mejores traducciones.

Optimización de Flujos de Trabajo con IntlPull

Gestionar archivos ARB manualmente funciona para proyectos pequeños, pero a medida que tu equipo y el recuento de traducciones crecen, necesitas mejores herramientas. IntlPull proporciona una plataforma completa de gestión de traducción diseñada específicamente para desarrolladores.

¿Por Qué IntlPull para Flutter?

Soporte Nativo de ARB: IntlPull comprende la estructura de archivos ARB, incluido el formato de mensaje ICU, marcadores de posición y metadatos.

Editor Visual de ICU: Crea formas plurales y de género complejas sin memorizar la sintaxis ICU.

Integración CLI: Automatiza la sincronización de traducciones en tu pipeline CI/CD.

Actualizaciones OTA: Despliega correcciones de traducción instantáneamente sin envíos a la tienda de aplicaciones.

Extensión de Chrome: Edita traducciones directamente en tu aplicación en ejecución.

Configuración de IntlPull CLI

Instala el CLI globalmente:

Terminal
npm install -g @intlpullhq/cli

Inicializa en tu proyecto Flutter:

Terminal
cd my_flutter_app
intlpull init --framework flutter

El CLI detecta automáticamente tus archivos ARB y crea un archivo de configuración:

JSON
1{
2  "projectId": "tu-id-de-proyecto",
3  "apiKey": "ip_live_...",
4  "framework": "flutter",
5  "sourcePath": "lib/l10n",
6  "format": "arb",
7  "languages": ["en", "es", "fr", "de"],
8  "defaultLanguage": "en"
9}

Push y Pull de Traducciones

Sube tus archivos ARB existentes:

Terminal
intlpull push

Descarga las últimas traducciones:

Terminal
intlpull pull

Observa cambios durante el desarrollo:

Terminal
intlpull watch

Este comando sincroniza traducciones en tiempo real mientras tu equipo realiza actualizaciones en el panel de IntlPull.

Edición Visual de Traducciones

El panel de IntlPull proporciona una experiencia de edición enriquecida:

  • Ver todos los idiomas lado a lado
  • Editor visual de ICU para plurales y formas de género
  • Contexto de captura de pantalla para cada traducción
  • Hilos de comentarios para preguntas de traductores
  • Sugerencias de memoria de traducción
  • Traducción impulsada por IA con conciencia de contexto

Extracción Automatizada de Cadenas

IntlPull puede escanear tu código Dart y extraer cadenas codificadas:

Terminal
intlpull scan --auto-wrap

Antes:

DART
Text('Bienvenido a nuestra aplicación')

Después:

DART
Text(AppLocalizations.of(context)!.welcomeToOurApp)

El CLI agrega automáticamente la nueva clave a tus archivos ARB.

Actualizaciones de Traducción OTA

Una de las características más poderosas de IntlPull son las actualizaciones Over-The-Air (OTA). Corrige errores tipográficos y actualiza traducciones sin pasar por el proceso de revisión de la tienda de aplicaciones.

Agrega el paquete OTA:

Terminal
flutter pub add intlpull_ota

Inicializa en tu aplicación:

DART
1import 'package:intlpull_ota/intlpull_ota.dart';
2
3void main() async {
4  WidgetsFlutterBinding.ensureInitialized();
5
6  final ota = IntlPullOTA(
7    projectId: 'tu-id-de-proyecto',
8    apiKey: 'ip_live_...',
9    environment: 'production',
10  );
11
12  await ota.initialize();
13
14  runApp(MyApp(ota: ota));
15}

Integra con tu localización:

DART
1class MyApp extends StatelessWidget {
2  final IntlPullOTA ota;
3  const MyApp({required this.ota, super.key});
4
5  
6  Widget build(BuildContext context) {
7    return OTAProvider(
8      ota: ota,
9      child: MaterialApp(
10        localizationsDelegates: [
11          OTALocalizationsDelegate(ota),
12          AppLocalizations.delegate,
13          GlobalMaterialLocalizations.delegate,
14          GlobalWidgetsLocalizations.delegate,
15        ],
16        supportedLocales: const [
17          Locale('en'),
18          Locale('es'),
19          Locale('fr'),
20        ],
21        home: const HomeScreen(),
22      ),
23    );
24  }
25}

Ahora cuando publiques actualizaciones desde el CLI:

Terminal
intlpull publish --version 1.2.0 --message "Corregido error tipográfico en botón de pago"

Todos los usuarios reciben la actualización en su próximo inicio de aplicación. Sin envío a la tienda de aplicaciones, sin esperar revisión, sin forzar a los usuarios a actualizar.

Integración CI/CD

Agrega validación de traducción a tu pipeline CI:

YAML
1# .github/workflows/ci.yml
2name: CI
3
4on: [push, pull_request]
5
6jobs:
7  validate-translations:
8    runs-on: ubuntu-latest
9    steps:
10      - uses: actions/checkout@v3
11      
12      - name: Configurar Node
13        uses: actions/setup-node@v3
14        with:
15          node-version: '18'
16      
17      - name: Instalar IntlPull CLI
18        run: npm install -g @intlpullhq/cli
19      
20      - name: Validar Traducciones
21        env:
22          INTLPULL_API_KEY: ${{ secrets.INTLPULL_API_KEY }}
23        run: |
24          intlpull validate --missing --unused --fail-on-error
25      
26      - name: Descargar Últimas Traducciones
27        run: intlpull pull
28      
29      - name: Generar Localizaciones
30        run: flutter gen-l10n

Esto asegura:

  • No hay traducciones faltantes en ningún idioma
  • No hay claves no utilizadas que desordenen tus archivos ARB
  • Las últimas traducciones siempre se incluyen en las compilaciones

Pruebas de tu Internacionalización

Las pruebas adecuadas aseguran que tu aplicación funcione correctamente en todos los idiomas admitidos.

Pruebas Unitarias para Traducciones

Prueba que las traducciones se carguen correctamente:

DART
1import 'package:flutter_test/flutter_test.dart';
2import 'package:flutter_gen/gen_l10n/app_localizations.dart';
3
4void main() {
5  test('Las traducciones en español se cargan', () async {
6    final localizations = await AppLocalizations.delegate.load(
7      const Locale('es'),
8    );
9    
10    expect(localizations.appTitle, 'Mi Aplicación Increíble');
11    expect(localizations.greeting('Alicia'), '¡Hola, Alicia!');
12  });
13
14  test('Las formas plurales funcionan correctamente', () async {
15    final localizations = await AppLocalizations.delegate.load(
16      const Locale('es'),
17    );
18    
19    expect(localizations.itemCount(0), 'Sin artículos');
20    expect(localizations.itemCount(1), 'Un artículo');
21    expect(localizations.itemCount(5), '5 artículos');
22  });
23}

Pruebas de Widget

Prueba que tu UI muestre las traducciones correctamente:

DART
1testWidgets('La pantalla de inicio muestra el título traducido', (tester) async {
2  await tester.pumpWidget(
3    MaterialApp(
4      locale: const Locale('es'),
5      localizationsDelegates: const [
6        AppLocalizations.delegate,
7        GlobalMaterialLocalizations.delegate,
8        GlobalWidgetsLocalizations.delegate,
9      ],
10      supportedLocales: const [Locale('es')],
11      home: const HomeScreen(),
12    ),
13  );
14
15  expect(find.text('Mi Aplicación Increíble'), findsOneWidget);
16});

Mejores Prácticas y Errores Comunes

Hacer: Usar Claves Descriptivas

Las claves deben describir el contenido, no la ubicación:

Malo:

JSON
1{
2  "homeScreen_title": "Bienvenido",
3  "screen2_button1": "Enviar"
4}

Bueno:

JSON
1{
2  "welcomeTitle": "Bienvenido",
3  "submitButton": "Enviar"
4}

Hacer: Proporcionar Contexto

Siempre agrega descripciones y ejemplos:

JSON
1{
2  "save": "Guardar",
3  "@save": {
4    "description": "Texto del botón para guardar cambios del perfil de usuario",
5    "context": "Pantalla de edición de perfil"
6  }
7}

No Hacer: Concatenar Traducciones

Malo:

DART
Text(l10n.hello + ' ' + userName + '!');

Bueno:

JSON
{
  "greeting": "¡Hola, {name}!"
}
DART
Text(l10n.greeting(userName));

Diferentes idiomas tienen diferentes órdenes de palabras, por lo que la concatenación rompe las traducciones.

No Hacer: Reutilizar Claves para Diferentes Contextos

Malo:

JSON
{
  "delete": "Eliminar"
}

Usado tanto para botones "Eliminar Cuenta" como "Eliminar Mensaje".

Bueno:

JSON
1{
2  "deleteAccount": "Eliminar Cuenta",
3  "deleteMessage": "Eliminar Mensaje"
4}

El contexto importa para una traducción precisa.

Hacer: Manejar Idiomas RTL

Si admites árabe o hebreo, prueba el diseño RTL:

DART
1MaterialApp(
2  localizationsDelegates: [...],
3  supportedLocales: const [
4    Locale('en'),
5    Locale('ar'), // De derecha a izquierda
6  ],
7  builder: (context, child) {
8    final locale = Localizations.localeOf(context);
9    final isRTL = locale.languageCode == 'ar' || locale.languageCode == 'he';
10    
11    return Directionality(
12      textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
13      child: child!,
14    );
15  },
16)

Lista de Verificación de Producción

Antes de lanzar tu aplicación internacionalizada:

  • Todos los archivos ARB contienen las mismas claves
  • Los metadatos incluyen descripciones para todas las cadenas
  • Formas plurales probadas para todos los idiomas
  • Formatos de fecha/hora verificados por configuración regional
  • Formatos de número/moneda probados
  • Diseños RTL probados (si admites árabe/hebreo)
  • Memoria de traducción poblada en IntlPull
  • CI/CD valida traducciones antes de fusionar
  • Actualizaciones OTA configuradas para producción
  • Equipo capacitado en flujo de trabajo de edición de archivos ARB
  • Configuración regional de respaldo configurada (generalmente inglés)

Conclusión

Internacionalizar tu aplicación Flutter con archivos ARB proporciona una base robusta y con seguridad de tipos para llegar a audiencias globales. Siguiendo los patrones de este tutorial, evitarás errores comunes y construirás un sistema de localización mantenible que escala con tu aplicación.

Conclusiones clave:

  1. Los archivos ARB proporcionan metadatos enriquecidos y soporte de formato de mensaje ICU
  2. La generación de código de Flutter asegura seguridad de tipos y detecta errores temprano
  3. La organización y convenciones de nomenclatura adecuadas mantienen las traducciones manejables
  4. IntlPull optimiza la colaboración en equipo y los flujos de trabajo de despliegue
  5. Las actualizaciones OTA eliminan el cuello de botella de la tienda de aplicaciones para correcciones de traducción
  6. Las pruebas exhaustivas aseguran calidad en todos los idiomas admitidos

¿Listo para optimizar tu flujo de trabajo de localización de Flutter? Prueba IntlPull gratis con 100 claves y 3 idiomas, o explora nuestra documentación de Flutter para patrones de integración avanzados. Tus usuarios globales te agradecerán la atención al detalle lingüístico, y tu equipo de desarrollo apreciará el tiempo ahorrado.

Tags
flutter
arb
i18n
internacionalización
localización
intl
dart
móvil
Equipo IntlPull
Equipo IntlPull
Ingeniería

Building tools to help teams ship products globally. Follow us for more insights on localization and i18n.