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 翻译出错,但单篇文章翻译时暂未遇到出错现象。

All textual works on this website are protected by copyright, and the authors reserve all rights. The photos on this website, unless specifically stated, licensed under the CC BY-NC-ND 4.0 license.
Built with Hugo, Powered by Github.
全站约 317 篇文章 合计约 870611 字
本站已加入BLOGS·CN