Your slogan here

Flutter Localization the Easy Way – Internationalization with JSON

Flutter localization- Let's face it. When you're building an app which you plan to release to the public, having it in just one language isn't going to cut it. While English is definitely one of the most spoken languages throughout the world, internationalizing your apps is really a must.

 

Contrary to frameworks like native Android, Flutter doesn't have an absolutely set way of how localization is done. It gives you a lot of freedom which can be good if you know what you're doing, but also extremely confusing if you're just starting out.

 

In this tutorial, you're going to learn how to localize your apps the simple way by using JSON files to store your strings in multiple languages.

 

Prepare your project

 

Before writing Dart code to access the JSON files containing translated strings, you actually need to create the files first and update the pubspec file.

 

Create the language files

 

Create a new folder lang in the project root. This folder will hold all of the language files. Because I'm Slovak, I've created two files - en.json and sk.json. If you want to follow along in a different language, feel free to do so, just remember to change any reference to 'sk' to your preferred language.

 

These files will contain only simple key-value pairs of strings. Using JSON is beneficial, because similar to XML, you can just give it to a translator without them needing to access your code.

 

en.json

 

{

  "first_string": "Hello! This is the first message.",

  "second_string": "If this tutorial helps you, give it a like and subscribe to Reso Coder ?"

}

sk.json

 

{

  "first_string": "Ahoj! Toto je prvá správa.",

  "second_string": "Ak ti tento tutoriál pomáha, daj mu like a prihlás sa na odber u Reso Codera ?"

}

 

Update pubspec.yaml

Localization requires a dependency which comes directly from the Flutter SDK. Also, since you've just added new language JSON files, you need to specify them as assets in order to access them in code.

 

pubspec.yaml

 

...

dependencies:

  flutter:

    sdk: flutter

 

  flutter_localizations:

    sdk: flutter

 

...

 

flutter:

  ...

 

  assets:

   - lang/en.json

   - lang/sk.json

 

 

Make the MaterialApp localized

 

Setup of the localization happens inside the MaterialApp widget, which is the root of a Flutter app. Here you specify which languages are supported and what happens if the current language of a device is not supported. You also initialize localization objects (more on them later) here.

 

You don't have to use MaterialApp as the root widget. CupertinoApp and plain WidgetsApp support localization too.

Of course, you wouldn't specify GlobalMaterialLocalizations, but rather DefaultCupertinoLocalizations.

main.dart

 

import 'package:flutter/material.dart';

import 'package:flutter_localizations/flutter_localizations.dart';

 

import 'app_localizations.dart';

 

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

 

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      title: 'Flutter Demo',

      theme: ThemeData(

        primarySwatch: Colors.blue,

      ),

      // List all of the app's supported locales here

      supportedLocales: [

        Locale('en', 'US'),

        Locale('sk', 'SK'),

      ],

      // These delegates make sure that the localization data for the proper language is loaded

      localizationsDelegates: [

        // THIS CLASS WILL BE ADDED LATER

        // A class which loads the translations from JSON files

        AppLocalizations.delegate,

        // Built-in localization of basic text for Material widgets

        GlobalMaterialLocalizations.delegate,

        // Built-in localization for text direction LTR/RTL

        GlobalWidgetsLocalizations.delegate,

      ],

      // Returns a locale which will be used by the app

      localeResolutionCallback: (locale, supportedLocales) {

        // Check if the current device locale is supported

        for (var supportedLocale in supportedLocales) {

          if (supportedLocale.languageCode == locale.languageCode &&

              supportedLocale.countryCode == locale.countryCode) {

            return supportedLocale;

          }

        }

        // If the locale of the device is not supported, use the first one

        // from the list (English, in this case).

        return supportedLocales.first;

      },

      home: MyHomePage(),

    );

  }

}

 

One thing that may be difficult to grasp in the code above is the localizationDelegates list. A LocalizationsDelegate is an object which knows what to do when it's time to load a particular language.

 

 

Apart from using AppLocalizations which you haven't yet created, you also specify some predefined material and widgets localizations.

 

Many widgets from the material package contain some text. For example, a material alert dialog can contain a "cancel" button. This button is there by default, you don't need to write the text yourself. Flutter has these kinds of standard strings already localized, all you need to do is to specify the delegate.

 

 

Working with the custom localization strings

 

 

Similar to how there are GlobalMaterialLocalizations, you want to have localizations specific to your app, hence the class name AppLocalizations.  Its most important method will be translate. You can then call method throughout your UI widgets to specify localized strings.

 

