Question #20MediumFlutter Basics

Multi lang usage in flutter

#flutter

Answer

Overview

Multi-language (internationalization/i18n) support in Flutter allows your app to display content in multiple languages based on user preferences or device locale. Flutter provides built-in tools and packages for localization.


Setup Methods

Method 1: Flutter Intl (Recommended)

Official Flutter approach using ARB files.

Method 2: Easy Localization Package

Popular third-party package with simpler setup.


Method 1: Flutter Intl (Official)

Step 1: Add Dependencies

yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.18.0

flutter:
  generate: true

Step 2: Create l10n.yaml

yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

Step 3: Create ARB Files

lib/l10n/app_en.arb (English)

json
{
  "@@locale": "en",
  "hello": "Hello",
  "welcome": "Welcome, {name}",
  "@welcome": {
    "placeholders": {
      "name": {
        "type": "String"
      }
    }
  },
  "itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}",
  "@itemCount": {
    "placeholders": {
      "count": {
        "type": "int"
      }
    }
  }
}

lib/l10n/app_es.arb (Spanish)

json
{
  "@@locale": "es",
  "hello": "Hola",
  "welcome": "Bienvenido, {name}",
  "itemCount": "{count, plural, =0{Sin elementos} =1{1 elemento} other{{count} elementos}}"
}

lib/l10n/app_fr.arb (French)

json
{
  "@@locale": "fr",
  "hello": "Bonjour",
  "welcome": "Bienvenue, {name}",
  "itemCount": "{count, plural, =0{Aucun élément} =1{1 élément} other{{count} éléments}}"
}

Step 4: Configure MaterialApp

dart
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('en'), // English
        Locale('es'), // Spanish
        Locale('fr'), // French
        Locale('ar'), // Arabic
      ],
      locale: Locale('en'), // Default locale
      home: HomeScreen(),
    );
  }
}

Step 5: Use Translations

dart
class HomeScreen extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;
    
    return Scaffold(
      appBar: AppBar(title: Text(l10n.hello)),
      body: Column(
        children: [
          Text(l10n.welcome('John')),
          Text(l10n.itemCount(5)),
        ],
      ),
    );
  }
}

Method 2: Easy Localization Package

Step 1: Install Package

yaml
dependencies:
  easy_localization: ^3.0.0

Step 2: Create Translation Files

assets/translations/en.json

json
{
  "hello": "Hello",
  "welcome": "Welcome, {}",
  "item_count": {
    "zero": "No items",
    "one": "1 item",
    "other": "{} items"
  }
}

assets/translations/es.json

json
{
  "hello": "Hola",
  "welcome": "Bienvenido, {}",
  "item_count": {
    "zero": "Sin elementos",
    "one": "1 elemento",
    "other": "{} elementos"
  }
}

Step 3: Update pubspec.yaml

yaml
flutter:
  assets:
    - assets/translations/

Step 4: Initialize

dart
import 'package:easy_localization/easy_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  
  runApp(
    EasyLocalization(
      supportedLocales: [Locale('en'), Locale('es'), Locale('fr')],
      path: 'assets/translations',
      fallbackLocale: Locale('en'),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      home: HomeScreen(),
    );
  }
}

Step 5: Use Translations

dart
import 'package:easy_localization/easy_localization.dart';

class HomeScreen extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('hello'.tr())),
      body: Column(
        children: [
          Text('welcome'.tr(args: ['John'])),
          Text('item_count'.plural(5)),
          
          // Change language
          ElevatedButton(
            onPressed: () => context.setLocale(Locale('es')),
            child: Text('Español'),
          ),
          ElevatedButton(
            onPressed: () => context.setLocale(Locale('en')),
            child: Text('English'),
          ),
        ],
      ),
    );
  }
}

Dynamic Language Switching

dart
class LanguagePicker extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return DropdownButton<Locale>(
      value: context.locale,
      items: [
        DropdownMenuItem(
          value: Locale('en'),
          child: Text('English'),
        ),
        DropdownMenuItem(
          value: Locale('es'),
          child: Text('Español'),
        ),
        DropdownMenuItem(
          value: Locale('fr'),
          child: Text('Français'),
        ),
      ],
      onChanged: (locale) {
        if (locale != null) {
          context.setLocale(locale);
        }
      },
    );
  }
}

Handling RTL Languages (Arabic, Hebrew)

dart
MaterialApp(
  localizationsDelegates: [...],
  supportedLocales: [
    Locale('en'),
    Locale('ar'), // Arabic (RTL)
    Locale('he'), // Hebrew (RTL)
  ],
  // Auto-detects RTL
  builder: (context, child) {
    return Directionality(
      textDirection: _getTextDirection(context),
      child: child!,
    );
  },
)

TextDirection _getTextDirection(BuildContext context) {
  final locale = Localizations.localeOf(context);
  return ['ar', 'he', 'fa', 'ur'].contains(locale.languageCode)
      ? TextDirection.rtl
      : TextDirection.ltr;
}

Best Practices

Tip: Use context-aware translations, not hardcoded strings

✅ Do

dart
Text(AppLocalizations.of(context)!.hello)

❌ Don't

dart
Text('Hello') // Hardcoded

Use Pluralization

dart
// Good
Text(l10n.itemCount(items.length))

// Bad
Text('${items.length} items') // Doesn't work for all languages

Extract All Strings

dart
// ✅ Good
final title = l10n.appTitle;
final subtitle = l10n.appSubtitle;

// ❌ Bad
final title = 'My App';
final subtitle = 'Welcome';

Comparison Table

FeatureFlutter IntlEasy Localization
SetupModerateEasy
File FormatARBJSON/YAML
Type Safety✅ Strong⚠️ Weak
Code Generation✅ Yes❌ No
Hot Reload✅ Yes✅ Yes
Pluralization✅ Built-in✅ Built-in
Dynamic Switch⚠️ Complex✅ Simple
Official✅ Yes❌ No

Resources