基于PdfTranslate的docx文档翻译
项目地址:https://gitee.com/Shanyalin/pdf-tranlate
项目名称拼写错了,就先将错就错吧,懒得改动了。
由于需求扩展,要对docx文档进行兼容,因此就在pdftranslate的基础上进行了扩展。python可以通过docx库操作word文档,但是需要注意的是只能处理docx文档,python对doc格式无能为力。解决思路是先将doc转换格式为docx,再对docx进行解析翻译。由此核心问题集中在两个方面:1.不同平台doc文件格式的转换;2.docx文档解析。
不同平台doc文件格式转换
对于windows平台,使用win32com调用word把doc转换。需要注意的是doc文档路径尽量写绝对路径,且使用\\分割路径。
word = client.Dispatch('Word.Application') def doc2docx_win(filename): doc = word.Documents.Open(filename) doc.SaveAs(f'{filename}x', 12) doc.Close() return f'{filename}x'
对于linux平台,需要先安装libreoffice,使用命令将doc格式转换。有实际需要的可以将转换放在多线程里,但是python的多线程嘛,懂得都懂。
yum install libreoffice-headless libreoffice-writer --nogpgcheck
# 直接安装会提示需要gpg验证 因此需要加参数 --nogpgcheck
def doc2docx_linux(filename): outpot = subprocess.check_output(['soffice', '--headless', '--invisible', '--convert-to', 'docx', filename,'--outdir',doc_path_linux]) return f'{filename}x'
再加一个根据平台自适应的外部调用就ok了,其他平台可以根据需要自行扩展:
doc_path_win = 'E:\\works\\pdf_translate\\demo\\' doc_path_linux = '/userdata/pdf-translate/demo/' def doc2docx(filename): try: if sys.platform == 'linux': res = doc2docx_linux(f'{doc_path_linux}{filename}') else: res = doc2docx_win(f'{doc_path_win}{filename}') return res except Exception as ex: print(ex) return ''
docx文档解析
docx的解析与pdf的解析差别很大,docx中的解析是基于xml的,无法获取到文本的坐标,需要研究的对象主要包括paragraph和run。通过观察可以发现一个paragraph里包含有多个run,run通常是一个结构简单的对象,paragraph的text属性可以以拼接的方式读取到所有run的文本(如果run中放的是文本)。run对象可以添加break,picture,tab(对应
由于翻译接口可以使用批量翻译,因此可以将docx中的文本以paragraph为单位提取文本,批量翻译之后将原文译文对齐压缩成键值对,采用替换的方式来更改原docx。
但实际中出于保留图片表格之类的考虑,不直接对paragraph的text进行比较替换。
def trans_docx(doc_path, filename, src_lang='zh', is_debug=False, is_all=False): if doc_path.endswith('.doc'): docx_path = doc2docx(doc_path) if len(docx_path) == 0: return "fail" else: docx_path = doc_path doc = Document(docx_path) new_name = f'debug/{"all" if is_all else ""}{filename}' if is_debug else filename sentences = [p.text.replace('\n', '').replace('\t', '') for p in doc.paragraphs if len(p.text.replace('\n', '').replace('\t', '')) > 0] tgts, tgt_lang = translate(sentences, src_lang) # 批量翻译服务 返回译文和译文语种 dict_st = dict(zip(sentences, tgts)) for p in doc.paragraphs: key = p.text.replace('\n', '').replace('\t', '') if len(key) > 0 and key in dict_st.keys(): v = dict_st.get(key, '') v = strQ2B(v) # 译文全角转半角 if v not in key and len(key) != len(v): for r in p.runs: if r.text.strip() == p.text.strip(): # 比对run的text 来确定是否替换 r.text = f'{r.text.strip()}{v}' if is_all else v break else: # p.text是一个拼接结果时 直接替换 p.text = f'{p.text.strip()}{v}' if is_all else v doc.save(new_name) return "success"
至此,docx可实现内容翻译且尽可能保持原格式。
参考资料:
python-docx — python-docx 0.8.11 documentation