Skip to content
Blog

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:

  1. Dart’s intl package — formatting, parsing, and message handling
  2. Flutter’s flutter_localizations — locale-aware widgets
  3. ARB files — translation storage format
  4. 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

  1. Always provide a template ARB file — it’s the source of truth
  2. Use code generation — ensures type safety and catches missing translations
  3. Test with multiple locales — verify translations work correctly
  4. Handle missing translations gracefully — provide fallback strings
  5. Consider cultural differences — dates, numbers, currencies vary by region
  6. 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.