技术文档国际化实战:用Python+PDFTranslator实现自动化文档翻译流水线

前言

团队最近要发布产品的多语言文档,需要把50多份中文技术文档翻译成英文版。手动上传、下载、校对,一份文档就要花十几分钟。作为一个程序员,第一反应当然是:能不能自动化?

答案是能。虽然PDFTranslator是个Web端工具,但结合Python的自动化能力,可以搭建一套半自动的文档翻译流水线,大幅提升效率。这篇文章记录完整的实现方案。

环境准备

  • Python 3.10+
  • 依赖库:
pip install requests beautifulsoup4 watchdog openpyxl
  • 浏览器:Chrome/Edge(用于手动上传下载环节)
  • 文件组织:源文档放在 docs/source/,翻译后输出到 docs/output/

整体架构

docs/source/    →    [Python Watcher]    →    [PDFTranslator]    →    docs/output/
  (待翻译文档)          (文件监控+调度)          (在线翻译)            (翻译后文档)
                              ↓
                       [翻译记录.xlsx]
                         (状态追踪)

核心思路:用Python监控源文件夹变化 → 自动检测新文件 → 提示上传翻译 → 轮询下载状态 → 归档。

实现步骤

Step 1: 文件监控模块

使用 watchdog 库监控源文件夹,自动发现新文件:

import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from pathlib import Path


class TranslationHandler(FileSystemEventHandler):
    """监控源文件夹,发现新PDF文件"""
    
    def __init__(self, callback):
        self.callback = callback
    
    def on_created(self, event):
        # 只处理PDF文件
        if not event.is_directory and event.src_path.endswith('.pdf'):
            print(f"[检测到新文件] {event.src_path}")
            self.callback(Path(event.src_path))


def start_watcher(source_dir: str, callback):
    """启动文件监控"""
    observer = Observer()
    handler = TranslationHandler(callback)
    observer.schedule(handler, source_dir, recursive=False)
    observer.start()
    print(f"[监控已启动] 监听目录: {source_dir}")
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

Step 2: 翻译任务队列

多文档并行管理,需要一个任务队列追踪每份文档的状态:

import openpyxl
from datetime import datetime
from enum import Enum


class TranslationStatus(Enum):
    PENDING = "待翻译"       # 文件已检测到,等待上传
    UPLOADED = "已上传"      # 已上传到翻译平台
    TRANSLATING = "翻译中"   # 平台正在处理
    COMPLETED = "已完成"     # 翻译完成,可以下载
    FAILED = "失败"          # 翻译失败


class TranslationQueue:
    """翻译任务队列,用Excel做持久化存储"""
    
    def __init__(self, excel_path: str):
        self.excel_path = excel_path
        self._init_excel()
    
    def _init_excel(self):
        """初始化Excel记录表"""
        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = "翻译记录"
        ws.append(["文件名", "源语言", "目标语言", "文件大小(KB)", 
                   "提交时间", "状态", "完成时间", "输出路径", "备注"])
        
        ws.column_dimensions['A'].width = 40
        ws.column_dimensions['H'].width = 40
        wb.save(self.excel_path)
    
    def add_task(self, file_path: Path, target_lang: str = "en"):
        """添加新翻译任务"""
        wb = openpyxl.load_workbook(self.excel_path)
        ws = wb["翻译记录"]
        
        file_size = round(file_path.stat().st_size / 1024, 1)
        ws.append([
            file_path.name,
            "zh",
            target_lang,
            file_size,
            datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            TranslationStatus.PENDING.value,
            "", "", f"源路径: {file_path}"
        ])
        wb.save(self.excel_path)
        print(f"[任务已创建] {file_path.name}{target_lang}")
    
    def update_status(self, filename: str, status: TranslationStatus, 
                      output_path: str = "", note: str = ""):
        """更新任务状态"""
        wb = openpyxl.load_workbook(self.excel_path)
        ws = wb["翻译记录"]
        
        for row in ws.iter_rows(min_row=2):
            if row[0].value == filename:
                row[5].value = status.value
                if status == TranslationStatus.COMPLETED:
                    row[6].value = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    row[7].value = output_path
                if note:
                    row[8].value = note
                break
        
        wb.save(self.excel_path)
    
    def get_pending_tasks(self) -> list:
        """获取待处理的任务"""
        wb = openpyxl.load_workbook(self.excel_path)
        ws = wb["翻译记录"]
        pending = []
        for row in ws.iter_rows(min_row=2, values_only=True):
            if row and row[5] == TranslationStatus.PENDING.value:
                pending.append(row[0])
        return pending


