Internationalizing and Localizing Your Flutter App

Learn how to use the flutter_localization and Intl packages to easily localize and internationalize your app, making it accessible to users in different locales. By Edson Bueno.

4.9 (22) · 1 Review

Download materials
Save for later

In this tutorial, you’ll learn how to use the Flutter Intl plugin to internationalize and localize your app. Why should anyone care about internationalization and localization, though? Well, let the numbers do the talking:

  • Eight of the top ten countries for app downloads are not English-speaking, according to Sensor Tower.
  • Localized apps are downloaded 128% as often and earn 26% more revenue per supported country, according to Distimo.

But more people learn English every day, so maybe these numbers will lose relevance over time, right? Nope. The next billion internet users will come from emerging economies. Here’s what Google already knows about them:

  • They have a mobile-only mindset. Most have never used a PC and never will — which is lucky for mobile developers.
  • They need localized content. Even the small percentage that knows English prefers content in their language.

Nelson Mandela captured that sentiment when he said: “If you talk to a man in a language he understands, that goes to his head. If you talk to him in his language, that goes to his heart.” You want users to have that kind of passion for your app.

Given all this, can you still think of a single reason not to localize your app? If your answer is that you don’t know how to do it, this tutorial will help.

By the end of this tutorial, you’ll know how to:

  • Tell the difference between internationalization and localization.
  • Internationalize a Flutter app.
  • Use the Intl package.
  • Use the Flutter Intl IDE plugin.
  • Localize materials and Cupertino widgets.
  • Make your app feel like you developed it in the user’s native language.
Note: This article assumes you’re comfortable with Flutter basics. If that’s not the case, check out Getting Started with Flutter.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.

Unzip the file and open Android Studio 4.0 or later. You can use Visual Studio Code instead, but you’ll need to adapt some instructions.

Click Open an existing Android Studio project and choose the starter folder from your unzipped download.

The IDE will prompt you with the message: ‘Pub get’ has not been run at the top of your screen. Click Get dependencies and wait for the download to finish.

Today, you’ll work on a very important app indeed — a death by caffeine calculator, the Buzz Kill.

Woman stirring a cup of coffee and staring

Start off by taking a brief look at the code. Open the pages/form_page.dart file and take a look around. There’s a lot of code, but don’t be intimidated! Most of it is simply setting up a list of coffee drinks for a user to select.

Next up open the pages/results_page.dart file. results_page is a simple widget that displays some safe coffee consumption information to the user.

Take a brief look at the code, focusing on pages/form_page.dart and pages/results_page.dart. Then build and run the project to get familiar with it.

Initial version of the sample app

For now, Buzz Kill only works in English. Your job is to make it welcoming for Brazilians.

Why Brazilian Portuguese (pt-BR)? Because Brazil has the third-most app downloads, but only 5% of the population speaks English. That makes it an excellent target for localization.

Talking about languages, do you know how to say internationalization in dt-FL (Flutterian Dart)? It’s i18n. Why? It encompasses the first and last letters of “internationalization” and then shortens the 18 letters in between.

Waving flag containing a Flutter logo

Before you start improving Buzz Kill, there’s one important thing to clear up: what internationalization and localization actually mean.

Differentiating Between Internationalization and Localization

It’s not uncommon to see the words internationalization (i18n) and localization (l10n) used — mistakenly — interchangeably. Where do you draw the line?

Territory shape divided between internationalization and localization

Localization is the process of making your app available to other locales. It includes the parameters defining the user’s language, region and any particular variant — for example, en-US (American English).

That sounds easy, but how do you do it? Do you create a copy of your code for each language? Or add if statements all over the place choosing which text to display? No, that’s where internationalization comes to the rescue.

Internationalization is how you architect and engineer your code to make it easy to localize. So, yes, you can have an internationalized app that supports just one locale, because it has the capacity to ultimately support more than one locale without dramatic engineering efforts. In fact, that’s encouraged. Internationalize even if becoming a polyglot isn’t in your app’s plans. It’ll make your code cleaner and more future-proof.

Next, you’ll see how you use Flutter to internationalize your apps.

Internationalizing in Flutter

These are the stepping stones to i18n in Flutter:

  1. Create a class containing dynamic String properties or functions for every translatable text of your app. For example, a formPageAppBarTitle property may return 'Death by Caffeine Calculator' or 'Calculadora de Morte por Cafeína', depending on the locale.
  2. Create an intermediary class in charge of setting up instances of the class created in the previous step when the app initializes or the locale changes.
  3. Provide an instance of this intermediary class to a Localizations widget living inside MaterialApp.
  4. Replace hard-coded texts with their new, dynamic versions. For example, Text('Death by Caffeine Calculator') becomes Text(Localizations.of<ClassFromTheFirstStepContainingValuesThatVaryPerLocale>(context, ClassFromTheFirstStepContainingValuesThatVaryPerLocale).formPageAppBarTitle).

Although ClassFromTheFirstStepContainingValuesThatVaryPerLocale is a meaningful name, for sure, it’s quite long, and you’ll be typing it a lot. From now on, you’ll call it S.

Maintaining Translations

The question that remains is: How should S store the Strings for all the supported languages?

That’s what you call an implementation detail, and as such, it’s up to you. But here are some ideas:

  1. Use a Map<String, Map<String, String>>, where the first Map‘s key is the language, and the second Map‘s key is the ID of the text, e.g., formPageAppBarTitle.
  2. Maintain — and read from — JSON-like files, one per locale.
  3. Use your creativity.

The second approach looks like an excellent choice, and it’s what you’ll use in this tutorial. You’ll count on the Intl package to help you read the values from the files.

Keeping content separate from logic keeps your code neat and makes it feasible even for non-coders to change it.

Blueprint of the Flutter's internationalization architecture

Even with Intl’s help, there’s plenty of work left for you to do. The process of changing the delegate every time a new language comes in and changing S whenever you need to add a new String — which happens often — is cumbersome and robotic.

As you know, wiping out cumbersome and robotic tasks is a developer’s superpower. That’s why the people at Localizely created the mind-blowing Flutter Intl plugin for Android Studio and Visual Studio Code that handles those tasks for you.

Whenever you add a new language or String, the plugin generates a new LocalizationsDelegate and S for you.

Note: Don’t confuse the Intl package with the Flutter Intl IDE plugin. The latter handles generating the classes that use the former. You’ll use both in this tutorial.