Introduzione

La localizzazione è un aspetto fondamentale per qualsiasi app che punti a un pubblico internazionale. In Flutter l'approccio ufficiale con flutter_localizations e intl è potente ma verboso: file ARB, generazione di codice, chiavi accessibili tramite metodi lunghi e nessun autocompletamento immediato sulle stringhe annidate.

In questo articolo vediamo slang, un package che offre una localizzazione type-safe, con autocompletamento completo, supporto a pluralizzazione, interpolazione e namespace, partendo da semplici file JSON o YAML.

Perché slang

  • Type-safe: le traduzioni sono accessibili tramite oggetti generati, niente stringhe magiche.
  • Autocompletamento: l'IDE suggerisce tutte le chiavi disponibili.
  • Struttura annidata: puoi organizzare le traduzioni in modo gerarchico.
  • Nessuna dipendenza da context (opzionale): puoi tradurre anche fuori dal widget tree.
  • Pluralizzazione e genere integrati.

Installazione

Aggiungi le dipendenze al pubspec.yaml:

dependencies:
  slang: ^3.31.0
  slang_flutter: ^3.31.0

dev_dependencies:
  slang_build_runner: ^3.31.0
  build_runner: ^2.4.0

Creare i file di traduzione

Crea una cartella lib/i18n con un file per ogni lingua. Il file base è quello senza suffisso di locale.

lib/i18n/strings.i18n.json (italiano, lingua base):

{
  "home": {
    "title": "Benvenuto",
    "greeting": "Ciao $name!",
    "itemCount": {
      "one": "$n elemento",
      "other": "$n elementi"
    }
  },
  "login": {
    "button": "Accedi"
  }
}

lib/i18n/strings_en.i18n.json (inglese):

{
  "home": {
    "title": "Welcome",
    "greeting": "Hi $name!",
    "itemCount": {
      "one": "$n item",
      "other": "$n items"
    }
  },
  "login": {
    "button": "Sign in"
  }
}

Generare il codice

Esegui il generatore:

dart run slang

Oppure con build_runner in modalità watch:

dart run build_runner watch

Verrà creato il file strings.g.dart con tutte le classi type-safe.

Configurare l'app

Avvolgi la tua app con TranslationProvider:

import 'package:flutter/material.dart';
import 'i18n/strings.g.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // Imposta la lingua in base al dispositivo
  LocaleSettings.useDeviceLocale();
  runApp(TranslationProvider(child: const MyApp()));
}

Collega i delegate di Flutter per il supporto completo:

MaterialApp(
  locale: TranslationProvider.of(context).flutterLocale,
  supportedLocales: AppLocaleUtils.supportedLocales,
  localizationsDelegates: GlobalMaterialLocalizations.delegates,
  home: const HomePage(),
)

Usare le traduzioni

Accedi alle stringhe tramite l'oggetto t, con autocompletamento completo:

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(t.home.title)),
      body: Column(
        children: [
          Text(t.home.greeting(name: 'Marco')),
          Text(t.home.itemCount(n: 3)), // -> "3 elementi"
          ElevatedButton(
            onPressed: () {},
            child: Text(t.login.button),
          ),
        ],
      ),
    );
  }
}

Nota come l'interpolazione (name) e la pluralizzazione (n) siano parametri tipizzati: l'IDE ti segnala subito eventuali errori.

Cambiare lingua a runtime

// Cambia lingua e ricostruisce i widget sotto TranslationProvider
LocaleSettings.setLocale(AppLocale.en);

// Oppure con codice locale
LocaleSettings.setLocaleRaw('it');

Se usi context, puoi ottenere le traduzioni reattive con:

final t = Translations.of(context);

In questo modo i widget si aggiornano automaticamente al cambio di lingua.

Namespace per file multipli

Per progetti grandi puoi suddividere le traduzioni in più file abilitando i namespace nel build.yaml:

targets:
  $default:
    builders:
      slang_build_runner:
        options:
          namespaces: true

Avrai file come home.i18n.json, login.i18n.json e li accederai con t.home.title, t.login.button.

slang vs intl

Caratteristica slang intl/ARB
Type-safe Sì, nativo Parziale
Autocompletamento annidato Ottimo Limitato
Formato file JSON/YAML/CSV ARB
Traduzione fuori dal context No
Standard ufficiale No

Conclusione

slang è un'alternativa moderna e produttiva per la localizzazione in Flutter. Se non hai vincoli sull'uso dello standard ARB, offre un'esperienza di sviluppo più fluida grazie all'autocompletamento e alla sicurezza dei tipi. Per progetti che devono integrarsi con flussi di traduzione basati su ARB, intl resta la scelta più conservativa, ma per la maggior parte delle app slang riduce sensibilmente il codice ripetitivo e gli errori.