Design the Flutter standalone app from 0 | Part 2: Complete international language support

Posted Jun 28, 20205 min read

In view of the advantages of Flutter high-performance rendering and cross-platform, the flash point list is developed on the mobile APP using a complete Flutter framework. Since it is a complete APP, the architecture is completely unaffected by the historical Native APP, without the precipitation of historical burdens, and the design can be more flexible and robust.

International language support is a strong requirement for many apps. As long as the app is large or small, as long as you don’t want to give up foreign customers, you generally need to support internationalization.

flutter internationalization

Official support

The official Flutter solution provides basic support for internationalization, such as internationalization of Flutter's built-in components, language proxies, language packs used by Widgets, language setting callbacks, etc., and supports custom third-party class extensions. You can refer to Flutter internationalization documents.
Examples of official support codes:

class DemoLocalizations {
  DemoLocalizations(this.locale);

  final Locale locale;

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

  static Map<String, Map<String, String>> _localizedValues ​​= {
    'en':{
      'title':'Hello World',
    },
    'es':{
      'title':'Hola Mundo',
    },
  };

  String get title {
    return _localizedValues[locale.languageCode]['title'];
  }
}

Defects of the official plan

The official support has several flaws:

  1. Depends on the BuildContext object. When calling in a non-Widget, you need to pass the BuildContext object layer by layer, or store the global BuildContext object.
  2. Internationalization cannot be used before MaterialApp is initialized(the reason is also dependent on the BuildContext object).
  3. It is recommended to use Map to define language packs, which cannot take advantage of static languages ​​(syntax hints, error checking, etc.); however, customizing classes and class fields for each attribute of language packs has high cost and poor flexibility in use and update.

i18n introduction

In view of the deficiencies of Flutter official support, we investigated many third-party libraries, and finally found i18n, and on this basis, combined with Flutter official support and its own packaging, to achieve a more flexible and easy-to-use solution.

flutter internationalization

Basic use

i18n uses the yaml format to define language packs, and provides a one-click build script to generate Dart language pack Class. as follows:

lib/messages.i18n.yaml

button:
  save:Save
  load:Load
users:
  welcome(String name):"Hello $name!"
  logout:Logout

This configuration will generate several Classes:Messages, ButtonMessages, and UserMessages. The generated Dart files are used as follows:

Messages m = Messages();
debugPrint(m.users.logout);
debugPrint(m.users.welcome('World'));

Preview of the generated Dart file(no need to care during development):

class Messages {
    const Messages();
    ButtonMessages get button => ButtonExampleMessages(this);
    UsersMessages get users => UsersExampleMessages(this);
}
class ButtonMessages {
    final Messages _parent;
    const ButtonMessages(this._parent);
    String get save => "Save";
    String get load => "Load";
}
class UsersMessages {
    final Messages _parent;
    const UsersMessages(this._parent);
    String get logout => "Logout";
    String welcome(String name) => "Hello $name!";
}

Advanced features

Here are some advanced usages.

Function definition

i18n supports function definition and parameter passing, such as the aforementioned welcome function:

debugPrint(m.users.welcome('World'));

There is basically no limit to the definition of parameters, and the number and type of parameters can be freely defined.

Built-in functions

i18n supports some built-in functions for optimizing the experience of parsing in different languages, such as plural, cardinal, ordinal. For specific rules and usage, you can refer to here: http://cldr.unicode.org/index...

Using Dart string templates

Dart string templates are very powerful, and in i18n, you can use string templates(which is great), such as:

count(int cnt):"You have created $cnt ${_plural(cnt, one:'invoice', many:'invoices')}."

Pre-compilation

i18n still relies on the official builder_runner tool provided by Dart to generate Dart files from yaml files, using:flutter pub run build_runner build.

flutter internationalization

Language pack usage

After pre-compilation, each language pack will generate N Classes(each class or combination of language packs will generate a Class file), and then will generate a root Class, we can directly use the root Class(of course, you can use any one Classification level).

For example, two language pack files:AppMessages.i18n.yaml and AppMessages_en.i18n.yaml(without language suffix, it will be considered as the default language pack, so AppMessages.i18n.yaml is the default language pack), will be generated 2 root Dart Class:class AppMessages and class AppMessages_en extends AppMessages.

AppMessages_en automatically inherits from AppMessages, so we can directly use the AppMessages type to store language packs and re-instantiate the corresponding subclasses when switching languages:

AppMessages appMessages = new AppMessages();

resetLocalLang(String localeName) {
  switch(localeName) {
    case'en':
      appMessages = AppMessages_en();
      break;
    case'zh':
    default:
      appMessages = AppMessages();
      break;
  }
}

Then you can use the language pack anywhere:

debugPrint('Load Button:${appMessages.button.load}');

FlatButton(
  child:Text(appMessages.button.save),
  onPressed:() {
    ///Do something
  },

)

Flutter integration

Integration into Flutter still depends on official support. Set and monitor local language packages in MaterialApp:

@override
Widget build(BuildContext context) {
  return MaterialApp(
    localeResolutionCallback:
       (Locale locale, Iterable<Locale> supportedLocales) {
      ///Local changed
    },
    localizationsDelegates:[
      GlobalMaterialLocalizations.delegate,
      GlobalWidgetsLocalizations.delegate,
   ],
    supportedLocales:['zh','en']
        .map((loc) => new Locale(loc))
        .toList(growable:false),
    ///...
 );
}

end

Internationalization support is the basic capability of a mobile APP framework layer. The design principle should be non-aware, flexible and easy to expand; but the maintenance cost is inevitably increased. For example, all language packs must be changed at the same time.

Speaking of this, we haven't completed the construction of the basic framework. We will explain more Flutter architecture design content, such as notification, sharing, UI design and so on.


Continue to share the development experience of Flashpoint List on Flutter. Flash point list , a floating list software:

Flash point list, a floating list software