3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

必要な部分だけを DeepL API で翻訳して置き換える Greple モジュール

Last updated at Posted at 2023-01-30

image.png

deepl コマンド

DeepL という精度の高い翻訳サービスがあります。ウェブに翻訳したい文章を入れると、翻訳結果を表示してくれます。Mac にアプリをインストールしていると、Command-C を2回叩くとカットバッファの内容を翻訳してくれて便利です。

とは言っても、いちいち画面を切り替えるのがちょっと面倒だと思っていたら、最近 API を通してコマンドラインから利用する方法が公開されていることに気がつきました。

このツールをインストールすると deepl というコマンドが使えるようになって、コマンドラインからテキストを翻訳することが可能になります。

deepl text --to JA 'even monkeys fall from trees'
さるもきからおちる

document というサブコマンドを使うと、ファイルの内容を翻訳することもできます。何も考えずにドキュメントを含むプログラムを対象にすると、こんな結果になりました。

image.png

奇妙な顔文字や不必要な部分を翻訳してしまっているのはともかくして、日本語がなんだか変です。これは、元の文章の途中に改行が入っているためです。ウェブやアプリで使う際にも、改行を取り除かないとうまく翻訳できません。テキストファイルの内容を翻訳しようとすると、どうも一手間二手間かかるのがストレスです。

greple -Mxlate::deepl

そこで greple コマンドを使って、ファイルの中の指定した部分を deepl コマンドで翻訳した結果に置き換えるモジュールを作りました。

次の画像はこのモジュールを実装しているファイルの中身です。POD という形式でドキュメントが記述されています。この内容を翻訳することを考えると、プログラム部分は当然として、POD のキーワードなども外して、必要な部分だけを対象にする必要があります。

image.png

POD ドキュメントは先頭が = の行から始まり =cut で終わるので ^=(?s:.*?)(^=cut|\z) というパターンで表せます。ドキュメント内の地の文は行の先頭からはじまるので、^(\w.*\n)+ というパターンで文章部分を選ぶことができます。文字から始まる行の連続という意味です。greple の --inside オプションで範囲を指定して検索すると次のようになります。

greple --all --ci=A --inside '^=(?s:.*?)(^=cut|\z)' '^(\w.*\n)+'

image.png

うまく対象部分が選べているようです。この例では、=encoding より前の部分は検索対象に入っていないので選ばれません。また、= で始まる POD コマンドやインデントしている部分はマッチしません。

--all はファイル全体を表示。--ci=A はマッチした部分毎に異なる色を割り当てます。そうしないと、連続しているテキストが1行ずつマッチしているのか、全体でマッチしたのか区別できません。

greple -Mxlate::deepl

このファイルを greple の xlate::deepl モジュールで翻訳してみます。このモジュールには POD のドキュメント部分を選ぶための --match-podtext というオプションが予め定義されています。

greple -Mxlate::deepl --match-podtext

のように実行すると、上と同じ結果が出るので、どこが処理対象になるかを事前に確認することができます。

--xlate

範囲に問題がなければ --xlate オプションをつけて翻訳します。

greple -Mxlate::deepl --match-podtext --xlate --xlate-fold --xlate-format=none

image.png

--xlate-fold は行を折り返すためのオプションで、なくても構いません。--xlate-format=none は出力形式に none を指定し、対象部分を翻訳結果で置き換えます。

--xlate-format=conflict

--xlate-format を指定しないとこうなります。

image.png

デフォルトの出力形式は conflict で、対象となる部分の原文と翻訳結果の両方を git の conflict marker の形式で出力します。DeepL の翻訳はかなり正確ではあるものの、すべて正しいとは限らないので原文を見ながらでないとやはり不安です。

<<<<<<< ORIGINAL
App::Greple::xlate - translation support module for greple
=======
App::Greple::xlate - greple 用の翻訳サポートモジュール
>>>>>>> JA

--xlate-format=ifdef

ifdef 形式で出力することもできます。

#ifdef ORIGINAL
App::Greple::xlate - translation support module for greple
#endif
#ifdef JA
App::Greple::xlate - greple 用の翻訳サポートモジュール
#endif

こうすると、unifdef コマンドで簡単に必要な部分を取り出すことができます。

sdif -V

conflict marker 形式のファイルを見やすく表示したくなったので、diff 出力を並べて表示する sdif コマンドを対応させました。実は cdif は以前から対応していたのですが、sdif の必要はあまり感じられなくて未対応でした。

