What is internationalization

Internationalization is the process of decoupling software from a specific language and locale when it is designed. When the software is ported to a different language region, no internal engineering changes or modifications are made to the software itself.

Localization refers to the process of adding information about specific locales and translating files when porting software. The distinction between internationalization and localization is subtle but important. Internationalization means that products have the potential to be used everywhere; Localization is a feature added to make it more suitable for use in a particular place. For a product, internationalization only needs to be done once, but localization needs to be done once for different regions. The two are complementary, and the combination of the two makes a system that works everywhere.

Difficulties in internationalization implementation

Internationalization and localization can be a challenging task for developers when developing software, especially if the software was not designed with this in mind. It is common practice to separate text and other environment-related resources from program code. In an ideal world, you don’t have to change your code to respond to a changing environment, just your resources, which makes your job significantly easier.

Internationalization of Flutter

Internationalization in Flutter includes both internationalization of Flutter components and internationalization of other texts;

Internationalization of Flutter components

The widgets that Flutter provides us support internationalization by default, but they are displayed in English regardless of the environment until special Settings are made.

If you want to add other languages, your application must specify additional MaterialApp properties and add a separate package called Flutter_localizations.

As of November 2020, the package supports 78 languages.

Pubspec adds dependencies

To use flutter_localizations, we need to add it as a dependency in the pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
Copy the code

Set the MaterialApp

  • In localizationsDelegates specifies which widgets will be internationalized

    • A factory used to produce localized sets of values
    • We’ve specified that Material, Widgets, and Cupertino all use internationalization
  • SupportedLocales specifies which internationals to support

    • We specify Chinese and English here (can also specify country code)
