Featured image of post 使用 Deepseek + Github Actions 将博客全自动翻译为英文

使用 Deepseek + Github Actions 将博客全自动翻译为英文

自 ChatGPT 3.0 以来,AI 翻译功能以前所未有的准确度横扫翻译市场。因为本博客曾经一度使用过英文写作,所以不少文章存在中英语混用现象,趁着 Deepseek 即将涨价,我花了几分钟时间,将本博客所有文章翻译为了英文。同时借助 Github Actions,实现全自动翻译。

翻译前期工作

  1. 确认自己的 HUGO 版本和主题已支持 i18n 功能

只要不是特别古董的 hugo 版本(低于0.60.0),应该都支持这个,而且大部分主流 hugo 主题也都默认可以支持 i18n 功能。可以在主题 yaml/toml 文件中查看是否有多语言配置。

  1. 安装 python

在 python 官网 下载 Windows 版本然后安装。

  1. 安装必要依赖

用 Windows 终端或者 Git bash 之类的命令行工具安装 requests 和 openai 两个库,前一个用于发送 HTTP 请求,后一个用于 deepseek api 配置(deepseek 使用标准 openai 格式)。

1
2
pip install requests
pip install openai
  1. 申请 deepseek api

到 deepseek 开放平台 创建 api KEY,创建时复制保存好。 (每个新手机号码注册时都会送 10 元余额,如果没有,可以自己充 10 块钱。)

编写 python 脚本并运行

这里可以直接使用我的脚本,将下边代码保存为 translate.py 文件,然后在 py 文件保存的位置,运行命令行工具,输入 python translate.py 即可开启自动翻译。使用说明:

  1. 替换 “sk-xxx” 为你自己的 deepseek api KEY
  2. 替换 “D:/hugo/lawtee/content/” 为你自己的 Hugo 文章目录
  3. 固定翻译映射主要是解决文章分类可能存在中英文字义差异问题,可以根据实际情况使用。
  4. MAX_TOKENS 可以自行修改,也可以不改,如果文章普遍很短,可以改小点。
  5. 这里的翻译逻辑是,将所有 hugo content 目录中的文件夹遍历,对文件夹中只有 index.md 的,将其翻译为 index.en.md ,如果已经同时存在 index.md 和 index.en.md 则不翻译。
查看代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import os
import re
from openai import OpenAI

# 配置
API_KEY = "sk-xxx"  # 替换为你的DeepSeek API密钥
CONTENT_DIR = "D:/hugo/lawtee/content/posts"  # Hugo的博客文章目录路径
MAX_TOKENS = 8192  # API的最大token限制
CHUNK_SIZE = 6000  # 每块的最大token数量(根据实际情况调整)

# 固定翻译映射
CATEGORY_TRANSLATIONS = {
    "生活": "Life",
    "法律": "Law",
    "社会": "Society"
}

# 初始化OpenAI客户端
client = OpenAI(api_key=API_KEY, base_url="https://api.deepseek.com")

# 翻译函数
def translate_text(text):
    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=[
            {"role": "system", "content": "You are a helpful translator. Translate the following text into English."},
            {"role": "user", "content": text},
        ],
        max_tokens=MAX_TOKENS,  # 指定最大输出长度
        stream=False
    )
    return response.choices[0].message.content

# 分块翻译函数
def translate_long_text(text, chunk_size=CHUNK_SIZE):
    chunks = [text[i:i + chunk_size] for i in range(0, len(text), chunk_size)]
    translated_chunks = []
    for chunk in chunks:
        try:
            translated_chunk = translate_text(chunk)
            translated_chunks.append(translated_chunk)
        except Exception as e:
            print(f"分块翻译失败,错误:{e}")
            translated_chunks.append("")  # 如果失败,添加空字符串
    return "".join(translated_chunks)

# 提取并处理Front Matter
def process_front_matter(content):
    # 匹配Front Matter部分
    front_matter_match = re.search(r"---\n(.*?)\n---", content, re.DOTALL)
    if not front_matter_match:
        return content  # 如果没有Front Matter,直接返回原文

    front_matter = front_matter_match.group(1)
    body = content[front_matter_match.end():].strip()

    # 处理Front Matter中的categories字段
    if "categories:" in front_matter:
        for cn_category, en_category in CATEGORY_TRANSLATIONS.items():
            front_matter = front_matter.replace(f"categories: {cn_category}", f"categories: {en_category}")

    # 重新组合Front Matter和正文
    return f"---\n{front_matter}\n---\n\n{body}"

# 遍历content目录
for root, dirs, files in os.walk(CONTENT_DIR):
    # 检查是否存在index.md但不存在index.en.md
    if "index.md" in files and "index.en.md" not in files:
        index_md_path = os.path.join(root, "index.md")
        index_en_md_path = os.path.join(root, "index.en.md")

        # 读取index.md内容
        with open(index_md_path, "r", encoding="utf-8") as f:
            content = f.read()

        # 处理Front Matter
        content = process_front_matter(content)

        # 分块翻译内容
        try:
            translated_content = translate_long_text(content)
            # 保存翻译后的内容为index.en.md
            with open(index_en_md_path, "w", encoding="utf-8") as f:
                f.write(translated_content)
            print(f"已翻译并保存:{index_en_md_path}")
        except Exception as e:
            print(f"翻译失败:{index_md_path},错误:{e}")

print("批量翻译完成!")

提示
AI 翻译速度整体来说不会很快,但 deepseek 已经是目前最快的了。 我 300 多篇文章 80 万汉字大概翻译了五个多小时,消耗 1.7 元 api 。
Hugo 的 frontmatter 部分有可能翻译失败,特别是 frontmatter 与正文衔接处,可能翻译后的结果会丢掉 --- ,翻译后建议人工排查下,大概每几篇文章就有可能出现一次。也可以在本地用 hugo server 调试是否存在错误。

启用英文站点

参照 hugo 主题配置启用。例如本站 hugo.yaml 设置如下:

  1. languageCode 设置为 zh-Hans 代表网站默认为中文,对于所有 index.md 文件,默认网址前缀是 https://lawtee.com ,对于所有 index.en.md 文件,网址前缀为 https://lawtee.com/en ,其他语言同理。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
baseurl: https://lawtee.com
languageCode: zh-Hans ## 默认为中文
languages:
    en:
        languageName: English
        title: Lawtee
        weight: 2
        params:
            sidebar:
                subtitle: Legal Practitioners
    zh-cn:
        languageName: 中文
        title: 法律小茶馆
        weight: 1
        params:
            sidebar:
                subtitle: 基层法律工作者

到这里,本地实现 AI 翻译功能已经设置完毕。后续需要翻译时,只需要在本地重新运行 python translate.py 即可自动翻译新的 index.md 文件。如果嫌麻烦,可以参照 我这篇文章 的设置,在本地设置一键启动自动翻译。另外也可以通过 Github Actions 强大的 CI/CD 工具实现自动翻译。区别在于,本地翻译结果可以先查看是否存在 Bug 再提交构建;而通过 Github Actions 自动翻译时则需要等构建后才知道是否有 Bug。

设置 Github Actions 自动翻译

  1. 在 Hugo 仓库中创建一个工作流文件 translate.yml,例如 D:/hugo/lawtee/.github/workflows/translate.yml),用于定义自动化任务,模板如下。请根据自己实际修改分支、用户名等信息。
查看代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
name: Translate Markdown Files

on:
  push:
    branches:
      - master  # 在 master 分支推送时触发

jobs:
  translate:
    runs-on: ubuntu-latest

    steps:
      # 1. 检出代码
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          persist-credentials: true 

      # 2. 设置 Python 环境
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.9'  

      # 3. 安装依赖
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install openai

      # 4. 运行翻译脚本
      - name: Run translation script
        env:
          DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}  
        run: |
          python translate.py

      # 5. 提交更改
      - name: Commit and push changes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  
        run: |
          git config --global user.name "USERNAME" # 你的 Github 用户名
          git config --global user.email "EMAIL@EMAIL.com" # 你的 Github 邮箱
          git add .
          git diff --quiet && git diff --staged --quiet || git commit -m "Auto-translate Markdown files"
          git push
  1. 在 Github 仓库设置中添加仓库密钥,Settings -> Secrets and variables -> Actions ,名称为 DEEPSEEK_API_KEY ,内容为自己的 Deepseek api KEY。( Github 禁止直接在文件中上传 API KEY,只能在仓库设置中添加)

  2. 在 Github 仓库设置 Actions -> general 中打开 Workflow permissions 的读写权限和创建、提交权限。

  3. 推送 translate.yml 和 translate.py 到 Github 仓库。

    • 注意将 translate.py 中的 CONTENT_DIR = "D:/hugo/lawtee/content/posts" 修改为仓库地址。例如:CONTENT_DIR = "content/posts"
    • 注意将 translate.py 中的 API_KEY = "sk-xxx" 修改为 API_KEY = os.getenv("DEEPSEEK_API_KEY")

如此,Github Actions 便会自动为新添加的 index.md 文档自动将其翻译为 index.en.md。

提示
建议首次使用 AI 批量翻译时全程在本地操作,方便调试,后续再使用 Github Actions 自动翻译。我在本地测试时发现批量翻译会偶发 frontmatter 翻译出错,但单篇文章翻译时暂未遇到出错现象。

Built with Hugo, Powered by Github.
全站约 328 篇文章 合计约 936278 字
本站已加入BLOGS·CN