実装Read this article in English

プレースホルダーが翻訳で壊れるパターン集

{playerName}のようなプレースホルダーのトークンは、単なる装飾的な文字列ではありません。原文と、それを実行時に整形するコードとの間の「契約」です。翻訳という作業は、すべての文をプレーンな散文として書き直す前提で進みます。そしてこの「文として書き直す」という行為こそが、原文と一字一句一致していなければならないトークンを壊します。この記事では、実際に起こる壊れ方を具体的に挙げていきます。

トークンの削除

翻訳者が自然な文になるよう文を書き直した際、トークンがそのまま抜け落ちるケースです。You have {itemCount} itemsが「持っているアイテムです」となり、個数がどこにも残っていません。実行環境には代入する値がないため、フォーマット処理がエラーになるか、より頻繁には型の緩いテンプレートシステムが個数の欠けたテキストを黙って生成し、プレイヤーから報告が来るまで誰も気づきません。

余分なトークンの追加

頻度は低いですが実際に起こります。翻訳者が同じファイル内の似た文からトークンをコピーし、違う文に混入する、あるいは既に正しく存在していたトークンを重複させてしまうケースです。訳文がコード側で渡されない引数を参照する形になると、多くのフォーマット実装は範囲外エラーを出すか、{2}のようなトークン文字列そのものをプレイヤーにそのまま表示します。

大文字小文字の変化: {playerName} が {playername} に

オートコンプリートやスペルチェッカー、一部言語の文頭を小文字化する習慣は、文頭に置かれたトークンの先頭文字を平気で小文字にします。名前付きプレースホルダーは通常、完全一致のキーで検索されるため、{playername}は{playerName}と同じ値には解決されません。実行環境から見れば、それは別の、未定義のキーです。

ASCII括弧が全角文字に置き換わる

これはCJK圏の入力に特有ですが、よく起こります。日本語や中国語の入力方式で入力していると、フォーマットパーサーが期待するASCIIの{や}の代わりに全角括弧({playerName})が入力されてしまうことがあります。多くのフォントでは、全角括弧と半角括弧は見た目上、ざっと読んだだけでは見分けがつきません。しかしパーサーにとっては別のUnicodeコードポイントであり、トークンとしてまったく認識されず、括弧ごとそのまま文字として表示されてしまいます。

実行環境が対応していない並べ替え

単純な%sや、明示的なインデックスを持たない{0}形式のシステムは、引数を呼び出し順に厳密に埋めていきます。翻訳者が訳文の文法に合わせて語順を入れ替え、2番目の引数を1番目より先に置くと、実行環境側は何が入れ替わったかを知らないまま、どの値がどの枠に入るかが変わってしまいます。結果として、文法的には自然だが、数値や名前やアイテムが入れ替わったテキストになります。

%s dealt %d damage   ->   %d damage dealt by %s (values now swapped)

括弧の内側の余分なスペース

{ playerName }({playerName}の内側にスペースが入ったもの)は一見無害に見えますが、多くのパーサーはプレースホルダーのキーを空白も含めた完全一致で照合します。スプレッドシートの自動整形やエディタの折り返しなどで紛れ込んだ余分なスペース1つで、キーの検索は黙って失敗します。

なぜこれらはすべて機械的に検出できるのか

上記の壊れ方はどれも、文の意味を理解する必要がありません。すべて、原文に存在するプレースホルダーのトークン集合と、訳文に存在するトークン集合との構造的な不一致であり、言語的な判断ではなく集合の比較です。だからこそこの種のバグは自動化する価値があります。正規表現で原文と訳文からトークンをすべて抽出し、2つの集合の差分を取れば、訳文がどの言語であるかを知らなくても、削除・追加・大文字小文字のずれ・全角化を検出できます。

  • トークンの削除: 原文にあり訳文にない
  • トークンの追加: 訳文にあり原文にない
  • 表記のずれ: トークンはあるが完全一致のキーが異なる
  • 全角化: 見た目上はトークンだが、実際は異なるUnicodeコードポイント
  • スペースのずれ: トークンはあるが内部に余分な空白がある

関連記事