MaterialApp( localizationsDelegates: [GlobalMaterialLocalizations. Delegate, / / specified localized string GlobalCupertinoLocalizations. Delegate, Corresponding GlobalWidgetsLocalizations Cupertino style. / / the delegate / / specify the default text orientation, from left to right or from right to left, supportedLocales: [ Locale("en"), Locale("zh") ], )Copy the code

Note: If you want to specify a language code, a text code, and a country code, you can specify it as follows:

// Full Chinese support for CN, TW, and HK
supportedLocales: [
  const Locale.fromSubtags(languageCode: 'zh'), // generic Chinese 'zh'
  const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans'), // generic simplified Chinese 'zh_Hans'
  const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'), // generic traditional Chinese 'zh_Hant'
  const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'), // 'zh_Hans_CN'
  const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'), // 'zh_Hant_TW'
  const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'), // 'zh_Hant_HK'
],
Copy the code

Internationalization of custom text in Flutter

Creating localization classes

This class defines the strings we need to localize and so on:

  • 1. We need a constructor and pass in a Locale object
  • 2. Define a Map to store the corresponding text in our different languages
  • 3. Define getter methods that return different results depending on the locale
import 'package:flutter/material.dart'; class QWLocalizations { final Locale locale; QWLocalizations(this.locale); static Map<String, Map<String, String>> _localizedValues = { "fr": {"title": "Titre", "hello": "Bonjour"}, "zh": {"title": "home ", "hello": "hello"}}; String get title { return _localizedValues[locale.languageCode]? ["title"] ?? 'title'; } String get hello { return _localizedValues[locale.languageCode]? ["hello"] ?? 'hello'; } static QWLocalizations of(BuildContext context) { return Localizations.of(context, QWLocalizations); }}Copy the code

A custom Delegate

Once the above class is defined, where or how do we initialize it? We can initialize Flutter widgets in the same manner as internationalization; We will also define an object’s Delegate class, and pass it into localizationsDelegates; The Delegate function is to call the load method when the Locale changes and reload the new Locale resource;

HYLocalizationsDelegate need to inherit from LocalizationsDelegate, and there are three methods must be rewritten: isSupported, shouldReload, load

import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'QWLocalizations.dart'; Class QWLocalizationsDelegate extends LocalizationsDelegate<QWLocalizations> {class QWLocalizations extends LocalizationsDelegate<QWLocalizations> isSupported(Locale locale) { return ["fr", "zh"].contains(locale.languageCode); Locale resources should be loaded only once during Locale switching, and Locale resources should be loaded only once during Locale switching. You don't need to load Localizations every time you rebuild them. So in general, return false; * */ @override bool shouldReload(LocalizationsDelegate<QWLocalizations> old) { return false; } /* * Loading HYLocalizations resources when Locale changes returns a Future, as it might be loaded asynchronously; But here we have a Map defined directly, Override Future<QWLocalizations> Load (Locale Locale) {return SynchronousFuture(QWLocalizations(locale)); } static QWLocalizationsDelegate delegate = QWLocalizationsDelegate(); }Copy the code

Asynchronously loading data

What if our data is loaded asynchronously, such as from a Json file or server?

In the QWLocalizations class, assume the following:

static Map<String, Map<String, String>> _localizedValues = {}; Future<bool> loadJson() async { // 1. JsonString = await rootbundle. loadString("assets/json/i18n.json"); Final map <String, dynamic> map = json.decode(jsonString); // 3. Note: Map<String, dynamic> = Map<String, Map<String, String>> value) { return MapEntry(key, value.cast<String, String>()); }); return true; }Copy the code

Load asynchronously in QWLocalizationsDelegate:

  @override
  Future<QWLocalizations> load(Locale locale) async {
    final localization = QWLocalizations(locale);
    await localization.loadJson();
    return localization;
  }
Copy the code

Using localization classes

We can then use the HYLocalization class in our code.

  • We can get throughQWLocalizations.of(context)Get the QWLocalizations object
Text(
  QWLocalizations.of(context).hello,
)
Copy the code

Tool for internationalization –Intl

Understand arB files

We can now localize it by loading the corresponding JSON file.

However, there is another problem. In the process of internationalization, the following code still needs to be written manually from json files:

String get title { return _localizedValues[locale.languageCode]? ["title"] ?? 'title'; } String get hello { return _localizedValues[locale.languageCode]? ["hello"] ?? 'hello'; }Copy the code

Is there a better way that we can quickly convert directly in the localization file -dart code file? The answer is arB files

  • The full name of the arB file is Application Resource Bundle, which stands for Application Resource Bundle.
  • It is essentially a JSON file, but it can be converted to the appropriate locale;
  • Arb documentation: github.com/google/app-…

Use the IDE plug-in to convert between ARB and DART files

  • Initialize the intl

Select tools-flutter intl-Initialize for the Project from the toolbar

After completing the above operations, the following directories are automatically generated:

  • Generated is the automatically generated Dart code
  • I10n is the corresponding arB file directory

Use the intl

Configured in localized localization: the generated class, known as S

  • 1. Add a delegate
  • 2. Use spyware doctor elegate supportedLocales. SupportedLocales
localizationsDelegates: [
  GlobalMaterialLocalizations.delegate,
  GlobalWidgetsLocalizations.delegate,
  GlobalCupertinoLocalizations.delegate,
  S.delegate
],
supportedLocales: S.delegate.supportedLocales,
Copy the code

Since we don’t have a localized string yet, we need to write it in intl_en.arb:

  • CTRL (Command) + S save after writing
{
  "title": "home",
  "hello": "hello"
}
Copy the code

Use it in code

  • The format is s.f (context).title

Add Chinese

If you want to add Chinese support: add local

  • In the dialog box that is displayed, enter zh

As you can see, the corresponding intl_zh.arb and Messages_zh. dart files are generated

Arb Other syntax

If we want to pass some parameters while using localization:

  • Like Hello Kobe or Hello James
  • Such as Hello ah, Li Yinhe or hello ah, Wang Xiaobo

Modify the corresponding ARB file:

  • {name} : indicates the parameter passed
{
  "title": "home",
  "hello": "hello",
  "sayHello": "hello {name}"
}
Copy the code

To use, pass in the corresponding parameter:

Text(s.f (context).sayhello (" Li Yinhe ")),Copy the code

conclusion

The essence of text internationalization is to obtain the corresponding text and perform corresponding operations on the UI (left-to-right or right-to-left display) according to the locale information provided by the system. Locale information refers to the country code and region code, etc. Usually, what we need to do locally is to put the text according to {country code: {common text: The format of localized text}} is organized. The country code here is en for China, en for the United States. Common texts are generally in English. Finally, the process of retrieving localized text values from dictionaries based on locale information and generic text.

Reference: Internationalization of Flutter