How to localize Flutter app with Localazy šŸ”—

Localization is the process of rendering the content of your app into other languages and customizing your app for each target market that you want to support.

Benefits Of Localazy šŸ”—

Save money on translations šŸ”—

Save up to 50% of translation costs thanks to shared translations. Localize your app to 80+ languages for free.

What is Localazy ShareTM

ShareTM is what makes Localazy unique and different from other translation platforms. We are developers; we share our code on Github, Gitlab, or in another place. We cooperate, share our knowledge and libraries. We have this in our DNA. It saves us time and money; it helps us to move forward faster and produce better software.

Why donā€™t we share translations to make our apps better for the worldwide audience? Why we pay for translating the same words again and again? Does it make sense? It does not, and ShareTM is here to fix this issue.

Upload your app to Localazy and instantly share your translations with other apps on the platform, and as a reward, get your app translated to more languages for free.

Stay assured about high quality šŸ”—

Verify translations with the pro-active review and use all tools for providing context to your translators for free.

Keep track of changes šŸ”—

While the review is a way to ensure translation quality in other translation platforms, Localazy is organized around it. But our review process is entirely different. Itā€™s not just a set of filtering options to find strings that may be inaccurately translated.

Our review process is a pro-active tool that helps you to verify translations and keep track of all changes that happened on Localazy while you spend your precious time developing your app and making it better. No matter if you visit Localazy every day or once per month, you never get lost! The best recipe for a peaceful mind.

Sign Up and Create an App šŸ”—

Firstly, you need to sign up and create an app in Localazy. In this article, weā€™ll create a basic Flutter app which is using multi-language support.

Register page

After you create a new account in Localazy, you will see a new page which name is Create a New App. We are giving a name as ā€œflutter-localazyā€.

App Type means, if you do it public, people can help to improve translation and if you choose private, only invited people can improve the translation.

And we are choosing English as the source language.

Also, we are using ShareTM feature. ShareTM is what makes Localazy unique and different from other translation platforms. Briefly, ShareTM is highly accurate translation memory. It allows using of community translations.

Create a new App

After all these things we can create a new project. Then you will see a ā€œSelect Your Integrationā€ page. You can integrate Localazy to all these platforms, we will choose Flutter for now.

Select Your Integration

Now, we need to install Localazy CLI tool to manage the upload and download of phrases.

Installation Localazy CLI is available as a native app for all major platforms (Windows, Linux and macOS), Javaā€™s JAR and Dockerā€¦

Localazy CLI is a command-line interface, and we can use it to upload files to the Localazy platform and download translations back to our app.

Also, Localazy CLI is available as a native app for all major platforms (Windows, Linux and macOS), Javaā€™s JAR and Docker image.

You need to install Localazy CLI inside project folder or update your path

Set Up Flutter Project šŸ”—

After install Flutter, we create a new Flutter project.

Use the flutter create the command to create a new project:

$ flutter create flutter_localazy
$ cd flutter_localazy

The command creates a Flutter project directory called flutter_localazy that contains a simple demo app that uses Material Components.

Demo App

First step is to include required packages in pubspec.yaml file. For that just add the two packages name under the dependencies. It would look something like this.

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:     //add this line
    sdk: flutter             //add this line
    
  intl_translation: ^0.17.1  //add this line

After you save this file, Flutter will automatically download and it will include the packages. You can now use it in your app anywhere simply by importing it. Weā€™ll import it in the main.dart file first. Go to, your main.dart file and add import the package.

import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart';
void main() => runApp(MyApp());

The next step is to set up the Localization delegates in your main.dart file. For that, you need to specify the two delegates first.

Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate
      ],
      supportedLocales: [
        const Locale('en', 'US'),
        const Locale('de', 'DE')
      ],
      ...

GlobalMaterialLocalizations.delegate provides localized strings and other values for the Material Components library. GlobalWidgetsLocalizations.delegate defines the default text direction, either left to right or right to left, for the widgets library. As you can see here, we added two lists to our Material app localizationsDelegates & supportedLocales. The supportedLocales parameter holds the list of languages that our app will support.

Next step is to create an AppLocalization & AppLocalizationDelegate. Classes in which weā€™ll be defining our keywords and their translations. Weā€™ll also use it throughout the app and for manually switching the Locale if required. Therefore Isuggest you create this class in a separate folder in your lib directory. Mine looks like /lib/locale/app_localization.dart The AppLocalization class will only have two static methods for now. The load() & of() method.

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

class AppLocalization {
  
