Google Translate にMarkDown文書の翻訳する

pythonでGoogle Translate APIを使用して、MarkDown文書を翻訳するコードを実装しました。 たとえば、ハングルで書かれたMarkDownファイルが ko.mdならこれ日本語に翻訳してja.mdという名前のファイルにしてくれるでしょう。

もちろん、MarkDownのすべての文法の例外処理をしていなくて、いくつかのは、手作業で修正してくれるとします。

私GatsbyJSでBlogを作成しており、GatsbyJSは次のようなMarkDownを読み込みます。

---
title: Google Translate(Google翻訳)にMarkDown翻訳する
date: 2019-12-08
tags: [python, python-example]
description: pythonでGoogle Translate APIを利用して、MarkDown文書を翻訳するコードを実装しました。 GatsbyJSで使用するMarkDown形式であり、希望の言語に翻訳をして、ファイルに出力します。私の実装したコードを共有します。
---
本文......

上記のMarkDownでmeta-dataはtitleとdescriptionのみ翻訳します。 そして本文はすべて翻訳する必要があります。

MarkDown parserは翻訳が必要な部分を探してGoogle Translate APIを介して翻訳します。 翻訳が必要としていない部分は、単にファイルに出力するように実装します。

私が作ったツールは、次のようなコマンドで実行することができます。 引数は3つの伝達し、 ko.md翻訳するドキュメントであり、en.mdは翻訳後生成するファイルの名前です。最後に、 enは翻訳したい言語のlocaleです。

$ python3 translate.py ko.md en.md en

あなたが必要か参考することの方がいるかどうか分からない、ここにコードを共有します。

translate.py

#!/usr/bin/env python3
from google.cloud import translate_v2 as translate
import sys
import os

SEPARATOR_META_DATA = "---"
SEPARATOR_CODE = "```"
SEPARATOR_IMG = "!["
SEPARATOR_IMG_CODE = "<img"
STR_TITLE = "title:"
STR_STAR = "*"
STR_SHARP = "#"
STR_DESCRIPTION = "description:"

translate_client = translate.Client()
USE_GOOGLE_TRANS = True

def is_english(text):
    for c in text:
        if not 0 <= ord(c) <= 128:
            return False
    return True

def correct_code_text(old, new):
    CHAR_CODE = '`'
    old_code_cnt = old.count(CHAR_CODE)
    new_code_cnt = new.count(CHAR_CODE)
    result = new
    if (old_code_cnt == new_code_cnt) and (old_code_cnt%2 == 0) and (new_code_cnt%2 == 0):
        old_idx = 0
        new_idx = 0
        for i in range(0, int(old_code_cnt/2)):
            first_old = old.index(CHAR_CODE, old_idx)
            old_idx = first_old + 1
            second_old = old.index(CHAR_CODE, old_idx)
            old_idx = second_old + 1
            first_new = new.index(CHAR_CODE, new_idx)
            new_idx = first_new + 1
            second_new = new.index(CHAR_CODE, new_idx)
            new_idx = second_new + 1
            old_str = old[first_old:(second_old + 1)]
            new_str = new[first_new:(second_new + 1)]
            result = result.replace(new_str, old_str)

    return result

def correct_link_text(new_text):
    new = new_text
    start = 0
    end = 0
    while True:
        try:
            start = new.index("](", end)
            if start >= 0:
                end = new.index(")", start)
                if end >= 0:
                    link = new[start:(end+1)]
                    removed_white = link.replace(" ", "")
                    new = new.replace(link, removed_white)
                    diff_idx = len(link) - len(removed_white)
                    end = end - diff_idx
            else:
                break
        except:
            break
    return new

def correct_bold_text(new_text):
    new = new_text
    start = 0
    end = 0
    while True:
        try:
            start = new.index("**", end)
            if start >= 0:
                end = new.index("**", start + 1) +2
                if end >= 0:
                    link = new[start:(end)]
                    removed_white = link.replace(" ", "")
                    new = new.replace(link, removed_white)
                    diff_idx = len(link) - len(removed_white)
                    end = end - diff_idx
            else:
                break
        except:
            break
    return new

