欢迎光临
我们一直在努力

CI/CD流水线集成文档翻译:Jenkins自动化方案

前言

在 DevOps 实践中,文档往往是被自动化流水线遗忘的一环。代码有 CI/CD,但文档翻译还靠手动上传下载。本文分享如何将 PDF 文档翻译集成到 Jenkins 流水线中,实现代码提交后自动翻译技术文档。

场景描述

团队维护一个多语言技术文档仓库,英文文档为源文件。每次更新英文文档后,需要同步生成中文、日文、西班牙文版本。手动操作耗时且容易遗漏。

目标:git push 后 Jenkins 自动触发翻译流水线,翻译完成后提交到对应语言的分支。

环境准备

  • Jenkins 2.400+
  • Python 3.10+(Jenkins agent 上安装)
  • 依赖:pip install requests pyyaml
  • Git plugin for Jenkins
  • PDFTranslator API 访问权限

实现步骤

Step 1: 编写翻译脚本

#!/usr/bin/env python3
"""
doc_translator.py – CI/CD 流水线文档翻译脚本
读取配置文件,批量翻译指定目录下的PDF文档
"""

import os
import sys
import time
import json
import requests
from pathlib import Path
from typing import List, Dict

class DocTranslator:
"""PDF文档翻译器,适配CI/CD流水线"""

def __init__(self, config_path: str = "translate_config.yml"):
self.config = self._load_config(config_path)
self.api_base = "https://pdftranslator.org/api"
self.timeout = 300 # 单文件超时5分钟

def _load_config(self, path: str) > Dict:
"""加载翻译配置"""
import yaml
with open(path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)

def translate_file(self, pdf_path: str, source_lang: str,
target_lang: str) > str:
"""翻译单个PDF文件,返回下载URL

Args:
pdf_path: PDF文件路径
source_lang: 源语言(auto为自动检测)
target_lang: 目标语言代码

Returns:
翻译结果下载URL

Raises:
Exception: 翻译失败时抛出异常
"""
# Step 1: 上传文件
with open(pdf_path, "rb") as f:
resp = requests.post(
f"{self.api_base}/upload",
files={"file": f},
data={"source_lang": source_lang, "target_lang": target_lang},
timeout=60
)
resp.raise_for_status()
job_id = resp.json()["job_id"]

# Step 2: 轮询翻译状态
start_time = time.time()
while time.time() start_time < self.timeout:
time.sleep(5)
status_resp = requests.get(
f"{self.api_base}/status/{job_id}",
timeout=30
)
status_resp.raise_for_status()
result = status_resp.json()

if result["status"] == "completed":
return result["download_url"]
elif result["status"] == "failed":
raise Exception(f"Translation failed: {result.get('error')}")

raise TimeoutError(f"Translation timeout for {pdf_path}")

def download_file(self, url: str, output_path: str):
"""下载翻译结果"""
resp = requests.get(url, timeout=120)
resp.raise_for_status()
with open(output_path, "wb") as f:
f.write(resp.content)

def run(self) > Dict:
"""执行翻译流水线

Returns:
执行结果摘要
"""
source_dir = self.config["source_dir"]
target_langs = self.config["target_languages"]
output_base = self.config.get("output_dir", "./translated")

pdf_files = list(Path(source_dir).glob("**/*.pdf"))
if not pdf_files:
return {"status": "skipped", "reason": "No PDF files found"}

results = {"total": 0, "success": 0, "failed": 0, "details": []}

for lang in target_langs:
lang_dir = os.path.join(output_base, lang)
os.makedirs(lang_dir, exist_ok=True)

for pdf_file in pdf_files:
results["total"] += 1
rel_path = pdf_file.relative_to(source_dir)
output_path = os.path.join(lang_dir, str(rel_path))
os.makedirs(os.path.dirname(output_path), exist_ok=True)

try:
print(f"[INFO] Translating {rel_path} -> {lang}")
download_url = self.translate_file(
str(pdf_file), "auto", lang
)
self.download_file(download_url, output_path)
results["success"] += 1
results["details"].append({
"file": str(rel_path),
"lang": lang,
"status": "success"
})
print(f"[OK] {rel_path} -> {lang}")
except Exception as e:
results["failed"] += 1
results["details"].append({
"file": str(rel_path),
"lang": lang,
"status": "failed",
"error": str(e)
})
print(f"[FAIL] {rel_path} -> {lang}: {e}")

return results

if __name__ == "__main__":
translator = DocTranslator()
result = translator.run()
print(json.dumps(result, indent=2, ensure_ascii=False))

# CI/CD 退出码:有失败则返回1
if result["failed"] > 0:
sys.exit(1)

Step 2: 创建配置文件

# translate_config.yml
source_dir: "./docs/en" # 英文源文档目录
output_dir: "./docs" # 输出根目录
target_languages: # 目标语言列表
"zh" # 中文
"ja" # 日文
"es" # 西班牙文

