課題紹介
業務でよく報告書を翻訳するので、いつもDeepLを使っていますが、DeepLは最近翻訳したパワポをダウンロードしたら、修復エラー出てしまうので、Google translate apiを呼び出して、パワポの自動翻訳を実現したいと思います。
参考文献
① Google Apps Scriptによる翻訳APIの利用
- 簡単にapiを作成
こちらの記事
3 分で作る無料の翻訳 API with Google Apps Script
を参考し、無料の翻訳apiを作成しました。
下記のコードをGoogle Apps Scriptにて入力し、ウェブアプリケーションとして導入
を選択したらhttps://script.google.com/macros/s/[api_key]/exec
のようなURLが生成してくれる。こちらを使って翻訳を行います。https://script.google.com/macros/s/[api_key]/exec?text=こんにちは&source=ja&target=en
で結果があったら、apiの作成が成功できたといえます。

1 | function doGet(e) { |
- PythonからAPIにアクセス
requests
を使ってAPIのURLにアクセスし、英訳を試してみました。1
2
3
4
5
6
7
8
9def translate(str_in, source='ja', target= 'en'):
url="https://script.google.com/macros/s/"
url += "[api_key]"
url += "/exec?text=" + str_in
url += "&source=" + source
url += "&target=" + target
rr = requests.get(url)
return rr.text
② deep-translatorを使って複数の翻訳ツールを利用する
- deep-translatorはgoogle_translator,Linguee translator,DeepL等複数翻訳ツールを対応してくれる複合型モジュールです。いくつかの翻訳ツールを比較したい場合、かなり便利なモジュールですね。本記事では、google translate、Linguee translator、DeepLを使いたいと思います。
- DeepL apiは現在アクセスできないため、とりあえずやめました。
- google_translatorを使用する場合、5000文字の制限があります。
- text must be a valid text with maximum 5000 character,otherwise it cannot be translated
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#google translate
def Google_Translator(str_in):
from_language = json_inputs['source_Google']
to_language = json_inputs['target_Google']
translated = GoogleTranslator(source = from_language,target = to_language).translate(text=str_in)
return translated
#Linguee translator
def Linguee_Translator(str_in):
from_language = json_inputs['source_Linguee']
to_language = json_inputs['target_Linguee']
translated = LingueeTranslator(source = from_language,target = to_language).translate(str_in)
return translated
#DeepL
#DeepLは今有料ユーザーにしかapiを提供しないため、auth_keyは必要です。
with open(os.getcwd() + '/config.json') as j:
config = json.load(j)
def DeepL_Translator(str_in):
from_language = json_inputs['source_deepl']
to_language = json_inputs['target_deepl']
translated = DeepL(config['auth_token']).translate(source=from_language,target=to_language,text=str_in)
return translated
- text must be a valid text with maximum 5000 character,otherwise it cannot be translated
- 各翻訳ツール対応している言語、及び言語の省略をdeep-translatorでそのまま調べます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15langs_list = GoogleTranslator.get_supported_languages(as_dict=True)
google_lang = pd.DataFrame(langs_list.keys(),langs_list.values()
).reset_index().rename(columns= {'index':'言語省略',0:'言語'})
print(google_lang[google_lang['言語']=='english'])
print(google_lang[google_lang['言語']=='japanese'])
print(google_lang[google_lang['言語']=='chinese (simplified)'])
print(google_lang[google_lang['言語']=='chinese (traditional)'])
# 言語省略 言語
21 en english
言語省略 言語
45 ja japanese
言語省略 言語
14 zh-cn chinese (simplified)
言語省略 言語
15 zh-tw chinese (traditional)
③ パワポを翻訳
- パワポの解析はslide→shape→paragraph→runに基づいて行いました。
- 本記事では最小単位であるrun.textごとのテキスト翻訳とrun一個上のparagraph.textごとのテキスト翻訳を行いました。
- notesの部分は
slide.notes_slide.notes_text_frame.text
でテキスト本文を指定できます。 - テーブルの部分は
shape.shape_type == MSO_SHAPE_TYPE.TABLE
を使ってテーブルを絞って、row→cellという構造に基づいてcell.text_frame.text
を用いて本文を指定できます。 - Google_Translatorは空白とNoneTypeに対応しないため、
if paragraph.text.isspace() != True and paragraph.text != ''
を使ってそれらを除外しました。 #
が入ってしまうと、通信エラーが生じてしまうらしいので、str_in = title.text.replace('#','')
を使って翻訳に投げるテキストに入っている#
を除外しました。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110json_inputs = {
'file_path':ファイルのパスをここに記入,
'Google': False, #deep-translator
'translate': True, #api with Google Apps Script
'Linguee':False, #deep-translator
'DeepL':False, #deep-translator
'notes':True,
'source_Google':'ja',
'target_Google':'en',
'source_translate':'ja',
'target_translate':'en',
'source_Linguee':'ja',
'target_Linguee':'en',
'source_deepl':'JA',
'target_deepl':'EN'
}
path_to_presentation = json_inputs['file_path']
prs = Presentation(path_to_presentation)
def ppt_translate(prs):
for ns,slide in enumerate(prs.slides): #slide
title = slide.shapes.title
if title:
if json_inputs['Google']:
str_in = title.text.replace('#','')
title_out = Google_Translator(str_in)
sleep(1.5)
title.text = title_out
elif json_inputs['translate']:
str_in = title.text.replace('#','')
title_out = translate(str_in)
sleep(1.5)
title.text = title_out
elif json_inputs['deepL']:
str_in = title.text.replace('#','')
title_out = deepl_translate(str_in)
sleep(1.5)
title.text = title_out
if json_inputs['notes']: #notes
if slide.has_notes_slide:
if json_inputs['Google']:
str_in = slide.notes_slide.notes_text_frame.text.replace('#','')
notes_out = Google_Translator(str_in)
sleep(1.5)
slide.notes_slide.notes_text_frame.text = notes_out
elif json_inputs['translate']:
str_in = slide.notes_slide.notes_text_frame.text.replace('#','')
notes_out = translate(str_in)
sleep(1.5)
slide.notes_slide.notes_text_frame.text = notes_out
elif json_inputs['deepL']:
str_in = slide.notes_slide.notes_text_frame.text.replace('#','')
notes_out = deepl_translate(str_in)
sleep(1.5)
slide.notes_slide.notes_text_frame.text = notes_out
for nsh,shape in enumerate(slide.shapes):
if shape.shape_type == MSO_SHAPE_TYPE.TABLE: #table
for row in shape.table.rows:
for cell in row.cells:
if json_inputs['Google']:
str_in = cell.text_frame.text.replace('#','')
cell_out = Google_Translator(str_in)
sleep(1.5)
cell.text_frame.text = cell_out
elif json_inputs['translate']:
str_in = cell.text_frame.text.replace('#','')
cell_out = translate(str_in)
sleep(1.5)
cell.text_frame.text = cell_out
elif json_inputs['deepL']:
str_in = cell.text_frame.text.replace('#','')
cell_out = deepl_translate(str_in)
sleep(1.5)
cell.text_frame.text = cell_out
#paragraph.textごとのテキスト翻訳
if shape.has_text_frame:
for np,paragraph in enumerate(shape.text_frame.paragraphs):
if json_inputs['Google']:
# Google_Translatorは空白とNoneTypeに対応しないため、それらを除外する
if paragraph.text.isspace() != True and paragraph.text != '':
str_in = paragraph.text.replace('#','')
str_out = Google_Translator(str_in)
paragraph.text = str_out
elif json_inputs['translate']:
str_in = paragraph.text.replace('#','')
str_out = translate(str_in)
paragraph.text = str_out
elif json_inputs['deepL']:
str_in = paragraph.text.replace('#','')
str_out = deepl_translate(str_in)
paragraph.text = str_out
#run.textごとのテキスト翻訳
# for rs,run in enumerate(paragraph.runs):
# if json_inputs['Google']:
# str_in = run.text.replace('#','')
# str_out = Google_Translator(str_in)
# run.text = str_out
# elif json_inputs['translate']:
# str_in = run.text.replace('#','')
# str_out = translate(str_in)
# sleep(1.5)
# run.text = str_out
# elif json_inputs['deepL']:
# str_in = run.text.replace('#','')
# str_out = deepl_translate(str_in)
# sleep(1.5)
# run.text = str_out
prs.save(os.path.split(path_to_presentation)[1].split('.pptx')[0]+'_en.pptx')
print(f'第{ns}スライドは完了')- run.textを単位とparagraph.textを単位に翻訳した結果は以下の通りです。
- paragraph.textのほうが若干ナチュラルと気がしますが、run.textの場合はちゃんとフォントサイトや、太字等を原本のままで保持できるので、場合によって取捨選択できたらと思います。
run.text | paragraph.text |
---|---|
![]() |
![]() |
④ Excel,csv,txtファイルを翻訳
- Excel,csv,txtの場合だとずっと簡単ですが、一応練習するため、以下の関数を書いてみました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22def excel_excel_txt(path):
if os.path.splitext(path)[1] == '.csv':
df = pd.read_csv(path,index_col=0)
elif os.path.splitext(path)[1] == '.xlsx':
df = pd.read_excel(path,header=None,index_col=0)
elif os.path.splitext(path)[1] == '.txt':
df = pd.read_table(path,header=None)
for i in df.columns:
if json_inputs['Google']:
i_en = [Google_Translator(str(m)) for m in df[i]]
sleep(1.5)
df[f'{i}_en'] = i_en
elif json_inputs['translate']:
i_en = [translate(str(m)) for m in df[i]]
sleep(1.5)
df[f'{i}_en'] = i_en
elif json_inputs['DeepL']:
i_en = [DeepL_Translator(str(m)) for m in df[i]]
sleep(1.5)
df[f'{i}_en'] = i_en
df.to_csv(os.path.splitext(json_inputs['file_path'])[0]+'.csv',encoding='utf-8-sig')
return df⑤ Next Action
- 上記コードで実現できたことをWeb ツールにて実現できたら良いかと思います。
- 現状パワポ内の画像テキストの翻訳はまだできていないので、今後画像の部分もクリアしたいです。
- word、pdf系のファイルもこちらに取り入れたいと思います。
Appendix
- 中国繁體語⇔簡体語
- deep-translatorを利用する場合
1
2
3
4
5text = '统计学入门'
result = GoogleTranslator(source = 'auto',target = 'zh-tw').translate(text=text)
result
#'統計學入門' - openccを利用する場合
1
2
3
4
5
6
7pip install opencc-python-reimplemented
from opencc import OpenCC
cc = OpenCC('S2t')
to_convert = '统计学入门'
converted = cc.convert(to_convert)
converted
#'統計學入門'
- 単語の同義語を取得
- deep-translatorのLingueeTranslatorを使って、単語の同義語を取得できる
- LingueeTranslator内の
return_all = True
にすると、該当単語の翻訳した言語の同義語がいくつか出てくる1
2
3
4word='面白い'
translated_linguee = LingueeTranslator(source = 'ja',target = 'en').translate(word,return_all = True)
translated_linguee
#['interesting', 'interesting', 'amusing']