【Flutter 實戰(zhàn)】 Intl 插件實現(xiàn)國際化以及修改系統(tǒng)組件的國際化

老孟導讀:本文介紹如何使用 Intl 插件實現(xiàn)國際化以及修改系統(tǒng)組件的國際化文案。
Intl 官方出品,包含用于處理國際化/本地化消息,日期和數(shù)字格式和解析,雙向文本以及其他國際化問題。
pub地址:https://pub.dev/packages/intl
Github地址:https://github.com/dart-lang/intl
Android Studio 和 VS Code 都有 Flutter Intl 插件,方便接入。
安裝插件
并不是一定要使用插件,也可以通過命令行,當然 Flutter Intl 插件簡化操作, Android Studio -> File -> Setting -> Plugins -> 搜索Flutter Intl:

安裝重啟即可。
VS Code 的 Flutter Intl 插件:https://marketplace.visualstudio.com/items?itemName=localizely.flutter-intl
添加依賴
在項目的 pubspec.yaml 文件中添加依賴:
dev_dependencies:
?...
??flutter_localizations:
????sdk:?flutter
執(zhí)行命令:
flutter?pub?get
Tool->Flutter Intl ->Initalize for the project:

成功后,在 pubspec.yaml末尾增加:
flutter_intl:
??enabled:?true
在lib下生成generated 和 l10n

generated包下的intl目錄默認生成 messages_all.dart 和 messages_en.dart 文件,messages開頭的文件無需手動修改,是自動生成的。 generated包下的 I10n.dart 是Localizations和Delegate的實現(xiàn),無需手動修改,是自動生成的。 l10n包下存在一個intl_en.arb文件,文案存放在此處。
添加語言
Tool->Flutter Intl -> Add Locale:

添加中文支持:

自動生成相關文件:

添加系統(tǒng)國際化支持
在pubspec.yaml文件中添加包依賴:
dependencies:
??flutter:
????sdk:?flutter
??flutter_localizations:
????sdk:?flutter
MaterialApp 修改如下:
MaterialApp(
??...
??localizationsDelegates:?[
????S.delegate,
????GlobalMaterialLocalizations.delegate,
????GlobalWidgetsLocalizations.delegate,
????GlobalCupertinoLocalizations.delegate,
??],
??supportedLocales:?S.delegate.supportedLocales,
??...
)
在 intl_en.arb 和 intl_zh.arb下添加文案
添加一個 title 文案,intl_en.arb:
{
??"title":?"hello?word"
}
intl_zh.arb:
{
??"title":?"你好"
}
按 command + s 保存,generated 目錄下相關文件將會重新生成。
使用:
class?LocalizationDemo?extends?StatelessWidget?{
??@override
??Widget?build(BuildContext?context)?{
????return?Scaffold(
??????body:?Center(
????????child:?Text('${S.of(context).title}'),
??????),
????);
??}
}

