Yet another localization approach in Flutter

Read in Ukrainian

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 the lib 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:

  1. 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.

  1. Create an empty Flutter project with flutter create command.
  2. 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?

https://www.twitter.com/FlutterComm

--

--

Anna Leushchenko πŸ‘©β€πŸ’»πŸ’™πŸ“±πŸ‡ΊπŸ‡¦
Flutter Community

Google Developer Expert in Dart and Flutter | Author, speaker at tech events, mentor, OSS contributor | Passionate mobile apps creator