🧠

React 日本語ドキュメントが実はわりと ChatGPT で翻訳されている件

2023/09/05に公開

React 公式ドキュメント日本語版メンテナの smikitky です。タイトルの通りですが、新版 React ドキュメント日本語版の翻訳においては、私が翻訳を担当したところ原則すべてにおいて、ChatGPT の翻訳がベースになっています。例えばチュートリアルブログ記事、最近何かと話題になりがちなこれこれもそうです。(流石にトップページは手でやりました。)

この目的のために、長文 Markdown ファイルを ChatGPT を使って翻訳するツールも作りました。個人的にはもうこれなしで長文 Markdown の翻訳をしたくなくなりました。

https://github.com/smikitky/chatgpt-md-translator

例として、このツールを使って単に生成してみた新版チュートリアルを以下に掲載します。

https://ja-react-8aa88t4yk-fbopensource.vercel.app/learn/tutorial-tic-tac-toe

上記は 100% AI 翻訳ですが、すでにぱっと見た程度で酷い違和感は感じないレベルには達していると思います。React ドキュメントを自動翻訳させると React が「反応」、props が「小道具」になるというのが一昔前の機械翻訳のお約束でしたが、そういう残念さはありません。特にこの記事の場合、move を「動き」ではなく「(着)手」、square を「正方形」ではなく「マス(目)」、board を「板」ではなく「盤面」、というように、ボードゲーム特有の用語を使って翻訳する必要もあるのですが、その辺も既にだいたい問題なく処理されています。

実際には上記をベースにしつつ、数百箇所に人間の手による修正・推敲・用語統一作業を加え、他のレビュアーによる確認が入ってから、ドキュメントはリリースされます。実際にリリースされているチュートリアルは以下の通りです。お暇な方は見比べてみてください。

https://ja.react.dev/learn/tutorial-tic-tac-toe

背景

React 公式サイトの新版 (react.dev) が公開されてしばらく経ちました。基本的に過去の記事はほとんど残らない、ほぼ全文書き換えです。経緯や見どころについてはこちらの和訳済みのブログ記事にあります。数年前から React ドキュメントの翻訳をお手伝いしている私としては、好評のドキュメントを多くの人に早く読んで欲しいと思いつつ、「これ全部翻訳し直しは大変だな~」という気分になっていたのも事実です。

一方で最近は機械翻訳もそこそこ優秀であり、特に ChatGPT は翻訳ソフトとして使わせても相当なものです。DeepL などの翻訳専用サービスにない利点として、「Markdown のタグを壊さないで」「この単語はこんな風に訳して」「欧文と和文の間にはスペースを入れて」「"ユーザ", "ハンドラ" のように語末の長音符は原則省略して」などなどの細かい指示を日本語プロンプトで与えることができます。大規模言語モデルたる GPT は、React も Markdown も普通に人間と同じような意味で『理解』しており、大抵の日本語による指示が通ります。長文の翻訳をする際にはこの点が非常に効いてきます。

ただし現状では ChatGPT は、数千行もある長文テキストファイルをそのまま貼り付けて全部翻訳してくれたりはしません。一度に処理できるのは精々英文で 1000 ワードといったレベルです。これは OpenAI が意地悪で制限しているのではなく、Transformer というニューラルアーキテクチャ自体の現状の技術的制約でもあります。

「だったら長文を適当に複数に分割して ChatGPT に投げて翻訳させ、その結果を結合すればいいじゃない」という大変シンプルな発想で、上記のツールができました。こんだけ AI ブームなので似たようなものはあるのかと思いきや、意外にも全く同じようなものは見つかりませんでした。

使い方

使い方の概要は以下の通りです。

https://github.com/smikitky/chatgpt-md-translator

  1. npm install --global chatgpt-md-translator でインストール
  2. OpenAI に開発者登録して API キーを生成し、ダウンロード
  3. 設定ファイルを作って API キーを記入
  4. プロンプトファイル(ChatGPT への指示ファイル)を作成
  5. chatgpt-md-translator your-first-component.md のようにして翻訳