# 使用示例
queue = TranslationQueue("翻译记录.xlsx")
queue.add_task(Path("docs/source/api-reference.pdf"), target_lang="en")
queue.update_status("api-reference.pdf", TranslationStatus.UPLOADED)

Step 3: 翻译平台调度流程

虽然上传下载需要手动操作(Web端限制),但可以用Python管理整个流程:

import subprocess
import webbrowser
from pathlib import Path


class PDFTranslatorPipeline:
    """PDF翻译自动化调度"""
    
    TRANSLATOR_URL = "https://pdftranslator.org"
    SOURCE_DIR = Path("docs/source")
    OUTPUT_DIR = Path("docs/output")
    
    def __init__(self):
        self.queue = TranslationQueue("翻译记录.xlsx")
        self.OUTPUT_DIR.mkdir(exist_ok=True)
    
    def process_next(self):
        """处理下一个待翻译文件(交互式)"""
        pending = self.queue.get_pending_tasks()
        if not pending:
            print("✅ 没有待处理的翻译任务")
            return
        
        filename = pending[0]
        filepath = self.SOURCE_DIR / filename
        
        print(f"\n{'='*50}")
        print(f"📄 当前文件: {filename}")
        print(f"📏 大小: {filepath.stat().st_size / 1024:.1f} KB")
        print(f"{'='*50}")
        
        # 1. 打开翻译平台(手动上传)
        print(f"\n🖱️  请在浏览器中操作:")
        print(f"   1. 打开 {self.TRANSLATOR_URL}")
        print(f"   2. 上传文件: {filepath}")
        print(f"   3. 选择目标语言: English")
        print(f"   4. 点击翻译")
        
        # 2. 打开本地文件夹(方便拖拽)
        webbrowser.open(self.TRANSLATOR_URL)
        
        # 3. 标记为已上传
        self.queue.update_status(filename, TranslationStatus.UPLOADED)
        
        input("\n⏳ 翻译完成后按Enter继续...")
        
        # 4. 引导下载到输出目录
        print(f"\n📥 请下载翻译文件到: {self.OUTPUT_DIR}")
        output_file = self.OUTPUT_DIR / f"translated_{filename}"
        self.queue.update_status(
            filename, 
            TranslationStatus.COMPLETED,
            output_path=str(output_file)
        )
        print(f"✅ {filename} 翻译完成!")
    
    def batch_summary(self):
        """查看批量翻译摘要"""
        print("\n📊 翻译任务摘要")
        print("-" * 60)
        wb = openpyxl.load_workbook("翻译记录.xlsx")
        ws = wb["翻译记录"]
        
        total = ws.max_row - 1
        completed = sum(
            1 for row in ws.iter_rows(min_row=2, values_only=True)
            if row[5] == TranslationStatus.COMPLETED.value
        )
        print(f"总数: {total} | 已完成: {completed} | 待处理: {total - completed}")
        print("-" * 60)


# 运行示例
pipeline = PDFTranslatorPipeline()
pipeline.batch_summary()
pipeline.process_next()

Step 4: 批量文档预处理

翻译前可以对文档做批量预处理,提高效率:

import shutil
from pathlib import Path


