基於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)

 

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