DeepLとObsidianをPythonで連携しましょう
について
技術記事を除いて、ノートを書くことはほぼObsidianを使うだけです。言語学習に関しては、ノートをとっている間に、翻訳サービスを使うため、ノート管理ツールとブラウザの間をしきりに切り替えることはあんまり便利じゃないと思います。先日「脱Google」についてのある文章を読んだのがきっかけで、Google翻訳の代わり DeepL を紹介してくれてから使い始めました。口コミにはGoogle翻訳より精度がよく高いと言われているし、他のシステムにAPIで連携させることもできます。それを利用してObsidianの中で翻訳することができれば、ノートを書くことに役立たせるかなと思います。
DeepL Pythonライブラリ・環境構築
| アプリケーション | バージョン | 
|---|---|
| macOS | 15.5 | 
| Python | 3.13.3 | 
| DeepL | 1.22.0 | 
| Obsidian | 1.8.10 | 
| Templater | 2.13.0 | 
私の環境構築
DeepLを登録する
DeepLに DeepL API Free 無料版のAPIキーをもらうため、登録することは必要があります。無料版では、1ヶ月当たり50万文字までの翻訳しかできませんいので、遠慮しなければ、1ヶ月経たないうちにすべて使いきってしまいそうと思います。
DeepLをインストールする
まずは 公式のAPI技術資料 に従ってライブラリ deepl [1] をインストールします。場合によって 仮想環境 [2] を準備しておいてから端末に:
pip3 install deepl
pip3 show deepl
Name: deepl
Version: 1.22.0
Summary: Python library for the DeepL API.
Home-page: https://github.com/DeepLcom/deepl-python
Author: DeepL SE
Author-email: python-api@deepl.com
License: MIT
Location: /Users/shinei/.pyenv/versions/3.13.3/lib/python3.13/site-packages
Requires: requests
Required-by: 
DeepL APIキーのシェル環境変数
公式にあの Sample Request File が用意されていますが、安全のため、どんなAPIキーでもアプリケーションに晒されるべきではありません。 [3] APIキーが無料だってなるべくシェル環境変数を設定します。
# .zshrcがないなら作成して
# touch ~/.zshrc
echo 'export DEEPL_API_KEY="{あなたのDeepL APIキー}"' >> ~/.zshrc
source ~/.zshrc
{あなたのDeepL APIキー} は公式にログインして アカウント で DeepL APIキーと制限 に記されます。設定してから cat ~/.zshrc で確認してください。
Pythonスクリプトを作る
シェル環境変数が設定したあとで、下記のとおりPythonスクリプトを作ります。 os.environ [4] の関数とエラーハンドリングを加えて、大体Sample Request Fileを参考にします。
import os
import deepl
auth_key = os.environ.get("DEEPL_API_KEY")
if not auth_key:
    raise ValueError("「DEEPL_API_KEY」環境変数が設定されていません")
translator = deepl.Translator(auth_key)
result = translator.translate_text("Hello, world!", target_lang="JA")
print(result.text)
プログラムがターミナルから実行できるかを確認しておいてください。
python3 deepl_test.py
出力された結果:
こんにちは、世界よ!
トップレベル要素
ターミナルに実行されるため、プログラムはtop-levelのコード環境を改める必要があります。また、DeepL APIで使用可能である引数の一つ formality という複数の選択肢から翻訳の丁寧さが選ばれるように argparse [5] に関しての構文も加えます。
import argparse
import os
import deepl
def main():
    parser = argparse.ArgumentParser(
        description='DeepL翻訳API',
        formatter_class=argparse.RawTextHelpFormatter
    )
    parser.add_argument('sentence', help='翻訳される文章')
    parser.add_argument(
        '-f', '--formality',
        choices=['default', 'more', 'less', 'prefer_more', 'prefer_less'],
        help='''\
        フォーマリティの度合いを引数で指定する
        ターゲット言語が日本語のみ
        '''
    )
    args = parser.parse_args()
    sentence = args.sentence
    formality = args.formality
    auth_key = os.environ.get('DEEPL_API_KEY')
    if not auth_key:
        raise ValueError('環境変数「DEEPL_API_KEY」がまだ設定されていない')
    translator = deepl.Translator(auth_key)
    result = translator.translate_text(
        sentence, 
        target_lang="JA", 
        formality=formality
    )
    print(result.text)
if __name__ == '__main__':
    main()
コマンドの後ろに -h 或いは --help を付いてヘルプメッセージを引き出します:
python3 deepl_api.py -h
ヘルプメッセージ:
usage: deepl_api.py [-h] [-f {default,more,less,prefer_more,prefer_less}]
                    sentence
DeepL翻訳API
positional arguments:
  sentence              翻訳される文章
options:
  -h, --help            show this help message and exit
  -f, --formality {default,more,less,prefer_more,prefer_less}
                                フォーマリティの度合いを引数で指定する
                                ターゲット言語が日本語のみ