Intl 還可以進行日期和數(shù)字格式化等, 具體功能可參考官方文檔:https://github.com/dart-lang/intl。
國際化系統(tǒng)組件
部分系統(tǒng)組件已經支持國際化,那么如何修改其國際化文案呢?下面以日期組件為例進行介紹。
新建類MyLocalizationsDelegate:
class?MyLocalizationsDelegate
????extends?LocalizationsDelegate<CupertinoLocalizations>?{
??const?MyLocalizationsDelegate();
??@override
??bool?isSupported(Locale?locale)?=>?locale.languageCode?==?'zh';
??@override
??Future?load(Locale?locale)?=>
??????ZhCupertinoLocalizations.load(locale);
??@override
??bool?shouldReload(MyLocalizationsDelegate?old)?=>?false;
??@override
??String?toString()?=>?'DefaultCupertinoLocalizations.delegate(zh)';
}
ZhCupertinoLocalizations定義如下:
class?ZhCupertinoLocalizations?implements?CupertinoLocalizations?{
??const?ZhCupertinoLocalizations();
??static?const?List<String>?_shortWeekdays?=?<String>[
????'自周一',
????'自周二',
????'自周三',
????'自周四',
????'自周五',
????'自周六',
????'自周日',
??];
??static?const?List<String>?_shortMonths?=?<String>[
????'1月',
????'2月',
????'3月',
????'4月',
????'5月',
????'6月',
????'7月',
????'8月',
????'9月',
????'10月',
????'11月',
????'12月',
??];
??static?const?List<String>?_months?=?<String>[
????'1月',
????'2月',
????'3月',
????'4月',
????'5月',
????'6月',
????'7月',
????'8月',
????'9月',
????'10月',
????'11月',
????'12月',
??];
??@override
??String?datePickerYear(int?yearIndex)?=>?yearIndex.toString();
??@override
??String?datePickerMonth(int?monthIndex)?=>?_months[monthIndex?-?1];
??@override
??String?datePickerDayOfMonth(int?dayIndex)?=>?dayIndex.toString();
??@override
??String?datePickerHour(int?hour)?=>?hour.toString();
??@override
??String?datePickerHourSemanticsLabel(int?hour)?=>?hour.toString()?+?"?o'clock";
??@override
??String?datePickerMinute(int?minute)?=>?minute.toString().padLeft(2,?'0');
??@override
??String?datePickerMinuteSemanticsLabel(int?minute)?{
????if?(minute?==?1)?return?'1?分';
????return?minute.toString()?+?'?分';
??}
??@override
??String?datePickerMediumDate(DateTime?date)?{
????return?'${_shortWeekdays[date.weekday?-?DateTime.monday]}?'
????????'${_shortMonths[date.month?-?DateTime.january]}?'
????????'${date.day.toString().padRight(2)}';
??}
??@override
??DatePickerDateOrder?get?datePickerDateOrder?=>?DatePickerDateOrder.mdy;
??@override
??DatePickerDateTimeOrder?get?datePickerDateTimeOrder?=>
??????DatePickerDateTimeOrder.date_time_dayPeriod;
??@override
??String?get?anteMeridiemAbbreviation?=>?'上午';
??@override
??String?get?postMeridiemAbbreviation?=>?'下午';
??@override
??String?get?todayLabel?=>?'今天';
??@override
??String?get?alertDialogLabel?=>?'Alert';
??@override
??String?timerPickerHour(int?hour)?=>?hour.toString();
??@override
??String?timerPickerMinute(int?minute)?=>?minute.toString();
??@override
??String?timerPickerSecond(int?second)?=>?second.toString();
??@override
??String?timerPickerHourLabel(int?hour)?=>?hour?==?1???'小時'?:?'小時';
??@override
??String?timerPickerMinuteLabel(int?minute)?=>?'分.';
??@override
??String?timerPickerSecondLabel(int?second)?=>?'秒.';
??@override
??String?get?cutButtonLabel?=>?'剪貼';
??@override
??String?get?copyButtonLabel?=>?'拷貝';
??@override
??String?get?pasteButtonLabel?=>?'黏貼';
??@override
??String?get?selectAllButtonLabel?=>?'選擇全部';
??static?Future?load(Locale?locale)?{
????return?SynchronousFuture(
????????const?ZhCupertinoLocalizations());
??}
??///?A?[LocalizationsDelegate]?that?uses?[DefaultCupertinoLocalizations.load]
??///?to?create?an?instance?of?this?class.
??static?const?LocalizationsDelegate?delegate?=
??????MyLocalizationsDelegate();
}
注意開始的屬性_shortWeekdays,這個屬性表示星期幾,故意寫成'自周x',為了和系統(tǒng)的區(qū)分,在根控件MaterialApp的localizationsDelegates屬性中增加:ZhCupertinoLocalizations.delegate,這個就是上面定義的國際化文件,效果如下:

注意:ZhCupertinoLocalizations.delegate要放在GlobalCupertinoLocalizations.delegate,的前面,系統(tǒng)加載順序為從上到下。
效果如下:


