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 。

注册登录 后评论
    // 作者
    张风捷特烈 发布于 掘金
    • 0
    // 本帖子
    分类
    // 相关帖子
    Coming soon...
    • 0
    DeepSeek 助力 FlutterUnit 组件数据国际化张风捷特烈 发布于 掘金