Flutter L10n (Localization): The Complete Guide to Localizing Your App
Master Flutter localization (l10n) with flutter_localizations, code generation, and the official localization workflow for Android, iOS, and web.
Published on • September 19, 2026
AI Assistant

Flutter L10n (Localization): The Complete Guide
Flutter’s localization system (l10n) provides a comprehensive framework for translating your app into multiple languages. With automatic code generation, locale-aware widgets, and built-in support for Material and Cupertino components, Flutter makes localization accessible and maintainable.
Understanding L10n vs I18n vs A11y
Before diving in, let’s clarify the common abbreviations:
- i18n (Internationalization) — designing your app to support multiple locales
- l10n (Localization) — translating content for a specific locale
- a11y (Accessibility) — making your app usable by everyone
Localization is the process of actually translating your app’s strings, adapting date formats, and handling locale-specific behavior.
Setting Up Flutter Localization
Step 1: Enable Code Generation
In your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
flutter:
generate: true # Enables code generation
Step 2: Create l10n.yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations
preferred-supported-locales: ["en"]
nullable-localization: false
Step 3: Create ARB Files
// lib/l10n/app_en.arb
{
"@@locale": "en",
"appTitle": "My App",
"welcomeMessage": "Welcome to {appName}!",
"loginButton": "Log In",
"itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}"
}
// lib/l10n/app_es.arb
{
"@@locale": "es",
"appTitle": "Mi Aplicación",
"welcomeMessage": "¡Bienvenido a {appName}!",
"loginButton": "Iniciar Sesión",
"itemCount": "{count, plural, =0{Sin artículos} =1{1 artículo} other{{count} artículos}}"
}
Step 4: Configure MaterialApp
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
home: const HomeScreen(),
);
}
}
Step 5: Use Localized Strings
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(l10n.appTitle)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(l10n.welcomeMessage('My App')),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {},
child: Text(l10n.loginButton),
),
const SizedBox(height: 16),
Text(l10n.itemCount(3)),
],
),
),
);
}
}
Advanced Localization Features
Date and Number Formatting
import 'package:intl/intl.dart';
class LocalizedDateFormat extends StatelessWidget {
final DateTime date;
const LocalizedDateFormat({super.key, required this.date});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final locale = l10n.localeName;
return Text(
DateFormat.yMMMMd(locale).format(date),
);
}
}
Handling Locale Changes
class LocaleProvider extends ChangeNotifier {
Locale _locale = const Locale('en');
Locale get locale => _locale;
void setLocale(Locale locale) {
if (AppLocalizations.supportedLocales.contains(locale)) {
_locale = locale;
notifyListeners();
}
}
}
Testing Localization
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() {
testWidgets('displays localized text', (tester) async {
await tester.pumpWidget(
MaterialApp(
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [Locale('es')],
locale: const Locale('es'),
home: const MyWidget(),
),
);
expect(find.text('Mi Aplicación'), findsOneWidget);
});
}
Platform-Specific Configuration
Android
In android/app/src/main/res/values/strings.xml:
<resources>
<string name="app_name">My App</string>
</resources>
In android/app/src/main/res/values-es/strings.xml:
<resources>
<string name="app_name">Mi Aplicación</string>
</resources>
iOS
In ios/Runner/InfoPlist.strings:
CFBundleDisplayName = "My App";
In ios/Runner/es.lproj/InfoPlist.strings:
CFBundleDisplayName = "Mi Aplicación";
Best Practices
- Use the official Flutter l10n workflow — it’s the most maintained and documented approach
- Always create ARB files — they’re the standard for Flutter localization
- Test with pseudo-localizations — Flutter DevTools supports this
- Keep translations up to date — run code generation regularly
- Handle missing translations gracefully — provide fallback strings
Flutter’s localization system is powerful and well-integrated. By following these patterns, you can create apps that feel native in every language and locale they support.