項目地址: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)