老孟导读:本文介绍如何使用 Intl 插件实现国际化以及修改系统组件的国际化文案。
Intl 官方出品,包含用于处理国际化/本地化消息,日期和数字格式和解析,双向文本以及其他国际化问题。
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
执行命令:
代码语言:javascript复制flutter pub get
Tool->Flutter Intl ->Initalize for the project:
成功后,在 pubspec.yaml末尾增加:
代码语言:javascript复制flutter_intl:
enabled: true
在lib下生成generated 和 l10n
- generated包下的intl目录默认生成 messages_all.dart 和 messages_en.dart 文件,messages开头的文件无需手动修改,是自动生成的。
- generated包下的 I10n.dart 是Localizations和Delegate的实现,无需手动修改,是自动生成的。
- l10n包下存在一个intl_en.arb文件,文案存放在此处。
添加语言
Tool->Flutter Intl -> Add Locale:
添加中文支持:
自动生成相关文件:
添加系统国际化支持
在pubspec.yaml文件中添加包依赖:
代码语言:javascript复制dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
MaterialApp 修改如下:
代码语言:javascript复制MaterialApp(
...
localizationsDelegates: [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
...
)
在 intl_en.arb 和 intl_zh.arb下添加文案
添加一个 title 文案,intl_en.arb:
代码语言:javascript复制{
"title": "hello word"
}
intl_zh.arb:
代码语言:javascript复制{
"title": "你好"
}
按 command s 保存,generated 目录下相关文件将会重新生成。
使用:
代码语言:javascript复制class LocalizationDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('${S.of(context).title}'),
),
);
}
}
Intl 还可以进行日期和数字格式化等, 具体功能可参考官方文档:https://github.com/dart-lang/intl。
国际化系统组件
部分系统组件已经支持国际化,那么如何修改其国际化文案呢?下面以日期组件为例进行介绍。
新建类MyLocalizationsDelegate
:
class MyLocalizationsDelegate
extends LocalizationsDelegate<CupertinoLocalizations> {
const MyLocalizationsDelegate();
@override
bool isSupported(Locale locale) => locale.languageCode == 'zh';
@override
Future<CupertinoLocalizations> 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<CupertinoLocalizations> load(Locale locale) {
return SynchronousFuture<CupertinoLocalizations>(
const ZhCupertinoLocalizations());
}
/// A [LocalizationsDelegate] that uses [DefaultCupertinoLocalizations.load]
/// to create an instance of this class.
static const LocalizationsDelegate<CupertinoLocalizations> delegate =
MyLocalizationsDelegate();
}
注意开始的属性_shortWeekdays
,这个属性表示星期几,故意写成'自周x',为了和系统的区分,在根控件MaterialApp
的localizationsDelegates
属性中增加:ZhCupertinoLocalizations.delegate
,这个就是上面定义的国际化文件,效果如下:
注意:ZhCupertinoLocalizations.delegate
要放在GlobalCupertinoLocalizations.delegate,
的前面,系统加载顺序为从上到下。
效果如下: