Perché internazionalizzare l'app
Se vuoi pubblicare la tua app su mercati diversi, supportare più lingue non è un optional. Flutter offre un sistema di internazionalizzazione (i18n) integrato e ufficiale basato sui pacchetti flutter_localizations e intl, che permette di gestire traduzioni, formattazione di date, numeri e valute in modo strutturato.
In questa guida vedremo come configurare la localizzazione, generare automaticamente le classi di traduzione a partire dai file ARB e gestire la formattazione locale-aware.
Configurazione iniziale
Aggiungi le dipendenze al tuo pubspec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true
La riga generate: true abilita la generazione automatica del codice di localizzazione da parte di Flutter.
Il file di configurazione l10n.yaml
Crea un file l10n.yaml nella root del progetto:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations
Questo dice a Flutter dove trovare i file di traduzione e come chiamare la classe generata.
Creare i file ARB
I file ARB (Application Resource Bundle) sono semplici file JSON che contengono le coppie chiave-valore delle traduzioni. Crea lib/l10n/app_en.arb:
{
"appTitle": "My Application",
"@appTitle": {
"description": "Il titolo dell'applicazione"
},
"welcome": "Welcome, {name}!",
"@welcome": {
"description": "Messaggio di benvenuto",
"placeholders": {
"name": {
"type": "String"
}
}
},
"itemCount": "{count, plural, =0{Nessun elemento} =1{1 elemento} other{{count} elementi}}",
"@itemCount": {
"placeholders": {
"count": {
"type": "int"
}
}
}
}
E la versione italiana in lib/l10n/app_it.arb:
{
"appTitle": "La mia applicazione",
"welcome": "Benvenuto, {name}!",
"itemCount": "{count, plural, =0{Nessun elemento} =1{1 elemento} other{{count} elementi}}"
}
Nota la sintassi ICU per i plurali: gestisce automaticamente le forme singolare/plurale in base al valore numerico.
Generare le classi
Le classi vengono generate automaticamente al primo flutter run o flutter build. In alternativa puoi forzare la generazione con:
flutter gen-l10n
Verrà creata la classe AppLocalizations con un getter tipizzato per ogni chiave.
Configurare MaterialApp
Ora colleghiamo tutto nel widget radice:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateTitle: (context) =>
AppLocalizations.of(context)!.appTitle,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en'),
Locale('it'),
],
home: const HomePage(),
);
}
}
Usare le traduzioni nei widget
Accedere alle stringhe è semplice e completamente tipizzato:
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(l10n.appTitle)),
body: Column(
children: [
Text(l10n.welcome('Marco')),
Text(l10n.itemCount(3)),
],
),
);
}
}
Il vantaggio rispetto alle stringhe sparse nel codice è enorme: l'IDE ti suggerisce le chiavi disponibili e gli errori vengono segnalati a tempo di compilazione.
Formattare date, numeri e valute
Il pacchetto intl permette di formattare valori rispettando la locale corrente:
import 'package:intl/intl.dart';
final locale = Localizations.localeOf(context).toString();
// Data: 8 febbraio 2025 in italiano
final data = DateFormat.yMMMMd(locale).format(DateTime.now());
// Valuta: € 1.234,56
final prezzo = NumberFormat.currency(
locale: locale,
symbol: '€',
).format(1234.56);
Cambiare lingua a runtime
Per permettere all'utente di scegliere la lingua, puoi gestire il locale con uno state management (ad esempio un ValueNotifier o Riverpod) e passarlo a MaterialApp:
MaterialApp(
locale: selectedLocale, // null = lingua di sistema
// ... resto della configurazione
)
Quando selectedLocale cambia, Flutter ricostruisce l'interfaccia con le nuove traduzioni.
Best practice
- Mantieni il file ARB template (
app_en.arb) sempre completo: è la fonte di verità per le chiavi. - Usa sempre i metadati
@chiavecon la descrizione per aiutare i traduttori. - Sfrutta i plurali e i placeholder ICU invece di concatenare stringhe a mano.
- Aggiungi i delegate
Global*Localizationsper tradurre anche i widget di sistema (date picker, menu, ecc.).
Conclusione
Il sistema di internazionalizzazione di Flutter è robusto, ufficiale e completamente integrato nel processo di build. Investire qualche ora nella sua configurazione iniziale ti ripaga ampiamente quando devi espandere la tua app verso nuovi mercati, mantenendo il codice pulito e type-safe.