image.png

sdif は、diff 形式ではないデータはそのまま表示します。これでも悪くはないのですが、diff 以外のテキストは共通部分として扱うための -V オプションを追加しました。

greple -Mxlate::deepl --match-podtext --xlate --xlate-fold | sdif --no-cdif -V | less

image.png

こちらの方が、かなり読みやすく感じられます。--no-cdif は、単語単位の差分を表示するための cdif を使わないためです。校正ならともかく、翻訳文章だとうるさいだけで役に立ちません。

次の画像は -Mxlate::deepl モジュールを使って韓国語と中国語に変換した2つのファイル比較して sdif で表示したものです。ほとんど同じように見えます。

image.png

ちなみに、これらのファイルを再び DeepL で変換すると、ちゃんと意味の通じる日本語になって出てくるのですごいです。

Emacs から使う

Emacs から使うのも簡単です。コマンド一発で変換できるようにしたので shell-command-on-region を直接使ってもなんとかできますが、オプションを覚えるのとか面倒なので xlate.el というマクロを作りました。これを読み込んで、選択した領域に対して xlate-region マクロを実行すると、次のような結果になります。

image.png

下手な英語でドキュメントを書いていると、ちゃんと意味が伝わるか不安になることがあります。そんな時にちょっと確認するのに便利です。安心したら undo すれば元に戻ります。

キャッシュ

DeepL を API で利用するためにはアカウント登録が必要です。フリーアカウントでも認証キーが発行できるので、それを使って deepl コマンドを利用することができます。ただし、月間50万文字が上限です。コマンドのテストということもあって、何度も同じ文章を変換する必要があり、だんだんもったいなくなってきたのでキャッシュの仕組みを実装しました。

xlate.pm というファイルなら xlate.pm.xlate-deepl-JA.json というファイルに、JSON 形式で原文と翻訳結果を格納するようになっています。

--xlate-cache オプションでキャッシュ方針を指定できます。デフォルトは auto で、キャッシュファイルがすでに存在すれば、それを読み込んで更新します。なければ何もしません。最初に --xlate-cache=create で空のキャッシュファイルを作っておくと、後は自動的に管理されます。

実装してみると、開発用途ではなくても有用なことがわかってきました。同じファイルを異なる形式で表示したいと思うことは結構あって、キャッシュのおかげで、一度変換しておけば次回からは瞬時に処理が終わります。

他の形式のファイルを処理するためには

この記事では POD 形式の文書ファイルの必要な部分だけを翻訳する方法について紹介しました。

異なる形式のデータに適用するためには、そのための準備をする必要があります。greple の --inside, --outside, --include, --exclude オプションを使うと、対象となる領域をパターンで絞り込むことができます。また、これらのオプションや検索パターンには関数を指定することもできるので、パターンマッチでは表現できないような複雑な書式にも対応することが可能です。

greple は、テキストファイルだけではなく Word や PDF のファイルも対象にできるので、結果を見るだけならある程度使い道はあると思います。使い方について不明な点などあれば、お尋ねいただければ可能な範囲で対応します。もし開発作業が必要ならご相談にのります :-)。

Greple に関しては、Hugo と docsy テーマを使って、こんなページを作ってみました。まだ作りかけですが、マニュアルや Qiita のアドベントカレンダーに書いた記事などを置いてあります。

今後の計画

実は、このモジュールは翻訳のためではなく、DeepL が最近始めた校正サービスに使えないかと思って作り始めたものです。現在は無料ウェブサービスでしか使えないようなので、API から利用できるようになったら、このモジュールをベースに対応しようと考えています。

今は、Python 実装の deepl コマンドを使っていますが、直越 API を叩くことも可能です。異常ケースを考えなければそんなに難しくはなさそうですが、サーバとのトランザクションに比べると効果は限定的なので、当面は様子見でしょうか。

2023-02-03 に更新した Version 0.04 では、deepl コマンドを一度だけ実行して、すべての翻訳を一回ですませるようにしました。これによって、初回の実行速度が大幅に改善しました。また、キャッシュを使わなくても、実用的な時間で結果を得ることができます。このために、greple--postgrep というオプションを追加してあります。

この記事を書いてから、-Mxlate モジュールをより簡単に使うための xlate というシェルスクリプトとポータブルな Docker 環境を作りました。これについては以下の記事に書いてあります。

関連記事

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?