def translate(origin, dest_lang):
    print(origin)
    result = translate_client.translate(origin, target_language=dest_lang)
    translated = result['translatedText']
    translated = translated.replace('(', '(')
    translated = translated.replace(')', ')')
    translated = translated.replace('#', '#')
    translated = translated.replace('【', '[')
    translated = translated.replace('】', ']')
    translated = translated.replace('&quot;', '"')
    translated = translated.replace('&gt;', '>')
    translated = translated.replace('「', '"')
    translated = translated.replace('」', '"')
    translated = translated.replace('&#39;', '`')
    translated = correct_code_text(origin, translated)
    translated = correct_link_text(translated)
    translated = correct_bold_text(translated)
    print(translated)
    return translated


def parse_metadata_and_translate(src_lines, des_lines, idx, dest_lang):
    text = src_lines[idx]
    if not text.startswith(SEPARATOR_META_DATA):
        return -1

    des_lines.append(text)
    idx = idx + 1
    start = idx
    for i in range(start, len(src_lines)):
        idx = i
        text = src_lines[idx]
        if text.startswith(SEPARATOR_META_DATA):
            idx = idx + 1
            des_lines.append(text)
            break
        elif text.startswith(STR_TITLE):
            title = text[len(STR_TITLE):-1].strip()
            translated = translate(title, dest_lang) + "\n"
            des_lines.append("%s %s"%(STR_TITLE, translated))
        elif text.startswith(STR_DESCRIPTION):
            description = text[len(STR_DESCRIPTION):-1].strip()
            translated = translate(description, dest_lang) + "\n"
            des_lines.append("%s %s"%(STR_DESCRIPTION, translated))
        else:
            des_lines.append(text)

    if (idx + 1) == len(src_lines):
        return -1

    return idx

def parse_body_and_translate(src_lines, des_lines, idx, dest_lang):
    start = idx
    is_in_code = False
    for i in range(start, len(src_lines)):
        idx = i
        text = src_lines[i].strip()
        if text == "\n" or text == "":
            des_lines.append(src_lines[i])
        elif text.startswith(SEPARATOR_CODE):
            is_in_code = not is_in_code
            des_lines.append(src_lines[i])
        elif text.startswith(SEPARATOR_IMG):
            des_lines.append(src_lines[i])
        elif text.startswith(SEPARATOR_IMG_CODE):
            des_lines.append(src_lines[i])
        elif len(text) > 4 and text[0] == STR_STAR and text[1] == STR_STAR and text[-1] == STR_STAR and text[-2] == STR_STAR:
            des_lines.append(src_lines[i])          
        elif is_english(text):
            des_lines.append(src_lines[i])
        else:
            if is_in_code:
                des_lines.append(src_lines[i])
            else:
                translated = translate(text, dest_lang) + "\n"
                des_lines.append(translated)

def parse_and_translate(src, des, lang):
    src_lines = []
    des_lines = []

    with open(src, "r") as f:
        src_lines = f.readlines()

    idx = 0
    idx = parse_metadata_and_translate(src_lines, des_lines, idx, lang)
    idx = parse_body_and_translate(src_lines, des_lines, idx, lang)

    if src != des:
        with open(des, "w") as f:
            for line in des_lines:
                f.write(line)

if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("please input src, des files and des lang")
        exit(1)

    src_file_name = sys.argv[1]
    des_file_name = sys.argv[2]
    des_lang = sys.argv[3]
    cur_dir = os.getcwd()

    for (root, dirs, files) in os.walk(cur_dir):
        src = root + "/" + src_file_name
        des = root + "/" + des_file_name
        if not os.path.exists(des) and os.path.exists(src):
            print(src)
            print(des)
            parse_and_translate(src, des, des_lang)

Google Translate APIを使用する方法は、この記事を参照してください。

codechachaCopyright ©2019 codechacha