  static Future<AppLocalization> load(Locale locale) {
    final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);
    return initializeMessages(localeName).then((_) {
      Intl.defaultLocale = localeName;
      return AppLocalization();
    });
  }

  static AppLocalization of(BuildContext context) {
    return Localizations.of<AppLocalization>(context, AppLocalization);
  }
  
  // list of locales
String get heyWorld {
  return Intl.*message*(
    'You have pushed the button this many times:',
    name: 'heyWorld',
    desc: 'Simple word for greeting ',
  );
}
}

PS: Note that your load() might be returning an error on the line: return initializeMessages() ignore this for now, weā€™ll remove it in a while.

load() : It will load/set all the Localized values. You can also call this method if you wish to switch the locale of app manually.

of() : This method will return the instance of current Localization of the app. Somewhat like a factory method.

get heyWorld: This getter returns the value of the heyWorld. This property is what will be using to get its translations based on locale of the app. For demo purpose I have only set 1 String as for now but you can as many as you can.

Now create an AppLocalizationDelegate for the AppLocalization class.

class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalization>{
  final Locale overriddenLocale;

  const AppLocalizationDelegate(this.overriddenLocale);

  @override
  bool isSupported(Locale locale) => ['en', 'de'].contains(locale.languageCode);

  @override
  Future<AppLocalization> load(Locale locale) => AppLocalization.load(locale);

  @override
  bool shouldReload(LocalizationsDelegate<AppLocalization> old) => false; 
}

As you can see this Delegate class is extended from main LocalizationsDelegate and we have pointed it to AppLocalization via add the above required methods and take a look at the isSupported() method:

@override
bool isSupported(Locale locale)=>['en','de'].contains(locale.languageCode);

This method will be called to check if the language is supported or not, based on the Locale instance provided. Make sure to you have your supported languages inserted in this list here such as: [ā€˜enā€™, ā€˜deā€™ ā€¦.]

Now create a l10n directory in your lib folder. This directory will hold all the translated values as per your Locale. Your final directory structure will look somewhat like this:

In your Terminal and run the following command to create the arb files:

$ flutter pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/locale/app_localization.dart

NOTE: The Dart intl package only creates one template file of .arb from your Localization class and names it intl_messages.arb. From here, you now have to manually create other resource files with convention intl_[LANGUAGE_CODE].arb and copy the content of intl_messages.arb directly with updated the values.

Eg: For English format you will create file intl_en.arb and the content copied from intl_messages.arb :

{
  "@@last_modified": "2020-11-07T23:41:23.983052",
  "heyWorld": "You have pushed the button this many times:",
  "@heyWorld": {
    "description": "Simple word for greeting ",
    "type": "text",
    "placeholders": {}
  }
}

Now letā€™s create one in the German language. So this will be:

{
  "@@last_modified": "2019-06-27T23:38:38.868199",
  "heyWorld": "Hey Welt",
  "@heyWorld": {
    "description": "Einfaches Wort zur BegrĆ¼ĆŸung",
    "type": "text",
    "placeholders": {}
  }
}

Once you created these files in your l10n folder. Now you need to run another command to create the corresponding .dart files that will be used to manage these resource files. For that run the following command:

$ flutter pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/intl_messages.arb lib/l10n/intl_de.arb lib/l10n/intl_en.arb lib/locale/app_localization.dart

NOTE that i have only 2 files intl_en.arb & intl_de.arb therefore I am only passing those in command. But if you have more or less, you need to pass them all.

Now import the messages_all.dart file in your AppLocalization Class and hereā€™s a final look at your AppLocalization Class:

class AppLocalization {
  
  static Future<AppLocalization> load(Locale locale) {
    final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);
    return initializeMessages(localeName).then((_) {
      Intl.defaultLocale = localeName;
      return AppLocalization();
    });
  }

  static AppLocalization of(BuildContext context) {
    return Localizations.of<AppLocalization>(context, AppLocalization);
  }

  String get heyWorld {
    return Intl.message(
      'Hey World',
      name: 'heyWorld',
      desc: 'Simpel word for greeting ',
    );
  }
}

class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalization> {
  final Locale overriddenLocale;

  const AppLocalizationDelegate(this.overriddenLocale);

  @override
  bool isSupported(Locale locale) => ['en', 'es', 'de'].contains(locale.languageCode);

  @override
  Future<AppLocalization> load(Locale locale) => AppLocalization.load(locale);
  
  @override
  bool shouldReload(LocalizationsDelegate<AppLocalization> old) => false;
}

