Flutter国际化插件l10n_mapper_generator的使用

发布于 1周前 作者 eggper 来自 Flutter

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 文件,生成用于动态访问本地化键的方法。

默认情况下,此操作会生成一个包含 l10nlocaleparseL10n 扩展方法的 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

1 回复

更多关于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.jsonzh.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', ''),
    ],
  ));
}

请注意,LocaleSelectorPageMyAppRouterDelegate 等代码是为了展示如何切换语言而添加的,实际项目中可能需要根据具体需求进行调整。

通过以上步骤,你应该能够成功地在Flutter应用中使用 l10n_mapper_generator 插件进行国际化。

回到顶部