← Back to Blog

Fix package:flutter_gen gen_l10n Import After Flutter 3.32

fluttergen-l10nlocalizationmigrationl10n.yaml

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.pre and reached stable in Flutter 3.32.0.
  • The flutter tool no longer generates package:flutter_gen or modifies package_config.json.
  • Localization code is generated into your own source tree, under lib/ by default.
  • Support for package:flutter_gen is removed in the stable release after 3.32.
  • generate: true in pubspec.yaml is 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.dart and app_localizations_<locale>.dart land in arb-dir (lib/l10n).
  • With output-dir: they land wherever you point it. A generated subfolder 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:

  1. Analysis in CI. A job that runs flutter analyze or dart analyze straight 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
  1. 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 (or flutter_gen_runner) is in your pubspec.yaml, then package:flutter_gen/gen_l10n/... resolves to that real package, which has no gen_l10n folder. You get the same error, and no amount of flutter clean fixes it. Only the import rewrite does.
  • FlutterGen's own output (for example assets.gen.dart) is imported from your app package, not from package: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: true in pubspec.yaml
  • l10n.yaml at the project root with synthetic-package: false
  • flutter gen-l10n produces app_localizations.dart under lib/
  • No package:flutter_gen/gen_l10n left: grep -rn 'flutter_gen/gen_l10n' lib test returns nothing
  • CI runs flutter gen-l10n before 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.

Try FlutterLocalisation free