The error is gone! right. šŸ˜‰ Now youā€™re just one step from using the language values based on your current localization settings. To use language specific text in your app, youā€™ll simply need to follow the two steps:

  • import AppLocalization class where you want to use the text

  • Call localized value of text via: AppLocalizations.of(context).heyWorld

Now what is happening here is that if you call the above method, it calls the getter of the AppLocalization class and returns its value based on the Locale of the context.

If the context is en (i.e. english) it will return the value from intl_en.arb and when the Locale changes to de ( i.e. german) it will return the value from intl_de.arb. And since weā€™re using the same class getter for both languages ie (heyWorld) therefore we donā€™t need to worry about that either. Flutter will take care of that. But wait, here comes the best part.

Integrate Localazy for strings management šŸ”—

Now itā€™s time to add the integration with Localazy. Create localazy.json in the root folder and paste the following configuration. Use the write and read keys from the step 2 of the integration guide page.

In your main.dart file will be like this:

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // This widget is the root of your application.
  AppLocalizationDelegate _localeOverrideDelegate =
  AppLocalizationDelegate(Locale('en', 'US'));

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(localizationsDelegates: [
      GlobalMaterialLocalizations.*delegate*,
      GlobalWidgetsLocalizations.*delegate*,
      _localeOverrideDelegate
    ], supportedLocales: [
      const Locale('en', 'US'),
      const Locale('de', 'DE')
    ],
        home: MyHomePage());
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
         title: Text("Flutter Demo Localazy"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              AppLocalization.*of*(context).heyWorld,
            ),
            Text(
              '$_counter',
              style: Theme.*of*(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.*add*),
      ),
    );
  }
}

Implement Localization to Flutter App šŸ”—

We created our localization files easily, now we will add localazy to our Flutter app according to documentation.

{
    "writeKey": "your-write-key",
    "readKey": "your-read-key",

    "upload": {
      "type": "arb",
      "files": "lib/l10n/intl_en.arb"
    },

    "download": {
      "files": "lib/l10n/intl_${lang}.arb"
    }

}

And the project structure will be like this.

Since weā€™ve set English to be the source language, this file will contain the source phrases for our application. You can fill in any key-value pair you like.

Flutterā€™s ARB format is fully supported including arrays, plurals and selected context information. No extra configuration is necessary, but you can enable certain features if you want so. File Format - Flutter ARB *Flutterā€™s ARB format is fully supported including arrays, plurals and selected context information.

{
    "@@last_modified": "2019-06-28T17:50:47.781400",
    "heyWorld": "You have pushed the button this many times:",
    "@heyWorld": {
      "description": "Simple word for greeting ",
      "type": "text",
      "placeholders": {}
    }
  }

We created language files for our project. Now, the application is ready to have localization managed by Localazy. We can upload our language to Localazy and add multi-language support with using Localazy features.

Letā€™s upload the English file to Localazy.

localazy upload

And itā€™s done in 2 seconds.

Localazy CLI, v1.1.9
Advanced file uploader/downloader for the Localazy translation platform.

Read more information at [https://localazy.com/docs/cli](https://localazy.com/docs/cli)

Uploading...
  - deprecate missing: false
  - import as new: false
  - app version: 0
  - groups: (default only)
  - folder: .

Processing files...

./lib/l10n/intl_en.arb
  (file=intl.arb, lang=inherited, type=arb)

Verifying...

Validating...

Uploading 432 B...

Your data has been uploaded to Localazy. It's scheduled for processing and will be imported soon.
You will be notified about the progress on the Localazy platform (through notifications).

Your app on Localazy: [https://connect.localazy.com/p/flutter-localazy](https://connect.localazy.com/p/flutter-localazy)

Done.

After refreshing this page, it shows our translations. Now we can add multiple languages.

Open the Add languages tab and there you find a couple of languages with info about the percentage of automated translations. Also you will see the suggestions for every key. You can just click and translate every key according to suggestions. Itā€™s really easy to implement multiple languages.

Whenever you want, you can improve your translation, add new keys, or remove old keys. When we go back to project we need to do just download with CLI.

localazy download

With this command, youā€™ll download all the newly accepted phrases and newly added languages. In the locales folder, we can see there is newly intl_de.arb.

We created our localization files easily, now we will add localization to our Flutter app according to documentation.

I hope youā€™ve enjoyed this short intro into Localazy with Flutter. If youā€™d like to get closer to us, join Discord.

You can get all code from the link in below:

https://github.com/durannumit/flutter-localazy