def preprocess_docs(source_dir: str, max_size_mb: float = 19.0):
    """预处理文档:检查大小、统一命名、分类"""
    source = Path(source_dir)
    
    for pdf_file in source.glob("*.pdf"):
        size_mb = pdf_file.stat().st_size / (1024 * 1024)
        
        # 检查文件大小(PDFTranslator限制20MB)
        if size_mb > max_size_mb:
            print(f"⚠️  {pdf_file.name} 过大 ({size_mb:.1f}MB),建议先压缩")
            continue
        
        # 规范化文件名
        new_name = pdf_file.name.replace(" ", "_").replace("(", "(").replace(")", ")")
        if new_name != pdf_file.name:
            new_path = pdf_file.with_name(new_name)
            pdf_file.rename(new_path)
            print(f"📝 重命名: {pdf_file.name}{new_name}")
        
        print(f"✅ {pdf_file.name} ({size_mb:.1f}MB) — 就绪")


def postprocess_docs(output_dir: str, prefix: str = "EN_"):
    """后处理:给翻译文件添加语言前缀、归档原文件"""
    output = Path(output_dir)
    archive = output / "_archive"
    archive.mkdir(exist_ok=True)
    
    for pdf_file in output.glob("*.pdf"):
        # 已有前缀的跳过
        if pdf_file.name.startswith(prefix):
            continue
        
        # 添加语言前缀
        new_path = pdf_file.with_name(f"{prefix}{pdf_file.name}")
        pdf_file.rename(new_path)
    
    print(f"✅ 文档后处理完成,前缀: {prefix}")


# 使用
preprocess_docs("docs/source")

完整工作流

def main():
    """完整翻译流水线入口"""
    import sys
    
    print("=" * 55)
    print("  📄 PDF文档翻译自动化流水线")
    print("=" * 55)
    
    pipeline = PDFTranslatorPipeline()
    
    while True:
        print("\n命令: [n]下一个 [s]摘要 [p]预处理 [q]退出")
        cmd = input("> ").strip().lower()
        
        if cmd == "n":
            pipeline.process_next()
        elif cmd == "s":
            pipeline.batch_summary()
        elif cmd == "p":
            preprocess_docs("docs/source")
        elif cmd == "q":
            print("👋 流水线已停止")
            break
        else:
            print("未知命令")


if __name__ == "__main__":
    main()

运行效果

运行后,终端会显示清晰的步骤指引:

==================================================
  📄 PDF文档翻译自动化流水线
==================================================
📊 翻译任务摘要
------------------------------------------------------------
总数: 52 | 已完成: 38 | 待处理: 14
------------------------------------------------------------

命令: [n]下一个 [s]摘要 [p]预处理 [q]退出
> n

==================================================
📄 当前文件: api-reference-v2.3.pdf
📏 大小: 3.2 MB
==================================================

🖱️  请在浏览器中操作:
   1. 打开 https://pdftranslator.org
   2. 上传文件: docs/source/api-reference-v2.3.pdf
   3. 选择目标语言: English
   4. 点击翻译

⏳ 翻译完成后按Enter继续...

优化建议

  1. 并发处理:如果有多台设备,可以分别上传不同文件,并行翻译
  2. 自动分类:根据文件名关键词(contract/report/manual)自动选择翻译策略
  3. 质量检查:翻译后自动对比文件页数、关键元素是否完整
  4. 通知集成:翻译完成时通过Webhook通知(企业微信/钉钉)

总结

这套方案虽然上传下载环节还需要手动操作,但已经把整个翻译流程的组织、追踪、归档做了系统化管理。50多份技术文档从"散落一桌不知道翻译了哪些"变成了清晰的状态追踪,效率提升明显。

核心价值不在于完全自动化(Web端工具天然有限制),而在于把重复的决策变成了自动化的流程——不用每次都想"这个文件翻了没?放哪了?还要翻什么?"

完整代码已上传,欢迎Star和PR。

标签:Python自动化、PDF翻译、技术文档、效率工具、国际化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值