プロンプトファイルには、「React ドキュメントの翻訳です、これを日本語に翻訳して」といった基本情報から、「◯◯ という単語はこう翻訳して」、「句読点やスペースはこのように使って」など、あらゆる指示を書きます。もちろん日本語で書けます。これで原理上、ChatGPT が理解するどんなプログラミング言語と自然言語の組み合わせでも対応できます。個人のニーズに合わせてカスタマイズすることが大切です。

翻訳結果を手作業で修正する作業量は、このプロンプトファイルの出来に大きく左右されます。試行錯誤の結果、現在自分が使っているプロンプトの例を以下に載せておきます。元は人間の翻訳者用に書いたルールをちょっと手直ししたものです。

react.dev 翻訳用プロンプトファイルの例
React ドキュメントの日本語翻訳プロジェクトです。
後で渡す Markdown ファイルを、できるだけ自然な日本語に翻訳してください。

以下の翻訳ルールを厳密に守ってください。

- 「です」「ます」調で書く(箇条書きの中を除く)。
- Markdown の構造(タグなど)はすべて保持する。URL は一切変えない(`en-US``ja` にしない)。
- コードブロック内は一切変更しない。特に「omittedCodeBlock」と書いてある行を翻訳しない(← 重要)。
- 見出しの行末にある `{/*try-react*/}` のようなものはパーマリンクなので一切変えない。`/*``*/` の前後にスペースを加えない。
- <Recap> <Challenges> <YouWillLearn> <Solution> などの JSX タグのような要素を `<まとめ>` などと翻訳しない。
- 原文と改行のしかた、空行の入れかたを厳密に一致させる。勝手に改行を増やしたり減らしたりしない。
- カッコは内部に和文を含む場合は全角、英数字のみ含む場合(特に原文の単語を示す場合など)は半角とする。
- 半角開きカッコの前と半角閉じカッコの後には半角スペースを入れる。ただし別の約物と直接隣接している場合は不要。

  > ```
  > 避難ハッチ␣(escape hatch)␣を(必要に応じて)利用します。
  > ```

- 英数字と和文との間には半角スペースを入れる。ただし他の約物(特に句読点 。, 、)と直接隣接している場合は不要。

  > ```
  > React␣の␣API␣で、`fooBar`␣を␣1␣回実行。
  > ```

- 和文内で文の一部として使う記号・約物類は原則全角とする。`「`, `」`, `、`, `。`, `:`, `!`, `?`, `/` などが該当する。
- 用例の直前の行で行末に現れるコロンについても全角とする。ただしこれは毎回使うべきというわけではない。
- `*強調*``**強調**` は、原文での使い方と同じにする。
- 3 音以上の場合のみ、片仮名語の末尾の長音符を原則省略。「ユーザ」「ハンドラ」など。ただし「レンダー」だけは「レンダー」とする。
- 補助動詞(~てください・~てみる・~ておく・~てくる・~てしまう)はかな書き。
- 「レンダリングする」ではなく「レンダーする」、「条件付きレンダリング」ではなく「条件付きレンダー」のように訳す。
- Effect は「エフェクト」と訳す。
- React の state は「状態」「ステート」ではなく「state」とする。props は「プロパティ」ではなく「props」とする。

工夫点

発想自体はシンプルですが、実際に使えるようになるまでには少々の工夫は必要でした。

Markdown ファイルの分割

