Multiple Language Support in Dart: Building Global Flutter Apps
Master multi-language support in Dart and Flutter. Learn locale detection, language switching, pluralization, and cultural adaptations for global audiences.
Published on • September 19, 2026
AI Assistant

Multiple Language Support in Dart: Building Global Flutter Apps
Dart and Flutter provide a comprehensive system for supporting multiple languages in your applications. From automatic locale detection to complex pluralization rules, the framework handles the heavy lifting so you can focus on creating great experiences for users worldwide.
The Multi-Language Stack
Flutter’s multi-language support consists of:
- Dart’s
intlpackage — formatting, parsing, and message handling - Flutter’s
flutter_localizations— locale-aware widgets - ARB files — translation storage format
- Code generation — type-safe access to translations
Setting Up Multi-Language Support
Step 1: Configure Dependencies
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true
Step 2: Create Translation Files
// lib/l10n/app_en.arb
{
"@@locale": "en",
"appTitle": "Global App",
"greeting": "Hello, {name}!",
"items": "{count, plural, =0{No items} =1{1 item} other{{count} items}}"
}
// lib/l10n/app_es.arb
{
"@@locale": "es",
"appTitle": "Aplicación Global",
"greeting": "¡Hola, {name}!",
"items": "{count, plural, =0{Sin artículos} =1{1 artículo} other{{count} artículos}}"
}
// lib/l10n/app_ar.arb
{
"@@locale": "ar",
"appTitle": "تطبيق عالمي",
"greeting": "!مرحباً، {name}",
"items": "{count, plural, =0{لا عناصر} =1{عنصر واحد} other{{count} عناصر}}"
}
Step 3: Configure l10n.yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
Step 4: Use in Your App
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: 'Global App',
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en', ''),
Locale('es', ''),
Locale('ar', ''),
],
home: const HomeScreen(),
);
}
}
Locale Detection and Switching
Automatic Locale Detection
Flutter automatically detects the device’s locale:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
// Flutter uses the device locale by default
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
);
}
}
Manual Locale Switching
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();
}
}
}
class MyApp extends StatelessWidget {
final LocaleProvider localeProvider;
const MyApp({super.key, required this.localeProvider});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: localeProvider,
child: Consumer<LocaleProvider>(
builder: (context, provider, child) {
return MaterialApp(
locale: provider.locale,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
home: const HomeScreen(),
);
},
),
);
}
}
Advanced Localization Features
Pluralization
// In your ARB file
"items": "{count, plural, =0{No items} =1{1 item} other{{count} items}}"
// Usage
final l10n = AppLocalizations.of(context)!;
Text(l10n.items(0)); // "No items"
Text(l10n.items(1)); // "1 item"
Text(l10n.items(5)); // "5 items"
Gender Selection
// In your ARB file
"greeting": "{gender, select, male{Hello, sir!} female{Hello, ma'am!} other{Hello there!}}"
// Usage
Text(l10n.greeting('male')); // "Hello, sir!"
Text(l10n.greeting('female')); // "Hello, ma'am!"
Text(l10n.greeting('other')); // "Hello there!"
Date and Number Formatting
import 'package:intl/intl.dart';
class LocalizedFormats {
static String date(BuildContext context, DateTime date) {
final locale = Localizations.localeOf(context).languageCode;
return DateFormat.yMMMMd(locale).format(date);
}
static String currency(BuildContext context, double amount, String symbol) {
final locale = Localizations.localeOf(context).languageCode;
return NumberFormat.currency(locale: locale, symbol: symbol).format(amount);
}
static String number(BuildContext context, int number) {
final locale = Localizations.localeOf(context).languageCode;
return NumberFormat.compact(locale: locale).format(number);
}
}
// Usage
Text(LocalizedFormats.date(context, DateTime.now())); // "September 19, 2026"
Text(LocalizedFormats.currency(context, 1234.56, '\$')); // "$1,234.56"
Text(LocalizedFormats.number(context, 1234567)); // "1.2M"
Platform-Specific Configuration
Android
<!-- android/app/src/main/res/values/strings.xml -->
<resources>
<string name="app_name">Global App</string>
</resources>
<!-- android/app/src/main/res/values-es/strings.xml -->
<resources>
<string name="app_name">Aplicación Global</string>
</resources>
<!-- android/app/src/main/res/values-ar/strings.xml -->
<resources>
<string name="app_name">تطبيق عالمي</string>
</resources>
iOS
<!-- ios/Runner/InfoPlist.strings -->
CFBundleDisplayName = "Global App";
<!-- ios/Runner/es.lproj/InfoPlist.strings -->
CFBundleDisplayName = "Aplicación Global";
<!-- ios/Runner/ar.lproj/InfoPlist.strings -->
CFBundleDisplayName = "تطبيق عالمي";
Testing Multi-Language Support
Widget Tests
testWidgets('displays correct language', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: const Locale('es', ''),
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: MyWidget(),
),
);
expect(find.text('Aplicación Global'), findsOneWidget);
});
Pluralization Tests
testWidgets('handles pluralization correctly', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: const Locale('en', ''),
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: ItemCountWidget(count: 5),
),
);
expect(find.text('5 items'), findsOneWidget);
});
Best Practices
- Always provide a template ARB file — it’s the source of truth
- Use code generation — ensures type safety and catches missing translations
- Test with multiple locales — verify translations work correctly
- Handle missing translations gracefully — provide fallback strings
- Consider cultural differences — dates, numbers, currencies vary by region
- Test RTL languages — ensure layouts work in both directions
Resources
Multiple language support is essential for building global Flutter apps. By leveraging Dart’s internationalization tools and following best practices, you can create experiences that feel native for users worldwide.