Internazionalizzazione (i18n) in Flutter con flutter_localizations e ARB
GuideIntermedio35 min Flutter 3.x

Internazionalizzazione (i18n) in Flutter con flutter_localizations e ARB

Perché internazionalizzare

Un'app pensata per un pubblico globale deve adattarsi alla lingua dell'utente. Flutter offre un sistema ufficiale di internazionalizzazione (i18n) basato sul pacchetto flutter_localizations e sui file ARB (Application Resource Bundle), con generazione automatica delle classi di traduzione tramite il tool gen-l10n.

In questo tutorial configureremo da zero il supporto multilingua per italiano e inglese, gestiremo testi con parametri e plurali, e vedremo come cambiare lingua a runtime.

Al termine avrai un'app capace di tradurre dinamicamente la propria interfaccia.

  1. 1

    Abilitare la generazione e aggiungere le dipendenze

    Apri il file pubspec.yaml e aggiungi flutter_localizations dal SDK, intl per la formattazione, e abilita il flag generate nella sezione flutter. Questo flag attiva il tool ufficiale gen-l10n che genererà automaticamente le classi a partire dai file ARB.

    dependencies:
      flutter:
        sdk: flutter
      flutter_localizations:
        sdk: flutter
      intl: any
    
    flutter:
      generate: true
      uses-material-design: true

    Risultato atteso

    Eseguendo `flutter pub get` le dipendenze vengono scaricate senza errori.

  2. 2

    Configurare l10n.yaml

    Crea nella root del progetto un file chiamato l10n.yaml. Questo file dice a gen-l10n dove trovare i file ARB, quale usare come template e come nominare la classe generata.

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

    Risultato atteso

    Il file di configurazione è pronto per essere letto durante la build.

  3. 3

    Creare i file ARB di traduzione

    Crea la cartella lib/l10n e all'interno due file: app_en.arb (template, inglese) e app_it.arb (italiano). Nei file ARB ogni chiave corrisponde a un metodo generato. I metadati con prefisso @ descrivono i placeholder. Includiamo un saluto semplice, uno con parametro e un plurale.

    // app_en.arb
    {
      "appTitle": "My App",
      "greeting": "Hello!",
      "welcomeUser": "Welcome, {name}",
      "@welcomeUser": {
        "placeholders": { "name": { "type": "String" } }
      },
      "messageCount": "{count, plural, =0{No messages} =1{1 message} other{{count} messages}}",
      "@messageCount": {
        "placeholders": { "count": { "type": "int" } }
      }
    }
    
    // app_it.arb
    {
      "appTitle": "La mia App",
      "greeting": "Ciao!",
      "welcomeUser": "Benvenuto, {name}",
      "messageCount": "{count, plural, =0{Nessun messaggio} =1{1 messaggio} other{{count} messaggi}}"
    }

    Risultato atteso

    I due file ARB sono presenti in lib/l10n con le stesse chiavi.

  4. 4

    Generare le classi di localizzazione

    Esegui un comando di build o flutter gen-l10n. Flutter creerà automaticamente la classe AppLocalizations (di solito in .dart_tool/flutter_gen/gen_l10n/). Da questo momento potrai importarla e usarla nel codice. Ricordati di rieseguire il comando ogni volta che modifichi i file ARB.

    flutter gen-l10n
    # oppure semplicemente:
    flutter run

    Risultato atteso

    Il file app_localizations.dart viene generato senza errori.

  5. 5

    Configurare MaterialApp con i delegate

    Nel widget principale collega AppLocalizations.localizationsDelegates e supportedLocales. I delegate gestiscono il caricamento delle traduzioni e dei testi standard di Material/Cupertino/Widgets. Usiamo una variabile di stato _locale per poterla cambiare a runtime.

    import 'package:flutter/material.dart';
    import 'package:flutter_gen/gen_l10n/app_localizations.dart';
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
      @override
      State<MyApp> createState() => MyAppState();
    }
    
    class MyAppState extends State<MyApp> {
      Locale? _locale;
    
      void setLocale(Locale locale) => setState(() => _locale = locale);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          locale: _locale,
          localizationsDelegates: AppLocalizations.localizationsDelegates,
          supportedLocales: AppLocalizations.supportedLocales,
          onGenerateTitle: (ctx) => AppLocalizations.of(ctx)!.appTitle,
          home: const HomePage(),
        );
      }
    }

    Risultato atteso

    L'app si avvia mostrando i testi nella lingua del dispositivo (it o en).

  6. 6

    Usare le traduzioni e il cambio lingua a runtime

    Recupera l'istanza con AppLocalizations.of(context)! e richiama i metodi generati, passando i parametri dove richiesto. Per cambiare lingua a runtime risali allo State dell'app con findAncestorStateOfType (oppure usa un gestore di stato come Provider) e chiama setLocale.

    class HomePage extends StatelessWidget {
      const HomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        final t = AppLocalizations.of(context)!;
        return Scaffold(
          appBar: AppBar(title: Text(t.appTitle)),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(t.greeting),
                Text(t.welcomeUser('Marco')),
                Text(t.messageCount(3)),
                const SizedBox(height: 24),
                ElevatedButton(
                  onPressed: () => MyApp.of(context)?.setLocale(const Locale('it')),
                  child: const Text('Italiano'),
                ),
                ElevatedButton(
                  onPressed: () => MyApp.of(context)?.setLocale(const Locale('en')),
                  child: const Text('English'),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    // Aggiungi questo helper statico dentro MyApp:
    // static MyAppState? of(BuildContext context) =>
    //     context.findAncestorStateOfType<MyAppState>();

    Risultato atteso

    Toccando i pulsanti l'interfaccia cambia istantaneamente tra italiano e inglese, con plurali e parametri corretti.

  7. 7

    Best practice e refinement

    Alcuni accorgimenti per un'app multilingua robusta:

    • Persisti la lingua scelta con shared_preferences per ricaricarla all'avvio.
    • localeResolutionCallback: usa un fallback esplicito quando la lingua del dispositivo non è supportata.
    • Non concatenare stringhe manualmente: usa sempre i placeholder ARB, perché l'ordine delle parole cambia tra le lingue.
    • Formattazione: usa intl (DateFormat, NumberFormat) per date e numeri localizzati.
    MaterialApp(
      localeResolutionCallback: (deviceLocale, supported) {
        if (deviceLocale != null) {
          for (final l in supported) {
            if (l.languageCode == deviceLocale.languageCode) return l;
          }
        }
        return const Locale('en');
      },
    );

    Risultato atteso

    L'app sceglie sempre una lingua valida, anche su dispositivi con locale non previsto.

CondividiXLinkedInFacebookWhatsApp

Commenti (0)

Ancora nessun commento. Inizia tu!