概要
最近Preferred Networksが開発したPLaMo 3 Translateという翻訳特化LLMのモデルが話題になっていますね。
これを使えば外部に情報を送らずに高速・高精度で翻訳できるとのことで、VSCodeのソースコード内のコメントや、メソッドにカーソルを当てた時に出てくるホバードキュメントを検出してリアルタイムに翻訳してくれる拡張機能を作ってみました。
その名もInterlinear!
職業プログラマーのくせに英語が苦手な私は、いつもドキュメントをコピーしてGoogle翻訳に投げるということをしていたので、カーソルを当てるだけで訳文が出てくるのはとても楽でした。
既存の翻訳拡張機能との違い
ソースコードのコメントを翻訳してくれる拡張機能自体は既に数多くあります。
しかしそれらの多くはGoogle翻訳などの外部APIにデータを送らなければならなかったり、ローカルモデルを利用できる場合でも自分でOllamaなどを用いて翻訳サーバーを構築しなければならなかったりと、すこし面倒でした。
今回作成したInterlinearは、VSCodeでインストールして、指示に従って初期セットアップを行うだけで簡単にローカルマシン上でPLaMo 3 Translateを動かして処理を行ってくれます。
内部的にはllama.cppを起動しモデルを動かしている形で、この拡張機能自体はただのクライアントです。
ただ、翻訳特化モデルであるPLaMo 3 Translateに適した形で構造化してプロンプトを渡すため、汎用LLMを必要とする既存の拡張機能と比べて、よりモデル本来の性能を引き出して高精度に翻訳することが可能になっています!
性能比較
既存の拡張機能+汎用モデルと、Interlinearの性能比較をClaudeに依頼してみました。
あくまで私の環境で動作させた比較です。
これらを保証するものではありません。参考程度に読んでください。
判断の基準
- 次のものは英語のまま残すのが正しい。訳していなくても
untranslatedにしない: 識別子、インラインコード、{@link X}、@param/@since/@returnなどのタグ名とその型・引数名、コード例、URL、バージョン番号 - 改行の位置の違いは評価しない(原文の行ごとに訳しても、段落をまとめて訳してもよい)
- 常体か敬体かは評価しない
- 原文がすでに不完全な文(メモ書きなど)なら、同じ程度の簡潔さの訳で満点にしてよい
| 方式 | モデルの大きさ | 正確さ | 自然さ | 正確さ 2 点以下 | 最良に選ばれた数 | 時間(中央値 / 90% / 最大) | 合計 |
|---|---|---|---|---|---|---|---|
| Interlinear+PLaMo 2B | 1.8 GB | 4.82 | 4.80 | 0 | 39(単独 17) | 1.8 / 5.5 / 10.4 秒 | 118 秒 |
| 既存の拡張機能+Gemma 4 E4B | 5.0 GB | 4.38 | 4.20 | 4 | 23(単独 4) | 6.0 / 15.9 / 29.0 秒 | 359 秒 |
| 既存の拡張機能+Qwen3.5 4B | 2.7 GB | 3.87 | 3.82 | 8 | 15(単独 2) | 4.7 / 13.3 / 24.8 秒 | 307 秒 |
| 既存の拡張機能+Qwen3.5 2B | 1.3 GB | 2.49 | 2.42 | 25 | 3(単独 0) | 3.7 / 8.6 / 14.5 秒 | 192 秒 |
- 正確さと自然さは 5 点満点の平均。採点役は、ファイルごとに 1 体ずつ、計 3 体の別エージェント
- 時間は、モデルとのやりとりにかかった時間の合計。4 方式すべてがモデルに問い合わせた 44 件で比べた。キャッシュで済んだ 1 件は除いている
採点役が付けた問題の種類と件数:
| 方式 | 誤訳 | 抜け | 余計な追加 | 英語のまま | 他言語(中国語) | コード・タグの破損 | 形式の崩れ |
|---|---|---|---|---|---|---|---|
| Interlinear+PLaMo 2B | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
| 既存の拡張機能+Gemma 4 E4B | 4 | 0 | 2 | 2 | 0 | 6 | 3 |
| 既存の拡張機能+Qwen3.5 4B | 12 | 1 | 2 | 2 | 0 | 5 | 5 |
| 既存の拡張機能+Qwen3.5 2B | 15 | 12 | 4 | 7 | 10 | 8 | 6 |
差の内訳
既存の拡張機能 のコメントの取り出し方(モデルによらない)
既存の拡張機能 は TextMate の文法でコメントの範囲を決め、1 行ずつ記号を外し、改行でつないで 1 回で翻訳先に渡す。翻訳先の拡張に渡されるのは原文と言語(from / to)だけで、ファイル名やコードは渡らない。
| 起きたこと | 例 |
|---|---|
{@link X} を含む行をコードと判断して送らないため、英語のまま残る |
|
| 行ごとに送ったものをモデルが組み替え、JSDoc タグの説明が別のタグにずれる | |
| 空白のない 1 語のコメントを単語に分解し、「元の語 => 訳」の形で表示する | |
| 隣り合うコメントを 1 つにまとめる。行末コメント、次の行のコメントアウトされたコード、TODO が 1 ブロックになる | |
docstring と、隣のコメントや shebang をまとめる。docstring を """ ごと送る |
|
| ディレクティブ、ライセンス、飾りの行もモデルに送る |
eslint-disable-next-line … →「…を無効にする eslint」(Qwen 2B)、SPDX-License-Identifier →「SPDX 許可ライセンス」、=====
|
| 日本語のコメントもモデルに送り、言い回しを書き換える | 「正規化してから返す」→「返却します」、「既定値を使う」→「デフォルト値を使用します」 |
Interlinear はこれらをすべて、翻訳しないか、正しい単位で訳している。
汎用モデルの誤り
- Qwen3.5 2B は 45 件中 10 件を中国語で返した。指示文が「to Japanese」ではなく「to ja」と言語コードになっていることも影響していそう(既存の拡張機能 の既定の指示文の問題)
- Qwen3.5 2B は、訳さずに英文をそのまま返すことがあった
- 動詞を名詞として読む誤りがあった(skip を「スキップオプション」とする。3 モデルとも)
- 意味を逆にする誤りがあった(stdout と stderr。Gemma)
- 原文にない引用符やかぎ括弧が付くことがあった
PLaMo を 既存の拡張機能 の後ろにつないだ場合
PLaMo 3 Translate の GGUF には、チャットテンプレートが入っている。このテンプレートは、最後のユーザー発言をそのまま原文として PFML3 に組み立てる。既存の拡張機能 の指示文をそのまま送ると、次のように指示文ごと訳される。
「以下の文章をjaに翻訳してください。解説や余計な文章は含めず、翻訳した内容のみを返してください。\n\n入力: "プロセスハンドルは保持し、スレッドハンドルは閉じる"」
原文だけを送れば正しく訳せる。ただし既存の翻訳先の拡張はどれも指示文を付けて送るので、この組み合わせは使えない。また、翻訳先には文脈(ファイル名や関連するコード)を渡せない。
結論
- 同じくらいの大きさの汎用モデルより、Interlinear+PLaMo 2B の方が訳ははっきり正確で、速い。
- 2.7 倍の大きさの Gemma 4 E4B と比べても、訳は Interlinear の方がよく、時間は約 3 分の 1 だった
- 差の原因は 2 つある
- 既存の拡張機能 のコメントの取り出し方の問題。Gemma の低得点 4 件のうち 3 件はこれが原因
- 汎用モデルの誤訳
- PLaMo を 既存の拡張機能 の後ろにつなぐことはできない。既存の翻訳先の拡張は指示文と原文を 1 つのメッセージで送るので、PLaMo は指示文ごと訳してしまう
おわり
リポジトリはこちらです:
実は初めてマーケットプレイスに公開しましたが、自分の作った拡張機能が検索に出てくるとなんだかうれしいですね。
この拡張機能自体はMITライセンスですが、内部で利用するPLaMo 3 Translateは商用利用に条件のあるライセンスのため、仕事の開発業務で使う際には条件を確認してください。