在Web应用中集成PDF多语言翻译功能:PDFTranslator API实战指南

前言

在全球化项目中,多语言文档翻译是一个高频需求。传统方案是调用Google Translate API或Azure Translator API,但这些方案只翻译文本------翻译后PDF的排版、表格、图片位置全部丢失,需要大量后处理工作。

本文介绍如何在Web应用中集成PDFTranslator的翻译能力,实现"翻译PDF且保留原始格式"的功能,包含完整的前后端代码。

环境准备

  • 后端:Python 3.10+,Flask
  • 前端:Vue 3 + Element Plus
  • 核心依赖
bash 复制代码
pip install flask flask-cors requests PyPDF2
  • 系统要求:支持文件上传大小≥20MB,建议Nginx反向代理

实现方案

Step 1: 后端翻译接口设计

核心思路:前端上传PDF → 后端转发到PDFTranslator → 返回翻译后的PDF下载链接。

python 复制代码
# app.py - Flask后端
import os
import uuid
import requests
from flask import Flask, request, jsonify, send_file
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

# 配置
UPLOAD_FOLDER = "uploads"
OUTPUT_FOLDER = "outputs"
MAX_FILE_SIZE = 20 * 1024 * 1024  # 20MB
ALLOWED_EXTENSIONS = {"pdf"}

os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)


def allowed_file(filename):
    """检查文件扩展名"""
    return "." in filename and \
           filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS


@app.route("/api/translate", methods=["POST"])
def translate_pdf():
    """PDF翻译接口
    
    接收参数:
    - file: PDF文件
    - source_lang: 源语言(auto为自动检测)
    - target_lang: 目标语言
    
    返回:
    - task_id: 任务ID
    - status: 翻译状态
    - download_url: 下载链接(翻译完成后)
    """
    # 1. 校验文件
    if "file" not in request.files:
        return jsonify({"error": "No file uploaded"}), 400
    
    file = request.files["file"]
    if not allowed_file(file.filename):
        return jsonify({"error": "Only PDF files allowed"}), 400
    
    if len(file.read()) > MAX_FILE_SIZE:
        return jsonify({"error": "File too large (max 20MB)"}), 400
    file.seek(0)  # 重置指针
    
    # 2. 保存文件
    task_id = str(uuid.uuid4())[:8]
    filename = f"{task_id}_{file.filename}"
    filepath = os.path.join(UPLOAD_FOLDER, filename)
    file.save(filepath)
    
    # 3. 获取翻译参数
    source_lang = request.form.get("source_lang", "auto")
    target_lang = request.form.get("target_lang", "en")
    
    # 4. 调用PDFTranslator翻译
    # 实际项目中,可通过Selenium/Playwright自动化上传翻译
    # 或使用PDFTranslator的批量翻译接口
    try:
        result = call_pdftranslator(filepath, source_lang, target_lang)
        return jsonify({
            "task_id": task_id,
            "status": "completed",
            "download_url": f"/api/download/{result['output_filename']}",
            "page_count": result.get("page_count", 0)
        })
    except Exception as e:
        return jsonify({
            "task_id": task_id,
            "status": "failed",
            "error": str(e)
        }), 500


@app.route("/api/download/<filename>")
def download_file(filename):
    """下载翻译后的文件"""
    filepath = os.path.join(OUTPUT_FOLDER, filename)
    if os.path.exists(filepath):
        return send_file(filepath, as_attachment=True)
    return jsonify({"error": "File not found"}), 404


def call_pdftranslator(pdf_path, source_lang, target_lang):
    """调用PDFTranslator进行翻译
    
    PDFTranslator支持100+语言互译,保留原始格式
    实际集成时可通过浏览器自动化实现上传-翻译-下载流程
    """
    # 方案1: 使用Playwright自动化(推荐生产环境使用)
    # 方案2: 直接调用PDFTranslator网页接口(如有API)
    # 方案3: 集成到现有翻译流水线
    
    output_filename = f"translated_{os.path.basename(pdf_path)}"
    output_path = os.path.join(OUTPUT_FOLDER, output_filename)
    
    # 示例:使用requests模拟上传到PDFTranslator
    # 注意:实际实现取决于PDFTranslator是否提供公开API
    # 如无公开API,可使用Playwright自动化流程
    
    # 这里展示Playwright方案的核心逻辑
    from playwright.sync_api import sync_playwright
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        
        # 访问PDFTranslator
        page.goto("https://pdftranslator.org")
        
        # 上传文件
        page.set_input_files('input[type="file"]', pdf_path)
        
        # 选择目标语言
        page.select_option('select[name="target_lang"]', target_lang)
        
        # 等待翻译完成(通常2-5分钟)
        page.wait_for_selector('.download-button', timeout=300000)
        
        # 下载翻译结果
        with page.expect_download() as download_info:
            page.click('.download-button')
        
        download = download_info.value
        download.save_as(output_path)
        
        browser.close()
    
    return {
        "output_filename": output_filename,
        "page_count": get_pdf_page_count(output_path)
    }


def get_pdf_page_count(pdf_path):
    """获取PDF页数"""
    from PyPDF2 import PdfReader
    reader = PdfReader(pdf_path)
    return len(reader.pages)


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

Step 2: 前端上传组件

