Using the Intl package, we can not only realize internationalization very easily, but also separate the string text into separate files to facilitate the division of labor and collaboration between developers and translators. In order to use the Intl package we need to add two dependencies:
dependencies:
#...省略无关项
intl: ^0.15.7
dev_dependencies:
#...省略无关项
intl_translation: ^0.17.2
The intl_translation package mainly contains some tools. Its main function in the development stage is to extract the string to be internationalized from the code to a separate arb file and generate the dart code of the corresponding language based on the arb file. The intl package is mainly for quoting and Load the dart code generated by intl_translation. Below we will explain how to use it step by step:
First, create a l10n-arb directory in the root directory of the project, which will save the arb file that we will generate through the intl_translation command. The content of a simple arb file is as follows:
{
"@@last_modified": "2018-12-10T15:46:20.897228",
"@@locale":"zh_CH",
"title": "Flutter应用",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
}
}
We can see from the "@@locale" field that this arb corresponds to the simplified Chinese translation, and the title
field inside corresponds to the simplified Chinese translation of our application title. @title
Fields are title
some descriptive information.
Next, we create a l10n directory in the lib directory, which is used to save the dart code file generated from the arb file.
Similar to the steps in the previous section, we still have to implement the Localizations
Delegate class. The difference is that now we need to use some methods of the intl package (some of them are dynamically generated).
Next, we lib/l10n
create a new "localization_intl.dart" file in the directory, the content of the file is as follows:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'messages_all.dart'; //1
class DemoLocalizations {
static Future<DemoLocalizations> load(Locale locale) {
final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
//2
return initializeMessages(localeName).then((b) {
Intl.defaultLocale = localeName;
return new DemoLocalizations();
});
}
static DemoLocalizations of(BuildContext context) {
return Localizations.of<DemoLocalizations>(context, DemoLocalizations);
}
String get title {
return Intl.message(
'Flutter APP',
name: 'title',
desc: 'Title for the Demo application',
);
}
}
//Locale代理类
class DemoLocalizationsDelegate extends LocalizationsDelegate<DemoLocalizations> {
const DemoLocalizationsDelegate();
//是否支持某个Local
@override
bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode);
// Flutter会调用此类加载相应的Locale资源类
@override
Future<DemoLocalizations> load(Locale locale) {
//3
return DemoLocalizations.load(locale);
}
// 当Localizations Widget重新build时,是否调用load重新加载Locale资源.
@override
bool shouldReload(DemoLocalizationsDelegate old) => false;
}
note:
- The "messages_all.dart" file in Note 1 is the code generated from the arb file through the intl_translation tool, so this file does not exist before the first run of the generate command. The
initializeMessages()
method in Note 2 is the same as the "messages_all.dart" file, which is generated at the same time. - Note 3 is different from the sample code in the previous section, here we can call it directly
DemoLocalizations.load()
.
Now we can add properties or methods that need to be internationalized in the DemoLocalizations class, such as the title
properties in the sample code above , then we will use some methods provided by the Intl library, which can help us easily implement some syntax in different languages Features, such as plural context. For example, if we have an email list page, we need to display the number of unread emails at the top. The number of unread emails is different, the text we display may be different:
Number of unread messages | Hint |
---|---|
0 | There are no emails left |
1 | There is 1 email left |
n(n>1) | There are n emails left |
We can Intl.plural(...)
achieve this by:
remainingEmailsMessage(int howMany) => Intl.plural(howMany,
zero: 'There are no emails left',
one: 'There is $howMany email left',
other: 'There are $howMany emails left',
name: "remainingEmailsMessage",
args: [howMany],
desc: "How many emails remain after archiving.",
examples: const {'howMany': 42, 'userName': 'Fred'});
You can see that the Intl.plural
method can howMany
output different prompt messages when the values are different.
The Intl package also has some other methods, readers can check their own documents, this book will not repeat them.
Now we can use the intl_translation package tool to extract the strings in the code to an arb file, and run the following naming:
flutter pub pub run intl_translation:extract_to_arb --output-dir=l10n-arb \ lib/l10n/localization_intl.dart
After running this command, the attributes and strings that we previously identified through the Intl API will be extracted into the "l10n-arb/intl_messages.arb" file, let's take a look at its content:
{
"@@last_modified": "2018-12-10T17:37:28.505088",
"title": "Flutter APP",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
},
"remainingEmailsMessage": "{howMany,plural, =0{There are no emails left}=1{There is {howMany} email left}other{There are {howMany} emails left}}",
"@remainingEmailsMessage": {
"description": "How many emails remain after archiving.",
"type": "text",
"placeholders": {
"howMany": {
"example": 42
}
}
}
}
This is the default Locale resource file. If we want to support Chinese Simplified now, we only need to create an "intl_zh_CN.arb" file in the same level directory of the file, and then copy the content of "intl_messages.arb" to the "intl_zh_CN.arb" file , Then translate English to Chinese, the translated "intl_zh_CN.arb" file content is as follows:
{
"@@last_modified": "2018-12-10T15:46:20.897228",
"@@locale":"zh_CN",
"title": "Flutter应用",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
},
"remainingEmailsMessage": "{howMany,plural, =0{没有未读邮件}=1{有{howMany}封未读邮件}other{有{howMany}封未读邮件}}",
"@remainingEmailsMessage": {
"description": "How many emails remain after archiving.",
"type": "text",
"placeholders": {
"howMany": {
"example": 42
}
}
}
}
We have to translate title
and the remainingEmailsMessage
field, which description
is the description of the field, which is usually shown to the translator and will not be used in the code.
There are two points to explain:
- If an attribute is missing in a particular arb, the application will load the corresponding attribute in the default arb file (intl_messages.arb), which is Intl's underpinning strategy.
- Every time you run the extraction command, intl_messages.arb will be regenerated according to the code, but other arb files will not, so when you want to add new fields or methods, other arb files are incremental, so don't worry about overwriting.
- The arb file is standard, and its format specification can be understood by yourself. The arb file is usually handed over to the translators. When they complete the translation, we then use the following steps to generate the final dart code based on the arb file.
The last step is to generate a dart file based on arb:
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/localization_intl.dart l10n-arb/intl_*.arb
When this command is run for the first time, multiple files will be generated in the "lib/l10n" directory, corresponding to multiple locales. These codes are the final dart codes to be used.
At this point, we will use the Intl package to introduce the internationalization process of the APP. We can find that the first and second steps are only needed for the first time, and our main work during development is the third step. . Since the last two steps are required every time after the third step is completed, we can put the last two steps in a shell script. When we complete the third step or complete the arb file translation, we only need to execute the script separately. . We create an intl.sh script in the root directory with the content:
flutter pub pub run intl_translation:extract_to_arb --output-dir=l10n-arb lib/l10n/localization_intl.dart
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/localization_intl.dart l10n-arb/intl_*.arb
Then grant execution permissions:
chmod +x intl.sh
Execute intl.sh
./intl.sh