まずは ChatGPT の API が一口で食べられるサイズになるよう、Markdown ファイルを空行部分でざく切りするという作業が必要です。デフォルトではだいたい 2000 文字で切るようにしています。コードブロック(```)内かどうかだけは判定していますが、見出しなどそれ以外の文脈は考慮せず、適当な空行部分でぶった切ります。

分割をあまりに粗くしすぎると、トークン数制限というものに引っかかってリクエストが失敗します。最初からリクエストを拒否してくれるならまだいいのですが、運が悪いとリクエストは受け付けてくれて一見正常に翻訳文が返り始めるのに、その途中でトークン数制限に引っかかって通信が中断される、という悲しい現象が発生します(多分課金は普通にされてるはず)。ChatGPT のウェブ UI でも長文を生成しているとレスポンスが急に途切れることがあると思うのですが、アレです。そういう状況を検出した場合、文字列を更に半分に分割して再帰的に再試行する仕組みを入れてあるので、いずれは翻訳は終了しますが、お金と時間の無駄なのでなるべく避けるようにしましょう。

逆に、Markdown をあまりに細かく刻みすぎてしまうと、個々の翻訳リクエスト中に含まれる文脈が少なくなるため、用語の統一性や翻訳の正確性が失われて味わいが悪くなります。

Temperature パラメータ

ChatGPT の API には temperature という調整可能なパラメータがあります。これは ChatGPT のウェブ UI にはない機能であり、出力結果の「ランダム性」をコントロールできるものです。大きくすればするほど翻訳結果がばらつきます。例えば以下が、Temperature を 1 にした場合と 0.1 にしてそれぞれ 5 回同じ文章を翻訳させてみた場合の結果です(長いので折りたたんでいます)。

原文:

Most pages in the Learn section end with a few challenges to check your understanding. For example, here are a few challenges from the page about Conditional Rendering. You don't have to solve them right now! Unless you really want to.

Temperature = 1 の場合
  • 「学習」セクションのほとんどのページは、理解度をチェックするためのいくつかのチャレンジで終わります。例えば、条件付きレンダーのページからいくつかのチャレンジを挙げてみましょう。すぐに解く必要はありませんよ! それが本当にやりたいなら、別ですけどね。
  • 「学習」セクションのほとんどのページは、あなたの理解度をチェックするためのいくつかのチャレンジで終わります。例えば、以下は「条件付きレンダー」についてのページからのいくつかのチャレンジです。すぐに解決する必要はありません!まあ、本当にしたいならばですけど。
  • 「学習」セクションのほとんどのページは、理解度を確認するためのいくつかの挑戦で終わります。たとえば、これらは「条件付きレンダー」に関するページからのいくつかの挑戦です。すぐに解決する必要はありません! ただし、本当に 解決したい場合は別です。
  • 👑 Learn セクションのほとんどのページは、理解度を確認するためのいくつかのチャレンジで終わっています。例えば、「条件付きレンダー」に関するページからいくつかのチャレンジを抜粋してみます。今すぐに解く必要はありません!ただし、本当にやりたいという場合は別です。
  • 「学び」セクションのほとんどのページは、理解度をチェックするためのいくつかの挑戦で終わります。例えば、条件付きレンダーセクションのページからのいくつかの挑戦です。すぐに解決しなくても構いません! ただし、あなたが本当に望むならば。
Temperature = 0.1 の場合
  • 「学習」セクションのほとんどのページは、理解度を確認するためのいくつかのチャレンジで終わります。例えば、以下は「条件付きレンダー」に関するページからのいくつかのチャレンジです。すぐに解決する必要はありません!ただし、本当に 解きたい場合は別です。
  • 「学習」セクションのほとんどのページは、理解度を確認するためのいくつかのチャレンジで終わります。例えば、以下は「条件付きレンダー」についてのページからのいくつかのチャレンジです。すぐに解決する必要はありません!ただし、本当に 解決したい場合は除きます。
  • 「学習」セクションのほとんどのページは、理解度を確認するためのいくつかのチャレンジで終わります。例えば、以下は「条件付きレンダー」に関するページからのいくつかのチャレンジです。すぐに解決する必要はありません!ただし、本当に 解決したい場合は別です。
  • 「学習」セクションのほとんどのページは、理解度を確認するためのいくつかのチャレンジで終わります。例えば、以下は「条件付きレンダー」に関するページからのいくつかのチャレンジです。今すぐ解決する必要はありません!ただし、本当に 解決したい場合は別です。
  • 「学習」セクションのほとんどのページは、理解度を確認するためのいくつかのチャレンジで終わります。例えば、以下は「条件付きレンダー」についてのページからのいくつかのチャレンジです。すぐに解決する必要はありません!ただし、本当に 解決したい場合は除きます。

本来の ChatGPT の API のデフォルトは 1.0 です。個人的にはこの中では temperature = 1 の中の 👑 で示した訳が一番良いと思います。数値を大きくすることでクリエイティブかつカッコいい意訳が出てくる可能性が上がるというメリットがありますが、一方で純然たる誤訳の頻度も増えてしまう印象があります。

本ツールでは 0.1 という小さめの値をデフォルトにすることにしました。文脈を考慮せず文章をぶった切って独立して翻訳する仕組みのため、temperature が高すぎると記事の途中で「ステート」「state」「状態」が入れ替わるなどの問題が起きて面倒なのです。temperature を低くしておけばとりあえず一貫した用語は出やすいので、気に食わなくてもエディタで置換すれば済みます。欠点として「受験英語的には正しいけどぎこちない翻訳が出がち」な気もするのですが、そこの手直しは人間がやっていても一番楽しい部分だったりするので、気にしないことにします。

また temperature を低く保つことで、「Markdown のタグが壊れる」「こちらの指示を無視する」といったトラブルも大幅に減らせます。デフォルトの temperature ではツール使用後にいきなり正しくプレビュー表示できる Markdown が生成される可能性は 3 割くらいで、どこかしらのマークアップが壊れていたのですが、temperature を減らすとほぼ毎回うまくいくようになりました。

ちなみに 1 よりかなり大きな値にすると、それこそ高熱にうなされた時のうわごとのようなものを出力し始めます。怖いものが見たい方は試してみてください。

ソースコードブロックの事前削除

React ドキュメント日本語版では、コードブロックは一切翻訳しない(コメントも含めて)ことにしていますので、ChatGPT に投げる前の時点で一旦リクエストから取り除き、中身をランダムな文字列に置換しておきます。そして、翻訳結果が返ってきてから上記の文字列をキーにコードを復元します。

特に React ドキュメントの場合は 100 行以上もあるライブデモ用のコードサンプルがファイル中に頻繁に含まれているので、これを先に除いておかないとお金と時間の無駄です。さらに ChatGPT が気を利かせたつもりでコード自体の問題を勝手に修正し始めることすらあります(それを修正してもらう練習問題なのに…)。

その他

  • ChatGPT の無料トライアルでは 1 分に 3 回までしか API が呼べないという制限があるため、API コールごとに指定秒数待つコードなどを入れてあります。
  • ChatGPT の API のリクエスト送信側は、この上なくプレーンなウェブ API であり application/json 形式で指示を POST します。レスポンス側も JSON で受け取れるのですが、長文を投げると返ってくるまで数分かかったりします。この間進行状況が見えないのは厳しいので、レスポンスをストリーミングしてもらう Server-sent Events での受信を実装しました。

使ってみての感想とまとめ

手前味噌ですが、全部自分で翻訳するのと比べた場合はもちろん、DeepL 翻訳や Google 翻訳に文章を放り込みながら翻訳するのと比べても、作業効率は断然に良いです。長文でも Markdown 記法が(ほぼ)壊れず、ツールにかけた瞬間にブラウザで結果が見えるという利点は大きいです。特にこれとかは超長い上にどうせほとんどの人が読まないので、このツールなしではやってられなかったと思います。また「ちゃんと React という技術を分かっている人が翻訳をしてくれているな」という安心感も感じられます(人じゃないけど)。

またメンテナ視点としては、人間相手のレビューに伴う(主に心理的な)負荷がなくなるというメリットも率直に言って大きいです。同じ 80 点の翻訳をベースにするのであれば、人による翻訳をレビューするよりは機械翻訳の結果を自分で修正する方が、遠慮や説明や待ちが不要なので楽だったりします。

一方で問題点としては「React と英語を両方理解した人間が丁寧に結果を確認しないと、分かりづらい誤訳や不自然な翻訳をスルーしまくってしまう」ということに尽きます。これは翻訳に限った問題ではなく、コード生成 AI だろうとイラスト生成 AI だろうと同じですが、まだまだ人間は仕事を AI 任せにはできませんし、ちゃんと勉強した人間の需要がなくなるわけではありません。今時ブラウザ上で右クリックするだけで雑な機械翻訳はすぐ読めるわけですから、むしろ我々人間の翻訳者の存在意義はここだと思っています。

と、上記のような問題はありますが、長文ドキュメント翻訳に関わっている方は是非試してみてください。プロンプトの工夫を忘れずに!

Discussion