DeepL 和 Google Translate 表现优秀,但其商业模式依赖云端:您的文本会经过它们的服务器,并且可能被保存或用于改进模型,具体取决于所选服务方案。对于一封无关紧要的邮件,这并不重要。但对于受保密协议(NDA)约束的合同、正在申请的专利、资产负债表或员工个人数据,这会带来切实的法律和竞争风险。
本地 AI 翻译改变了局面:模型下载到您的磁盘上,并在您的 CPU 或 GPU 上运行。没有网络请求,无需账户,也没有翻译量限制。您可以翻译一整个文件夹中的机密文档,而不会有任何一个字节离开您的电脑——即使离线、身处飞机上或使用隔离网络,也能做到。
# Récupérer un modèle multilingue adapté à la traduction
ollama pull qwen3.5:9b
# Vérifier qu'il répond
ollama run qwen3.5:9b "Traduis en anglais : Le contrat prend effet à sa signature."
终端
# Dépendances Python pour les formats de documents
pip install ollama python-docx pypdf markdown-it-py
import ollama
MODELE = "qwen3.5:9b"
SYSTEME = (
"Tu es un traducteur professionnel. Traduis le texte fourni de "
"{source} vers {cible}. Conserve le sens, le registre et la "
"terminologie technique. Ne commente pas, n'ajoute rien : "
"renvoie uniquement la traduction."
)
def traduire(texte, source="français", cible="anglais"):
reponse = ollama.chat(
model=MODELE,
messages=[
{"role": "system", "content": SYSTEME.format(source=source, cible=cible)},
{"role": "user", "content": texte},
],
options={"temperature": 0.2},
)
return reponse["message"]["content"].strip()
if __name__ == "__main__":
extrait = "Le présent contrat prend effet à la date de sa signature par les deux parties."
print(traduire(extrait))
from docx import Document
from traduire import traduire
def traduire_docx(entree, sortie, cible="anglais"):
doc = Document(entree)
for para in doc.paragraphs:
if para.text.strip():
para.text = traduire(para.text, cible=cible)
for table in doc.tables:
for ligne in table.rows:
for cellule in ligne.cells:
if cellule.text.strip():
cellule.text = traduire(cellule.text, cible=cible)
doc.save(sortie)
print(f"Traduit : {sortie}")
if __name__ == "__main__":
traduire_docx("contrat.docx", "contrat_en.docx")
!
段落包含多个文本片段(run)时,样式可能丢失
重写 para.text 会替换各个 run,并可能抹平细致的格式差异(例如一句话中某些文字的加粗效果)。对于格式复杂的文档,要获得完美的呈现效果,请逐个 run 翻译,而不是翻译整个段落——代价是这样的文本切分对模型来说不那么自然。
import ollama
SYSTEME_MD = (
"Traduis ce document Markdown en {cible}. Conserve EXACTEMENT la "
"syntaxe Markdown : titres (#), listes, liens, tableaux et blocs "
"de code. Ne traduis PAS le contenu des blocs de code. Renvoie "
"uniquement le Markdown traduit."
)
def traduire_markdown(chemin, sortie, cible="anglais"):
texte = open(chemin, encoding="utf-8").read()
reponse = ollama.chat(
model="qwen3.5:9b",
messages=[
{"role": "system", "content": SYSTEME_MD.format(cible=cible)},
{"role": "user", "content": texte},
],
options={"temperature": 0.2},
)
open(sortie, "w", encoding="utf-8").write(reponse["message"]["content"])
traduire_markdown("README.md", "README_en.md")
#PDF
PDF 是最棘手的格式:它是一种展示格式,而非内容格式。使用 pypdf 提取文本,进行翻译,再将其重新输出到新的文档中(通常为 DOCX 或生成的 PDF)。精确复现 PDF 的排版很少具有经济价值;应以可读性为目标,而非逐像素复制。
traduire_pdf.py
from pypdf import PdfReader
from docx import Document
from traduire import traduire
def pdf_vers_docx_traduit(entree, sortie, cible="anglais"):
lecteur = PdfReader(entree)
doc = Document()
for page in lecteur.pages:
texte = page.extract_text() or ""
for paragraphe in texte.split("\n\n"):
if paragraphe.strip():
doc.add_paragraph(traduire(paragraphe, cible=cible))
doc.save(sortie)
pdf_vers_docx_traduit("rapport.pdf", "rapport_en.docx")