Skip to content

Flutter - Internationalization

Internationalization (often abbreviated as i18n) is the process of designing and developing your application so it can be easily adapted to various languages and regions without engineering changes. Localization (l10n) is the subsequent process of adapting the internationalized app for a specific region or language by adding locale-specific components and translating text.

Flutter provides excellent support for i18n and l10n, allowing your app to reach a global audience.

  • Locale: An object representing the user’s preferred language and optional region (country code). Examples: Locale('en') (English), Locale('en', 'US') (US English), Locale('es', 'AR') (Argentinian Spanish).
  • Localized Messages: The text strings and other locale-sensitive data (like date/time formats, number formats, currencies) specific to each supported locale.
  • Localizations Widget: A widget that provides access to localized values within the widget tree. Widgets below it can obtain the current Locale and corresponding resources.
  • LocalizationsDelegate: A factory responsible for creating instances of a specific Localizations class (e.g., your app’s messages, Material/Cupertino widget translations). It determines which locales are supported and loads the appropriate resources.

Official Flutter Internationalization Approach

Section titled “Official Flutter Internationalization Approach”

The recommended approach uses the flutter_localizations package (for built-in widget translations) and the intl package (for handling your app’s specific messages and formatting).

Add the necessary packages to your pubspec.yaml:

dependencies:
flutter:
sdk: flutter
# Provides Material/Cupertino localizations
flutter_localizations:
sdk: flutter
# Core internationalization utilities (messages, date/number formatting)
intl: ^0.18.0 # Use latest version
# Add this section to enable code generation for intl
flutter:
uses-material-design: true
generate: true # Required for intl code generation

Run flutter pub get.

In your MaterialApp (or CupertinoApp), configure the localization delegates and supported locales:

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
// Import generated messages (will be created later)
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'i18n Demo App', // Title might also need localization
// Define supported locales
supportedLocales: const [
Locale('en', ''), // English, no country code
Locale('es', ''), // Spanish, no country code
// Add other locales your app supports
],
// Define localization delegates
localizationsDelegates: const [
AppLocalizations.delegate, // Your app's specific messages
GlobalMaterialLocalizations.delegate, // Built-in Material widgets translations
GlobalWidgetsLocalizations.delegate, // Text direction, etc.
GlobalCupertinoLocalizations.delegate, // Built-in Cupertino widgets translations
],
// Optional: Force a locale (for testing) or let Flutter decide
// locale: Locale('es', ''),
home: MyHomePage(),
);
}
}

Application Resource Bundle (.arb) files store your localized messages in JSON format.

  • Create a new file named l10n.yaml in the root of your project (alongside pubspec.yaml). Configure it to specify the template ARB file and the output directory:

  • Create the directory specified in arb-dir (e.g., lib/l10n).

  • Inside lib/l10n, create the template ARB file (app_en.arb in this case). This file defines the message keys, the default (English) text, and optional descriptions:

  • Create translation files for other supported locales (e.g., app_es.arb). Copy the keys from app_en.arb and provide the translations:

Whenever you modify ARB files or l10n.yaml, Flutter automatically generates the necessary Dart code (thanks to generate: true in pubspec.yaml). If it doesn’t auto-run, you might need to trigger a build or run flutter gen-l10n manually.

This generates files in the flutter_gen directory (usually hidden from the project view but accessible via imports), including app_localizations.dart and specific locale classes.

Import the generated AppLocalizations class and access messages using AppLocalizations.of(context)!.messageKey.

import 'package:flutter/material.dart';
// Import generated messages
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Access the localizations object
final l10n = AppLocalizations.of(context)!;
String userName = 'Flutter Dev'; // Example user name
int wombatCount = 2;
return Scaffold(
// Use localized app title
appBar: AppBar(title: Text(l10n.appTitle)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Use localized greeting
Text(l10n.helloWorld),
const SizedBox(height: 10),
// Use localized message with placeholder
Text(l10n.helloUser(userName)),
const SizedBox(height: 10),
// Use localized plural message
Text(l10n.nWombats(wombatCount)),
],
),
),
);
}
}
  • Device Settings: Change the language settings on your test device or emulator.
  • locale property: Temporarily set the locale property in MaterialApp to force a specific locale during development.

The intl package also provides locale-aware formatting for dates, numbers, and currencies.

import 'package:intl/intl.dart';
// Inside a widget or function where 'context' is available
void showFormattedData(BuildContext context) {
final currentLocale = Localizations.localeOf(context).toString(); // e.g., 'en_US', 'es'
// Date Formatting
final now = DateTime.now();
final dateFormatter = DateFormat.yMMMd(currentLocale); // Locale-aware format
print('Formatted Date: ${dateFormatter.format(now)}');
// Number Formatting
final number = 1234567.89;
final numberFormatter = NumberFormat.decimalPattern(currentLocale);
print('Formatted Number: ${numberFormatter.format(number)}');
// Currency Formatting
final currencyFormatter = NumberFormat.currency(locale: currentLocale, symbol: '€'); // Example symbol
print('Formatted Currency: ${currencyFormatter.format(number)}');
}

Internationalization is essential for reaching a wider audience. Flutter’s built-in support and the intl package provide a robust framework for managing translations and locale-specific data.