In today’s globalized world, providing multi-language support in your mobile application is crucial for reaching a wider audience and enhancing user experience. Flutter, with its rich set of tools and widgets, makes implementing internationalization (i18n) and localization (l10n) relatively straightforward. This blog post will guide you through the process of building multi-language support in your Flutter applications.
What is Internationalization (i18n) and Localization (l10n)?
- Internationalization (i18n): The process of designing and developing an application to support multiple languages and regions without needing engineering changes. It involves abstracting all locale-specific data and formatting.
- Localization (l10n): The process of adapting an internationalized application for a specific locale. It involves providing translations and formatting rules for that locale.
Why Implement Multi-Language Support?
- Wider Audience Reach: Makes your application accessible to a global audience.
- Enhanced User Experience: Provides users with a personalized experience in their native language.
- Increased Engagement: Improves user satisfaction and encourages longer app usage.
- Competitive Advantage: Distinguishes your application from competitors that only offer a single language.
How to Implement Multi-Language Support in Flutter
Implementing multi-language support in Flutter involves several key steps:
Step 1: Add Dependencies
First, add the flutter_localizations
and intl
dependencies to your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: ^0.18.1 # Use the latest version
dev_dependencies:
flutter_test:
sdk: flutter
intl_utils: ^2.8.5 # Use the latest version
Run flutter pub get
to install the dependencies.
Step 2: Configure flutter_localizations
In your main.dart
file, configure the MaterialApp
to use flutter_localizations
:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Localization Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'), // English
const Locale('es', 'ES'), // Spanish
const Locale('fr', 'FR'), // French
],
home: MyHomePage(),
);
}
}
In this setup:
localizationsDelegates
provide the necessary localization data.supportedLocales
lists the locales your application supports.
Step 3: Create Localization Files
Create a directory structure to hold your localization files. A common approach is:
lib/
l10n/
app_localizations.dart
app_localizations_en.arb
app_localizations_es.arb
app_localizations_fr.arb
app_localizations.dart
Create an app_localizations.dart
file to manage the localization process:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart';
class AppLocalizations {
AppLocalizations(this.localeName);
static Future load(Locale locale) {
final String name = locale.countryCode == null ? locale.languageCode : locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;
return AppLocalizations(localeName);
});
}
static AppLocalizations? of(BuildContext context) {
return Localizations.of(context, AppLocalizations);
}
final String localeName;
static const LocalizationsDelegate delegate =
_AppLocalizationsDelegate();
String get helloWorld {
return Intl.message(
'Hello World',
name: 'helloWorld',
desc: 'Simple hello world message',
);
}
String greet(String name) {
return Intl.message(
'Hello, $name!',
name: 'greet',
desc: 'Greets the user with their name.',
args: [name],
);
}
}
class _AppLocalizationsDelegate extends LocalizationsDelegate {
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ['en', 'es', 'fr'].contains(locale.languageCode);
}
@override
Future load(Locale locale) {
return AppLocalizations.load(locale);
}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
ARB Files (.arb
)
ARB files are JSON-based files that contain the translations for each locale. Here are example ARB files for English (app_localizations_en.arb
), Spanish (app_localizations_es.arb
), and French (app_localizations_fr.arb
):
app_localizations_en.arb
{
"helloWorld": "Hello World",
"greet": "Hello, {name}!"
}
app_localizations_es.arb
{
"helloWorld": "Hola Mundo",
"greet": "¡Hola, {name}!"
}
app_localizations_fr.arb
{
"helloWorld": "Bonjour le monde",
"greet": "Bonjour, {name} !"
}
Step 4: Generate Localization Code
Run the following command to generate the localization code based on your ARB files:
flutter pub pub run intl_utils:generate
This command uses the intl_utils
package to generate Dart code from the ARB files, which includes message lookup logic and type-safe access to translations.
Step 5: Use Localized Strings in Your UI
Access the localized strings in your Flutter widgets using the AppLocalizations
class:
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: Theme.of(context).textTheme.headlineMedium,
),
SizedBox(height: 20),
Text(
AppLocalizations.of(context)!.greet('Flutter'),
style: Theme.of(context).textTheme.titleLarge,
),
],
),
),
);
}
}
Now, your application will display text in the selected locale. You may need to restart the app to see the changes.
Step 6: Dynamically Change the Locale
To allow users to change the locale dynamically, you can use the setState
method to update the MyApp
widget. Here’s an example:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State {
Locale _locale = const Locale('en', 'US');
void setLocale(Locale value) {
setState(() {
_locale = value;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Localization Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'), // English
const Locale('es', 'ES'), // Spanish
const Locale('fr', 'FR'), // French
],
locale: _locale,
home: MyHomePage(setLocale: setLocale),
);
}
}
class MyHomePage extends StatelessWidget {
final Function(Locale) setLocale;
MyHomePage({required this.setLocale});
@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: Theme.of(context).textTheme.headlineMedium,
),
SizedBox(height: 20),
Text(
AppLocalizations.of(context)!.greet('Flutter'),
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 20),
DropdownButton(
value: Localizations.localeOf(context),
items: [
DropdownMenuItem(
value: const Locale('en', 'US'),
child: Text('English'),
),
DropdownMenuItem(
value: const Locale('es', 'ES'),
child: Text('Spanish'),
),
DropdownMenuItem(
value: const Locale('fr', 'FR'),
child: Text('French'),
),
],
onChanged: (Locale? locale) {
if (locale != null) {
setLocale(locale);
}
},
),
],
),
),
);
}
}
Conclusion
Implementing multi-language support in Flutter enhances user experience, expands your app’s reach, and demonstrates professionalism. By following these steps, you can seamlessly integrate internationalization and localization into your Flutter applications. Utilizing Flutter’s localization packages and best practices ensures that your application is accessible and user-friendly for a global audience.