Using the intl Package for Handling Translations in Flutter

In Flutter development, creating apps that cater to a global audience requires robust internationalization (i18n) and localization (l10n) support. The intl package in Flutter is a powerful tool designed to handle translations, number formatting, date formatting, and more, ensuring your app is accessible to users around the world. This comprehensive guide walks you through the process of using the intl package to manage translations effectively in your Flutter application.

What is the intl Package?

The intl package is a part of the Flutter ecosystem that provides internationalization and localization facilities. It includes APIs for:

  • Message Translation: Localizing text and messages.
  • Date and Time Formatting: Displaying dates and times according to locale-specific conventions.
  • Number Formatting: Formatting numbers, currencies, and percentages for different regions.
  • Pluralization: Handling different forms of text based on quantity.

Why Use the intl Package?

  • Globalization: Supports creating apps for a worldwide audience.
  • Easy Translation Management: Provides tools to manage translations efficiently.
  • Standardization: Follows international standards for date, time, and number formatting.
  • Integration: Seamlessly integrates with Flutter’s localization framework.

Setting Up the intl Package in Flutter

Step 1: Add the intl Package to pubspec.yaml

Add the intl package to your pubspec.yaml file under the dependencies section:


dependencies:
  flutter:
    sdk: flutter
  intl: ^0.18.1

Then, run flutter pub get in your terminal to install the package.

Step 2: Configure the Application for Localization

In your main.dart file, configure your Flutter application for localization:


import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Intl Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'), // English, United States
        const Locale('es', 'ES'), // Spanish, Spain
      ],
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Intl Demo'),
      ),
      body: Center(
        child: Text(
          Intl.message(
            'Hello, World!',
            name: 'helloWorld',
            desc: 'The conventional greeting',
          ),
        ),
      ),
    );
  }
}

Explanation:

  • flutter_localizations is imported to provide localized values for the core Flutter widgets.
  • localizationsDelegates specify how the app should handle localization.
  • supportedLocales define the locales your app supports.

Managing Translations with intl

Step 1: Create an l10n.yaml File

Create an l10n.yaml file in the root of your Flutter project to configure the localization settings:


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

This configuration tells Flutter where to find the ARB (Application Resource Bundle) files and where to output the generated localization file.

Step 2: Create ARB Files

Create ARB files in the lib/l10n directory for each supported locale. The template ARB file (e.g., app_en.arb) is the base translation file.

app_en.arb (English)

{
  "@@locale": "en",
  "helloWorld": "Hello, World!",
  "@helloWorld": {
    "description": "The conventional greeting"
  },
  "welcomeMessage": "Welcome to our app, {userName}!",
  "@welcomeMessage": {
    "description": "A personalized welcome message",
    "placeholders": {
      "userName": {
        "type": "String",
        "example": "John Doe"
      }
    }
  },
  "itemCount": "{count,plural, =0{No items} =1{One item} other{{count} items}}" ,
  "@itemCount": {
    "description": "Shows the number of items in a list",
     "placeholders": {
        "count": {
          "type": "int",
          "example": "3"
        }
     }
  }
}
app_es.arb (Spanish)

{
  "@@locale": "es",
  "helloWorld": "¡Hola, Mundo!",
  "@helloWorld": {
    "description": "El saludo convencional"
  },
  "welcomeMessage": "¡Bienvenido a nuestra aplicación, {userName}!",
  "@welcomeMessage": {
    "description": "Un mensaje de bienvenida personalizado",
    "placeholders": {
      "userName": {
        "type": "String",
        "example": "Juan Pérez"
      }
    }
  },
  "itemCount": "{count,plural, =0{No hay elementos} =1{Un elemento} other{{count} elementos}}",
    "@itemCount": {
    "description": "Muestra el número de elementos en una lista",
     "placeholders": {
        "count": {
          "type": "int",
          "example": "3"
        }
     }
  }
}

Step 3: Generate the Localization File

Run the following command in your terminal to generate the app_localizations.dart file:


flutter gen-l10n

Step 4: Use the Generated Localization in Your App

Import the generated app_localizations.dart file and use it to access the translated messages:


import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context)!.helloWorld),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              AppLocalizations.of(context)!.helloWorld,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            Text(
              AppLocalizations.of(context)!.welcomeMessage('John Doe'),
              style: TextStyle(fontSize: 20),
            ),
             SizedBox(height: 20),
             Text(
                AppLocalizations.of(context)!.itemCount(3),
                style: TextStyle(fontSize: 20),
             )
          ],
        ),
      ),
    );
  }
}

Formatting Dates and Numbers

Date Formatting

Use DateFormat from the intl package to format dates and times according to locale-specific conventions:


import 'package:intl/intl.dart';

String formatDate(DateTime date, Locale locale) {
  final formatter = DateFormat.yMMMd(locale.toString());
  return formatter.format(date);
}

Number Formatting

Use NumberFormat to format numbers, currencies, and percentages:


import 'package:intl/intl.dart';

String formatCurrency(double amount, Locale locale) {
  final formatter = NumberFormat.currency(locale: locale.toString(), symbol: '$');
  return formatter.format(amount);
}

String formatNumber(int number, Locale locale) {
  final formatter = NumberFormat.decimalPattern(locale.toString());
  return formatter.format(number);
}

Handling Pluralization

The intl package supports pluralization, allowing you to display different text based on quantity. As seen in the ARB file example, you can use the plural format directly in your translation files.


{
 "itemCount": "{count,plural, =0{No items} =1{One item} other{{count} items}}"
}

In your Dart code, call the localized string with the count:


Text(AppLocalizations.of(context)!.itemCount(itemCount))

Switching Locales Dynamically

To allow users to switch locales within your app, you can use the setState method in a stateful widget to update the locale:


import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class LocaleSwitcher extends StatefulWidget {
  @override
  _LocaleSwitcherState createState() => _LocaleSwitcherState();
}

class _LocaleSwitcherState extends State {
  Locale _currentLocale = Locale('en', 'US');

  void _changeLocale(Locale newLocale) {
    setState(() {
      _currentLocale = newLocale;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('es', 'ES'),
      ],
      locale: _currentLocale,
      home: Scaffold(
        appBar: AppBar(
          title: Text(AppLocalizations.of(context)?.helloWorld ?? 'Hello, World!'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                AppLocalizations.of(context)?.welcomeMessage('User') ?? 'Welcome, User!',
                style: TextStyle(fontSize: 20),
              ),
              SizedBox(height: 20),
              DropdownButton(
                value: _currentLocale,
                items: [
                  DropdownMenuItem(
                    child: Text('English'),
                    value: Locale('en', 'US'),
                  ),
                  DropdownMenuItem(
                    child: Text('Español'),
                    value: Locale('es', 'ES'),
                  ),
                ],
                onChanged: (Locale? locale) {
                  if (locale != null) {
                    _changeLocale(locale);
                  }
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Conclusion

The intl package in Flutter provides comprehensive tools for internationalization and localization, enabling you to create apps that cater to a global audience. By setting up the intl package, managing translations with ARB files, and formatting dates and numbers, you can ensure your app is accessible and user-friendly for people around the world. Effective use of the intl package enhances the user experience and expands the reach of your Flutter application.