※本記事にはアフィリエイト広告(Udemy)を含みます。
前回のおさらい
番外編②では、タイトル画面の追加、「最初からやり直す」リセット機能、隠しエンディングまで実装しました。今回は、STATION OPSを日本語・英語・簡体字中国語・ロシア語・スペイン語の5言語に対応させた記録です。
なぜ多言語対応をやることにしたか
きっかけは「itch.ioに公開しているタイトルは、実際どの言語に多く対応しているのか」を調べたことでした。itch.io上の言語別ゲーム件数を調べたところ、英語が16万件超と圧倒的に多く、次いでフランス語・スペイン語・ドイツ語という顔ぶれでした。
一方で、比較のためにSteamの言語シェアも調べてみると、まったく違う結果になりました。Valveが公開しているデータでは、簡体字中国語が英語を上回って最大シェアを占めており、簡体字中国語・英語・ロシア語・スペイン語の上位4言語で全体の約8割をカバーできるとのことでした。itch.ioが英語圏インディーコミュニティに寄った顔ぶれなのに対し、Steamはより商業的でグローバルな構図だと分かります。
STATION OPSは今のところitch.io公開ですが、この「4言語で8割カバー」という数字が分かりやすかったため、英語・簡体字中国語・ロシア語・スペイン語の4言語を追加することにしました。
なお、対応言語を増やす際の作業量については、事前に整理しておきました。多言語対応の「仕組み」を作る手間は言語数によらず一定ですが、「翻訳」と「フォント対応」は言語を追加するたびに積み上がっていきます。特にフォントは、ラテン文字ベースの言語同士なら使い回しが効く場合がある一方、文字体系が異なる言語(中国語、韓国語など)は個別に用意が必要になる、という違いがあります。
Godot標準のCSV翻訳を使わなかった理由
Godotには、CSVファイルをインポートして多言語対応する標準の仕組みがあります。ただし、この方式はGodotエディタでCSVを一度インポートし、言語ごとの翻訳リソースを生成してもらう必要があります。今回は開発環境の都合上、その場でエディタのインポート処理を実行して確認することができなかったため、標準機能ではなく、GDScriptの辞書(Dictionary)に翻訳を直接持たせるシンプルな自作の仕組みにしました。
extends Node
const STRINGS: Dictionary = {
"START_BUTTON": {
"ja": "スタート", "en": "Start", "zh_CN": "$5F00始", "ru": "Начать", "es": "Empezar",
},
# ...以下、キーごとに5言語分の翻訳を持たせる
}
var current_locale: String = "ja"
func t(key: String) -> String:
var entry: Dictionary = STRINGS[key]
return entry.get(current_locale, entry["ja"])
キーを指定してLocalization.t("START_BUTTON")のように呼び出すと、現在の言語に応じた文字列が返ってくる、という単純な仕組みです。UI側のコードは、これまでベタ書きしていた日本語の文字列を、この呼び出しに置き換えるだけで多言語対応できます。
フォント対応の考え方
日本語用フォントはラテン文字・キリル文字も含んでいた
これまで日本語表示の文字化け対策として使っていたNoto Sans CJK JPというフォントは、実は日本語の漢字・ひらがな・カタカナだけでなく、ラテン文字(英語・スペイン語で使うアルファベット)やキリル文字(ロシア語)もあわせて収録されていました。そのため、英語・ロシア語・スペイン語については、既存の日本語用フォントをそのまま流用できました。
中国語(簡体字)だけは別フェイスが必要だった
中国語は事情が違いました。日本語と中国語は同じ漢字を共有している部分が多いのですが、字形(グリフの見た目)が微妙に異なります。同じフォントファミリーの中に「日本語向け(JP)」「簡体字中国語向け(SC)」といった、地域ごとに字形を出し分けたバリエーション(フェイス)が用意されていたため、中国語表示のときだけSCフェイスを抽出してサブセット化し、言語切り替え時にフォントごと差し替える設計にしました。
複数言語が同時に表示される箇所で2回文字化けした
実装した後、2回文字化けの不具合が発生しました。原因はどちらも同じで、「言語切り替えボタン」や「タイトルロゴ」のように、選んでいる言語に関係なく常に複数の言語表記が画面に同時表示される箇所があったことです。
たとえば言語選択ボタンは「日本語 / EN / 中文 / RU / ES」を常に5つとも表示します。中国語を選ぶとSCフォントに切り替わりますが、SCフォント側には「日本語」という漢字や、「EN」「STATION OPS」といったラテン文字が含まれていなかったため、文字化けしてしまいました。
対処として、日本語用フォント・中国語用フォントの両方に、こうした「常時表示される共通部分」の文字をあらかじめ含めておくようにしました。
CHROME_TEXT = "日本語ENRUESSTATION OPS中文0123456789"
jp_font_text = ja_text + en_text + ru_text + es_text + CHROME_TEXT
sc_font_text = zh_text + CHROME_TEXT
新しいセリフやボタン文言を追加するたびに、フォントのサブセットに含まれる文字も見直す必要がある、というのは今回の実装を通じて得た教訓です。
数値表記・UIの言語ごとの出し分け
電力・酸素・部品の数値表記は、これまで日本語の「万・億」で統一していましたが、英語・ロシア語・スペイン語では意味が通じません。言語に応じて表記を切り替える処理を追加しました。
func _format_number(value: float) -> String:
if Localization.current_locale in ["ja", "zh_CN"]:
if value >= 100000000.0:
return "%.2f億" % (value / 100000000.0)
elif value >= 10000.0:
return "%.2f万" % (value / 10000.0)
else:
return str(int(value))
else:
if value >= 1000000000.0:
return "%.2fB" % (value / 1000000000.0)
elif value >= 1000000.0:
return "%.2fM" % (value / 1000000.0)
elif value >= 1000.0:
return "%.2fK" % (value / 1000.0)
else:
return str(int(value))
中国語も「万」という単位を日本語と共有しているため、日本語と同じ表記グループにしています。
また、ロシア語・スペイン語は日本語に比べて文章が長くなりがちで、ボタンの文字がはみ出す不具合も見つかりました。ボタンの高さとフォントサイズに余裕を持たせ、アップグレードカードの最小高さも拡大することで、どの言語でも同じレイアウトに収まるよう調整しました。
タイトル画面に言語選択を実装する
タイトル画面に、日本語・EN・中文・RU・ESの5つのボタンを並べ、押した言語がゲーム全体に反映されるようにしました。選んだ言語はセーブデータに保存されるため、次回起動時も前回選んだ言語のまま始まります。
func _on_language_selected(locale: String) -> void:
Localization.set_locale(locale)
GameManager.language = locale
_apply_locale_font()
_refresh_text()
itch.io側の対応
ゲーム内の対応言語に合わせて、itch.io側の設定も更新しました。
- 「Edit game」画面の「Metadata」タブ(プロジェクトを一度保存した後に表示されるタブです)にある「Languages」欄に、対応した5言語を登録
- ページの説明文に、日本語版に加えて英語版も追加(別ページに分けると評価・ダウンロード数が分散してしまうため、同じページ内に両方を載せる形にしました)
おわりに
多言語対応は「翻訳を追加すればいい」という単純な話ではなく、フォントの文字カバレッジや、言語ごとの文章の長さの違いなど、UI設計にも影響が及ぶ作業だと実感しました。特に、複数言語が同時に画面に出る箇所(今回で言えば言語選択ボタン)は見落としやすいポイントなので、同じような対応をする際は注意してみてください。
Godot学習におすすめのオンライン講座
多言語対応やフォント周りの実装は情報が少なく、つまずきやすい分野です。基礎からの体系的な学習が土台になります。


コメント