In today’s globalized world, making your app accessible to a diverse audience is crucial. Implementing internationalization (i18n) and localization (l10n) ensures your Flutter application can adapt to different languages, regions, and cultures. This article will guide you through the process of internationalizing and localizing your Flutter app.
What are Internationalization (i18n) and Localization (l10n)?
- Internationalization (i18n): The process of designing an application so that it can be adapted to various languages and regions without engineering changes. It involves abstracting all strings and user interface elements into external resources.
- Localization (l10n): The process of adapting an internationalized application for a specific region or language by translating text and adding locale-specific components.
Why Implement i18n and l10n in Flutter?
- Reach a Wider Audience: Increase user adoption by supporting multiple languages.
- Improve User Experience: Provide a more personalized and culturally relevant experience.
- Competitive Advantage: Stand out by catering to global markets.
How to Implement i18n and l10n in Flutter
Implementing i18n and l10n in Flutter involves the following key steps:
Step 1: Add Dependencies
Add the flutter_localizations and intl dependencies to your pubspec.yaml file:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
Run flutter pub get to install the dependencies.
Step 2: Configure MaterialApp for Localization
In your main.dart file, configure the MaterialApp widget to support localization:
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(
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 Localization Example'),
),
body: Center(
child: Text('Hello, World!'), // Replace with localized text later
),
);
}
}
Explanation:
localizationsDelegates: Provides delegates for core Flutter widgets and localization functionality.supportedLocales: Defines the locales that your app supports.
Step 3: Create Localization Files
Create a directory named l10n at the root of your Flutter project. Inside this directory, create ARB (Application Resource Bundle) files for each supported locale.
For English (en_US.arb):
{
"@@locale": "en_US",
"helloWorld": "Hello, World!",
"@helloWorld": {
"description": "The conventional greeting"
}
}
For Spanish (es_ES.arb):
{
"@@locale": "es_ES",
"helloWorld": "¡Hola, Mundo!",
"@helloWorld": {
"description": "El saludo convencional"
}
}
The @@locale field specifies the locale of the file, and the @helloWorld field provides metadata about the helloWorld string.
Step 4: Generate Localization Classes
To generate the necessary Dart classes for accessing your localized strings, you can use the intl_utils package and the flutter gen-l10n command. First, add intl_utils as a dev dependency:
dev_dependencies:
intl_utils: ^2.8.2
Next, add the following configuration to your pubspec.yaml file under the flutter section:
flutter:
generate: true
Then, run the following command in your terminal:
flutter gen-l10n
This command generates the AppLocalizations class in lib/l10n/app_localizations.dart, which you’ll use to access your localized strings.
If you get error
flutter gen-l10n error: Directory lookup failed for: Packagesflutter_toolslibsrcproject, searching ../../../..
Run command “flutter packages pub get”
it could be solved with `flutter pub upgrade`
Step 5: Use Localized Strings in Your App
Update your MyHomePage widget to use the localized strings:
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 StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
AppLocalizations.delegate, // Add this line
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('es', 'ES'),
],
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.helloWorld), // Use localized string here
),
body: Center(
child: Text(AppLocalizations.of(context)!.helloWorld), // Use localized string here
),
);
}
}
Now, the text in your app will change based on the device’s locale.
Step 6: Handling Pluralization
To handle pluralization, you can use the intl package’s plural format. Create a new entry in your ARB files:
In en_US.arb:
{
"@@locale": "en_US",
"itemCount": "{count,plural, =0{No items} =1{1 item} other{{count} items}}",
"@itemCount": {
"description": "Describes the number of items"
}
}
In es_ES.arb:
{
"@@locale": "es_ES",
"itemCount": "{count,plural, =0{Sin elementos} =1{1 elemento} other{{count} elementos}}",
"@itemCount": {
"description": "Describe el número de elementos"
}
}
Update your Dart code to use the pluralized string:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
int _itemCount = 0;
void _incrementItemCount() {
setState(() {
_itemCount++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.helloWorld),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(AppLocalizations.of(context)!.itemCount(_itemCount)),
ElevatedButton(
onPressed: _incrementItemCount,
child: Text('Add Item'),
),
],
),
),
);
}
}
Step 7: Handling Gender
To handle gender-specific text, use the intl package’s select format. Define gender-specific entries in your ARB files:
In en_US.arb:
{
"@@locale": "en_US",
"profileMessage": "{gender, select, male{He is awesome} female{She is awesome} other{They are awesome}}",
"@profileMessage": {
"description": "A message about a person based on their gender"
}
}
In es_ES.arb:
{
"@@locale": "es_ES",
"profileMessage": "{gender, select, male{Él es increíble} female{Ella es increíble} other{Ellos son increíbles}}",
"@profileMessage": {
"description": "Un mensaje sobre una persona basado en su género"
}
}
Update your Dart code to use the gender-specific string:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyHomePage extends StatelessWidget {
final String gender;
MyHomePage({Key? key, required this.gender}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.helloWorld),
),
body: Center(
child: Text(AppLocalizations.of(context)!.profileMessage(gender: gender)),
),
);
}
}
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyHomePage(gender: "male")),
);
},
child: Text('Go to male profile'),
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyHomePage(gender: "female")),
);
},
child: Text('Go to female profile'),
),
Best Practices for i18n and l10n in Flutter
- Externalize All Strings: Ensure all user-facing text is stored in localization files.
- Use Metadata: Provide descriptions for each localized string to aid translators.
- Test Thoroughly: Test your app with multiple locales to catch any localization issues.
- Consider RTL Languages: Support right-to-left languages by using the
Directionalitywidget and checkingTextDirection.ltr. - Handle Date, Time, and Currency Formatting: Use the
intlpackage to format dates, times, and currencies according to the user’s locale.
Conclusion
Implementing internationalization and localization is essential for creating Flutter apps that appeal to a global audience. By following the steps outlined in this article, you can efficiently adapt your app to different languages and regions, providing a better user experience and increasing your app’s reach. The flutter_localizations and intl packages provide robust tools for handling various aspects of i18n and l10n, making it easier to create a truly global Flutter app.