Internationalization (i18n) is the process of designing an app so that it can be easily localized (L10n) for different languages and cultures. Localization involves translating the text, images, and other resources in your app into different languages.
In a Flutter app, you can achieve internationalization and localization by defining string resources in a specific format and then loading the appropriate resources based on the user’s language preference.
Step-by-Step Guide
Here are the steps to implement internationalization and localization in a Flutter app:
Step 1: Add dependencies
In your app’s pubspec.yaml
file, add the following dependencies:
dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter intl: ^0.17.0
The flutter_localizations
package provides the built-in localization support for Flutter, while the intl
package provides the tools for internationalization.
Step 2: Define your string resources
Create a new directory in your project’s root directory called i18n
. Inside this directory, create a file called messages_en.arb
(replace en
with the appropriate language code for your base language). This file will contain the string resources for your app in the base language.
Here’s an example of what the messages_en.arb
file might look like:
{ "@@locale": "en", "helloWorld": "Hello, world!", "greeting": "Welcome, {name}!", "buttonText": "Press me" }
The @@locale
key specifies the language code for this file. The other keys correspond to the string resources used in your app.
Step 3: Create a class to load the string resources
Create a new file called i18n.dart
in your project’s lib
directory. In this file, define a class called AppLocalizations
:
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; class AppLocalizations { final Locale locale; AppLocalizations(this.locale); static AppLocalizations? of(BuildContext context) { return Localizations.of<AppLocalizations>(context, AppLocalizations); } static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate(); late Map<String, String> _localizedStrings; Future<bool> load() async { final jsonString = await rootBundle.loadString('i18n/messages_${locale.languageCode}.arb'); final jsonMap = Map<String, dynamic>.from(json.decode(jsonString)); _localizedStrings = jsonMap.map((key, value) => MapEntry(key, value.toString())); return true; } String? translate(String key) { return _localizedStrings[key]; } String translateFormatted(String key, List<Object> args) { return Intl.message( translate(key) ?? '', name: key, args: args, locale: locale.toString(), ); } } class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> { const _AppLocalizationsDelegate(); @override bool isSupported(Locale locale) { return ['en', 'fr'].contains(locale.languageCode); } @override Future<AppLocalizations> load(Locale locale) async { final localizations = AppLocalizations(locale); await localizations.load(); return localizations; } @override bool shouldReload(_AppLocalizationsDelegate old) => false; }
The `AppLocalizations` class loads the string resources for the current locale and provides methods to access them. The `_AppLocalizationsDelegate` class is responsible for loading the `AppLocalizations` instance for the current locale. ### Step 4: Load the string resources in your app In your app’s `main.dart` file, wrap your `MaterialApp` widget with a `Localizations` widget:
void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( localizationsDelegates: [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], supportedLocales: [ const Locale('en', ''), const Locale('fr', ''), ], home: MyHomePage(), ); } }
The localizationsDelegates
property specifies the localization delegates to use. In this example, we’re using the AppLocalizations
delegate we defined earlier, as well as the built-in material and widget localizations delegates.
The supportedLocales
property specifies the list of locales that your app supports.
Step 5: Use the localized strings in your app
In your app’s widgets, use the AppLocalizations
class to access the localized strings:
class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { final AppLocalizations localizations = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar( title: Text(localizations.translate('helloWorld') ?? ''), ), body: Center( child: Text( localizations.translateFormatted('greeting', ['John']), ), ), floatingActionButton: FloatingActionButton( onPressed: () {}, tooltip: localizations.translate('buttonText'), child: Icon(Icons.add), ), ); } }
In this example, we’re using the translate
method to retrieve the helloWorld
string, and the translateFormatted
method to retrieve the greeting
string and format it with the name “John”.
Conclusion
Internationalization and localization are essential features for making your Flutter app accessible to users around the world. By following these simple steps, you can easily add support for multiple languages and cultures to your app.