New and easy internationalization of Flutter apps

5 minute read

Flutter provides a set of useful APIs that enable you to support multiple languages out of the box. In this post you’ll learn how to use new simplified approach to i18n and see ways to conveniently manage the ARB files.

After 1 year since previous i18n tutorial here comes the updated and simplified version!

See the short video version:

Foreword

When building a mobile app, especially if it’s a side project, it’s common to skip the translation process until the very last moment before release. I often hear from other developers and clients that it’s difficult to manage multiple languages and there’s no common way to manage translations in Flutter apps. In this post I want to debunk this statement and show you how easy internationalization can be in Flutter.

With Flutter 1.22 a new approach to localization is available. You no longer need to run Flutter commands to generate Dart localization classes. The setup is described in the official guide, but here I want to lay out the basics that you need to get started.

Check out my video linked above for more visual guide.

General overview

The new approach to i18n introduced to Flutter in 2020 requires from you a basic setup in pubspec.yaml, l10n.yaml and a template ARB file. After that the code generation will run automatically during flutter packages get or before building your app.

Steps to follow

  1. Add flutter_localizations and intl packages

    flutter_localizations gives you out of the box support for almost 80 languages supported by Flutter in its built-in widgets

  2. Add generate: true flag to pubspec.yaml in flutter section

     dependencies:
       flutter:
         sdk: flutter
       flutter_localizations: # Add this package
         sdk: flutter
       intl: ^0.16.1 # Add this package
    
     flutter:
       generate: true # Add this flag
    
  3. Add l10n.yaml file with default configuration in the root of your app (next to pubspec.yaml)

     arb-dir: lib/l10n
     template-arb-file: app_en.arb
     output-localization-file: app_localizations.dart
    
  4. Add template ARB file (and optionally desired language file) in lib/l10n directory as app_en.arb:

     {
         "helloWorld": "Hello Flutter Engage!",
         "@helloWorld": {
             "description": "The greeting shown to the Flutter Engage attendees"
         }
     }
    
  5. To add a new language just add another ARB file e.g. app_pl.arb. The Flutter translation tool will pick it up automatically and assume its locale based on the file name.

  6. Run flutter packages get to trigger the localization classes generation. Flutter transaltion tool will create localization delegate in the .dart-tool directory (i.e. it will be hidden and should not be committed to the repository).

  7. Use newly generated class in your MaterialApp by adding built-in localization delegates and AppLocalizations.delegate

     import 'package:flutter/material.dart';
     import 'package:flutter_localizations/flutter_localizations.dart'; // important
     import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // important
    
     class MyApp extends StatelessWidget {
       @override
       Widget build(BuildContext context) {
         return MaterialApp(
           localizationsDelegates: AppLocalizations.localizationsDelegates, // important
           supportedLocales: AppLocalizations.supportedLocales, // important
           home: MyHomePage(),
         );
       }
     }
    
  8. That’s all! 🎉 Now you can use your translated term helloWorld in your widget tree:

     Text(AppLocalizations.of(context).helloWorld),
    

Thanks to this new approach the only thing you need to do in order to add a new term is to edit the template ARB file (and potentially other languages). After each flutter packages get the term should be automatically added to the generated localization delegate.

Automate adding terms to ARB file

I came up with a setup to use Flutter Intl extension to add terms automatically to template ARB file, but it’s a bit tricky (see the end of the post). I’m working on the extension that will support vanilla Flutter setup so that it will look more or less like this:

Translation services and ARB files

Only few translation services support ARB files out of the box. This is the list I came up with:

  • Arbify - self hosted, ARB as first class citizen ✔️
  • Localizely - ARB as first class citizen ✔️
  • Crowdin - ARB supported ✔️ but a bit tricky (e.g. names not changed automatically and source file has to be ARB too)
  • POEditor - not supported, but json can be converted to ARB without plural support ✔️
  • Loco - ARB supported, but without placeholders and genders ✔️
  • Lingohub - not supported
  • Weblate - not supported
  • Transifex - not supported
  • Pootle - not supported

There are also some standalone editors like this web-based (without plurals support) and BabelEdit which is a desktop editor.

In my case the most convenient to use was Localizely even though it’s paid for closed source projects. It has a free plan and is available for open source projects as well. I’m not paid to promote them :)

ARB files

A typical ARB file can look like this:

{
  "@@locale" : "en",
  "page_home_counter" : "{count, plural, one{You have pushed the button once} other{You have pushed the button {count} times}}",
  "@page_home_counter" : {
    "type" : "text",
    "description" : ""
  },
  "helloWorldOn": "Hello World on {date}",
  "@helloWorldOn": {
    "description": "A message with a date parameter",
    "placeholders": {
      "date": {
        "type": "DateTime",
        "format": "yMd"
      }
    }
  }
}

The syntax used in case of the plural form in the page_home_counter is called ICU message and allows for pretty complex terms (e.g. number formatting or currencies). There’s a great overview available in the official Flutter guide.

VS Code/Android Studio extension - Flutter Intl

One of the best tools to streamline internationalization of Flutter apps is Flutter Intl extension (also available for Android Studio). I described this in detail in previous post, but unfortunately right now it’s not compatible with new official i18n approach i.e. it will generate its own localization delegate. It’s completely fine to use it, though, so check out my previous video and post to see how it can be used.

I found a way to force it to be compatible with the approach described above. In the pubspec.yaml set following configuration of Flutter Intl:

flutter_intl:
  arb_dir: lib/l10n_new
  class_name: Translations
  enabled: true

And in l10n.yaml use following configuration:

arb-dir: lib/l10n_new
template-arb-file: intl_en.arb
output-localization-file: app_localizations.dart
output-class: Translations

This will cause Flutter Intl extension to add new terms to intl_en.arb. However, it will still generate its own delegate inside lib/generated directory. What you can do is just to ignore them and user the Translations class from .dart-tool as described above.

Wrap up

I hope this short tutorial helped you to understand the new Flutter internationalization approach. The ARB files are very powerful, but at the same time almost no translation services support it. Because of the multitude of i18n tutorials on the Internet, it feels like the official guide somehow got lost. Please check it out and feel free to reach out to me with any questions.

The example app code script are available in the project repository.

Updated: