gettext .mo カタログ検査ツール
.mo ファイルは msgfmt が .po をコンパイルして残したもので、実際に locale/<lang>/LC_MESSAGES/ に配置されるファイルです。.po を失うと誰にも読めないバイナリになりますが、構造そのものは小さく、マジックナンバー、リビジョン、二つの文字列テーブルの個数とオフセット、そして読み手が無視してよい省略可能なハッシュテーブルだけでできています。マジックナンバーは 0x950412de であると同時にバイトを入れ替えた 0xde120495 でもあり、これが残りのワードのバイト順を宣言する唯一の手段です。.mo に隠れている二つの要素はどちらも埋め込まれた NUL バイトで、テキストエディターでは見えません。コンテキスト付きの項目は msgctxt と 0x04 バイトと msgid を一つの文字列につないだもの、複数形の項目は原文側に msgid と msgid_plural を NUL で区切って入れ、訳文側に各形を NUL でつないだものです。本ツールは両方を分解し、コンテキストは専用の列に、複数形は番号付きで並べます。msgid が空のメタデータ項目は Project-Id-Version、Language、Content-Type、Plural-Forms、POT-Creation-Date に分解し、他のすべての文字列は推測ではなくそのヘッダーが宣言した文字コードで解読します。ヘッダーが無い、あるいは嘘をついている場合は、黙って文字化けを出すのではなくその事実を伝えます。複数形の式は自前で解析して n = 0 から 20 まで評価するので、各個数がどの形を選ぶかが分かり、項目が持つ形の数を nplurals と照合します。この食い違いは特定の個数でだけ誤った文字列になる実際の不具合です。さらに未翻訳項目、msgid と完全に同一の訳文、訳文で落ちた %s や {}、整列していない原文テーブル、項目数に対して小さすぎるハッシュテーブルも指摘します。ただし .po に戻すことはできず、翻訳の良し悪しも判定しません。
使い方
- locale/<lang>/LC_MESSAGES/ にある .mo ファイルをボックスにドロップします。msgfmt が出力したものなら何でも読めます。
- まずファイルヘッダーの行を見ます。バイト順、リビジョン、項目数、二つの文字列テーブルとハッシュテーブルがファイル内のどこにあるかが分かります。
- メタデータ項目で文字コードを確認します。以下のすべての文字列がそれで解読されるので、Content-Type の誤りは最初に直すべき点です。
- n = 0 から 20 までの複数形の表で各個数が選ぶ形を確かめ、複数形項目の形の数を nplurals と比べます。
- 指摘の一覧に目を通し、フィルターで目的の msgid・訳文・コンテキストを表から探します。
よくある質問
- マジックナンバーが二つの値で現れるのはなぜですか。
- マジックナンバーは 0x950412de の一つだけです。ただし .mo ファイルはすべての32ビットワードをコンパイルした計算機のバイト順で格納し、マジックナンバーも同じように格納します。読み手は先頭4バイトを両方向で読み、リトルエンディアンとして読んだときに 0x950412de になればファイル全体がリトルエンディアン、ビッグエンディアンとして読んだときにそうなれば全体がビッグエンディアンだと判断します。他の場所にフラグはありません。だからビッグエンディアンの機械で作ったカタログがリトルエンディアンの機械でもそのまま動きます。このページは判定結果の隣に生の4バイトも出すので、判定を信じるかわりに自分で確かめられます。
- 一部の msgid の中にある 0x04 バイトは何ですか。
- msgctxt の格納方法です。gettext にはコンテキスト専用のフィールドが無いため、msgfmt はコンテキストと 0x04 バイト一つ(ASCII の EOT)と msgid を一本の文字列につなぎ、pgettext はその連結した文字列を引きます。だから同じ msgid "Open" を持つ二つの項目が別々の項目になり得ます。一方は "menu\x04Open"、もう一方は "state\x04Open" です。エディターや素朴なダンプでは区切りが見えず重複に見えます。本ツールはそこで分割してコンテキストを専用の列に置くので、同じ msgid を共有する項目が並んで確認できます。
- 複数形はどう格納され、nplurals とは何が一致すべきですか。
- 原文側は msgid、NUL バイト、msgid_plural の順で、訳文側は各形を NUL でつないだものです。形がいくつあるべきかはヘッダーが決めます。Plural-Forms に nplurals と、使う形の添字を返す n についての式が入っています。項目の形が nplurals より少ないと、欠けた添字を選ぶ個数では何も返らず、gettext は未翻訳の msgid や msgid_plural に戻ります。一部の数でだけ起きるので試験を通り抜けてしまいます。このページはすべての複数形項目の形の数を数え、ヘッダーと食い違うものを表示します。
- Content-Type ヘッダーが無い、または誤っているとどうなりますか。
- ファイル内で自分の文字コードを示すのはそのヘッダーだけなので、読み手は信じるほかありません。Python の gettext はそのまま拒否します。未記入の charset=CHARSET は未知のエンコーディングのエラーになり、宣言された文字コードで妥当でないバイトは復号エラーになります。このページは意図的にもっと寛容で、UTF-8 に退避して読める範囲を読み、どちらが起きたかを伝えます。そもそもこのファイルを開く理由が、アプリで文字化けする原因を突き止めるためだからです。メタデータ項目が全く無ければ文字コードも言語も複数形規則も無く、gettext は文字列を ASCII として扱い n != 1 の規則を当てはめます。
- 項目の並び順は重要ですか。
- 重要です。手書きの .mo 生成器が最も見落とす点でもあります。gettext の仕様は、原文文字列がバイト順に整列していることを求めます。読み手が原文テーブルに対する二分探索で項目を見つけてよいからです。C の実装は使えるハッシュテーブルが無いとき実際にそうするので、整列していないカタログは一部の項目を黙って見つけられません。一方、ファイル全体から辞書を作る Python は問題なく読めます。試験用スクリプトでは動くのにアプリでは動かない、厄介な種類の不具合です。このページは整列を検査し、順序が逆転している組の数を報告します。
- ハッシュテーブルは何のためのもので、無視してよいですか。
- 省略可能な検索の高速化装置です。msgfmt は項目数より三分の一ほど大きい hashpjw のテーブルを開番地法で作り、読み手が二分探索なしで msgid を見つけられるようにします。読み手は完全に無視してよく、Python は実際に無視します。サイズが 0 のカタログも正当です。正当でないのは、スロット数が項目数を上回らないテーブルです。開番地法は最低でも一つ空きが必要だからです。その組み合わせは書式を理解しない道具が書いた印なので、ここで報告します。表示されるサイズとオフセットはヘッダーのワードそのものです。
関連ツール
Java クラスファイル解析ツール
コンパイル済みの .class ファイルをブラウザーで解析します。クラスファイルバージョンと Java リリース、アクセスフラグ、定数プール、フィールド、メソッド、参照クラスを表示します。
フォントファイル検査ツール
.ttf、.otf、.woff を開いて、本当のファミリー名、グリフ数と対応文字数、バージョン、ライセンス文、埋め込み許諾を読み取ります。
WAV ファイル インスペクター
.wav をドロップ → フォーマット・チャンネル・サンプルレート・ビット深度・再生時間・全 RIFF チャンク・埋め込み LIST/INFO タグを表示。完全クライアントサイド。
STL 3D モデル インスペクタ(三角形・体積・バウンディングボックス・ベッド適合)
.stl ファイル(バイナリまたは ASCII)をドロップすると、三角形数・バウンディングボックス・X×Y×Z サイズ・体積・表面積・水密性チェック・3 方向直交プレビュー・主要 3D プリンタベッド(Bambu・Prusa・Voron・Ender)適合可否を即時表示。
Mbox アーカイブビューア
mbox アーカイブをブラウザーで分割。メッセージ境界、デコード済みヘッダー、MIME 構造、スレッド、重複 Message-ID を表示し、アップロードはしません。
ZIP 内容ビューア
ZIP をドロップすると展開せずに中身を一覧・サイズ・プレビュー・個別ダウンロード可能。