How to Provide Localizations Feature to a Flutter App with Bloc Library & Shared Preferences

A comprehensive step-by-step of how to create app localizations in Flutter with the help of Bloc as the state management and Shared Preferences for caching the user language preference.

Aditya Rohman
Level Up Coding

--

A good user experience needs to be usable, equitable, enjoyable, and useful. If you are building an app and targeting broad users worldwide who speak different languages, you need to provide localizations which is one of the equitable aspects of UX.

Localizations means you provide your app in different languages (i.e. English, Bahasa Indonesia, etc). If you are consuming a RestAPI, it usually provides you responses in different language queries. But, this article will focus on providing app static localizations with built-in flutter_localizations package. To follow along, you can use a brand-new Flutter app or your previous Flutter projects.

Step 1 — Setup Flutter Localizations

Open the pubspec.yaml file and add the following packages:

dependencies:
flutter:
sdk: flutter
flutter_localizations: # Add this line
sdk: flutter # Add this line
intl: ^0.17.0 # Add this line

Also, because we are going to provide our own localized texts then we need to add this line too:

flutter:
generate: true # Add this line

The next step is to create a new folder inside lib where our localization files are stored. This folder is usually called l10n (which stands for localizations) or l18n (which stands for internationalization). That’s the commonly used name, but you can still use your own folder name.

Inside that folder, create a file with the .arb extension. In my case, I want to provide two languages to my app, English and Bahasa Indonesia. Then I create two files, app_en.arb and app_id.arb. Inside the .arb file, there are key-value pairs for the localized texts.

{
"onboarding": "The Easy Way\nTo Manage Your\nDaily Expense ✨",
"getStarted": "Get Started",
"haveAccount": "I Have Account"
...
}
{
"onboarding": "Cara Mudah\nAtur Pengeluaran\nHarian ✨",
"getStarted": "Mulai",
"haveAccount": "Saya Punya Akun"
...
}

To create a new localized text, all you need to do is add a new key-value pair inside the bracket. Neat!

Next, in the root project directory create a new .yaml file called l10n.yaml and add the following:

arb-dir: lib/l10n # 1
template-arb-file: app_en.arb # 2
output-localization-file: app_localizations.dart # 3

Here are what the above code does:

  1. Specified the localization location in the project. This will point to the folder that was created early, lib/l10n.
  2. Specified the default language for the app when the user installs it for the first time. In this case, the default language is English (app_en.arb).
  3. Specified the name of generated localization file. The commonly used name for that is app_localizations.dart, but you can use your own name for more convenience.

To start generating the localizations, build and run the app or run the command below in the terminal:

flutter gen-l10n

This will generate the localizations files like so:

.dart_tool
├── flutter_gen
│ ├── gen_l10n
│ │ ├── app_localizations.dart <--
│ │ ├── app_localizations_en.dart <--
│ │ └── app_localizations_id.dart <--
│ └── pubspec.yaml
...

After that, open lib/main.dart and set thesupportedLocales and localizationsDelegates properties of MaterialApp with the generated localizations code.

Finally, the localized texts are ready to use. To access the localized texts, use the following syntax:

AppLocalizations.of(context)!.<YOUR_TEXT_KEY>

For more information and best practices about flutter_localizations, read the official Flutter documentation here:

Step 2 — Create Real-Time Language Changes using Bloc Library

So far we’ve set up the localizations. The next thing we need to do is provide the users with in-app language settings so the users can choose their preferred language. This can be achieved using state management. In this article, we’ll be using Bloc Library. Make sure you’ve already familiar with Bloc state management implementation to follow along. If you are new to Bloc, then you can read the documentation first.

To make things simple, we can use an enhanced enum, which was introduced on Dart 2.17. So, make sure you use SDK version 2.17 or above. You can read more about enhanced enums here:

Create a new file called language.dart and add the following code:

Next, create a new bloc to handle the app language change.

Now, you can use that bloc in your app. Here is my implementation for the example:

Here, we wrap the MaterialApp with BlocBuilder to rebuild the widget tree when the state changes. Also, don’t forget to register the bloc with BlocProvider. Then, set the locale property with the state value.

In the code above, we trigger the state changes using the following syntax:

context.read<LanguageBloc>().add(ChangeLanguage(selectedLanguage: Language.values[index]));

Step 3 — Save User Language Preference using Shared Preferences

We have implemented app localizations successfully, but something is still missing. If you change the app language to your preferred one, then hit the hot reload, guess what happens here? Yes, the language is back to default, in this case, English. To solve this problem, all we need to do is to cache the user's preferred language using shared_preferences.

Open the pubspec.yaml file and add the package.

shared_preferences: ^2.0.17

Next, we need to modify our bloc. First, add a new bloc event to retrieve the cached language preference:

After that, update the LanguageBloc with the following code:

Here are what the above code does:

  1. When the user changes their preferred language, store it in the shared preference, then emit the state changes.
  2. When the user opens the app, loads the preferred language from the shared preference, then emits the state changes. If the user opens the app for the first time, which means the shared preferences are currently null, then provide the default language.

Lastly, update the BlocProvider inside main.dart with the following:

create: (context) => LanguageBloc()..add(GetLanguage()),

Try to run the app again, change the language and then hit hot reload. Now, the app language doesn’t return to the default language again. Great!

--

--