Skip to main content

Guía completa de localización de Flutter

De los archivos ARB a la compatibilidad RTL: localice su aplicación Flutter con easy_localization, gestione plurales en todos los idiomas y automatice las traducciones con IA.

1

Instalar easy_localization

Añada easy_localization a pubspec.yaml. Es el paquete de i18n para Flutter más popular y admite archivos ARB/JSON, plurales y extensiones de contexto. Añada también flutter_localizations desde el SDK para dar formato a fechas y números y establecer la dirección del texto según la región.

easy_localization proporciona extensiones como context.tr() y 'key'.tr() para acceder de forma concisa a las traducciones. Gestiona la carga y conservación de la región y la recarga en caliente de archivos durante el desarrollo.
pubspec.yaml
dependencies:
  easy_localization: ^3.0.7
  flutter_localizations:
    sdk: flutter
2

Crear archivos de traducción ARB

Los archivos Application Resource Bundle (ARB) son el formato estándar de Flutter. Cada uno contiene pares de clave y valor con metadatos opcionales que describen marcadores, reglas de plural y contexto para traductores. Cree un archivo por región en assets/translations.

assets/translations/en.arb
{
  "@@locale": "en",
  "appTitle": "My App",
  "@appTitle": {
    "description": "The title of the application"
  },
  "greeting": "Hello, {name}!",
  "@greeting": {
    "description": "Greeting with user name",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "Alice"
      }
    }
  },
  "itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}",
  "@itemCount": {
    "description": "Number of items in the cart",
    "placeholders": {
      "count": {
        "type": "num",
        "format": "compact"
      }
    }
  }
}
Las claves con prefijo @ —como @greeting— son metadatos que describen la cadena anterior. Incluya tipos de marcadores y ejemplos para ayudar a producir traducciones precisas. Estas claves se eliminan durante la ejecución y no añaden sobrecarga.
3

Configurar la aplicación

Envuelva su aplicación con el widget EasyLocalization. Gestiona el estado regional, carga las traducciones desde los recursos y proporciona los delegates que necesita MaterialApp. Las tres propiedades obligatorias son localizationsDelegates, supportedLocales y locale, todas disponibles mediante extensiones de contexto.

lib/main.dart
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();

  runApp(
    EasyLocalization(
      supportedLocales: [
        Locale('en'),
        Locale('ar'),
        Locale('ja'),
        Locale('de'),
      ],
      path: 'assets/translations',  // Path to your ARB/JSON files
      fallbackLocale: Locale('en'),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      home: HomePage(),
    );
  }
}
«Easy Localization not initialized»: olvidó llamar a EasyLocalization.ensureInitialized() antes de runApp(). Debe esperarla después de WidgetsFlutterBinding.ensureInitialized() y antes de runApp().
4

Traducir widgets

Utilice el método de extensión .tr() sobre claves para obtener texto traducido en cualquier widget. Para plurales, use .plural() con el número. easy_localization ofrece tanto la sintaxis de extensión ('key'.tr()) como el método de contexto (context.tr('key')).

lib/widgets/home_page.dart
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('appTitle'.tr()),   // Simple key
      ),
      body: Column(
        children: [
          // String with variable interpolation
          Text('greeting'.tr(args: ['Alice'])),

          // Named arguments
          Text('greeting'.tr(namedArgs: {'name': 'Alice'})),

          // Plural form
          Text('itemCount'.plural(3)),
        ],
      ),
    );
  }
}
Si devuelve claves sin procesar, compruebe: 1) que EasyLocalization envuelva MaterialApp, no al contrario; 2) que los archivos estén declarados en pubspec.yaml bajo assets; 3) que la ruta de EasyLocalization coincida con el directorio real.
5

Gestionar plurales y variables

Flutter utiliza ICU MessageFormat para plurales, el mismo estándar que iOS, Android y la web. Defina las formas mediante la sintaxis {count, plural, ...} en los ARB. Cada idioma necesita su conjunto según CLDR. El árabe tiene 6 formas, el ruso 4 y el japonés 1.

Plural forms by language
// English: 3 useful forms (=0, =1, other)
"itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}"

// Arabic: 6 forms (=0, =1, =2, few, many, other)
"itemCount": "{count, plural, =0{لا عناصر} =1{عنصر واحد} =2{عنصران} few{{count} عناصر} many{{count} عنصرًا} other{{count} عنصر}}"

// Japanese: 1 form (other)
"itemCount": "{count, plural, other{{count}個のアイテム}}"

