Flutter Localization Tutorial

Learn how to implement localization on a flutter application.

· 5 min read
Flutter Localization Tutorial

Have you ever thought of making your flutter app available in multiple languages, so that users from different regions can interact with your app more easily.

So here in this article, I am going to tell you how you can localize your flutter app and make it available to any region.

This article also contains a script that you can use to generate the translations for any number of languages in one go.

What is localization?

Localization describes the process of making a product available for a different market, in a different language or different culture.

Implementing localization on your flutter application

To implement localization in the flutter application we are going to use easy_localization plugin.

Here is the link to the plugin page -

https://pub.dev/packages/easy_localization

Installation

To install easy_localization just write it on your pubspec.yaml file

dependencies:
  easy_localization: <latest-version>

Android Setup

  1. There is no extra step is required to setup

iOS Setup

  1. For iOS, you need to mention the supported languages or locale on your Info.plist file, which is located in ios/Runner .

Example -

<key>CFBundleLocalizations</key>
<array>
      <string>en</string>
      <string>hi</string>
</array>

Implementation

To implement localization using this plugin we had to store the translation of the words that are used in our app in a file, Which this plugin loads when the app is running and show the word in the selected locale.

These are the file format in which the translations can be saved -

  1. JSON
  2. CSV
  3. YAML
  4. XML

We can store these files in the app assets folder or we can fetch it from two different methods -

  1. HTTP (Can be fetched from server)
  2. FILE (Can be loaded from the file available on your device)

Here in this tutorial, we are going to use JSON files that are going to be saved on the assets folder.

To implement this what we do is we make a JSON file of every word used on our app and then we can make the translation JSON file of every other language we like to support.

Structure of JSON files

So here I am going to save all the translation JSON files in assets/translations/  folder. There is a specific pattern in which you have to name your translation files.

{languageCode}.{ext}
{languageCode}-{countryCode}.{ext}

For example -

  1. en.json
  2. en-US.json (To fully localize your app according to a specific country or region)

We must save the files using the proper pattern, then only the plugin can detect your translation file.

You also have to declare all your translation files on pubspec.yaml file -

flutter:
  assets:
    - assets/translations/

App Setup

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:easy_localization/easy_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  
  runApp(
    EasyLocalization(
      supportedLocales: [Locale('en', 'US'), Locale('de', 'DE')],
      path: 'assets/translations',
      fallbackLocale: Locale('en', 'US'),
      child: MyApp()
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      home: MyHomePage()
    );
  }
}

Code Explanation -

  1. Firstly we'll do all the necessary library imports.
  2. WidgetsFlutterBinding.ensureInitialized();

You might have used this above code earlier also but do you really understand what it does. So here's the explanation -

Flutter needs to call native code before calling runApp(). So this method makes sure that you have an instance of WidgetsBinding, which is required to use platform channels to call native code.

3. await EasyLocalization.ensureInitialized();

This method initializes the EasyLocalization Plugin.

4.

EasyLocalization(
      supportedLocales: [Locale('en', 'US'), Locale('de', 'DE')],
      path: 'assets/translations',
      fallbackLocale: Locale('en', 'US'),
      child: MyApp()
 ),

Here on the above code, we are adding the support for the EasyLocatization Plugin. The EasyLocalization class had been called here.

supportedLocales - This is the List containing the list of locales supported by our app. There are two methods by which you can define the supported locales.

  1. Locale('<LanguageCode>')

Example -

Locale('en')

When you define your locale like this it will look for en.json file in the translation folder.

2. Locale('<LanguageCode>', '<CountryCode>')

Example -

Locale('en', 'US')

When you define your locale likes this it will look for en-US.json file in the translation folder.

path - Here you declare the path where all the locales files are located.

fallbackLocale - Here you define the locale for a case where any locale failed to load due to any reason.

child - Here you can just write the name of your base class.

Let's now talk about the MyApp class. In MaterialApp you pass these parameters

  1. localizationDelegates
  2. supportedLocales - Defines the list of supported locales
  3. locale - Defines the current locale of the app

You just have to pass the value as mentioned in the code.

Usage

  1. Checking the current locale of the app - context.locale
  2. Checking the device locale - context.deviceLocale
  3. Changing the locale - context.locale = Locale('en', 'US')
  4. Resetting the locale - context.resetLocale()
  5. Deleting the saved locale - context.deleteSaveLocale()

Now before moving forward let's take a sample JSON file so that you can understand it much better

{
"title": "Hello World"
}
en-US.json

A sample file for the german translation

{"title": "Hallo Welt"}
de-DE.json

Let us consider that the current locale is en-US so it will look for en-US.json file . So this is how we are going to use this

Method 1

Text('title').tr()

Method 2

'title'.tr()

Method 3

tr('title')

All above methods will return - Hello World

tr() is the method that converts the language of the text according to the locale.

In the above example when we use tr() method in key title it gets converted into the value of the title from the en-US.json file.

If you change the locale then it will search for the title value on the JSON file as per the locale.

For example -

For de-DE it will look into the de-DE.json file. And will return - Hallo Welt.

Arguments

You can also pass arguments to the tr() method.

There are three types of arguments that you can pass here

  1. List<String> - List of arguments
  2. Map<String, String> - Named Arguments
  3. string - Gender switcher. Changes the localized string based on gender string.

Sample en-US.json. This is the sample JSON file taken from the official documentation.

{
   "msg":"{} are written in the {} language",
   "msg_named":"Easy localization are written in the {lang} language",
   "msg_mixed":"{} are written in the {lang} language",
   "gender":{
      "male":"Hi man ;) {}",
      "female":"Hello girl :) {}",
      "other":"Hello {}"
   }
}
en-US.json
// args
Text('msg').tr(args: ['Easy localization', 'Dart']),

// namedArgs
Text('msg_named').tr(namedArgs: {'lang': 'Dart'}),

// args and namedArgs
Text('msg_mixed').tr(args: ['Easy localization'], namedArgs: {'lang': 'Dart'}),

// gender
Text('gender').tr(gender: _gender ? "female" : "male"),

Linked Translations

easy_localization plugin also provides a  way to link translations.

{
  ...
  "example": {
    "hello": "Hello",
    "world": "World!",
    "helloWorld": "@:example.hello @:example.world"
  }
  ...
}
en.json

Just take the example from the above code. In helloWorld key the translations are linked. Linking a translation follows a special pattern

@.modifier:key or Just @:key

In the helloWorld key the key hello & world are linked using this pattern.

@:example.hello & @:example.world

Linked messages can be formatted with modifiers.

The below modifiers are available currently.

  • upper: Uppercase all characters in the linked message.
  • lower: Lowercase all characters in the linked message.
  • capitalize: Capitalize the first character in the linked message.

For example -

@.upper:example.hello will result into HELLO.



So this is the basic usage of localization. If you want to learn more about it just go through the official documentation of the easy_localization plugin.

There is a script below that you can use to generate traslated JSON files for multiple languages. Initially, you just need to have en.json file.