Step 3: 编写 Jenkinsfile

pipeline {
agent any

environment {
PYTHON_PATH = '/usr/bin/python3'
VENV_DIR = '.venv'
}

triggers {
// 监听 docs/ 目录的变更
pollSCM('H/5 * * * *')
}

stages {
stage('Checkout') {
steps {
checkout scm
}
}

stage('Setup Python') {
steps {
sh '''
${PYTHON_PATH} -m venv ${VENV_DIR}
. ${VENV_DIR}/bin/activate
pip install requests pyyaml
'''

}
}

stage('Detect Changes') {
steps {
script {
// 检查 docs/en/ 目录是否有变更
def changes = sh(
script: "git diff –name-only HEAD~1 HEAD — docs/en/",
returnStdout: true
).trim()

if (!changes) {
echo "No document changes detected. Skipping."
currentBuild.result = 'NOT_BUILT'
return
}
echo "Changed files:\\n${changes}"
}
}
}

stage('Translate Documents') {
steps {
sh '''
. ${VENV_DIR}/bin/activate
python doc_translator.py
'''

}
}

stage('Commit Translations') {
steps {
sh '''
git config user.name "Jenkins CI"
git config user.email "jenkins@company.com"
git add docs/
git commit -m "Auto-translate documents [skip ci]" || echo "No changes to commit"
git push origin ${env.BRANCH_NAME}
'''

}
}
}

post {
success {
echo "Document translation pipeline completed successfully."
}
failure {
echo "Document translation pipeline failed!"
// 发送通知
emailext(
subject: "Translation Pipeline Failed: ${env.JOB_NAME}",
body: "Check: ${env.BUILD_URL}",
to: "${env.TEAM_EMAIL}"
)
}
}
}

Step 4: 配置 Jenkins Job

  • 创建新的 Pipeline 任务
  • Pipeline 定义选择 “Pipeline script from SCM”
  • 指定仓库地址和分支
  • Script Path 填写 Jenkinsfile
  • 保存并构建
  • 运行效果

    Jenkins 构建日志示例:

    [INFO] Translating api-guide.pdf -> zh
    [OK] api-guide.pdf -> zh
    [INFO] Translating api-guide.pdf -> ja
    [OK] api-guide.pdf -> ja
    [INFO] Translating api-guide.pdf -> es
    [OK] api-guide.pdf -> es
    [INFO] Translating architecture.pdf -> zh
    [OK] architecture.pdf -> zh

    {
    "total": 9,
    "success": 9,
    "failed": 0,
    "details": […]
    }

    3个文件 × 3种语言 = 9个翻译任务,总耗时约15分钟。翻译完成后自动提交到仓库。

    优化建议

    1. 并发翻译

    在 doc_translator.py 中引入 ThreadPoolExecutor:

    from concurrent.futures import ThreadPoolExecutor, as_completed

    # 在 run() 方法中替换串行循环
    with ThreadPoolExecutor(max_workers=3) as executor:
    futures = []
    for lang in target_langs:
    for pdf_file in pdf_files:
    future = executor.submit(self._translate_one, pdf_file, lang)
    futures.append(future)

    for future in as_completed(futures):
    result = future.result()
    # 处理结果

    3线程并发可将9个任务的总耗时从15分钟压缩到5分钟。

    2. 增量翻译

    只翻译有变更的文件,避免重复翻译:

    import hashlib

    def get_file_hash(filepath: str) > str:
    """计算文件MD5,用于判断是否需要重新翻译"""
    with open(filepath, "rb") as f:
    return hashlib.md5(f.read()).hexdigest()

    # 在翻译前检查文件是否变更
    hash_file = ".translation_hashes.json"
    stored_hashes = json.load(open(hash_file)) if os.path.exists(hash_file) else {}

    current_hash = get_file_hash(str(pdf_file))
    key = f"{rel_path}_{lang}"
    if stored_hashes.get(key) == current_hash:
    print(f"[SKIP] {key} unchanged")
    continue

    3. 失败重试与通知

    在 Jenkinsfile 中添加重试逻辑:

    stage('Translate Documents') {
    steps {
    retry(3) {
    sh '''
    . ${VENV_DIR}/bin/activate
    python doc_translator.py
    '''

    }
    }
    }

    总结

    将文档翻译集成到CI/CD流水线后,团队不再需要手动翻译文档。开发者更新英文文档后,Jenkins自动翻译并提交多语言版本,整个过程无需人工干预。

    核心收益:

    • 自动化:git push 触发,零手动操作
    • 多语言:一次配置,同步生成多种语言版本
    • 格式保留:PDFTranslator保留原文档排版,翻译后直接可用
    • 可追溯:翻译记录在Git历史中,方便回溯

    标签:CI/CD、Jenkins、自动化、PDF翻译、DevOps

    赞(0)
    未经允许不得转载:171主机测评 » CI/CD流水线集成文档翻译:Jenkins自动化方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址