// German: 2 forms (=1, other)
"itemCount": "{count, plural, =1{1 Artikel} other{{count} Artikel}}"

// Russian: 3 forms (one, few, many)
"itemCount": "{count, plural, =0{Нет товаров} one{{count} товар} few{{count} товара} many{{count} товаров} other{{count} товаров}}"
Variables and named arguments
// Simple variable
"welcome": "Welcome, {name}!"

// Multiple variables
"orderStatus": "Order #{orderId} — {status}"

// Variable in plural context
"unreadMessages": "{count, plural, =0{No unread messages} =1{1 unread message from {sender}} other{{count} unread messages}}"

// In widgets:
Text('welcome'.tr(namedArgs: {'name': userName}));
Text('orderStatus'.tr(namedArgs: {'orderId': '1234', 'status': 'Shipped'}));
Text('unreadMessages'.plural(count, namedArgs: {'sender': senderName}));
Nunca codifique la lógica singular/plural con if (count == 1). Idiomas como el francés consideran singular el 0. El ruso, el polaco y el árabe tienen formas que no existen en inglés. Utilice siempre la sintaxis ICU y deje que el framework seleccione.
6

Admitir idiomas RTL

Flutter refleja automáticamente todo el diseño cuando la configuración regional se escribe de derecha a izquierda —árabe, hebreo, persa o urdu—. Sin embargo, su código debe utilizar widgets y propiedades conscientes de la dirección. Sustituya left/right codificados directamente por sus equivalentes start/end.

lib/widgets/adaptive_layout.dart
import 'package:flutter/material.dart';

class AdaptiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final isRtl = Directionality.of(context) == TextDirection.rtl;

    return Scaffold(
      body: Row(
        children: [
          // Use start/end instead of left/right
          Expanded(
            child: Padding(
              padding: EdgeInsetsDirectional.only(
                start: 16.0,  // Leading edge (left in LTR, right in RTL)
                end: 8.0,     // Trailing edge
              ),
              child: Text('content'.tr()),
            ),
          ),
          // Flip icons for RTL
          Icon(
            isRtl ? Icons.arrow_back : Icons.arrow_forward,
          ),
        ],
      ),
    );
  }
}
RTL-aware widget patterns
// Use Directional widgets for RTL-aware layouts
EdgeInsetsDirectional.only(start: 16, end: 8)   // Not EdgeInsets.only(left: 16, right: 8)
AlignmentDirectional.centerStart                  // Not Alignment.centerLeft
BorderRadiusDirectional.only(topStart: Radius.circular(8))

// Automatically mirrors when locale changes to Arabic, Hebrew, etc.
// No conditional logic needed — Flutter handles text direction from locale
Pruebe RTL definiendo temporalmente la región de la aplicación como árabe (Locale('ar')). Flutter refleja toda la interfaz: los paneles de navegación se abren desde la derecha, las flechas de retroceso se invierten y el texto se alinea a la derecha. Utilice EdgeInsetsDirectional, AlignmentDirectional y BorderRadiusDirectional para que sus diseños personalizados se reflejen bien.
7

Cadenas inteligentes de respaldo regional

De forma predeterminada, cuando falta una traducción pt-BR, Flutter pasa directamente al inglés y omite traducciones pt-PT perfectamente válidas. El paquete locale_chain lo corrige con cadenas configurables. Una línea de configuración y ninguna migración: sus llamadas .tr() existentes funcionan sin cambios.

lib/main.dart with LocaleChain
import 'package:locale_chain/locale_chain.dart';
import 'package:locale_chain/easy_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  LocaleChain.configure();  // Enable smart fallback chains

  runApp(
    EasyLocalization(
      supportedLocales: [
        Locale('en'),
        Locale('pt', 'BR'),
        Locale('pt', 'PT'),
        Locale('es'),
        Locale('es', 'MX'),
      ],
      path: 'assets/translations',
      assetLoader: LocaleChainAssetLoader(  // Swap in the chain loader
        baseLoader: RootBundleAssetLoader(),
      ),
      fallbackLocale: Locale('en'),
      child: MyApp(),
    ),
  );
}

// Result: pt-BR user sees pt-PT translations when pt-BR keys are missing,
// instead of falling back directly to English.
Custom fallback configuration
// Override specific chains while keeping built-in defaults
LocaleChain.configure(
  fallbacks: {
    'pt-BR': ['pt-PT', 'pt'],      // pt-BR → pt-PT → pt → en
    'es-MX': ['es-419', 'es'],     // es-MX → es-419 → es → en
    'fr-CA': ['fr'],               // fr-CA → fr → en
  },
);

