Fix package:flutter_gen gen_l10n Import After Flutter 3.32
You upgraded Flutter, ran flutter analyze, and every screen now shows this:
Target of URI doesn't exist: 'package:flutter_gen/gen_l10n/app_localizations.dart'.
Undefined name 'AppLocalizations'.
Your ARB files are fine. The package your imports point at is gone. This guide walks through the official breaking change and the migration, which takes about five minutes on most apps.
What changed and why
For years, flutter gen-l10n wrote AppLocalizations into a hidden synthetic package under .dart_tool/flutter_gen/ and edited your app's package_config.json so that package:flutter_gen resolved to it. That hack was fragile with workspaces, other build tools, and any pub package that happened to be called flutter_gen.
The Flutter team removed it. According to the official breaking change page ("flutter generate i10n source"):
- The change landed in
3.28.0-0.0.preand reached stable in Flutter 3.32.0. - The
fluttertool no longer generatespackage:flutter_genor modifiespackage_config.json. - Localization code is generated into your own source tree, under
lib/by default. - Support for
package:flutter_genis removed in the stable release after 3.32. generate: trueinpubspec.yamlis now required for generated l10n code.
So package:flutter_gen/gen_l10n/... either still works with a deprecation warning (3.32) or doesn't resolve at all (later releases). Either way, the fix is the same.
Step 1: Keep generate: true in pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true
If you used gen-l10n without this flag before, add it now. The docs list it as required.
Step 2: Update l10n.yaml
A typical file from the old setup:
# l10n.yaml (before)
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
After the migration:
# l10n.yaml (after)
synthetic-package: false
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
# Optional. Without it, files are generated next to your ARB files in arb-dir.
output-dir: lib/l10n/generated
Two choices here:
- No
output-dir:app_localizations.dartandapp_localizations_<locale>.dartland inarb-dir(lib/l10n). - With
output-dir: they land wherever you point it. Ageneratedsubfolder keeps them away from the ARB files your translators touch.
Now regenerate:
flutter gen-l10n
You should see lib/l10n/app_localizations.dart (or the file under your output-dir).
Step 3: Rewrite every import in one go
The old import:
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
The new one uses your own package name (the name: in pubspec.yaml). With arb-dir: lib/l10n and no output-dir:
import 'package:my_app/l10n/app_localizations.dart';
A package import works the same from any folder depth and from test/, so prefer it over relative paths like ../../l10n/app_localizations.dart.
To rewrite every file at once, replace my_app with your package name and adjust l10n/ if you set output-dir.
macOS (BSD sed):
grep -rl --include='*.dart' 'package:flutter_gen/gen_l10n/' lib test \
| xargs sed -i '' 's#package:flutter_gen/gen_l10n/#package:my_app/l10n/#g'
Linux or Git Bash (GNU sed):
grep -rl --include='*.dart' 'package:flutter_gen/gen_l10n/' lib test \
| xargs sed -i 's#package:flutter_gen/gen_l10n/#package:my_app/l10n/#g'
If you used output-dir: lib/l10n/generated, the replacement becomes package:my_app/l10n/generated/.
The pattern matches only gen_l10n/, so it leaves other package:flutter_gen imports alone (see the name clash section below). Your MaterialApp setup does not change:
import 'package:flutter/material.dart';
import 'package:my_app/l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Builder(
builder: (context) => Text(AppLocalizations.of(context)!.helloWorld),
),
);
}
}
Run flutter analyze and the URI errors should be gone.
The traps people hit next
l10n.yaml sits in lib/ instead of the project root
gen-l10n reads l10n.yaml from the project root, next to pubspec.yaml. A file at lib/l10n.yaml is never read, so your synthetic-package: false and output-dir are silently ignored and the tool runs with defaults. If the generated files keep appearing in the wrong place, or not at all, check this first:
ls pubspec.yaml l10n.yaml
Both must be listed from the same directory.
Generated files missing in git or CI
With the synthetic package, generated code lived in .dart_tool/, which nobody commits. Now it lives in lib/, and that changes two things:
- Analysis in CI. A job that runs
flutter analyzeordart analyzestraight after checkout fails with the same "Target of URI doesn't exist" error if the files are not committed and nothing generated them. Add an explicit step:
# GitHub Actions example
- run: flutter pub get
- run: flutter gen-l10n
- run: flutter analyze
- Commit or ignore, pick one. Committing the generated files makes reviews show translation changes as Dart diffs and lets tools that never run Flutter (some linters, code search) see the class. Ignoring them keeps the diff clean but means every environment must run
flutter gen-l10n. If you ignore them, be specific:
# only if you regenerate in every environment
lib/l10n/generated/
This is a good reason to use output-dir: one folder to ignore, without touching your ARB files.
The third-party flutter_gen name clash
FlutterGen is a popular, unrelated asset code generator, and its pub package is literally named flutter_gen. That name collision is one of the reasons the synthetic package was dropped.
What it means for you now:
- If
flutter_gen(orflutter_gen_runner) is in yourpubspec.yaml, thenpackage:flutter_gen/gen_l10n/...resolves to that real package, which has nogen_l10nfolder. You get the same error, and no amount offlutter cleanfixes it. Only the import rewrite does. - FlutterGen's own output (for example
assets.gen.dart) is imported from your app package, not frompackage:flutter_gen, so the sed command above leaves it untouched.
Stale analyzer state
If the files exist and imports are correct but the IDE still complains, restart the Dart analysis server (VS Code: "Dart: Restart Analysis Server"). flutter clean && flutter pub get also clears the old .dart_tool/flutter_gen leftovers.
Quick checklist
flutter: generate: trueinpubspec.yamll10n.yamlat the project root withsynthetic-package: falseflutter gen-l10nproducesapp_localizations.dartunderlib/- No
package:flutter_gen/gen_l10nleft:grep -rn 'flutter_gen/gen_l10n' lib testreturns nothing - CI runs
flutter gen-l10nbefore analyzing, or the generated files are committed
Next steps
Once imports are stable, two follow-ups pay off quickly. If one app_en.arb has grown to hundreds of keys, see how to split app_en.arb into per-feature ARB files with gen-l10n. And now that CI runs gen-l10n anyway, use that step to fail CI when a locale is missing translations.
If editing raw ARB JSON by hand is where your time goes, the FlutterLocalisation ARB editor lets you manage app_<locale>.arb files across all your locales in one UI, and it flags locales missing a plural category the language needs, like few or many for Polish or Arabic. The generated output works with the setup above unchanged.