0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【海賊版】Restのコンパイルエラーを日本語化する

Posted at

はじめに

以下のような記事を見かけました。

ざっくり日本語訳するとこうなります:

error[E0382]: 移動された値の借用: `s1`
 --> src/main.rs:5:20
  |
3 |     let s1 = String::from("Hello, ");
  |         -- `s1`  `Copy` トレイトを実装しない `std::string::String` 型なので移動が発生します
4 |     let s2 = s1;
  |              -- 値はここで移動されました
5 |     println!("{}", s1);
  |                    ^^ 移動後値はここで借用されました
  |
help: パフォーマンスコストが許容できる場合値のクローンを検討してください
  |
4 |     let s2 = s1.clone();
  |                ++++++++

このエラーについての詳細は、`rustc --explain E0382` を実行してください

わかりやすい!!

おお、たしかにわかりやすい!

あんまりダラダラしてると苛つかせてしまうので、先に結果を貼っておきます。

すごい!

(およそ人様に見せられるようなコードをしていないので、もっといい感じになったら公開します...タブン...)

えー(ケチ

というわけで、自分でも同じようなことを(雑に)やってみました。

RUSTC ラッパーの仕様

元記事には

rustcラッパーに関する情報が全然見つかりませんでした。

とありました。確かに情報はあまりありませんが、第1引数に rustc のパスを指定されて起動される以外は、基本的に rustc と同じように動作すればよいのだと考えました。

まずは、何もせずに rustc を呼び出するだけの空っぽのラッパーを作成しました。

次にラッパー内で、コマンドライン引数と、標準出力、標準エラー出力、rustc の終了コードを適当なログファイルへ出力するようにして、どのように呼ばれるのか、どのように動いているのかを観察してみました。

どうやら、cargo build を 1 回だけ実行しただけでも、実は何度か rustc が呼び出されることがあるようです(バージョン情報を確認したり、機能を確認したり?)。

また、実際のコンパイル時にはコマンドライン引数に --error-format=json を付けて呼び出していることもわかりました。rustc のコマンドライン引数の詳細は以下が参考になります。

そして実際のエラー情報は、標準エラー出力へ1行ごとにJSONとして、つまり JSONL (JSON Lines) 形式で出力されているようです。

さらに、JSON にはいくつかの種類があって、$message_type で種類が判別できるようです。
rustc の出力する JSON ファイルのフォーマットは以下のページが参考になりました。

今回日本語化したいコンパイルエラーメッセージは(元記事にもある通り)$message_typediagnostic のものです。

日本語化の対象は、おそらく以下の項目を対象とすればよいと判断しました。

  • message
  • spans[].label
  • children[].message
  • children[].spans[].label
  • rendered

翻訳は、とりあえず JSON ファイルに英語と日本語のペアを記載して、置き換えるようにしています。

translate.json
[
    {
        "en": "borrow of moved value",
        "ja": "移動された値の借用しました"
    },
    {
        "en": "value moved here",
        "ja": "ここで値を移動しました"
    },
    {
        "en": "value borrowed here after move",
        "ja": "移動後の値をここで借用しました"
    },
    {
        "en": "move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait",
        "ja": "`{$ty}`型の`{$name}`は`Copy`トレイトを実装していないので、移動します"
    }
]

{$name} などはプレースホルダで、実際には正規表現でキャプチャして、日本語版のメッセージの同じ場所へ埋め込むようにしました。

このあたりはかなり雑な対応で、メッセージによってはうまく変換できないような気がするのですが、まあ、とりあえず仮版ということで。

元記事では rendered の日本語化は、自力でメッセージを組み立てる対応をしているようですが、そこまで根性がなかったので、以下のようにしてみました。

上記の messagelabel と全く同じ文字列が、rendered にも含まれているように思われる(つまり messagelabel のメッセージの途中に ANSI エスケープシーケンスなどが挿入されていない)ので、かつほとんどが行末(あるいは後ろに付加情報がついているだけ)で、文字の長さが多少変わってもレイアウトは崩れなさそうに思いました。そこで rendered に含まれる「messagelabel の英語文」を「それらを翻訳した日本語文」に単純置換をするようにしました。

もちろん、ソースコードにコンパイルメッセージと同じものがあると、そちらも置換されてしまいます。まあレアなケースだと思うので、重要度の低い既知のバグということにします。

他にも、コンパイルエラーメッセージの中に、他のコンパイルエラーメッセージが含まれているようなケースだと、うまく変換できないこともありえますが、暫定的に「英語文」が長いものから順番に変換するような対策をしてみました(が、うまくいかないケースもあるかもしれません)。

RUSTC ラッパーを起動する設定

元記事にも書いてある通り、RUST の標準的な機能として、環境変数 RUSTC_WRAPPER にラッパーのパスを指定すると cargo 経由でビルドするときに、直接 rustc を呼び出すのではなく、ラッパーを呼び出すようです。

環境変数だけではなく設定ファイルでも指定可能なようです。

設定ファイル自体は、いろいろなところに置けるみたいですが、とりあえず PROJECT_ROOT/.cargo/config.toml に以下のように記載してみました(実際指定したパスは、ラッパーの存在するパスですが)。

PROJECT_ROOT/.cargo/config.toml
[build]
rustc-wrapper = "/path/to/rustc-ja-wrapper"

実行結果は以下のような感じ

$ cargo build
   Compiling a v0.1.0 (/tmp/foo)
warning: 変数が使われていません: `b`
 --> src/main.rs:4:9
  |
4 |     let b = a[10];
  |         ^ help: 意図的ならアンダースコアを前に付けて下さい: `_b`
  |
  = note: `#[warn(unused_variables)]`はデフォルトで有効です

error: この操作は実行時にパニックします
 --> src/main.rs:4:13
  |
4 |     let b = a[10];
  |             ^^^^^ 添え字が範囲外です: 長さは3、添え字は10
  |
  = note: `#[deny(unconditional_panic)]`はデフォルトで有効です

warning: `foo` (bin "foo") generated 1 warning
error: could not compile `foo` (bin "foo") due to 1 previous error; 1 warning emitted

動いた!

リポジトリ

急ぎでっち上げた雑なソースですが、以下のリポジトリに置いてあります。

また、翻訳用の JSON ファイルは assets/translate.json で、コンパイル時に埋め込んでビルドするようにしています。

(環境変数で外部の JSON ファイルを指定できたほうが、簡単にメッセージを変えられて良かったかも?)

最低限の動作確認しかしていないため、実際の翻訳用 JSON ファイルを見てもらえばわかる通りごくごく一部のメッセージしか翻訳していません。
もし、他のメッセージも翻訳したいとかあれば、フォークしてもらって勝手に改造してもかまいませんし、プルリクしてもらってももちろん構いません。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?