ゲームの言語切り替え実装とセーブデータの設計
オプション画面に言語の選択肢を足すのは、半日で終わる作業に見えます。ドロップダウンを置いて、ローカライズ側の切り替え関数を呼ぶだけです。実際に時間を食うのはその周辺で、プレイヤーがまだその画面を開いていない段階でどの言語を出すかを決めること、すでに表示されている画面を描き直すこと、そしてある言語で作られたセーブデータを別の言語で読み込んでも破綻しないようにすることです。
起動時の言語判定とセーブデータは、たいてい別の時期に別の担当が作ります。だからこそ衝突します。特にセーブ側の問題はリリースから数か月後に表面化しがちで、プレイヤーが言語を切り替えたときに、クエストログの半分が前の言語のまま固まっていることに気づく、という形で発覚します。
この記事では、実装で出会う順番どおりに扱います。誰もまだ言語を選んでいない段階での決め方、実行中の切り替え、そして永続化するデータから言語を追い出す設計です。
初回起動でどの言語を出すか
新規インストール直後、プレイヤーはまだオプションを開いていないので、こちらが推測するしかありません。その推測が自然に感じられるかどうかは二つの細部で決まり、どちらも判定コードそのものより重要です。
一つ目は、「まだ選んでいない」と「たまたま既定と同じ言語を自分で選んだ」を区別することです。自動判定の結果を、明示的な選択とまったく同じ形で保存してしまうと、あとから両者を見分けられません。自動判定であることを示すフラグを持たせるか、プレイヤーが選ぶまで設定値そのものを書かないでおきます。これを怠ると、意図して英語を選んだプレイヤーが、プラットフォーム側の言語が変わった拍子に日本語へ戻されます。プレイヤーから見れば、ゲームが勝手に判断を変えたことになります。
二つ目は、言語タグを文字列一致ではなく段階的に解決することです。地域つきのタグが来たら、まず最も近い対応言語へ、次に基底の言語へ、最後に既定へと落とします。ブラジルのポルトガル語環境が、ポルトガル語を飛び越えて英語まで落ちてしまうのは典型的な失敗です。中国語は特に注意が必要で、意味のある区別は地域ではなく字体(簡体字か繁体字か)であり、字体情報のない言語コードだけでは本当に判断できません。ここは小さな関数に切り出してテストを書く価値があります。単純に見えて、たいてい三か所くらい間違っています。
もう一つ、コストがほぼゼロで問い合わせを減らせる工夫があります。言語の選択肢を最初の画面から到達できる場所に置き、選択肢のラベルはその言語自身の表記(日本語、English、Deutsch)にすることです。読めない言語で起動してしまったプレイヤーは、自分の言語を字面で見つけるしかありません。
そのうえで、判定の優先順位は手がかりの強い順に並べます。
- 設定ファイルに保存された、プレイヤー自身の明示的な選択 — これが常に最優先で、あとからシステム言語が変わっても覆らない
- ストアやプラットフォームがゲームを起動した際に渡してくる言語 — 多くのプレイヤーはゲームごとに設定しており、OSの設定より強い手がかりになる
- OSの表示言語
- 上のどれも対応言語に一致しなかった場合の、開発元の元の言語
言語設定はプレイヤーのものであって、プレイデータのものではない
言語は音量やキー設定と同じ、プレイヤー単位・端末単位の設定です。置き場所はオプション用の設定ファイルであって、セーブスロットの中ではありません。
セーブに言語を入れると三つのことが起きます。古いセーブを読み込んだだけでUIの言語が勝手に変わり、これはバグにしか見えません。新規ゲームを始めると既定に戻り、プレイヤーが意図して選んだ設定が捨てられます。そして、読めない言語で起動してしまったプレイヤーは、そもそもセーブを読み込めずに設定へたどり着けないかもしれません。言語はタイトル画面から、何も読み込まずに変更できる必要があります。
設定ファイルをクラウド同期している場合は、ここを明示的に決めてください。デスクトップと携帯機でシステム言語が違うプレイヤーは、言語の項目が同期されると片方がもう片方を上書きします。同期対象から言語を外すか、承知のうえで同期させるか。どちらでもかまいませんが、不具合報告で初めて知る事態は避けたいところです。
実行中の切り替えは「画面上のすべてを解決し直す」こと
再起動を求めることで回避しているゲームもたくさんあります。正直な設計ですし動きますが、体験としては気持ちのよいものではなく、プラットフォームによっては許容されないこともあります。その場で切り替えるなら、ルールは一つです。解決済みの文字列のコピーを、どこにも保持しない。
現実的な実装は、言語変更イベントを全テキストコンポーネントが購読し、自分のキーを引き直すという形になります。ここには明示しておくべき設計上の帰結があります。すべてのテキストコンポーネントは、表示した文字列ではなくキーを保持していなければなりません。生成時に完成した文字列を渡されただけのコンポーネントは、自力で更新する手段を持ちません。イベントの配線をいくら丁寧にしても直りません。
フォントとレイアウトも同じ瞬間に動かす必要があります。言語が変われば使うフォントが変わることがあり(字形の収録範囲が違うため)、行の高さも変わり、場合によっては文字の流れる方向まで変わります。測定済みの幅、折り返し位置、確定したレイアウトはすべてその瞬間に無効になるので、再計測は同じイベントの中で行い、次の画面に持ち越さないようにします。
確認は必ず画面の内側から行ってください。メインメニューで言語を切り替えるケースは、いつでも問題なく動きます。ショップとアイテムのツールチップと確認ダイアログを開いた状態で切り替えるケースが、バグを見つけてくれます。
取り残されたコピーは決まった場所に潜んでいます。どれも症状は同じで、新しい言語と古い言語が半分ずつ混ざった画面になります。
- 画面生成時に一度だけ値を入れ、その後さわっていないラベル
- 書式整形した結果をキャッシュしているテキスト(スコア表示やタイマーなど)
- 必要になったときに組み立てて記憶しているツールチップや説明パネル
- 言語依存の照合順序で並べ替えたリスト(並べ替え直しが必要)
- 前の言語の書式で整形された数値・日付・通貨
- テクスチャやアトラスに焼き付けた文字(生成し直しが必要)
- すでに開いている画面 — 言語ドロップダウンが載っているポーズ画面そのものを含む
セーブを汚染する事故: 表示テキストを保存してしまう
リリース後に最も厄介になる言語のバグは、画面上ではなくセーブファイルの中にあります。プレイヤーの言語で描画済みのテキストを、もう一度描画するための識別子の代わりに保存してしまったときに起きます。
現れる場所はどのプロジェクトでもだいたい同じです。文章のまま保存されたクエストログ、所持品レコードに複製されたアイテム名、ストーリーゲームの会話バックログ、章タイトルを含む自動生成のセーブスロット名、統計やリザルト画面の文言、アイテム名から自動入力された装備セットの名前。
被害は積み重なります。言語を切り替えたプレイヤーは、ゲームの一部が前の言語のまま固定され、最初からやり直す以外に直す手段がありません。セーブ内のテキストは互換性の地雷でもあります。言語ごとの旧来のエンコーディングで書かれていたり、現在のフォントに収録されていない文字を含んでいたりすると、プレイヤーには文字化けや豆腐が見え、しかも自分では修復できません。さらに、あとから翻訳を改善しても、単なる誤字修正であっても、既存のセーブには決して反映されません。
// セーブを汚染する保存
{ "quest": { "title": "消えた配達人を探す", "step": "波止場を調べる" } }
// 言語を切り替えても壊れない保存
{ "quest": { "id": "q_courier", "stepIndex": 2, "params": { "town": "riverport" } } }セーブに入れてよいテキスト
すべてを識別子にできるわけではないので、例外も明示しておきます。プレイヤーが入力したテキスト — 主人公の名前、セーブのメモ、自分で付けたラベル — は正真正銘の自由入力です。そのまま保存し、翻訳せず、勝手に正規化しないでください。記録した時点で自由入力だった値(自動生成された名前など)も同じ扱いです。
こうした項目が存在する以上、セーブの形式はプレイ中の言語に関係なくUTF-8である必要があります。現在のロケールに合わせて言語ごとのエンコーディングを選ぶ実装は、ある環境で作ったセーブが別の環境で読めなくなる典型的な原因で、しかも完全に回避できるものです。
セーブが作られたときの言語をメタデータとして残しておくのも有効です。UIをその言語に戻すためではなく、サポート対応や不具合報告の調査が格段に楽になるためと、現在のフォントで表示できない文字がセーブに含まれていることを検出できるためです。
ここまでをほぼ捕まえられる確認リスト
大げさなテスト計画は要りませんが、誰かが腰を据えて順番に試す必要はあります。どれも1言語で開発している間はまったく見えない項目だからです。
- 設定ファイルがない状態で、対応言語ごとにプラットフォームの言語を変えて起動し、何が出るか確認する
- 設定ファイルがなく、未対応の言語環境で起動し、フォールバック先を確認する
- プレイヤーが明示的に選んだあとでシステム言語を変え、選択が優先されることを確認する
- すべての画面を開いた状態で、その画面のまま言語を切り替える
- 会話の途中、および時間制限のある演出の最中に切り替える
- ある言語で保存し、言語を変えて読み込み、クエストログ・所持品・会話履歴を最後まで読んで前の言語が残っていないか確認する
- フォントが変わる言語に切り替え、先に測定・描画済みだった要素を見直す