flutter-localizing-apps
Localizing Flutter Applications
Contents
- Core Configuration
- Defining ARB Resources
- App Integration
- Advanced Formatting
- Workflows
- Troubleshooting & Gotchas
Core Configuration
Configure the project to support code generation for localizations.
- Add required dependencies to
pubspec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true # Required for l10n code generation
- Create an
l10n.yamlfile in the project root to configure thegen-l10ntool:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
# Optional: Set to false to generate files into lib/ instead of the synthetic package
# synthetic-package: false
Defining ARB Resources
Store localized strings in Application Resource Bundle (.arb) files within the configured arb-dir.
Create the template file (e.g., lib/l10n/app_en.arb):
{
"helloWorld": "Hello World!",
"@helloWorld": {
"description": "The conventional newborn programmer greeting"
}
}
Create translation files (e.g., lib/l10n/app_es.arb):
{
"helloWorld": "¡Hola Mundo!"
}
App Integration
Initialize the Localizations widget by configuring the root MaterialApp or CupertinoApp.
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // Adjust import if synthetic-package is false
return MaterialApp(
title: 'Localized App',
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en'), // English
Locale('es'), // Spanish
],
home: const MyHomePage(),
);
Access localized values in the widget tree using the generated AppLocalizations class:
Text(AppLocalizations.of(context)!.helloWorld)
Note: If using WidgetsApp instead of MaterialApp, omit GlobalMaterialLocalizations.delegate.
Advanced Formatting
Use placeholders, plurals, and selects for dynamic content. Define parameters in the @key metadata.
Placeholders
"hello": "Hello {userName}",
"@hello": {
"description": "A message with a single parameter",
"placeholders": {
"userName": {
"type": "String",
"example": "Bob"
}
}
}
Plurals
"nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
"@nWombats": {
"placeholders": {
"count": {
"type": "num",
"format": "compact"
}
}
}
Selects (Gender/Enums)
"pronoun": "{gender, select, male{he} female{she} other{they}}",
"@pronoun": {
"placeholders": {
"gender": {
"type": "String"
}
}
}
Dates and Numbers
Use format and optionalParameters to leverage intl formatting.
"dateMessage": "Date: {date}",
"@dateMessage": {
"placeholders": {
"date": {
"type": "DateTime",
"format": "yMd"
}
}
}
Workflows
Task Progress: Adding a New Language
Copy this checklist to track progress when introducing a new locale.
- Create a new
.arbfile in thearb-dir(e.g.,app_fr.arb). - Translate all keys present in the template
.arbfile. - Add the new
Localeto thesupportedLocaleslist inMaterialApp. - Run validator -> Execute
flutter gen-l10nto verify ARB syntax and regenerateAppLocalizations. - Review errors -> Fix any missing placeholders or malformed plural/select statements.
- If targeting iOS, complete the "Configuring iOS App Bundle" workflow.
Task Progress: Configuring iOS App Bundle
Flutter handles runtime localization, but iOS requires bundle-level configuration for the App Store and system settings.
- Open
ios/Runner.xcodeprojin Xcode. - Select the
Runnerproject in the Project Navigator. - Navigate to the
Infotab. - Under the Localizations section, click the
+button. - Add the newly supported languages/regions.
- Run validator -> Build the iOS app to ensure
project.pbxprojis correctly updated.
Troubleshooting & Gotchas
Missing Localizations Ancestor
Widgets like TextField and CupertinoTabBar require a Localizations ancestor with specific delegates (MaterialLocalizations or CupertinoLocalizations).
Error: No MaterialLocalizations found. or CupertinoTabBar requires a Localizations parent...
Fix: Ensure the widget is a descendant of MaterialApp/CupertinoApp. If building a standalone widget tree (e.g., in tests or a custom WidgetsApp), wrap the widget in a Localizations widget:
Localizations(
locale: const Locale('en', 'US'),
delegates: const [
DefaultWidgetsLocalizations.delegate,
DefaultMaterialLocalizations.delegate, // Required for TextField
DefaultCupertinoLocalizations.delegate, // Required for CupertinoTabBar
],
child: child,
)
Advanced Locale Definition
If supporting languages with multiple scripts (e.g., Chinese), use Locale.fromSubtags to explicitly define the scriptCode and countryCode to prevent Flutter from resolving to an unexpected variant.
supportedLocales: const [
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'),
]