Create a new file app_localizations.dart under the lib folder. First, create a class AppLocalizations which will have two methods - load() for loading the JSON into an in-memory Map<String, String>,  and translate() for accessing the map of translated strings.

 

app_localizations.dart

 

import 'dart:async';

import 'dart:convert';

 

import 'package:flutter/material.dart';

import 'package:flutter/services.dart';

 

class AppLocalizations {

  final Locale locale;

 

  AppLocalizations(this.locale);

 

  // Helper method to keep the code in the widgets concise

  // Localizations are accessed using an InheritedWidget "of" syntax

  static AppLocalizations of(BuildContext context) {

    return Localizations.of<AppLocalizations>(context, AppLocalizations);

  }

 

  Map<String, String> _localizedStrings;

 

  Future<bool> load() async {

    // Load the language JSON file from the "lang" folder

    String jsonString =

        await rootBundle.loadString('lang/${locale.languageCode}.json');

    Map<String, dynamic> jsonMap = json.decode(jsonString);

 

    _localizedStrings = jsonMap.map((key, value) {

      return MapEntry(key, value.toString());

    });

 

    return true;

  }

 

  // This method will be called from every widget which needs a localized text

  String translate(String key) {

    return _localizedStrings[key];

  }

}

The class above is where the actual logic is located. However, you still need to provide a way for Flutter to step in and decide when the load() method will be called and which locale will be used.

 

Flutter localization uses delegates for this initialization. Create a new package-private class _AppLocalizationsDelegate which extends a LocalizationsDelegate<AppLocalizations>. Its private, because you don't need to instantiate it inside any other file.

 

Instead, to access this delegate, make a new static field on AppLocalizations class.

 

app_localizations.dart

 

import 'dart:async';

import 'dart:convert';

 

import 'package:flutter/material.dart';

import 'package:flutter/services.dart';

 

class AppLocalizations {

  ...

  // Static member to have a simple access to the delegate from the MaterialApp

  static const LocalizationsDelegate<AppLocalizations> delegate =

      _AppLocalizationsDelegate();

  ...

}

 

// LocalizationsDelegate is a factory for a set of localized resources

// In this case, the localized strings will be gotten in an AppLocalizations object

class _AppLocalizationsDelegate

    extends LocalizationsDelegate<AppLocalizations> {

  // This delegate instance will never change (it doesn't even have fields!)

  // It can provide a constant constructor.

  const _AppLocalizationsDelegate();

 

  @override

  bool isSupported(Locale locale) {

    // Include all of your supported language codes here

    return ['en', 'sk'].contains(locale.languageCode);

  }

 

  @override

  Future<AppLocalizations> load(Locale locale) async {

    // AppLocalizations class is where the JSON loading actually runs

    AppLocalizations localizations = new AppLocalizations(locale);

    await localizations.load();

    return localizations;

  }

 

  @override

  bool shouldReload(_AppLocalizationsDelegate old) => false;

}

 

Translating text in the UI

 

Once you have all of this setup done, how do you actually use this translating contraption? It's simple! Just call the of() helper static method on AppLocalizations() to get the instance properly set up by Flutter and then translate to your heart's content using the keys you've specified in the JSON files!

 

main.dart

 

class MyHomePage extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      body: Center(

        child: Padding(

          padding: const EdgeInsets.all(8.0),

          child: Column(

            mainAxisSize: MainAxisSize.min,

            children: <Widget>[

              Text(

                AppLocalizations.of(context).translate('first_string'),

                style: TextStyle(fontSize: 25),

                textAlign: TextAlign.center,

              ),

              SizedBox(height: 10),

              Text(

                AppLocalizations.of(context).translate('second_string'),

                style: TextStyle(fontSize: 25),

                textAlign: TextAlign.center,

              ),

              SizedBox(height: 10),

              Text(

                'This will not be translated.',

                style: TextStyle(fontSize: 25),

                textAlign: TextAlign.center,

              ),

            ],

          ),

        ),

      ),

    );

  }

}

 

Conclusion

 

With this approach, translating your Flutter apps will go like a breeze. Simply create a JSON file for every supported language and use AppLocalizations throughout your UI.

 

To test whether this internationalizing works on the device/emulator, try changing the device language from the settings.


To know more about flutter localization example and flutteri18n, visit our website https://pub.dev/packages/flutter_translate

This website was created for free with Own-Free-Website.com. Would you also like to have your own website?
Sign up for free