// Or replace all defaults with your own chains
LocaleChain.configure(
  fallbacks: {
    'zh-Hant-HK': ['zh-Hant-TW', 'zh-Hans'],
    'pt-BR': ['pt-PT', 'pt'],
  },
  mergeDefaults: false,  // Only your chains, no built-in defaults
);
locale_chain incluye cadenas integradas para variantes regionales de portugués, español, francés, alemán, italiano, neerlandés, noruego y malayo. Un usuario pt-BR verá contenido pt-PT antes que inglés. Uno es-MX verá primero es-419 y después es antes de la región predeterminada.
8

Automatizar traducciones

Cuando termine de configurar la localización, traduzca sus archivos ARB con IA. Desde el IDE, pida a su asistente que traduzca el ARB de origen o utilice la CLI de i18n Agent en CI/CD. Los metadatos —marcadores y descripciones— aportan contexto y mejoran la calidad.

Terminal
# In your IDE, ask your AI assistant:
> Translate assets/translations/en.arb to Arabic, Japanese, and German

✓ ar.arb created (1.4s)
✓ ja.arb created (1.2s)
✓ de.arb created (1.1s)

# Or use the CLI in CI/CD:
npx i18n-agent translate assets/translations/en.arb --lang ar,ja,de
Traduzca de forma incremental: cuando añada claves nuevas al ARB de origen, traduzca solo las diferencias en vez de volver a generar todos los archivos. Así conserva las traducciones revisadas por personas y mantiene intactos los metadatos.

Automatizar la calidad de la traducción

Detecte las claves ausentes y los marcadores rotos antes de publicar con i18n-validate. Pruebe la interfaz con pseudotraducciones mediante i18n-pseudo antes de recibir las reales.

Errores habituales

No se encuentran los archivos de traducción durante la ejecución

Debe declarar los archivos ARB/JSON en pubspec.yaml, dentro de assets. Si omite este paso, Flutter no los encontrará durante la ejecución aunque estén en el disco. Añada: assets: - assets/translations/

Sintaxis no válida en archivos ARB

Los archivos ARB son JSON estricto: sin comas finales, comillas simples ni comentarios. Un solo error impide silenciosamente que se cargue todo el archivo. Valide sus ARB con un analizador JSON antes de depurar problemas de traducción.

Los cambios de traducción no aparecen con la recarga en caliente

easy_localization almacena las traducciones en memoria. Añadir claves o cambiar traducciones puede requerir un reinicio en caliente completo —no una recarga—. Durante el desarrollo, utilice hot restart (Mayús+R) después de editar los archivos.

Left/right codificados directamente rompen RTL

Utilizar EdgeInsets.only(left: 16) en vez de EdgeInsetsDirectional.only(start: 16) impide que Flutter refleje el diseño en idiomas RTL. Busque en el código EdgeInsets, Alignment y BorderRadius sin el sufijo Directional.

Estructura de archivos recomendada

Project Structure
my_flutter_app/
├── assets/
│   └── translations/
│       ├── en.arb          # Source language (English)
│       ├── ar.arb          # Arabic (with 6 plural forms)
│       ├── de.arb          # German
│       ├── ja.arb          # Japanese
│       ├── pt-BR.arb       # Brazilian Portuguese
│       └── pt-PT.arb       # European Portuguese
├── lib/
│   ├── main.dart           # App entry with EasyLocalization
│   ├── app.dart            # MaterialApp with locale delegates
│   └── widgets/
│       └── language_switcher.dart
├── pubspec.yaml            # Dependencies
└── analysis_options.yaml

Pruebe i18n Agent ahora

Arrastre y suelte aquí su archivo de traducción

JSON, YAML, PO, XML, CSV, Markdown, Properties

o haga clic para seleccionar

Idiomas de destino

No es necesario registrarsePresupuesto al instante

Respaldo de configuraciones regionales con locale_chain

Cuando falta una clave en una configuración regional como pt-BR, Flutter pasa directamente al idioma de la plantilla en vez de comprobar primero el principal pt.

Terminal
flutter pub add locale_chain
Configuration
import 'package:locale_chain/locale_chain.dart';

LocaleChain.configure(fallbacks: {
  'pt-BR': ['pt', 'en'],
  'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
});

LocaleChainAssetLoader(baseLoader: RootBundleAssetLoader());

Consulte nuestra guía de respaldo de configuraciones regionales para ver todos los frameworks admitidos y las 75 cadenas integradas. Learn more →

Preguntas frecuentes