オプション値の使い方は:
# --formality prefer_lessでも良い
# 常体はデフォルトであると思う
python3 deepl_api.py "Thank you." -f prefer_less
# より丁寧な訳文が出力される
python3 deepl_api.py "Thank you." -f prefer_more
出力された結果:
ありがとう。
ありがとうございます。
和英翻訳を双方向に
しばらく使ってみてから、英和翻訳するばかりでなかなか役に立たなかったことに気がついたのだけど、どこかを見直そうかとずっと思っています。結局、答えは考えていたほど複雑ではなかったです。まず、1回目の翻訳は原文がどの言語でも必ず 英語の訳文 ( detect_lang_result )と自動検出された 原文の言語 ( source_lang )を伴って返します。 source_lang によって日本語じゃなければ、もう一回の翻訳する関数を呼び出して原文から日本語の訳文を返します。 source_lang が日本語ならば、1回目の訳文がそのままを返します。
@@ -27,12 +27,18 @@
    translator = deepl.Translator(auth_key)
  
-   result = translator.translate_text(
-       sentence, 
-       target_lang="JA", 
-       formality=formality
-   )
+   detect_lang_result = translator.translate_text(sentence, target_lang='EN-US')
+   source_lang = detect_lang_result.detected_source_lang
+
+   if source_lang != 'JA':
+       result = translator.translate_text(
+           sentence,
+           target_lang='JA',
+           formality=formality
+       )
+   else:
+       result = detect_lang_result
    print(result.text)
if __name__ == '__main__':
    main()
スクリプト全文
import argparse
import os
import deepl
def main():
    parser = argparse.ArgumentParser(
        description='DeepL翻訳API(日英双方向)',
        formatter_class=argparse.RawTextHelpFormatter
    )
    parser.add_argument('sentence', help='翻訳される文章')
    parser.add_argument(
        '-f', '--formality',
        choices=['default', 'more', 'less', 'prefer_more', 'prefer_less'],
        help='''\
        フォーマリティの度合いを引数で指定する
        ターゲット言語が日本語のみ
        '''
    )
    args = parser.parse_args()
    sentence = args.sentence
    formality = args.formality
    auth_key = os.environ.get('DEEPL_API_KEY')
    if not auth_key:
        raise ValueError('環境変数「DEEPL_API_KEY」がまだ設定されていない')
    translator = deepl.Translator(auth_key)
    detect_lang_result = translator.translate_text(sentence, target_lang='EN-US')
    source_lang = detect_lang_result.detected_source_lang # type: ignore[attr-defined]
    if source_lang != 'JA':
        result = translator.translate_text(
            sentence,
            target_lang='JA',
            formality=formality
        )
    else:
        result = detect_lang_result
    print(result.text) # type: ignore[attr-defined]
if __name__ == '__main__':
    main()
作成したファイル deepl_api.py のパスを書き留めておいてください。
ObsidianとTemplater
Pythonスクリプトを作っていたあとで、もしまだ オブシディアン を準備していないなら、インストールしてください。そしてオブシディアンプラグインの一つ Templater をインストールします。
Templaterのtemplateを作成する
Template folder location [6] に deepl_api という名前の新規ノート(.mdファイル)を作成します。内容は:
<%*
const selection = tp.file.selection();
if (!selection) {
    new tp.obsidian.Notice("文章を選んでください");
    setTimeout(() => notice.hide(), 3000);
} else {
    const translate = await tp.user.deepl_api({ sentence: selection });
    tR += selection + "\n" + translate;
}
-%>
Templaterを設定する
Templaterの設定:
- 「設定」>「コミュニティプラグイン」に「制限モード」を 無効化 して、「インストールされたプラグイン」に Templater をつける
 - 「設定」>「コミュニティプラグイン Templater」>「User system command functions」: Enable user system command functions をつける
 
 python3 の絶対パス(absolute path)を探しておきます。端末に:
# python3の実行ファイルのフルパスを表示する
python3 -c 'import sys; print(sys.executable)'
# pyenvを使っているなら
pyenv which python3
# 仮想環境の場合
env | grep -i python3
# 例えば私の環境にpython3の絶対パスは
# /Users/shinei/.pyenv/versions/3.13.3/bin/python3
User function n゜# にファンクションを追加します( Add new user function ):
- 
deepl_api(左) - 
zsh -c '. ~/.zshrc; /Users/shinei/.pyenv/versions/3.13.3/bin/python3 /Users/shinei/Documents/deepl_api.py "$sentence" -f prefer_more'(※右) 
※ 上記のパスが自分の環境だけでご参考までに。仮にAPIキーがシェル環境変数でなかったら、ここにはじめの . ~/.zshrc; が必要ありません。つまり、右に zsh -c {/python3の絶対パス/python3} {/Pythonスクリプトの絶対パス/deepl_api.py} "$sentence"' もう充分です。
最後にTemplateをhotkeyを加えて:
- 「設定」>「コミュニティプラグイン Templater」>「Template hotkeys」: Add new hotkey for template (推奨ののキーボードショートカット: 
C-t) 
詳しくは前回の「Macの辞書アプリとObsidianをPythonで連携しましょう」という記事をご参考ください。
おわりに
最後まで読んでくれてありがとうございます。ぜひ、やってみましょう。不備がありましたらご指摘ください。
Discussion