Flutter国际化插件l10n_mapper_generator的使用
Flutter国际化插件l10n_mapper_generator的使用
获取开始
安装依赖
在你的 pubspec.yaml
文件中添加以下依赖项:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
dev_dependencies:
build_runner: ^2.3.3
l10n_mapper_generator: <latest-version>
激活安装插件
在终端中运行以下命令以全局激活插件:
dart pub global activate l10n_mapper_generator
示例用法
注意:参数作为位置参数传递,这些参数应与翻译键值对中指定的顺序一致。
final applicationName = context.parseL10n('application_name'); // 翻译映射
final depositTimeFrame = context.parseL10n('deposit_timeframe'); // 即时
// 解析占位符参数
final convertBeforeWithdraw = context.parseL10n('convert_before_withdraw', arguments: ['CAD', 'EUR']);
// * 在提取您的CAD之前,您需要先将其转换回EUR
映射器
生成一个 app_localizations.g.dart
文件(前提是你已经设置了本地化)。通过生成的 app_localizations.dart
文件,生成用于动态访问本地化键的方法。
默认情况下,此操作会生成一个包含 l10n
、locale
和 parseL10n
扩展方法的 app_localizations.g.dart
文件,并且还会生成一个包含 app_localizations.dart
中定义的所有键值对的 AppLocalizationsMapper
类。
你可以通过在项目的 build.yaml
文件中指定一些构建配置来自定义生成的行为,或者使用默认配置来生成所有所需的方法。以下是所有可能的配置选项:
# build.yaml
targets:
$default:
builders:
l10n_mapper_generator:l10n_mapper_builder:
enabled: true # 启用或禁用生成器
options:
l10n: true # 可选,默认为true
locale: true # 可选,默认为true
parseL10n: true # 可选,默认为true
message: "Translation key not found!" # 可选,默认为null
classNames: "AppLocalizations,AppLocalizationsPushNotifications" # 可选,默认为AppLocalizations
为了生成可以解析动态翻译键的本地化映射器,你只需执行以下步骤:
- 运行
flutter gen-l10n
来生成app_localizations.dart
文件及相关文件。 - 运行
flutter pub run build_runner build --delete-conflicting-outputs
来生成app_localizations.g.dart
文件(如果尚未生成)。
可用选项
l10n
: 布尔值,默认为true - 需要生成l10n
扩展方法。locale
: 布尔值,默认为true - 需要生成locale
扩展方法。l10nParser
: 布尔值,默认为true - 需要生成l10nParser
扩展方法。appLocalizations
: 在运行flutter gen-l10n
后生成的app_localizations.dart
文件的位置。message
: 当找不到翻译键时返回的回退消息。当提供了此选项时,parseL10n
扩展方法会在找不到翻译键时返回该消息,否则它将返回可空字符串类型String?
。classNames
: 生成映射器的逗号分隔的类名列表。这在你有多个由flutter gen-l10n
生成的本地化文件并且你想为它们生成映射器时非常有用。
脚本运行
格式化 (–format)
此生成器标志表示将翻译文件键格式化为符合Dart命名约定的翻译键,以便生成Dart相关的翻译文件。一个简单的用例是利用原本为其他框架定义的相同翻译文件。
例如:
<!-- en-English.arb -->
<!-- 这个文件最初是为兼容TypeScript/JavaScript项目定义的 -->
"test.send_your_USDT(TRON)_withdraw": "Send your USDT (TRC-20) withdrawal to:",
"@test.send_your_USDT(TRON)_withdraw": {
"type": "text"
},
最初,上述示例是为了支持TypeScript/JavaScript而定义的。使用 --format
标志会将这些键格式化为兼容Dart的命名约定,以便在运行 flutter gen-l10n
时不出现错误。
为了格式化翻译文件,你可以:
- 在项目的根目录中设置
l10n_mapper.json
配置文件,其中包含以下选项:
// l10n_mapper.json
{
"formatterOptions": {
"prefix": "app", // 应用到创建后的翻译文件的文件名前缀
"inputPath": "lib/localization/translations/remote", // 包含需要格式化的翻译文件的目录
"outputPath": "lib/localization/translations/local", // 格式化后翻译文件存放的目录
"translations": [
{
"locale": "ar", // 格式化后的翻译文件的语言环境
"input": "ar-Arabic.arb", // 需要格式化的翻译文件
"output": "ar.arb" // 格式化后的翻译文件名称(例如 app_ar.arb)
},
{
"locale": "de",
"input": "de-German.arb",
"output": "de.arb"
},
{
"locale": "en",
"input": "en-English.arb",
"output": "en.arb"
}
],
"keyPredicateMatch": { // 包含所有匹配和替换的谓词,例如 `.` 将被替换为 `_`
"-": "_",
".": "_",
"^": "_",
"(": "_",
")": "_"
}
},
}
- 运行
flutter gen-l10n
生成app_localizations.dart
文件及相关文件。 - 运行
flutter pub run build_runner build
命令生成格式化的文件和其他生成器文件。
脚本集合
为了方便和更整洁的重用方法,你可以在项目的根目录中创建一个shell脚本来集体运行上述脚本。
你应该在运行 dart pub run l10n_mapper_generator
命令之前设置 l10n_mapper.json
配置文件。
#!/bin/bash
# 格式化 `translations/remote` 目录中的翻译文件以兼容Dart格式
dart pub run l10n_mapper_generator --format
# 生成本地化相关文件
flutter gen-l10n
# 生成所需的代码(这应该生成 `app_localizations.g.dart` 文件,包含 `AppLocalizationsExtension` 和 `AppLocalizationsMapper` 类)
flutter pub run build_runner build --delete-conflicting-outputs
要运行此脚本,你可以在终端中执行以下步骤(项目根目录下):
- 使
./generate_localization.sh
可执行,运行chmod +x ./generate_localization.sh
。 - 运行脚本,运行
./generate_localization.sh
。
自定义路径
如果你的 l10n_mapper.json
文件未定义在项目的根目录(默认预期位置),则可以在运行 dart pub run l10n_mapper_generator
命令时解析目录路径。
# 提供 `l10n_mapper.json` 文件所在的目录路径
dart pub run l10n_mapper_generator --config=lib/config # 目录包含 `l10n_mapper.json` 配置文件
替换规则
提供带有 keyPredicateMatch
值的格式化配置,确保匹配的谓词被配置中指定的值替换。例如,{"^": "_"}
表示所有在翻译键中找到的 ^
将被替换为 _
(下划线)。
// 格式化前
"test^send^your^usdt": "Send your USDT (TRC-20) withdrawal to:",
// 格式化后
"test_send_your_usdt": "Send your USDT (TRC-20) withdrawal to:",
当 keyPredicateMatch
定义为空值时,例如:
"keyPredicateMatch": {
"-": "",
".": "",
"^": "_",
"(": "_",
")": "_"
}
翻译键将使用驼峰命名法进行格式化,其中匹配 ^
和 .
的谓词将被替换。给定之前的示例,键将被格式化为:
// 格式化前
"test^send.your-usdt": "Send your USDT (TRC-20) withdrawal to:",
// 格式化后
"test_sendYourUsdt": "Send your USDT (TRC-20) withdrawal to:",
这种灵活性允许用户决定偏好驼峰命名还是蛇形命名,这两种命名方式都兼容Dart方法命名签名,并适合Dart生成的翻译对象。
辅助扩展
为了动态访问翻译并解析占位符参数,生成了 app-localizations.dart
的部分文件,其中包括对构建上下文的访问扩展和一个映射器。
// 自动生成的代码 - 不要手动修改
// ***************************************************************************
// L10nMapperGenerator
// ***************************************************************************
import 'app_localizations.dart';
import 'package:flutter/widgets.dart';
extension AppLocalizationsExtension on BuildContext {
AppLocalizations get _localizations => AppLocalizations.of(this)!;
AppLocalizations get l10n => _localizations;
Locale get locale => Localizations.localeOf(this);
String parseL10n(String translationKey, {List<Object>? arguments}) {
const mapper = AppLocalizationsMapper();
final object = mapper.toLocalizationMap(this)[translationKey];
if (object == null) return 'Cannot find translation-key!';
if (object is String) return object;
assert(arguments != null, 'Arguments should not be null!');
assert(arguments!.isNotEmpty, 'Arguments should not be empty!');
return Function.apply(object, arguments);
}
}
class AppLocalizationsMapper {
const AppLocalizationsMapper();
Map<String, dynamic> toLocalizationMap(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return {
'localeName': localizations.localeName,
'application_name': localizations.application_name,
'deposit_timeframe': localizations.deposit_timeframe,
'balance_reverted': (currency) => localizations.balance_reverted(currency),
'convert_before_withdraw': (convertFrom, convertTo) => localizations.convert_before_withdraw(convertFrom, convertTo),
'convert_before_withdraw_again': (convertFrom, convertTo) => localizations.convert_before_withdraw_again(convertFrom, convertTo),
};
}
}
更多关于Flutter国际化插件l10n_mapper_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter国际化插件l10n_mapper_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用Flutter国际化插件 l10n_mapper_generator
的代码示例。这个插件可以帮助你自动生成和管理Flutter应用的本地化文件。
1. 添加依赖
首先,你需要在你的 pubspec.yaml
文件中添加 l10n_mapper_generator
依赖:
dependencies:
flutter:
sdk: flutter
# 其他依赖项
dev_dependencies:
build_runner: ^2.0.0
l10n_mapper_generator: ^0.x.x # 请使用最新版本号
2. 创建本地化文件
接下来,在你的项目根目录下创建一个 assets/locales
文件夹,并在其中添加你的本地化文件,例如 en.json
和 zh.json
。
assets/locales/en.json
{
"greeting": "Hello",
"farewell": "Goodbye"
}
assets/locales/zh.json
{
"greeting": "你好",
"farewell": "再见"
}
3. 配置 pubspec.yaml
在 pubspec.yaml
中添加你的本地化文件作为资产:
flutter:
assets:
- assets/locales/en.json
- assets/locales/zh.json
4. 生成本地化映射类
使用 build_runner
来生成本地化映射类。首先,创建一个 localizations.dart
文件,内容如下:
lib/localizations.dart
import 'package:flutter/material.dart';
import 'package:l10n_mapper/l10n_mapper.dart';
part 'localizations.g.dart';
@LocaleMap()
class AppLocalizations {
final Map<String, String> translations;
AppLocalizations(this.translations);
String get greeting => translations['greeting'] ?? 'Hello';
String get farewell => translations['farewell'] ?? 'Goodbye';
}
然后,在项目根目录下运行以下命令来生成本地化文件:
flutter pub run build_runner build
这个命令会生成一个 localizations.g.dart
文件,其中包含了从 JSON 文件映射到 Dart 类的代码。
5. 使用本地化
现在你可以在你的 Flutter 应用中使用生成的本地化类了。首先,你需要将 AppLocalizations
委托给你的 MaterialApp
:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'localizations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
localizationsDelegates: [
// 添加 AppLocalizations 委托
AppLocalizations.delegate,
// 添加全局本地化委托
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
Locale('en', ''),
Locale('zh', ''),
],
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final AppLocalizations localizations = AppLocalizations.of(context);
return Scaffold(
appBar: AppBar(
title: Text(localizations.greeting),
),
body: Center(
child: Text(localizations.farewell),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 切换语言示例
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) {
return LocaleSelectorPage();
},
),
);
},
tooltip: 'Pick Locale',
child: Icon(Icons.add),
),
);
}
}
class LocaleSelectorPage extends StatefulWidget {
@override
_LocaleSelectorPageState createState() => _LocaleSelectorPageState();
}
class _LocaleSelectorPageState extends State<LocaleSelectorPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Select Locale')),
body: ListView(
children: <Locale>[
Locale('en', ''),
Locale('zh', ''),
].map<Widget>((Locale locale) {
return ListTile(
title: Text(locale.languageCode),
onTap: () {
Navigator.popAndPushNamed(context, '/', arguments: locale);
},
);
}).toList(),
),
);
}
}
// 在 MyApp 中处理路由参数以更改语言
class MyAppRouterDelegate extends RouterDelegate<Locale?> with ChangeNotifier, PopNavigatorRouterDelegate<Locale?> {
final GlobalKey<NavigatorState> navigatorKey;
Locale? _locale;
MyAppRouterDelegate({required this.navigatorKey, Locale? locale}) : _locale = locale;
@override
Locale? get currentConfiguration => _locale;
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: [
MaterialPage<void>(
key: ValueKey<Locale?>(_locale),
child: MyApp(locale: _locale),
),
],
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/') {
final Locale? locale = settings.arguments as Locale?;
_locale = locale;
notifyListeners();
return MaterialPageRoute<void>(
settings: settings,
builder: (_) => MyApp(locale: locale),
);
}
return null;
},
);
}
@override
Future<void> setNewRoutePath(Locale? path) async {
_locale = path;
notifyListeners();
}
}
class MyAppRouterInformationParser extends RouterInformationParser<Locale?> {
@override
Future<Locale?> parseRouteInformation(RouteInformation routeInformation) async {
// 在这里解析 URL 或其他路由信息以返回 Locale
// 本示例仅返回 null,因为我们是通过按钮点击更改语言
return null;
}
@override
RouteInformation restoreRouteInformation(Locale? configuration) {
// 在这里根据 Locale 生成 URL 或其他路由信息
// 本示例仅返回默认路由信息
return RouteInformation(location: '/');
}
}
void main() {
final routerDelegate = MyAppRouterDelegate(navigatorKey: GlobalKey<NavigatorState>());
runApp(MaterialApp.router(
routerDelegate: routerDelegate,
routeInformationParser: MyAppRouterInformationParser(),
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
Locale('en', ''),
Locale('zh', ''),
],
));
}
请注意,LocaleSelectorPage
和 MyAppRouterDelegate
等代码是为了展示如何切换语言而添加的,实际项目中可能需要根据具体需求进行调整。
通过以上步骤,你应该能够成功地在Flutter应用中使用 l10n_mapper_generator
插件进行国际化。