You’ll need to localize your app if it’s going to be used by people who speak a different language. That implies you’ll need to develop the program in such a way that values like text and layouts may be localized for each language or locale it supports. Flutter includes widgets and classes that aid with internationalization, as well as internationalized Flutter libraries.
In this article, I’ll show you how to localize your Flutter application.
By the end of this article, you will have a localized Flutter app with support for English, French and Arabic languages as shown below. In the second part of this article, we will implement the ability for the user to switch between the supported languages using the riverpod package.
To complete this tutorial you will need to:
Download and install Android Studio or Visual Studio Code
Download and install Flutter.
Set up your editor as described here.
After you’ve set up your Flutter environment, execute the following command to build a new application:
$ flutter create localization_example
Create a folder called “i18n” in your project root directory, this folder will contain all the supported languages as JSON files.
Inside the i18n folder add the en.json file, fr.json file, and ar.json as below respectively.
en.json
1 2 3 4
{ "appName": "Go Home", "description": "Are you lost? find your way home now." }
fr.json
1 2 3 4
{ "appName": "Rentrer chez soi", "description": "Es-tu perdu? trouve ton chemin à la maison maintenant." }
ar.json
1 2 3 4
{ "appName": "اذهب للمنزل", "description": " هل أنت تائه؟ تجد طريقك إلى المنزل الآن " }
Open the pubspec.yaml for the newly created project and add the dependencies like this:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
You will also need to add the image and language folder to pubspec.yaml like this;
flutter:
assets:
images/
i18n/
To include the package in your project, run the command “flutter pub get” on your terminal.
MaterialApp comes with a supportedLocales field, where we can add all the locales (languages) our app supports.
1 2 3 4 5 6 7
MaterialApp( localizationsDelegates: [ GlobalCupertinoLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], )
The default delegates are used to translate Flutter-inbuilt widgets like the Calendar, TimePicker, DataPicker. etc. For the Material Components library, GlobalMaterialLocalizations.delegate provides localized strings and other values. GlobalWidgetsLocalizations.delegate handles the default text direction, either right-to-left or left-to-right, for the widgets library.
We must now determine whether or not the user’s device locale is supported by our app. We can use the localeResolutionCallback to check and then provide a fallback if our app does not support the user’s device locale.
1 2 3 4 5 6 7 8 9 10 11
MaterialApp( localeResolutionCallback: (Locale userLocale, Iterable < Locale > supportedLocales) { for (var locale in supportedLocales) { if (locale.languageCode == userLocale.languageCode && locale.countryCode == userLocale.countryCode) { return userLocale; } } return supportedLocales.first; }, );
To translate our text, we need a custom delegate like GlobalWidgetsLocalizations.delegate or GlobalMaterialLocalizations.delegate.
Create a dart file and call it localization_helper.dart and add the following content;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class LocalizationHelper {
final Locale locale;
LocalizationHelper(this.locale);
static LocalizationHelper of (BuildContext context) {
return Localizations.of < LocalizationHelper > (context, LocalizationHelper);
}
static
const LocalizationsDelegate < LocalizationHelper > delegate =
_AppLocalizationsDelegate();
Map < String, String > _localizedStrings;
Future < bool > _load() async {
String jsonString =
await rootBundle.loadString('i18n/{locale.languageCode}.json');
Map < String, dynamic > jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
String _translate(String key) {
return _localizedStrings[key];
}
String get appName => _translate('appName');
String get description => _translate('description');
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate < LocalizationHelper > {
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ['en', 'fr', 'ar', ].contains(locale.languageCode);
}
@override
Future < LocalizationHelper > load(Locale locale) async {
LocalizationHelper localizations = new LocalizationHelper(locale);
await localizations._load();
return localizations;
}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
Add the newly created delegate to MaterialApp.
MaterialApp(
localizationsDelegates: [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
LocalizationHelper.delegate
], )
To use the localized text, you will call the LocalizationHelper.of(context) as shown below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class HomePage extends StatelessWidget {
static
const imageLocation = 'images/home_image.png';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('{LocalizationHelper.of(context).appName}'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Spacer(
flex: 3,
),
Image.asset(
imageLocation,
fit: BoxFit.cover,
),
Spacer(),
Text('{LocalizationHelper.of(context).description}',
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.headline5),
Spacer(
flex: 3,
),
],
),
),
);
}
}
Finally, your main.dart file should look like this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'localization_helper.dart';
void main() {
runApp(LocalizationDemo());
}
class LocalizationDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Localization Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
supportedLocales: [
Locale('en', 'US'),
Locale('fr', 'FR'),
Locale('ar'),
],
localizationsDelegates: [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
LocalizationHelper.delegate
],
home: HomePage(),
);
}
}
Congratulations, you now have a Flutter app that is localized in three different languages. To see the app in action, change the language of your device to French and notice that the app text is now in the French language. In the second part of this tutorial, we will add a pop-up menu button to the UI that will let the user switch between languages.
Github: https://github.com/De-Morgan/localiztion-demo/tree/part-one