Flutter国际化插件i18n_omatic的使用
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
更多关于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.json
和zh.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中使用翻译文本。注意,在实际应用中,你可能需要更复杂的逻辑来处理语言切换和用户偏好设置。