用 Ollama + Python 搭建完全离线的 AI 翻译工具。支持文档批量翻译、术语一致性管理、自定义翻译风格。隐私安全,零成本,告别付费翻译 API。
你要翻译一份英文技术文档,丢给 Google 翻译,术语翻得一塌糊涂。用 DeepL,一个字符一次,月底账单看着心疼。丢给 ChatGPT,又担心内容泄露。
我上个月翻译了一份 30 页的产品说明书,全是技术术语。DeepL 翻出来的中文读着别扭,改了两小时还是不满意。最后我花了三个小时搭了这个本地翻译工具,Ollama 跑在本地,翻译质量比机翻好太多,术语还保持一致。
现在翻译 30 页文档,二十分钟搞定。
项目背景
传统翻译工具的问题是:
- 在线翻译:隐私风险,内容传给别人服务器
- 付费 API:按字符计费,大批量翻译成本太高
- 机翻工具:术语不统一,同一段话翻出三个版本
本地 Ollama 完美解决这些问题。文档完全在本地处理,术语可以定制,翻译质量接近人工。
一个 Python 脚本 + Ollama 就够了。
技术选型
| 组件 | 选型 | 理由 |
|---|---|---|
| 语言 | Python 3.10+ | 生态成熟 |
| LLM | Ollama + Qwen2.5-7B | 中文翻译能力强,7B 模型 8GB 内存够跑 |
| 文档解析 | python-docx + PyPDF2 | 支持 .docx 和 .pdf |
| 术语管理 | JSON 文件 | 简单直观,随时编辑 |
实现步骤
第一步:安装 Ollama 和模型
# 安装 Ollama
curl -fsSL https://ollama.com/install.sh | sh
# 拉取翻译模型,qwen2.5-7b 翻译质量很好,8GB 内存就能跑
ollama pull qwen2.5:7b
如果想更省资源,用 qwen2.5:3b,翻译质量略降但速度更快。
第二步:项目结构
local-translator/
├── config/
│ └── terms.json # 术语表
├── documents/ # 放待翻译文档
├── output/ # 翻译结果输出
├── translator.py # 主脚本
└── requirements.txt
第三步:术语表配置
新建 config/terms.json:
{
"source_lang": "en",
"target_lang": "zh",
"terms": {
"latency": "延迟",
"throughput": "吞吐量",
"idempotent": "幂等的",
"eventual consistency": "最终一致性",
"circuit breaker": "熔断器",
"rate limiting": "速率限制",
"microservice": "微服务"
}
}
术语表就是翻译时的"标准答案",模型会优先用这些翻译,保证全文术语一致。
第四步:翻译核心脚本
新建 translator.py:
#!/usr/bin/env python3
"""本地 AI 翻译工具:支持 .docx / .pdf 文档批量翻译"""
import json
import sys
from pathlib import Path
import ollama
# ============ 配置 ============
BASE_DIR = Path(__file__).parent
CONFIG_DIR = BASE_DIR / "config"
TERMS_PATH = CONFIG_DIR / "terms.json"
OUTPUT_DIR = BASE_DIR / "output"
OUTPUT_DIR.mkdir(exist_ok=True)
# ============ 加载术语表 ============
def load_terms() -> dict:
with open(TERMS_PATH) as f:
cfg = json.load(f)
return cfg.get("terms", {})
# ============ 文档读取 ============
def read_docx(path: Path) -> str:
"""读取 .docx 文档内容"""
from docx import Document
doc = Document(path)
return "\n".join(p.text for p in doc.paragraphs if p.text.strip())
def read_pdf(path: Path) -> str:
"""读取 .pdf 文档内容"""
import PyPDF2
text_parts = []
with open(path, "rb") as f:
reader = PyPDF2.PdfReader(f)
for page in reader.pages:
t = page.extract_text()
if t:
text_parts.append(t)
return "\n".join(text_parts)
def read_text(path: Path) -> str:
return path.read_text(encoding="utf-8")
def read_document(path: Path) -> str:
if path.suffix == ".docx":
return read_docx(path)
elif path.suffix == ".pdf":
return read_pdf(path)
elif path.suffix == ".txt":
return read_text(path)
else:
raise ValueError(f"不支持的文件类型: {path.suffix}")
# ============ 翻译核心 ============
def translate_chunk(text: str, terms: dict, model: str = "qwen2.5:7b") -> str:
"""翻译一段文本,插入术语表保证一致性"""
# 构建术语提示
term_hint = ""
if terms:
lines = [f"- {k} → {v}" for k, v in terms.items()]
term_hint = "\n请优先使用以下术语翻译:\n" + "\n".join(lines)
prompt = f"""你是一个专业的技术翻译助手。请将以下英文文本翻译成中文,要求:
1. 翻译准确、流畅,符合中文技术文档的表达习惯
2. 专业术语保持一致{term_hint}
3. 保留原文的段落结构和格式
4. 直接输出翻译结果,不要加任何解释
原文:
{text}
中文翻译:
"""
response = ollama.chat(model=model, messages=[{"role": "user", "content": prompt}])
return response["message"]["content"].strip()
# ============ 批量翻译 ============
def translate_document(doc_path: Path, model: str = "qwen2.5:7b", chunk_size: int = 2000):
"""翻译整个文档,分段处理避免超出上下文限制"""
terms = load_terms()
raw_text = read_document(doc_path)
if not raw_text.strip():
print(f"⚠️ 文档内容为空:{doc_path.name}")
return
print(f"📄 正在翻译:{doc_path.name}(共 {len(raw_text)} 字)")
# 分段翻译
chunks = [raw_text[i:i + chunk_size] for i in range(0, len(raw_text), chunk_size)]
translated_parts = []
for i, chunk in enumerate(chunks):
print(f" 段落 {i + 1}/{len(chunks)} ...")
translated = translate_chunk(chunk, terms, model)
translated_parts.append(translated)
full_translation = "\n\n".join(translated_parts)
# 输出到文件
out_name = doc_path.stem + "_translated" + doc_path.suffix
out_path = OUTPUT_DIR / out_name
out_path.write_text(full_translation, encoding="utf-8")
print(f"✅ 翻译完成,已保存:{out_path}")
return out_path
# ============ 命令行入口 ============
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="本地 AI 翻译工具")
parser.add_argument("document", nargs="?", help="要翻译的文档路径(.docx/.pdf/.txt)")
parser.add_argument("--batch", "-b", action="store_true", help="批量翻译 documents/ 目录下的所有文档")
parser.add_argument("--model", "-m", default="qwen2.5:7b", help="Ollama 模型名称")
args = parser.parse_args()
if args.batch:
docs = list((BASE_DIR / "documents").glob("*"))
docs = [d for d in docs if d.suffix in (".docx", ".pdf", ".txt")]
if not docs:
print("📁 documents/ 目录下没有找到可翻译的文档")
sys.exit(1)
print(f"🔍 发现 {len(docs)} 个待翻译文档\n")
for doc in docs:
translate_document(doc, args.model)
print()
elif args.document:
doc_path = Path(args.document)
if not doc_path.exists():
print(f"❌ 文件不存在:{doc_path}")
sys.exit(1)
translate_document(doc_path, args.model)
else:
parser.print_help()
第五步:requirements.txt
ollama
python-docx
PyPDF2
pip install -r requirements.txt
第六步:使用
翻译单个文件:
python translator.py documents/product_spec.docx
批量翻译整个目录:
python translator.py --batch
翻译结果自动保存到 output/ 目录。
运行效果
$ python translator.py --batch
🔍 发现 3 个待翻译文档
📄 正在翻译:product_spec.docx(共 4832 字)
段落 1/3 ...
段落 2/3 ...
段落 3/3 ...
✅ 翻译完成,已保存:output/product_spec_translated.docx
📄 正在翻译:api_guide.pdf(共 6120 字)
段落 1/4 ...
段落 2/4 ...
段落 3/4 ...
段落 4/4 ...
✅ 翻译完成,已保存:output/api_guide_translated.pdf
翻译质量对比:
| 翻译方式 | “circuit breaker” | “eventual consistency” | 整体流畅度 |
|---|---|---|---|
| Google 翻译 | 电路断路器 | 事件最终一致性 | ⭐⭐ |
| DeepL | 断路器 | 最终一致性 | ⭐⭐⭐⭐ |
| 本文工具(带术语表) | 熔断器 | 最终一致性 | ⭐⭐⭐⭐⭐ |
术语表让同一篇文档里,“circuit breaker” 不会出现两种翻法。
优化方向
- 更快的模型:换
qwen2.5:3b或deepseek-r1:1.5b,翻译速度翻倍,质量略降 - GPU 加速:显存 8GB 以上可以跑量化版本,翻译速度提升 5-10 倍
- 自定义风格:在术语表里加
style字段,指定"技术文档风格"或"通俗风格" - 翻译后校对:用
diff命令对比原文和译文,快速定位差异大的段落 - 添加更多格式支持:补充
.pptx、.md解析,覆盖更多场景
术语表这个设计特别实用——你只配一次,以后翻译同类文档自动生效。试试看,你的文档翻译效率至少翻三倍。
这篇文章对你有帮助吗?