环境
Flutter 3.29
macOS Sequoia 15.4.1
Xcode 16.3
配置
安装依赖包
默认情况下,Flutter只提供美式英语的本地化,可以通过flutter_localizations这个package来实现国际化。
创建flutter工程后执行
sh
¥ flutter pub add flutter_localizations --sdk=flutter
¥ flutter pub add intl:any
执行后的pubspec.yaml
文件的效果
yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
flutter_localizations:
sdk: flutter
intl: any
安装对应的package
sh
¥ flutter pub get

pubspec.yaml文件
在 Flutter 项目的根目录中添加一个新的 yaml 文件,命名为 l10n.yaml,其内容如下:
yaml
arb-dir: lib/common/localization/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
- 将 应用资源包 (.arb) 的输入路径指定为 ${FLUTTER_PROJECT}/lib/common/localization/l10n。
- 将英文的语言模板设定为 app_en.arb。
- 指定 Flutter 生成本地化内容到 app_localizations.dart 文件。
要在pubspec.yaml 文件中,设置generate为true,执行命令时才会生成对应的app_localizations.dart文件
yaml
flutter:
generate: true
指定这个是为了生成项目时能自动生成对应的.dart代码文件
在 ${FLUTTER_PROJECT}/lib/common/localization/l10n
添加 app_en.arb
模板文件
json
{
"helloWorld": "Hello World!"
}
在同一目录下添加中文的模板文件 app_zh.arb
json
{
"helloWorld":"你好,世界"
}
执行命令生成.dart文件
sh
¥ flutter run
运行报错
sh
Synthetic package output (package:flutter_gen) is deprecated: https://flutter.dev/to/flutter-gen-deprecation. In a future release, synthetic-package will
default to `false` and will later be removed entirely.
Generating synthetic localizations package failed with 1 error:
Error: Attempted to generate localizations code without having the flutter: generate flag turned on.
Check pubspec.yaml and ensure that flutter: generate: true has been added and rebuild the project. Otherwise, the localizations source code will not be
importable.
有两个问题,一个是使用flutter_gen
生成synthetic package 的方式已经过期,推荐使用在 Flutter 项目中指定的目录下生成国际化资源代码文件。该标志默认为 true,还有一个报错是因为pubspec.yaml
没有设置允许自动生成代码
解决方案: l10n.yaml文件中追加设置不使用Synthetic package的方式生成国际化资源文件
yaml
synthetic-package: false
解决方案: pubspec.yaml
设置允许自动生成代码
yaml
flutter:
generate: true
重新运行 flutter run
报错消失,并在l10n
目录下生成对应的.dart代码文件

打开 app_localizations.dart
dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_en.dart';
import 'app_localizations_zh.dart';
abstract class AppLocalizations {
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
/// 国际化代理对象的集合
/// 代理中实现支持哪些语言,是否重新加载
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
delegate,
/// Material风格的组件的国际化
GlobalMaterialLocalizations.delegate,
/// iOS风格的组件的国际化
GlobalCupertinoLocalizations.delegate,
/// Widget组件的国际化
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
/// 支持的语言列表
static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
Locale('zh')
];
/// 国际化的词条
String get helloWorld;
}
/// 自定义的词条的代理对象
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
/// 同步加载资源
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) => <String>['en', 'zh'].contains(locale.languageCode);
@override
/// Returns true if the resources for this delegate should be loaded again by calling the [load] method.
/// 调用load方法后是否要重新加载
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en': return AppLocalizationsEn();
case 'zh': return AppLocalizationsZh();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.'
);
}
使用
场景: 系统的Widgets
使用系统的组件,比如日历
dart
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "localization示例",
/// 1. 设置代理对象列表
/// 一般开发都会有业务相关的词条,会创建词条,根据上面的代码可以传AppLocalizations.localizationsDelegates
/// 没有其它自定义词条时也可以
/// GlobalMaterialLocalizations.delegate,
/// GlobalWidgetsLocalizations.delegate,
/// GlobalCupertinoLocalizations.delegate,
localizationsDelegates: AppLocalizations.localizationsDelegates,
/// 2. 设置支持语言
supportedLocales: [Locale('en'), Locale('zh')],
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: MyHomePage(title: 'home page'),
locale: Locale("zh"), /// 设置应用是中文还是英文,默认跟随系统
);
}
dart
...
children: <Widget>[
CalendarDatePicker(
initialDate: DateTime.now(),
firstDate: DateTime(2020, 3, 30),
lastDate: DateTime(2025, 6, 31),
onDateChanged: (value) => {logger.d(value.toString())},
),
],
...

