本节主要介绍如何对 Flutter 应用进行国际化
使用3种方式来介绍国际化的使用
- 方法1: 编写DemoLocalizations本地化类 ,定义每种语言的 Map
-
方法2: 编写DemoLocalizations本地化类,使用
import 'package:intl/intl.dart';
调用Intl.message
获取本地化,使用intl_translation命令,扫描项目中用到的intl.message生成 arb,然后配置arb文件添加不同语言 -
方法3: 先编写xxx_xx.arb,flutter gen-l10n 命令生成本地化代码 AppLocalizations本地化类. 拆分成不同的文件
编写DemoLocalizations 类 本地化,使用Intl.message使用intl_translation
是指一个不依赖于 intl package 的 示例。手写一个语言资源的类,来代替intl pcakge基于arb json文件资源生成的类。
为app的本地化资源定义一个类DemoLocalizations
//选择自己的方法来管理本地化的值
//一个不依赖于 intl package 的 示例。
// #docregion Demo
//为 app 的本地化资源定义一个类
class DemoLocalizations {
DemoLocalizations(this.locale);
final Locale locale; //通过appMaterialApp创建时候,app启动时候,app获取系统的locale首选设置语言
static DemoLocalizations of(BuildContext context) {
//查看 app 当前的语言环境:
Locale myLocale = Localizations.localeOf(context);
//获取DemoLocalizations 实例
return Localizations.of<DemoLocalizations>(context, DemoLocalizations)!;
}
//这里是手动编写代码
static const _localizedValues = <String, Map<String, String>>{
//定义每种语言的 Map
'en': {
'title': 'Hello World',
},
'es': {
'title': 'Hola Mundo',
},
};
static List<String> languages() => _localizedValues.keys.toList();
String get title {
//这里手动编写的代码, 在map中获取对应文字
return _localizedValues[locale.languageCode]![
'title']!; //这个app启动时候获取到的locale
}
}
// #enddocregion Demo
定义一个DemoLocalizationsDelegate,给MaterialApp用,用于传递上述资源类
// #docregion Delegate
class DemoLocalizationsDelegate
extends LocalizationsDelegate<DemoLocalizations> {
const DemoLocalizationsDelegate();
@override
bool isSupported(Locale locale) =>
DemoLocalizations.languages().contains(locale.languageCode);
@override
Future<DemoLocalizations> load(Locale locale) {
// Returning a SynchronousFuture here because an async "load" operation
// isn't needed to produce an instance of DemoLocalizations.
//创建 DemoLocalizations实例,传入当前的locale对象,系统的语言类型
return SynchronousFuture<DemoLocalizations>(DemoLocalizations(locale));
}
@override
bool shouldReload(DemoLocalizationsDelegate old) => false;
}
MaterialApp中使用
class Demo extends StatefulWidget {
Demo({super.key});
@override
State<Demo> createState() => _DemoState();
}
class _DemoState extends State<Demo> {
Locale? myLocale1;
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateTitle: (context) => DemoLocalizations.of(context).title,
localizationsDelegates: const [
//一个不依赖于 intl package 的 示例。
DemoLocalizationsDelegate(),
//创建 DemoLocalizations 实例,app获取系统 locale 传入DemoLocalizations
// //修改手机系统的语言后,所有后台app其实都被推出了,切换app触发冷启动
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
//语言环境定义
supportedLocales: const [
Locale('en', ''),
Locale('es', ''),
],
home: const DemoApp(),
);
}
}
void main() {
runApp(Demo());
}
页面中使用
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(DemoLocalizations.of(context).title), //获取实例
),
body: Column(
children: [
Localizations.override(
context: context,
locale: const Locale('en'),
//这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
child: Builder(builder: (context) {
return Column(
children: [
Center(
child: Text(DemoLocalizations.of(context).title),
),
],
);
}),
),
Container(
height: 2,
color: Colors.red,
width: double.maxFinite,
),
Localizations.override(
context: context,
locale: const Locale('es'),
//这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
child: Builder(builder: (context) {
return Column(
children: [
Center(
child: Text(AppLocalizations.of(context)!.helloWorld),
),
],
);
}),
),
],
),
);
}
}
上面就完成了一个手写的方式实现的国际化文本的展示。
intl_translation扫描项目生成
实例:
intl_main.dart
// #docregion DemoLocalizations
class DemoLocalizations {
DemoLocalizations(this.localeName);
static Future<DemoLocalizations> load(Locale locale) {
final String name =
locale.countryCode == null || locale.countryCode!.isEmpty
? locale.languageCode
: locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
return DemoLocalizations(localeName);
});
}
static DemoLocalizations of(BuildContext context) {
return Localizations.of<DemoLocalizations>(context, DemoLocalizations)!;
}
final String localeName;
String get title {
return Intl.message(
'Hello World',
name: 'title',
desc: 'Title for the Demo application',
locale: localeName,
);
}
}
// #enddocregion DemoLocalizations
class DemoLocalizationsDelegate
extends LocalizationsDelegate<DemoLocalizations> {
const DemoLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode);
@override
Future<DemoLocalizations> load(Locale locale) =>
DemoLocalizations.load(locale);
@override
bool shouldReload(DemoLocalizationsDelegate old) => false;
}
命令:
flutter pub get
dart run intl_translation:extract_to_arb --output-dir=lib/l10n lib/main.dart
结果,生成了intl_message.dart内容为:
{
"@@last_modified": "2024-02-27T10:39:49.387951",
"title": "Hello World",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
}
}
命令2:
dart run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/main.dart lib/l10n/intl_*.arb
结果为 这3个文件:
![](https://img.haomeiwen.com/i45726/59c7d2a0d60412be.jpeg)
使用脚本自动生成代码
工程配置
pubspec.yaml添加intl库
environment:
sdk: ">=2.17.0 <3.0.0"
flutter: ">=2.5.0 <4.0.0"
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
生成的结果在.dart_tool目录下。
[图片上传失败...(image-3634de-1708952732637)]
通过
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
可以使用生成的代码。
创建配置文件l10n.yaml
在项目目录根目录创建文件名 的 l10n.yaml 文件。
内容为:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
在lib目录下创建文件夹名为l10n
在此文件夹下面添加语言资源文件
分别创建app_en.arb 和 app_es.arb
app_en.arb内容为:
{
"title": "Hello World",
"@title":
{
"description": "Title for the Demo application",
"type": "text"
},
"helloWorld": "Hello World!英文我修改了,直接pub get,只用一次 flutter gen-l10n ",
"@helloWorld":
{
"description": "The conventional newborn programmer greeting"
},
"numberOfDataPoints": "Number of data points: {value}",
"@numberOfDataPoints":
{
"description": "A message with a formatted int parameter",
"placeholders":
{
"value":
{
"type": "int",
"format": "compactCurrency",
"optionalParameters":
{
"decimalDigits": 2
}
}
}
},
"pronoun": "{gender, select, male{他} female{她} other{它}}",
"@pronoun":
{
"description": "A gendered message",
"placeholders":
{
"gender":
{
"type": "String"
}
}
},
"nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
"@nWombats":
{
"description": "A plural message",
"placeholders":
{
"count":
{
"type": "num",
"format": "compact"
}
}
},
"hello": "Hello {userName}",
"@hello":
{
"description": "A message with a single parameter",
"placeholders":
{
"userName":
{
"type": "String",
"example": "Bob"
}
}
}
}
app_es.arb内容为:
{
"title": "Hola Mundo",
"@title":
{
"description": "Title for the Demo application",
"type": "text"
},
"helloWorld": "¡Hola Mundo!esessssss",
"numberOfDataPoints": "Number of data points: {value}",
"@numberOfDataPoints":
{
"description": "A message with a formatted int parameter",
"placeholders":
{
"value":
{
"type": "int",
"format": "compactCurrency",
"optionalParameters":
{
"decimalDigits": 2
}
}
}
},
"pronoun": "{gender, select, male{he} female{she} other{they}}",
"@pronoun":
{
"description": "A gendered message",
"placeholders":
{
"gender":
{
"type": "String"
}
}
},
"nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
"@nWombats":
{
"description": "A plural message",
"placeholders":
{
"count":
{
"type": "num",
"format": "compact"
}
}
},
"hello": "Hello {userName}",
"@hello":
{
"description": "A message with a single parameter",
"placeholders":
{
"userName":
{
"type": "String",
"example": "Bob"
}
}
}
}
执行命令生成代码
flutter pub get
flutter gen-l10n
生成结果如下:
![](https://img.haomeiwen.com/i45726/a5c6975ca91aa18d.png)
使用生成的代码
在main文件导入库:
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
MaterailApp初始化:
class Demo extends StatefulWidget {
Demo({super.key});
@override
State<Demo> createState() => _DemoState();
}
class _DemoState extends State<Demo> {
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateTitle: (context) => DemoLocalizations.of(context).title,
localizationsDelegates: const [
//这个示例是基于 intl package 提供的 API 和工具开发的, app 本地化资源的替代方法 里面讲解了
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
//语言环境定义
supportedLocales: [
Locale('en', ''),
Locale('es', ''),
],
// intl工具也能生成,可以直接使用
//localizationsDelegates: AppLocalizations.localizationsDelegates,
//supportedLocales: AppLocalizations.supportedLocales,
home: const DemoApp(),
)
}
}
void main() {
runApp(Demo());
}
页面使用
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Localizations.override(
context: context,
locale: const Locale('en'),
//这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
child: Builder(builder: (context) {
return Column(
children: [
Center(
child: Text(AppLocalizations.of(context)!.helloWorld),
),
Text(AppLocalizations.of(context)!.numberOfDataPoints(100)),
// Returns 'he'
Text(AppLocalizations.of(context)!.pronoun('male')),
// Returns 'she'
Text(AppLocalizations.of(context)!.pronoun('female')),
// Returns 'they'
Text(AppLocalizations.of(context)!.pronoun('other')),
// Returns 'no wombats'
Text(AppLocalizations.of(context)!.nWombats(0)),
// Returns '1 wombat'
Text(AppLocalizations.of(context)!.nWombats(1)),
// Returns '5 wombats'
Text(AppLocalizations.of(context)!.nWombats(5)),
Text(AppLocalizations.of(context)!.hello('John')),
],
);
}),
),
Container(
height: 2,
color: Colors.red,
width: double.maxFinite,
),
Localizations.override(
context: context,
locale: const Locale('es'),
//这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
child: Builder(builder: (context) {
return Column(
children: [
Center(
child: Text(AppLocalizations.of(context)!.helloWorld),
),
Text(AppLocalizations.of(context)!.numberOfDataPoints(100)),
// Returns 'he'
Text(AppLocalizations.of(context)!.pronoun('male')),
// Returns 'she'
Text(AppLocalizations.of(context)!.pronoun('female')),
// Returns 'they'
Text(AppLocalizations.of(context)!.pronoun('other')),
// Returns 'no wombats'
Text(AppLocalizations.of(context)!.nWombats(0)),
// Returns '1 wombat'
Text(AppLocalizations.of(context)!.nWombats(1)),
// Returns '5 wombats'
Text(AppLocalizations.of(context)!.nWombats(5)),
Text(AppLocalizations.of(context)!.hello('John')),
],
);
}),
),
],
),
);
}
}
通过Localizations.override设置,覆盖系统中的语言环境
Localizations.override(
context: context,
locale: const Locale('es'),
//这里手动设置语言,app启动通过 delegate的load方法获取到的语言,会被这里的覆盖
child: Builder(builder: (context) {
}
);
总结
本文2种方法国际化设置,一种基于intl库,编写_en.arb和_es.arb,通过 flutter gen-l10n
自动生成代码,程序中使用自动生成的代码类完成多语言的获取。通过pubspec.yaml添加的 generate: true 每次修改arb运行app都实时有效。
另一种方式是手写语言资源类。通过直接的dart代码中通过定义的map,语言环境定义的locale.languageCode获取对应的语言文本。
- 方法1: 编写DemoLocalizations类 本地化,定义每种语言的 Map
//这里是手动编写代码
static const _localizedValues = <String, Map<String, String>>{
//定义每种语言的 Map
'en': {
'title': 'Hello World',
},
'es': {
'title': 'Hola Mundo',
},
};
static List<String> languages() => _localizedValues.keys.toList();
String get title {
//这里手动编写的代码, 在map中获取对应文字
return _localizedValues[locale.languageCode]![
'title']!; //这个app启动时候获取到的locale
}
- 方法2: 编写DemoLocalizations 类,使用
import 'package:intl/intl.dart';
调用Intl.message
获取本地化,使用intl_translation命令,扫描项目中用到的intl.message生成 arb,然后配置arb文件添加不同语言
String get title {
return Intl.message(
'Hello World',
name: 'title',
desc: 'Title for the Demo application',
locale: localeName,
);
}
- 方法3: 先编写xxx_xx.arb,flutter gen-l10n 命令生成本地化代码 AppLocalizations. 拆分成不同的文件
switch (locale.languageCode) {
case 'en': return AppLocalizationsEn();
case 'es': return AppLocalizationsEs();
}
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
最后demo效果如下:
![](https://img.haomeiwen.com/i45726/da713967f53775bf.jpeg)
网友评论