In Flutter 3.47, what does it take to set up gen-l10n so .arb files become an AppLocalizations class wired into MaterialApp?
answer
- two dependencies, one sdk
- flutter: generate: true
- l10n.yaml at the project root
- output lands next to the ARB files
- localizationsDelegates plus supportedLocales
basics
~10 sAdd flutter_localizations (from the SDK) and intl, set flutter: generate: true in pubspec.yaml, add l10n.yaml and the .arb files, then pass AppLocalizations.localizationsDelegates and AppLocalizations.supportedLocales to MaterialApp. The generated Dart lands in your source tree.
solid answer
~40 sFour pieces. First, depend on `flutter_localizations` with `sdk: flutter` and on `intl`. Second, set `generate: true` under the `flutter:` section of `pubspec.yaml`; without it `flutter gen-l10n` exits with an error. Third, add `l10n.yaml` at the project root, typically `arb-dir: lib/l10n` and `template-arb-file: app_en.arb`, and put `app_en.arb`, `app_de.arb` and `app_pl.arb` there. `flutter pub get` and `flutter run` then regenerate the code, and since Flutter 3.32 it is written into the source tree (the `arb-dir` unless `output-dir` says otherwise), not into a synthetic `package:flutter_gen`. Fourth, import the generated `app_localizations.dart` and give `MaterialApp` `localizationsDelegates: AppLocalizations.localizationsDelegates` and `supportedLocales: AppLocalizations.supportedLocales`, which also brings in the Material, Cupertino and Widgets delegates.
code
yaml · 15 lines# pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true
# l10n.yaml (project root)
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dartgo deeper
Recall the four pieces: flutter_localizations plus intl, generate: true in pubspec, l10n.yaml with ARB files in lib/l10n, and the two AppLocalizations lists passed to MaterialApp.
Explain what each l10n.yaml key controls, that l10n.yaml drives automatic regeneration on pub get and run, and that since 3.32 output is plain source instead of package:flutter_gen.
Decide whether generated files are committed, keep CI regenerating and reporting untranslated messages, and migrate old flutter_gen imports without breaking the build.
Set the team convention for where catalogs live, who owns the template file, and how translation vendors hand ARB files back without touching generated code.
## The moving parts Flutter's built-in localization pipeline has three layers, and setting it up means touching each one: - **`flutter_localizations`**, a package shipped inside the Flutter SDK, which carries translated strings for Material and Cupertino widgets (date pickers, back-button tooltips, text-selection menus) in many languages, plus the text direction for each language. - **`intl`**, the Dart package whose `Intl.pluralLogic`, `Intl.selectLogic`, `NumberFormat` and `DateFormat` the generated code calls. - **gen-l10n**, the code generator inside the `flutter` tool, which reads your **App Resource Bundle** (`.arb`) files and writes the `AppLocalizations` class. ## Step by step 1. **Dependencies.** `flutter pub add flutter_localizations:"{sdk: flutter}" intl:any`, or edit `pubspec.yaml` by hand so it lists `flutter_localizations: {sdk: flutter}` and `intl`. 2. **The generate flag.** Under the `flutter:` section, set `generate: true`. The tool checks this before generating anything; without it, `flutter gen-l10n` stops with *"Attempted to generate localizations code without having the flutter: generate flag turned on."* 3. **`l10n.yaml`.** Create it next to `pubspec.yaml`. Its presence is also what makes `flutter pub get`, `flutter run` and hot reload regenerate the code automatically: the build step that runs gen-l10n is skipped when the file is missing. 4. **ARB files.** Put the template (`app_en.arb`) and one file per language (`app_de.arb`, `app_pl.arb`) in the `arb-dir`. The locale comes from the file-name suffix or from an `@@locale` key. 5. **Wire the app.** Import the generated file and pass its lists to `MaterialApp` (or `CupertinoApp`, or `WidgetsApp`). ## The `l10n.yaml` keys and their defaults | Key | Default | Meaning | |---|---|---| | `arb-dir` | `lib/l10n` | Where the template and translated `.arb` files live | | `template-arb-file` | `app_en.arb` | The file whose messages and metadata define the API | | `output-localization-file` | `app_localizations.dart` | Name of the main generated file | | `output-class` | `AppLocalizations` | Name of the generated class | | `output-dir` | same as `arb-dir` | Where the generated Dart is written | | `nullable-getter` | `true` | Whether `of(context)` returns a nullable type | | `untranslated-messages-file` | none | JSON report of messages missing per locale | When `l10n.yaml` exists, `flutter gen-l10n` ignores its command-line options and says so; delete the file if you want to drive the tool purely from flags. ## Where the output goes (and what changed in 3.32) Before Flutter 3.32 the tool generated a **synthetic package**, imported as `package:flutter_gen/gen_l10n/app_localizations.dart`, by rewriting the app's `package_config.json`. Flutter 3.32 made generation into source the default and required `generate: true`; the synthetic package has since been removed. In Flutter 3.47: - the generated files are ordinary Dart files in `arb-dir` (or `output-dir`), imported like any other file, for example `import 'l10n/app_localizations.dart';`; - `synthetic-package: true` in `l10n.yaml` is a tool error, and `synthetic-package: false` only prints a warning that the key no longer does anything. Because the files are real source, teams either commit them (reviewers see the generated API change) or ignore them and rely on `flutter pub get` regenerating them in CI. Pick one and apply it consistently. ## Wiring `MaterialApp` The generated class carries two ready-made lists: - **`AppLocalizations.localizationsDelegates`**: your `AppLocalizations.delegate` followed by `GlobalMaterialLocalizations.delegate`, `GlobalCupertinoLocalizations.delegate` and `GlobalWidgetsLocalizations.delegate`. - **`AppLocalizations.supportedLocales`**: one `Locale` per ARB file, in alphabetical order unless `preferred-supported-locales` reorders it. Passing both keeps the app's own strings and the framework's strings in step: every language you ship an ARB file for also gets translated Material widgets and the right text direction. If you need extra delegates, spread the list and append: `[...AppLocalizations.localizationsDelegates, MyExtraDelegate()]`. ## Day-to-day regeneration Once `generate: true` and `l10n.yaml` are in place, you rarely run the generator by hand: - `flutter pub get` regenerates the classes after dependency resolution. - `flutter run` regenerates them before the first build, and hot reload and hot restart run the same source generators again, so an edited ARB string appears without restarting the tool. - `flutter gen-l10n` remains useful in CI and when you want the console summary of untranslated messages without launching an app. A syntax error in an ARB file (an unbalanced brace, a plural without `other`) stops generation with the file name, message id and position, so the error appears before any Dart compiles against a stale class. ## Checking it works - Run `flutter gen-l10n` once; it reports untranslated messages per locale on the console. - Switch the device language to German and Polish and confirm both your strings and Material widgets such as a date picker change language. - On iOS, also list the supported languages in the Xcode project's localizations so the store listing shows them; Flutter's own localization does not do that for you.
- You pass --arb-dir=assets/l10n to flutter gen-l10n but it still reads lib/l10n; why?When `l10n.yaml` exists, `flutter gen-l10n` takes every option from that file and ignores the command-line flags, printing a notice that it did so. Either change `arb-dir` in `l10n.yaml` or delete the file to drive the tool from flags; note that automatic regeneration on `pub get` and `run` needs `l10n.yaml`.
- How do you migrate an older app that imports package:flutter_gen/gen_l10n/app_localizations.dart?Make sure `flutter: generate: true` is set, remove `synthetic-package` from `l10n.yaml`, regenerate, and change the import to the generated file inside your source tree, such as `import 'l10n/app_localizations.dart';`. Set `output-dir` if you want the Dart files somewhere other than the ARB folder.
- Why pass AppLocalizations.localizationsDelegates instead of just AppLocalizations.delegate?The generated list also includes the Global Material, Cupertino and Widgets delegates from `flutter_localizations`. Without them, a Polish or German locale has no `MaterialLocalizations`, so Flutter logs that the locale is not supported by all delegates and Material widgets that need localized labels fail.
saying these in an interview costs you the question
- gen-l10n needs build_runner and a watch command to regenerate strings.
- Import the generated class from package:flutter_gen in Flutter 3.47.
- flutter: generate: true is optional when l10n.yaml exists.
- AppLocalizations.delegate alone also translates Material widgets like date pickers.
- Command-line flags override the values in l10n.yaml.