Flutter国际化插件i18n_omatic的使用

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

Flutter国际化插件i18n-o-matic的使用

i18n-o-matic 是一个用于简化 Flutter 应用程序中翻译工作的 Dart 包。它能够自动搜索源代码中的可翻译字符串,并为每种语言构建翻译表。这种方法受到 Qt 框架的启发。

特点

  • 无痛翻译工作流
  • 自动发现可翻译字符串
  • 人类可读的 YAML 格式翻译文件
  • 格式化字符串用于变量替换

如何工作

i18n-o-matic 使用源代码中标记为可翻译的原始字符串作为翻译键。I18nOMatic 类将每个可翻译字符串替换为当前语言对应的字符串。建议在应用程序中使用英语作为翻译字符串的参考语言。

1. 导入 i18n_omatic

首先,需要在包含可翻译字符串的每个源文件中导入 i18n_omatic 包:

import 'package:i18n_omatic/i18n_omatic.dart';

2. 标记字符串为可翻译

为了标记字符串为可翻译,需要使用 i18n_omatic 提供的 tr() 方法:

String firstString = 'My first string'.tr();
// ...
Text('Share on network'.tr());

如果可翻译字符串的一部分基于外部值(即字符串插值),可以在字符串中使用占位符,并提供相应的键值对表。这些占位符以 % 字符开头,并且必须与键名匹配:

String birthdayMsg = 'Happy birthday %name, you are %age years old'.tr({'name': 'Peter', 'age': '21'});

3. 准备翻译配置

一旦标记了需要翻译的字符串,你需要编辑 Flutter 应用程序的 pubspec.yaml 配置文件,并添加每个翻译语言的资产文件。这些文件位于 assets/i18nomatic 目录下,文件名使用“语言_国家”代码(例如法国的 fr_FR.yaml,西班牙的 es_ES.yaml 等)。

pubspec.yaml 示例:

flutter:
  assets:
    - assets/
    - assets/i18nomatic/es_ES.yaml
    - assets/i18nomatic/fr_FR.yaml

对于 iOS 平台,还需要更新 ios/Runner/info.plist 文件以注册支持的语言。需要添加或更新 <CFBundleLocalizations> 元素,包含支持的语言列表:

<key>CFBundleLocalizations</key>
<array>
    <string>es_ES</string>
    <string>fr_FR</string>
</array>

4. 自动构建翻译表

i18n_omatic 包提供了一个命令行工具,该工具会扫描应用程序的源代码并查找可翻译的字符串。然后,它会创建或更新翻译文件以包含找到的字符串。

运行以下命令行工具:

dart pub run i18n_omatic:update

默认情况下,该工具会递归地扫描 lib 目录下的 .dart 文件,并更新位于 assets/i18nomatic 目录下的翻译文件。如果在 pubspec.yaml 文件中声明的翻译文件尚不存在,它会自动创建。

你可以根据需要运行此工具来更新翻译表,包括新引入的可翻译字符串。以前已翻译的字符串将保留在翻译文件中。

5. 在应用中启用翻译

你需要启用 i18n_omatic 的本地化代理,并在应用程序定义类中添加支持的语言。

MaterialApp(
    // ...
    localizationsDelegates: [
      I18nOMatic.delegate,
      GlobalMaterialLocalizations.delegate,
      GlobalCupertinoLocalizations.delegate,
      GlobalWidgetsLocalizations.delegate,
    ],
    supportedLocales: [
      const Locale('en', 'US'),
      const Locale('fr', 'FR'),
      const Locale('es', 'ES'), 
    ],
)

完成上述步骤后,带有 .tr() 方法的每个字符串都会被翻译为目标语言中的相应字符串。

6. 编辑翻译文件

假设以下源代码片段:

String firstString = 'My first string'.tr();
// ...
Text('Share on network'.tr());
// ...
String birthdayMsg = 'Happy birthday %name, you are %age years old'.tr({'name': 'Peter', 'age': '21'});
// ...
String ignoredString = 'ignored string';

首次运行 i18n_omatic:update 命令行工具时,将会生成如下的法语文档文件 (assets/i18nomatic/fr_FR.yaml):

format_version: 1

strings:
  "My first string" : null
  "Share on network" : null
  "Happy birthday %name, you are %age years old" : null

这 3 个收集到的字符串现在可供翻译,但默认为 null。你必须编辑文件并提供正确的翻译,例如法语:

format_version: 1

strings:
  "My first string" : "Ma première chaîne de caractères"
  "Share on network" : "Partager sur le réseau"
  "Happy birthday %name, you are %age years old" : "Bon anniversaire %name, tu as %age ans"

如果你在后续开发中删除了一个或多个可翻译字符串(例如上面示例中的 firstString),并在再次运行 i18n_omatic:update 命令行工具时,这些已翻译的字符串不会丢失,而是会被放置在一个 unused_strings 分类中:

