Skip to content
Back to archipelago.banuacoder.com

UI, Assets & L10N

How to add type-safe localization to a Flutter app with Slang ​

Free Reference for flutter_l10n: every variable, option and package it generates. Command: archipelago generate flutter_l10n

Generate the shared localization package, add translation keys and regenerate, change language so it survives a restart, and scope translations per feature.

What you'll learn ​

  • Generating the shared localization package with Slang
  • Adding translation keys and regenerating
  • Changing the language so the choice survives a restart
  • Scoping translations per feature

Prerequisites ​

New projects already include this brick.

Step 1: Generate the Localization Package ​

bash
archipelago generate flutter_l10n

The prompts are:

  • appName: your app name, for example MyApp
  • prefix: the prefix for the locale enum, such as AppLocale
  • isForMonorepo: leave this as true

Or use a config file:

json
{
  "appName": "MyApp",
  "prefix": "App",
  "isForMonorepo": true
}
bash
archipelago generate flutter_l10n --config l10n_config.json

Step 2: Understand the Generated Structure ​

text
shared/locale_core/
├── l10n/                           # Translation sources
│   ├── general/
│   │   ├── general_en.i18n.json
│   │   └── general_id.i18n.json
│   └── feedback/                   # dialog, error and success namespaces
├── lib/src/
│   ├── persistence/                # AppLocaleController, LocaleStore
│   ├── translations/translations.g.dart   # Generated by slang
│   └── utils/                      # Formatting and the Indonesian plural resolver
├── slang.yaml
└── build.yaml

Namespaces come from the folders under l10n/.

Step 3: Add Translation Keys ​

Add keys to a namespace file in each language:

json
// l10n/general/general_en.i18n.json
{
  "appName": "My App",
  "welcome": "Welcome, {name}!"
}
json
// l10n/general/general_id.i18n.json
{
  "appName": "Aplikasi Saya",
  "welcome": "Selamat datang, {name}!"
}

Regenerate:

bash
dart run slang

Run slang after build_runner, not before. The packages here have no direct build_runner dependency, so melos run build alone does not generate them.

Step 4: Use Translations ​

dart
Text(context.l10n.general.appName);
Text(context.l10n.general.welcome(name: user.name));

Step 5: Change the Language and Keep It ​

slang's LocaleSettings lives in memory only. A language switch that uses it alone reverts on the next cold start. Route the change through AppLocaleController:

dart
await AppLocaleController.setLocale(AppLocale.id); // sets and saves

bootstrap.dart awaits AppLocaleController.restore() before runApp(). AppLocaleController.clear() forgets the choice. To store it somewhere else, set AppLocaleController.store = MyLocaleStore() before restore() runs.

Never call LocaleSettings.setLocale of this package from UI. It looks right and saves nothing.

Step 6: Scope Translations per Feature ​

A feature has its own slang.yaml and its own locale enum, for example AuthLocale and context.authL10n. A feature that offers a language switch changes both:

dart
LocaleSettings.setLocale(HomeLocale.id);  // the feature rebuild
unawaited(AppLocaleController.setLocale(AppLocale.id)); // app-wide and saved

The feature shell page copies the app locale into the feature locale when it first builds.

Key Customization Points ​

CustomizationWhere to Change
Add a languageAdd *_<code>.i18n.json files per namespace, then run dart run slang
Interpolation{variable} in the JSON value
PluralsSlang plural syntax. Indonesian rules are in utils/resolver.dart
Base languagebase_locale in slang.yaml
Locale storageA custom LocaleStore

Next Steps ​