基于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(对应<w:tab/>标签),text(对应<w:t>标签)内容。

  由于翻译接口可以使用批量翻译,因此可以将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

linux下doc转docx - 海-哥 - 博客园 (cnblogs.com)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章