format_version: 1

strings:
  "Share on network" : "Partager sur le réseau"
  "Happy birthday %name, you are %age years old" : "Bon anniversaire %name, tu as %age ans"

unused_strings:
  "My first string" : "Ma première chaîne de caractères"

一旦确定不再使用这些字符串,可以将其从 YAML 文件中删除。建议在发布应用程序的新版本之前清理这些文件。

如何测试使用 i18n_omatic 的小部件

你可以使用 Mockito 包来模拟 tr() 函数的翻译:

import 'package:i18n_omatic/i18n_omatic.dart';
import 'package:mockito/mockito.dart';

class MockI18nOMatic extends Mock implements I18nOMatic {}

class MockSetUp {
 static void mockI18nOMatic() {
   I18nOMatic.instance = MockI18nOMatic();
   when(I18nOMatic.instance.tr(any, any)).thenAnswer((realInvocation) {
     var strTranslated = realInvocation.positionalArguments[0].toString();
     if (realInvocation.positionalArguments[1] != null) {
       realInvocation.positionalArguments[1].forEach((String key, String value) {
         value ??= '';
         strTranslated = strTranslated.replaceAll('%$key', value.toString());
       });
     }
     return strTranslated;
   });
 }
}

在 Flutter 小部件测试的开始处调用 MockSetUp.mockI18nOMatic()

void main() {
  setUp(()  {
    MockSetUp.mockI18nOMatic();
  });
  [...]
}

更多关于Flutter国际化插件i18n_omatic的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter国际化插件i18n_omatic的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用i18n_omatic插件进行国际化的代码示例。i18n_omatic是一个流行的Flutter插件,用于简化和加速应用的国际化过程。请注意,实际使用时,你需要确保已经将该插件添加到了你的pubspec.yaml文件中。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加i18n_omatic依赖:

dependencies:
  flutter:
    sdk: flutter
  i18n_omatic: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

2. 创建翻译文件

假设你要支持英语和中文,你可以在项目的assets文件夹下创建两个JSON文件:en.jsonzh.json

en.json

{
  "greeting": "Hello",
  "farewell": "Goodbye"
}

zh.json

{
  "greeting": "你好",
  "farewell": "再见"
}

3. 配置pubspec.yaml

pubspec.yaml中配置这些翻译文件作为资产:

flutter:
  assets:
    - assets/en.json
    - assets/zh.json

4. 初始化i18n_omatic

在你的主应用文件(通常是main.dart)中,初始化i18n_omatic并设置默认语言:

import 'package:flutter/material.dart';
import 'package:i18n_omatic/i18n_omatic.dart';
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 加载翻译文件
  Map<String, dynamic> enTranslations = jsonDecode(await rootBundle.loadString('assets/en.json'));
  Map<String, dynamic> zhTranslations = jsonDecode(await rootBundle.loadString('assets/zh.json'));

  // 初始化i18n
  I18nOmatic.instance.loadTranslations({
    'en': enTranslations,
    'zh': zhTranslations,
  });

  // 设置默认语言
  I18nOmatic.instance.currentLocale = Locale('en');

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: I18nOmatic.instance.translate('app.title', locale: I18nOmatic.instance.currentLocale),
      home: MyHomePage(),
      localizationsDelegates: [
        // 添加i18n_omatic的本地化委托
        I18nOmatic.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: I18nOmatic.instance.supportedLocales,
      locale: I18nOmatic.instance.currentLocale,
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(I18nOmatic.instance.translate('greeting', locale: I18nOmatic.instance.currentLocale)),
      ),
      body: Center(
        child: TextButton(
          onPressed: () {
            // 切换语言示例
            I18nOmatic.instance.currentLocale = I18nOmatic.instance.currentLocale.languageCode == 'en'
                ? Locale('zh')
                : Locale('en');

            // 更新UI(在实际应用中,你可能需要通知监听器或使用Provider来更新UI)
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(I18nOmatic.instance.translate('farewell', locale: I18nOmatic.instance.currentLocale)),
              ),
            );
          },
          child: Text(I18nOmatic.instance.translate('farewell', locale: I18nOmatic.instance.currentLocale)),
        ),
      ),
    );
  }
}

5. 使用翻译文本

在你的应用中,你可以使用I18nOmatic.instance.translate方法来获取翻译后的文本。上面的代码示例已经展示了如何在按钮和AppBar的标题中使用翻译文本。

总结

以上代码展示了如何在Flutter项目中使用i18n_omatic插件进行国际化。这包括加载翻译文件、初始化插件、设置默认语言以及在UI中使用翻译文本。注意,在实际应用中,你可能需要更复杂的逻辑来处理语言切换和用户偏好设置。

回到顶部