Flutter本地化翻译管理插件applanga_flutter的使用
Flutter本地化翻译管理插件applanga_flutter的使用
Applanga SDK for Flutter 是一个强大的工具,它可以帮助开发者轻松实现应用的国际化和本地化。通过与 Applanga 平台的集成,开发者可以更方便地管理应用中的文本资源,并且支持通过空中更新(Over-the-Air Updates, OTA)来即时更新应用内的文字内容。
目录
基本用法
Applanga CLI 安装
对于 Applanga Command Line Interface (CLI) 的安装,请参考官方文档:Applanga CLI 文档。
在 Flutter 中不需要通过 CLI 初始化项目,applanga_flutter
会自动处理这些步骤。你可以随时修改 .applanga.json
文件来自定义 CLI 配置。
本地化准备
applanga_flutter
与 flutter_localizations
包兼容良好。请按照官方国际化指南添加 flutter_localizations
和 intl
到你的依赖项中,在 pubspec.yaml
中启用生成器,并创建 l10n.yaml
文件以及第一个基础语言的 .arb
文件,例如:
{
"@@locale": "en",
}
将本地化代理添加到你的 MaterialApp
:
const MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: MyApp(),
)
在 pubspec.yaml
底部添加 API Token:
applanga_flutter:
access_token: xxxxxxxxxxxxxxxx
你可以从项目的仪表板上的设置页面获取 API Token。这个令牌用于拉取和推送新的翻译。
拉取 & 推送新翻译
要执行推送或拉取命令,你需要先设置 Applanga CLI。
- 使用
dart run applanga_flutter:pull
下载所有新字符串并将它们保存到相应的 arb 文件中。 - 使用
dart run applanga_flutter:push
将所有新增加的字符串上传到 Applanga 仪表板。
默认情况下,基础语言 .arb
文件是唯一的真相来源。因此,pull
操作会为除基础语言外的所有语言获取并保存翻译,而 push
操作只会更新尚未上传到仪表板的基础语言字符串及其元数据(对 ICU 字符串很重要)。你可以在 .applanga.json
中更改此行为。
推荐使用 dart run applanga_flutter:push --force
来确保基础语言及其元数据的完整更新。
可选的空中更新
空中更新适用于 Android 和 iOS。
iOS 注意事项
确保在 info.plist
中添加了支持的语言。更多信息请参见Flutter 国际化教程。
添加 Applanga 的设置文件
- 在 Applanga 项目概览中点击
[Prepare Release]
按钮,然后点击[Get Settings File]
获取 Applanga 设置文件。 - 将 Applanga 设置文件 添加到 Android 模块的资源
res/raw
目录。 - 同样将 Applanga 设置文件 添加到 iOS 模块的主要目标。打开 Xcode 中的 iOS 模块,并将设置文件拖入项目中,确保选中你要应用的目标。
生成并替换 AppLocalizationsClass
生成 ApplangaLocalizationsClass
:
dart run applanga_flutter:generate
在 MaterialApp
中添加类并替换旧的代理和语言环境:
import 'package:applanga_flutter/applanga_flutter.dart';
const MaterialApp(
localizationsDelegates: ApplangaLocalizations.localizationsDelegates,
supportedLocales: ApplangaLocalizations.supportedLocales,
localeListResolutionCallback: ApplangaLocalizations.localeListResolutionCallback,
home: MyApp(),
),
你可以像往常一样获取翻译:AppLocalizations.of(context)!.helloWorld
ApplangaWidget
建议将 ApplangaWidget
放置为 widget 树的顶级 widget,以便在异步更新空中传输时通知所有子 widget。这对于更好的截图体验也很有帮助。
void main() async {
runApp(
const ApplangaWidget(child: MyApp()),
);
}
默认语言
默认情况下,Applanga 的 OTA 字符串是在运行时懒加载的。如果用户更改应用程序语言,Applanga 会为所选语言获取所有新的翻译。这可能会导致用户界面出现意外的行为,特别是在短时间内有大量新的翻译变更时。如果你有一个自定义的语言切换器,可以在应用程序启动前预加载所有常用语言以避免延迟。
在 pubspec.yaml
中添加默认语言,例如:
applanga_flutter:
...
update_languages: [en, en_US, es, es_CL]
默认组
如果你使用了分组,可以定义所有默认组,这些组将在应用程序启动时下载。默认情况下只下载 main
组。
我们遵循与 update_languages
相同的模式:
applanga_flutter:
...
update_groups: [main, chapter1, chapter2]
手动 OTA 更新
ApplangaFlutter 在应用程序启动时为默认语言和默认组获取所有新的翻译。你也可以编程启动一个新的更新,并定义你的语言或组。
// 自定义语言和组
ApplangaFlutter.update({languages: ['en_US'], groups: ['main', 'chapter2']});
// 使用默认语言和默认组进行默认更新调用
ApplangaFlutter.update();
草案模式
注意:草案模式仅适用于 Android 和 iOS。
Applanga 的草案模式可以通过多点触摸手势激活,在 iOS 构建中开箱即用,但对于 Android,你需要转发输入事件给 SDK,这可以在自定义 MainActivity 中完成如下所示:
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
com.applanga.applanga_flutter.ApplangaFlutterPlugin.dispatchTouchEvent(ev, this)
return super.dispatchTouchEvent(ev)
}
}
在 AndroidManifest 中的 manifest 标签内添加以下权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
要通过代码触发草案模式对话框,可以调用 ApplangaFlutter.showDraftModeDialog();
截图菜单
注意:截图菜单仅适用于 Android 和 iOS - 必须先启用草案模式。
一旦进入草案模式,你可以通过两指下滑或通过代码显示或隐藏截图菜单:ApplangaFlutter.setScreenShotMenuVisible(bool);
为了获得良好的截图体验,确保用 ApplangaScreenshotScope
或添加 ApplangaScreenshotScopeMixin
包装所有屏幕或小部件,如下面的例子所示。
使用 ApplangaScreenshotScope
:
class MyDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ApplangaScreenshotScope(child: Drawer(
// ...
));
}
}
或者将 ApplangaScreenshotScopeMixin
添加到屏幕的状态:
class _HomeScreenState extends State<HomeScreen> with ApplangaScreenshotScopeMixin {
// ...
}
为了获得更好的截图体验,建议使用 ApplangaWidget
和 ApplangaScreenshotScope
(或 ApplangaScreenshotScopeMixin
)。
自动化截图上传
在运行Flutter 集成测试时,你可以简单地捕获截图:
await ApplangaFlutter.I.captureScreenshotWithTag("main");
请阅读Screenshot Menu以改善截图中的字符串位置收集。示例包含了一个展示自动截图用法的集成测试。
显示 ID 模式
启用 Applanga 的显示 ID 模式将返回翻译键而不是实际的翻译。这对于调试字符串位置很有帮助,也用于提高屏幕上的字符串检测准确性。
await ApplangaFlutter.I.setShowIdModeEnabled(true);
// 或者
await ApplangaFlutter.I.setShowIdModeEnabled(false);
自动设置文件更新
这在执行拉取请求后会自动启用。要手动执行此操作,请使用以下命令:
dart run applanga_flutter:update_settingsfiles
要禁用自动行为,请在 pubspec.yaml
中添加:
applanga_flutter:
access_token: xxxx
update_settingsfiles_on_pull: false
对于空中更新,Applanga 设置文件是必需的。它包含仪表板上所有语言的最新翻译。最好在应用发布前更新此文件。Applanga 只会获取新的翻译。如果设置文件是最新的,第一次(自动)ApplangaFlutter.update 将导致非常轻量级的 GET 请求。如果设置文件较旧,则获取请求将包含更多信息。
分支
如果你的项目是一个分支项目,请使用至少版本 3.0.47 的 applanga_flutter
并更新你的设置文件。你可以在 pubspec.yaml
中定义默认分支:
applanga_flutter:
access_token: xxxx
branch_id: xxxx
你可以在 Applanga 仪表板的项目设置中找到分支 ID。在更改 pubspec.yaml
中的分支 ID 后,你需要运行 dart run applanga_flutter:generate
以重新生成你的 Applanga 配置。如果你更改了默认分支,你也需要手动下载并更新你的设置文件。如果设置文件的默认分支与 pubspec.yaml
中指定的默认分支不同,applanga_flutter
将抛出异常。
默认分支用于应用程序启动和更新调用。要确认分支工作正常,请查找日志行:Branching is enabled.
有关分支的更多信息,请参阅这里。
启用自定义语言回退
你可以在 pubspec.yaml
中配置 Flutter 的自定义语言回退。当 SDK 需要用指定语言翻译一个键时,它会使用提供的顺序。这覆盖了任何其他系统或默认回退,但仅限于那些语言。其他语言根据 custom_language_fallback
值(或未设置时的默认值)指定的回退工作。回退仅覆盖顶级语言,因此不可能“嵌套”自定义回退。
applanga_flutter:
custom_language_fallback:
es-CL: [fr, es-US, de, es]
de-AT: [es, de-AT, de]
示例代码
import 'package:applanga_flutter/applanga_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
const MyApp(),
);
}
class MyApp extends StatefulWidget {
final Locale? startupLocale;
const MyApp({Key? key, this.startupLocale}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Locale? _currentLocale;
@override
void initState() {
super.initState();
_currentLocale = widget.startupLocale;
}
@override
Widget build(BuildContext context) {
return ApplangaWidget(
child: Column(
children: [
Expanded(
child: MaterialApp(
title: 'Flutter Demo',
locale: _currentLocale,
localizationsDelegates: ApplangaLocalizations.localizationsDelegates,
supportedLocales: ApplangaLocalizations.supportedLocales,
localeListResolutionCallback: ApplangaLocalizations.localeListResolutionCallback,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
),
),
Directionality(
textDirection: TextDirection.ltr,
child: Wrap(
spacing: 8,
children: ApplangaLocalizations.supportedLocales
.map(
(locale) => ElevatedButton(
child: Text(
locale.toString(),
style: TextStyle(
fontWeight: (_currentLocale == locale)
? FontWeight.bold
: FontWeight.normal,
textScaleFactor: (_currentLocale == locale) ? 1.3 : 1,
),
),
onPressed: () {
setState(() {
_currentLocale = locale;
});
},
),
)
.toList(),
),
),
],
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with ApplangaScreenshotScopeMixin {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
AppLocalizations.of(context).homePageTitle(DateTime.now()),
key: const ValueKey('homePageTitle'),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
AppLocalizations.of(context)
.youHavePushedTheButtonXTimes(_counter, 'thumb'),
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const SecondPage(),
));
},
label: Text(AppLocalizations.of(context).goToSecondPage),
icon: const Icon(Icons.arrow_forward),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: AppLocalizations.of(context).increment,
child: const Icon(Icons.add),
),
);
}
}
更多关于Flutter本地化翻译管理插件applanga_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter本地化翻译管理插件applanga_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用 applanga_flutter
插件进行 Flutter 应用本地化翻译的示例代码案例。applanga_flutter
是一个方便管理 Flutter 应用本地化的插件,支持从 Applanga 平台动态获取翻译内容。
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 applanga_flutter
依赖:
dependencies:
flutter:
sdk: flutter
applanga_flutter: ^最新版本号 # 请替换为当前最新版本号
然后运行 flutter pub get
来获取依赖。
2. 配置 Applanga
在你的 Flutter 项目中,你需要配置 Applanga 的 API 密钥和项目 ID。这通常在 main.dart
或初始化文件中完成。
import 'package:flutter/material.dart';
import 'package:applanga_flutter/applanga_flutter.dart';
void main() {
// 初始化 Applanga
Applanga.init(
apiKey: '你的API密钥',
projectId: '你的项目ID',
languageCode: 'en', // 默认语言
fallbackLanguageCode: 'en', // 备选语言
// 如果需要,可以配置更多参数,比如自定义的 API 端点等
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
3. 使用翻译功能
在需要使用翻译的地方,你可以使用 Applanga.translate
方法。下面是一个简单的示例,展示如何在按钮文本中使用翻译。
import 'package:flutter/material.dart';
import 'package:applanga_flutter/applanga_flutter.dart';
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<String> _translateButtonLabel() async {
// 从Applanga获取翻译
return await Applanga.translate('button.label');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Applanga Demo'),
),
body: Center(
child: FutureBuilder<String>(
future: _translateButtonLabel(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return ElevatedButton(
onPressed: () {},
child: Text(snapshot.data ?? 'Loading...'),
);
}
} else {
return CircularProgressIndicator();
}
},
),
),
);
}
}
4. 更新语言
你也可以让用户在应用内切换语言。以下是一个简单的示例,展示如何通过按钮切换语言。
import 'package:flutter/material.dart';
import 'package:applanga_flutter/applanga_flutter.dart';
class LanguageSwitcher extends StatefulWidget {
@override
_LanguageSwitcherState createState() => _LanguageSwitcherState();
}
class _LanguageSwitcherState extends State<LanguageSwitcher> {
void _changeLanguage(String languageCode) {
Applanga.setLanguageCode(languageCode);
// 通常这里可以刷新UI或重建某些组件以显示新的语言内容
setState(() {});
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => _changeLanguage('zh'),
child: Text('中文'),
),
SizedBox(width: 20),
ElevatedButton(
onPressed: () => _changeLanguage('en'),
child: Text('English'),
),
],
);
}
}
总结
上述代码展示了如何在 Flutter 应用中使用 applanga_flutter
插件进行本地化翻译管理。你可以根据需要进一步定制和扩展这些示例代码。记得将 你的API密钥
和 你的项目ID
替换为你在 Applanga 平台获取的实际值。