locale
参数传Locale("en")
再次运行

场景: 自定义
实现业务过程中相关的自定义的词条
dart
...
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(AppLocalizations.of(context)!.helloWorld),
),
...
效果同上,中文时显示你好,世界,英文时显示Hello World
场景: 切换语言
添加get
依赖
pubspec.yaml
get: 4.7.2
dart
@override
Widget build(BuildContext context) {
/// 1.MaterialApp => GetMaterialApp
return GetMaterialApp(
title: "localization示例",
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: [Locale('en'), Locale('zh')],
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: MyHomePage(title: 'home page'),
locale: Locale("en"),
);
}
dart
/// 使用updateLocale来设置语言
if (Get.locale?.languageCode == "zh") {
Get.updateLocale(Locale('en'));
} else {
Get.updateLocale(Locale('zh'));
}

场景: 占位符,复数和选项
当需要再词条中接收变量时可以使用占位符
json
"hello": "Hello {userName}"
"@hello": {
"description": "A message with a single parameter",
"placeholders": {
"userName": {
"type": "String",
"example": "Bob"
}
}
}
json
"hello": "你好 {userName}",
"@hello": {
"description": "A message with a single parameter",
"placeholders": {
"userName": {
"type": "String",
"example": "张三"
}
}
}
dart
...
Text(AppLocalizations.of(context)!.hello("Programmer")),
...

你还可以使用数字占位符来指定多个值。不同的语言有不同的单词复数化形式。该语法还支持指定单词的复数化形式。
json
"{countPlaceholder, plural, =0{message0} =1{message1} =2{message2} few{messageFew} many{messageMany} other{messageOther}}"
countPlaceholder: 变量名
plural: 固定搭配
=0{message0} =1{message1}...: 参数0时显示message0,参数1时显示message1
app_en.arb
json
"people": "{count, plural, =0{no people} =1{person} other{people} }",
"@people": {
"description": "A plural people",
"placeholders": {
"count": {
"type": "num",
"format": "compact"
}
}
}
app_zh.arb
json
"people": "{count, plural, =0{没有人} =1{一个人} other{人群}}",
"@people": {
"description": "A plural people",
"placeholders": {
"count": {
"type": "num",
"format": "compact"
}
}
}
other的情况必须填写,不然会报
app_en.arb:people\] ICU Syntax Error: Plural expressions must have an "other" case. {count, plural, =0{no people} =1{person} few{some people} } \^ \[app_zh.arb:people\] ICU Syntax Error: Plural expressions must have an "other" case. {count, plural, =0{没有人} =1{一个人} few{一些人} } \^ Found syntax errors.
添加词条后可以在.arb文件中右键然后选择Generate Localizations
生成国际化的.dart文件

dart
...
Text(AppLocalizations.of(context)!.people(0)),
Text(AppLocalizations.of(context)!.people(1)),
Text(AppLocalizations.of(context)!.people(2)),
...

也可以使用String
占位符来表示选择一个值,类似词条使用case语句的感觉
json
"{selectPlaceholder, select, case{message} ... other{messageOther}}"
selectPlaceholder: 变量名
select: 固定搭配
case...other: 情况1,情况2,其它情况
json
"pronoun": "{gender, select, male{he} other{she}}",
"@pronoun": {
"description": "A gendered message",
"placeholders": {
"gender": {
"type": "String"
}
}
}
json
"pronoun": "{gender, select, male{他} other{她}}",
"@pronoun": {
"description": "A gendered message",
"placeholders": {
"gender": {
"type": "String"
}
}
}
dart
Text(AppLocalizations.of(context)!.pronoun('male')),
Text(AppLocalizations.of(context)!.pronoun('female')),

其它
避免语法解析
有时候符号(例如{
或}
)也可能是普通文本的部分,如果不想被解析为一种语法,可以在l10n.yaml
中设置use-escaping
yaml
use-escaping: true
启用后,解析器会忽略使用一对单引号包括的文字,如果在文字中又想使用单个单引号,需要使用成对的单引号进行转义。
配置l10n.yaml文件
通过l10n.yaml
文件,可以配置gen-l10n
工具,指定以下内容
- 所有输入文件的位置
- 所有输出文件的创建位置
- 为本地化代理设置自定义的类名
可以在命令行运行 flutter gen-10n --help
获取命令的具体使用