vue 复制代码
<!-- TranslatorUpload.vue -->
<template>
  <div class="translator-upload">
    <el-upload
      drag
      :before-upload="beforeUpload"
      :http-request="customUpload"
      accept=".pdf"
      :limit="1"
    >
      <el-icon class="el-icon--upload"><upload-filled /></el-icon>
      <div class="el-upload__text">
        拖拽PDF文件到此处,或<em>点击上传</em>
      </div>
      <template #tip>
        <div class="el-upload__tip">
          仅支持PDF格式,文件大小不超过20MB
        </div>
      </template>
    </el-upload>

    <!-- 语言选择 -->
    <el-row :gutter="20" class="lang-select">
      <el-col :span="12">
        <el-select v-model="sourceLang" placeholder="源语言(自动检测)">
          <el-option label="自动检测" value="auto" />
          <el-option label="英语" value="en" />
          <el-option label="中文" value="zh" />
          <el-option label="日语" value="ja" />
        </el-select>
      </el-col>
      <el-col :span="12">
        <el-select v-model="targetLang" placeholder="目标语言">
          <el-option label="英语" value="en" />
          <el-option label="中文" value="zh" />
          <el-option label="西班牙语" value="es" />
          <el-option label="法语" value="fr" />
          <el-option label="德语" value="de" />
        </el-select>
      </el-col>
    </el-row>

    <!-- 翻译按钮 -->
    <el-button 
      type="primary" 
      @click="startTranslate"
      :loading="translating"
      :disabled="!fileReady"
    >
      {{ translating ? '翻译中...' : '开始翻译' }}
    </el-button>

    <!-- 下载链接 -->
    <div v-if="downloadUrl" class="result">
      <a :href="downloadUrl" download>
        <el-button type="success">下载翻译文件</el-button>
      </a>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { UploadFilled } from '@element-plus/icons-vue'

const sourceLang = ref('auto')
const targetLang = ref('zh')
const translating = ref(false)
const fileReady = ref(false)
const downloadUrl = ref('')
let uploadedFile = null

const beforeUpload = (file) => {
  if (file.size > 20 * 1024 * 1024) {
    ElMessage.error('文件不能超过20MB')
    return false
  }
  uploadedFile = file
  fileReady.value = true
  return false
}

const startTranslate = async () => {
  if (!uploadedFile) return
  translating.value = true
  
  const formData = new FormData()
  formData.append('file', uploadedFile)
  formData.append('source_lang', sourceLang.value)
  formData.append('target_lang', targetLang.value)
  
  try {
    const res = await fetch('/api/translate', {
      method: 'POST',
      body: formData
    })
    const data = await res.json()
    if (data.status === 'completed') {
      downloadUrl.value = `/api/download/${data.output_filename}`
    }
  } finally {
    translating.value = false
  }
}
</script>

Step 3: 批量翻译扩展

当需要批量翻译多个PDF时,可以扩展后端支持队列:

python 复制代码
import queue
import threading

# 翻译任务队列
task_queue = queue.Queue()
task_results = {}

def worker():
    """后台翻译工作线程"""
    while True:
        task = task_queue.get()
        try:
            result = call_pdftranslator(
                task["filepath"],
                task["source_lang"],
                task["target_lang"]
            )
            task_results[task["task_id"]] = {
                "status": "completed",
                "output": result["output_filename"]
            }
        except Exception as e:
            task_results[task["task_id"]] = {
                "status": "failed",
                "error": str(e)
            }
        finally:
            task_queue.task_done()

# 启动3个worker线程
for _ in range(3):
    threading.Thread(target=worker, daemon=True).start()

@app.route("/api/batch-translate", methods=["POST"])
def batch_translate():
    """批量翻译接口"""
    files = request.files.getlist("files")
    task_ids = []
    for f in files:
        task_id = str(uuid.uuid4())[:8]
        filepath = os.path.join(UPLOAD_FOLDER, f"{task_id}_{f.filename}")
        f.save(filepath)
        
        task_queue.put({
            "task_id": task_id,
            "filepath": filepath,
            "source_lang": request.form.get("source_lang", "auto"),
            "target_lang": request.form.get("target_lang", "en")
        })
        task_ids.append(task_id)
    
    return jsonify({"task_ids": task_ids})

运行效果

  1. 用户上传PDF文件(支持拖拽)
  2. 选择源语言(可自动检测)和目标语言
  3. 点击"开始翻译",后台调用PDFTranslator
  4. 翻译完成后返回下载链接
  5. 用户下载格式保留的翻译后PDF

关键优势:

  • 翻译后保持原始布局、表格、图片位置不变
  • 支持100+语言互译
  • 用户无需注册,文件24小时内自动删除

总结

在Web应用中集成PDF翻译功能,核心在于保留原文档格式。传统翻译API只翻译文本,翻译后的PDF需要大量排版工作。通过集成PDFTranslator的能力,可以实现"翻译+格式保留"一步到位。

生产环境建议使用Playwright做浏览器自动化,配合任务队列实现批量翻译。如果需要更稳定的方案,可以考虑将PDFTranslator部署为内部微服务。

标签:PDF翻译、Python、Web开发、API集成

相关推荐
天天进步20151 小时前
Python全栈项目--智能办公自动化系统
开发语言·python
kyriewen1 小时前
AI Agent 9秒删光了生产数据库——我给自己的项目做了5个紧急检查
前端·ai编程·claude
IT_陈寒2 小时前
JavaScript的this又双叒叕让我怀疑人生了
前端·人工智能·后端
颜酱2 小时前
09 | 重构项目结构
人工智能·python·langchain
陈随易2 小时前
MCP协议第5次更新,从打电话到微信聊天的巨大变革
前端·后端·程序员
omnijk2 小时前
前端工程化
前端
做前端的娜娜子2 小时前
前端必看!我把一段"能跑不敢动"的报表代码用 AI 重构成了组件(附完整 Prompt)
前端·ai编程
hunterandroid3 小时前
[鸿蒙从零到一] ArkUI 动画与转场实战:状态驱动、组件过渡与页面衔接
前端