Yet another localization approach in Flutter
I recently came across the task of localization for Flutter application and was surprised by the variety of approaches, while none of them combined all the features I was looking for.
My requirements for the approach were:
- translations are stored in separate files, one file per each language (format didnβt really matter, smth commonly used like
json
), located anywhere in the project; - translation keys are generated to Dart code, no manual keys declaration, and no guessing whether such key exists;
- support constant watching for file system changes, rather than using the one-time generating command;
- the less code the better.
Pub package i69n with some bridging code did the trick for me!
If you prefer consuming video content, checkout this talk by Anna (Domashych) Leushchenko π©βπ»ππ±πΊπ¦
So why consider using i69n?
- It works with translations in
.yaml
files. Files can be put in any location under thelib
folder, have to be named<file_name>.i69n.yaml, <file_name>_fr.i69n.yaml, <file_name>_uk.i69n.yaml
etc. - It generates
String
getters for translations keys into.dart
files in the same folder the.yaml
files are located.
What you put in translations.i69n.yaml
:
What gets generated in translations.i69n.dart
:
- It supports watching file system changes with standard
build_runner
command.
- Coupling the results of its code generation with Flutterβs localization mechanism is done in a single file (dart code later in this article).
Bonus i69n features:
- It generates methods instead of just
String
getters if the string is intended to be used as a format.
What you put in translations.i69n.yaml
:
What gets generated in translations.i69n.dart
:
2. Pluralization support.
What you put in translations.i69n.yaml
:
What gets generated in translations.i69n.dart
:
3. Dynamic access to translation values by using String
keys.
What you put in translations.i69n.yaml
:
What else gets generated in translations.i69n.dart
:
4. Translation classes nesting.
What you put in translations.i69n.yaml
:
What gets generated in translations.i69n.dart
:
5. Translation classes inheritance from default language class.
What you put in translations.i69n.yaml
:
What you put in translations_fr.i69n.yaml
:
What you put in translations_uk.i69n.yaml
:
What gets generated in translations.i69n.dart
:
What gets generated in translations_fr.i69n.dart
:
What gets generated in translations_uk.i69n.dart
:
More featured are described by package authors in the documentation.
Limitations:
- no automatic language detection, it is your responsibility to decide which translation to use;
- English has to be the default language.
How?
So how to implement Flutter app localization with i69n?
Iβll use the default Flutter counter app as an example. You can follow a step-by-step tutorial here or jump into a complete project sample on GitHub.
- Create an empty Flutter project with
flutter create
command. - Edit
pubspec.yaml
.
3. Run flutter pub get
to get new dependencies.
4. Run the build_runner
command to watch file system changes.
5. Add a .yaml
file for each language.
translations.i69n.yaml
:
translations_fr.i69n.yaml
:
translations_uk.i69n.dart
:
6. Make sure the corresponding .dart
files were generated.
7. Now itβs time to bind generated translation files to Flutterβs localization mechanism. Here I create an ExampleLocalizations
class that provides delegate
and supportedLocales
static fields. It lazily creates instances of Translations
when load
is called with new locale
.
8. Register ExampleLocalizations.delegate
in MaterialApp
.
9. Now we can use localized messages inside HomePage
.
Itβs up to you how to get your translations around. In this example ExampleLocalizations.of(context)
returns a Translations
instance right away rather than ExampleLocalizations
, just like Theme.of(context)
returns ThemeData
. You can choose to create a context.translations()
extension, inject them into Provider
, or put them somewhere you can access without having to provide BuildContext
instance.
10. To localize iOS application you also have to add CFBundleLocalizations
key in Info.plist
.
Finally, you can run the app! When the device language settings change, it will be translated into French or Ukrainian or will default to English for other languages.
Thatβs it! Thanks for reading till the end.
Letβs talk! Please share your opinion on this approach. What is your preferred way to implement localization in Flutter?