DeepSeek 助力 FlutterUnit 组件数据国际化
0. 前言
虽然 FlutterUnit 应用支持了国际化,但是组件相关介绍信息的数据仍是中文。在新版的 FlutterUnit 组件数据设计中已经为组件数据的国际化埋下了伏笔。但是摆在面前的一座大山是:
354 个组件的数据,如何翻译为多国语言。
DeepSeek 给了我一个可以基于 AI 批量完成翻译的机会。不得不说,DeepSeek 的 api 调用已经砍到白菜价了,普通的开发者自己玩玩也可以承受:
另外登录 DeepSeek 后,在 控制台 可以看到会赠送 10 元的余额,所以不用白不用。本文我将基于 DeepSeek 的开发 api ,通过 Dart 的代码调用,完成 354 个组件 数据的 10 国 语言翻译:
中文: zh_CN
英文: en_US
俄语: ru_RU
法语: fr_FR
韩文: ko_KR
德语: de_DE
日语: js_JP
意大利: it_IT
葡萄牙语: pt_PT
西班牙语: es_ES
1. Dart 调用 DeepSeek 接口
首先,需要到 DeepSeek 的控制台中生成一个 API key 作为调用接口的令牌。
这里通过 dio 进行网络请求,简单封装一个 AiChatApi 类维护 ai 聊天的逻辑处理:
import 'package:dio/dio.dart';
class AiChatApi {
final String apiUrl = 'https://api.deepseek.com';
final String apiKey = '你的 api key';
late Dio dio = Dio(BaseOptions(baseUrl: apiUrl));
}
这里简单写一个 translation 方法,输入待翻译的文本和对应的语言。后面有时间可以细致地封装一下,提供一个通用的 ai 会话功能。 官方的对话补全文档 中详细介绍了各个参数的作用。对当前的翻译需求,定制 env 提示词:
Future<String> translation(String src, String locale) async {
String env = "你是一个翻译专家, "
"只需要将传入的 json 中文文本翻译为指定的 locale 语言即可,"
"输入中的数字和英文不用翻译。"
"不用返回 json 文本以外及任何额外的信息。";
final Map<String, dynamic> data = {
"messages": [
{"content": env, "role": "system"},
{"content": "将 {$src} 翻译为 $locale", "role": "user"}
],
"model": "deepseek-chat",
"frequency_penalty": 0,
"max_tokens": 2048,
"presence_penalty": 0,
"response_format": {"type": "text"},
"stop": null,
"stream": false,
"stream_options": null,
"temperature": 1.3,
"top_p": 1,
"tools": null,
"tool_choice": "none",
"logprobs": false,
"top_logprobs": null
};
//接口调用见下:
}
会话补全使用 /chat/completions
接口,发生普通的 post 请求即可,在响应的数据中,choices 字段携带着我们需要的内容:
try {
final response = await dio.post(
'/chat/completions',
options: Options(headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Accept': 'application/json; charset=UTF-8',
'Authorization': 'Bearer $apiKey',
}),
data: data,
);
final dynamic repData = response.data;
if (repData != null) {
String result = repData['choices'].first['message']['content'];
return result;
} else {
return '';
}
} catch (e) {
return 'Error: $e';
}
另外 usage 字段中记录着当前请求消耗 token 的情况:
2. 封装方法翻译组件数据
有了翻译的方法,接下来只需要读取指定组件中的 desc_zh-CN.json
内容,将它交给 AI 翻译处理,在得到结果后,将内容写入到对应语言的文件里即可:
Future<void> translation(AiChatApi api, String widgetDir, String locale) async{
String inputName = r'desc_zh-CN.json';
String content = await File(p.join(widgetDir,inputName)).readAsString();
String ret = await api.translation(content, locale);
String outputName = 'desc_$locale.json';
File distFile = File(p.join(widgetDir,outputName));
if(ret.isNotEmpty){
await distFile.writeAsString(ret);
print("翻译成功:[${p.basename(widgetDir)}]::$locale");
}else{
print("翻译失败:[${p.basename(widgetDir)}]::$locale");
}
}
比如下面的俄语,通过 WidgetDataL10nTool 进行处理后,即可将结果写入到 desc_ru_RU.json
文件中
main() async {
String widgetDir = r'D:\Projects\Flutter\Github\FlutterUnit\modules\widget_system\widgets\lib\StatelessWidget\CloseButtonIcon';
WidgetDataL10nTool tool = WidgetDataL10nTool();
String targetLocale = 'ru_RU';
await tool.translation(widgetDir, targetLocale);
}
一个组件的一种语言处理完毕,接下来只需要遍历待翻译的九种语言,依次调用 translation
方法即可:
Future<void> translationWidget(String widgetDir) async {
List<String> locales = [
'en_US', 'ru_RU', 'fr_FR', 'ko_KR', 'de_DE',
'js_JP', 'it_IT', 'pt_PT', 'es_ES'
];
for (String locale in locales) {
await translation(widgetDir, locale);
}
}
运行一次之后,FlutterUnit 对应的组件就完成了 10 国语言的原始数据积累:
3. 遍历翻译所有组件
一个文件的生成,通过遍历可以生成一批文件;同理,一个组件完成了目标,通过遍历可以完成全部的组件翻译任务。 在 FlutterUnit 的设计上,所有组件分为七大家族,每个家族的组件都放置在对应的文件夹中。所以可以先提供一个翻译家族的方法 translationFamily
Future<void> translationFamily(String family) async {
String familyDir = p.join(dataDir, family);
Directory directory = Directory(familyDir);
List<FileSystemEntity> entity = directory.listSync();
for (FileSystemEntity e in entity) {
if (e is Directory) {
await translationWidget(e.path);
}
}
}
一个家族的组件处理完毕,遍历七大家族即可完成全部组件的翻译任务,也就是下面 translationAll
方法。到这里就完成了 FlutterUnit 组件数据国际化的可行性。目前只是最简单的 "能用"
, 后期还可以强化一下任务过程中的日志、错误收集处理,甚至给出 UI 反馈翻译进度等功能。
final Map<int, String> familyMap = {
0: 'StatelessWidget',
1: 'StatefulWidget',
2: 'SingleChildRenderObjectWidget',
3: 'MultiChildRenderObjectWidget',
4: 'Sliver',
5: 'ProxyWidget',
6: 'Other',
};
Future<void> translationAll() async{
for(String family in familyMap.values){
await translationFamily(family);
}
}
4.尾声
不得不说,AI 的存在让很多不可能的事成为了可能。如果是传统翻译,中文介绍中的英文、数字很难控制其不处理。对于 AI 来说,调用者可以通过自然语言来描述翻译过程中的细节,AI 会推理理解,从而完美完成任务:
试想一下,如果没有 AI 的支持,FlutterUnit 中 354 个组件的 10 国语言翻译,那就是 3540 个文件的翻译工作。这需要花费巨大的人力、财力、时间来处理,还不一定能翻译地到 AI 的水平。
而接入 Deepseek 支持之后,我只是轻轻地敲了 一个小时 的代码,顺便还水了一篇文章,一边等待翻译任务的执行。预计也就 2 元左右的接口调用费,而且还是免费赠送的余额。
最近 deepseek 接口白天非常慢甚至不能用,晚上和清晨会好很多。等 FlutterUnit 仓库中全部组件数据的国际化后,会继续完善,通过 FlutterUnitTool 解析为多国语言,另外数据库也需要增加数据国际化的支持。巧妇难为无米之炊,现在米已经有了,那么离一席大餐也不远了,敬请期待真正 10 国语言支持的 FlutterUnit 。