GREE Tech Conference 2023で発表された資料です。 https://techcon.gree.jp/2023/session/TrackB-3
Unity,PHP+Jenkins+GAS多言語対応を意識させない開発を目指したシステム構築株式会社ポケラボ基盤エンジニア篠原 功
View Slide
自己紹介● 篠原 功 (Isao Shinohara)○ 2013年株式会社ポケラボに入社。○ 「SINoALICE -シノアリス-」「アサルトリリィ Last Bullet」などを経て現在は基盤チームに所属。○ ローカライズやリソース管理のシステム構築を中心に「開発・運用フローも踏まえた最適化」を目指して絶賛開発中。2
● これまでの海外対応状況と課題点・改修方針● システム化のための実装ルール● 翻訳依頼から反映までの作業フロー● 積み残しになっている課題● まとめアジェンダ3
● 多言語対応のために開発メンバーにお願いしている具体的な実装ルール● ゲーム内で使っている日本語テキストの抽出や翻訳後のフロー話すこと4
● 言語や地域の違いで発生する問題● リリース済みアプリを多言語対応するために役立つ情報● 画像に埋め込まれた日本語テキストやフォントなど話さないこと(話せないこと)5
● これまでの海外対応状況と課題点・改修方針● システム化のための実装ルール● 翻訳依頼から反映までの作業フロー● 積み残しになっている課題● まとめアジェンダ6
● 海外対応状況○ 「SINoALICE -シノアリス-」「戦姫絶唱シンフォギア XD UNLIMITED」などいくつかのアプリですでに海外リリース実績あり● 開発体制○ 日本版リリース後、海外版をリリース○ 開発チームは日本版、開発版で別チームこれまでの海外対応状況7
課題点● 日本語テキストの抽出作業負担● 連番によるID管理と翻訳間違い● git管理で発生していたコンフリクト問題● 翻訳チェックと巻き戻し作業の負荷8
日本語テキストの抽出作業負担● 内容○ 実装が完了したタイミングでプランナー、エンジニアそれぞれが翻訳対象となるテキストをまとめていた● 課題○ 日本語テキスト実装箇所は多岐に渡るので抽出が大変○ 手動で行うため抜け漏れが発生する可能性がある9
連番によるID管理と翻訳間違い● 内容○ 翻訳対象の日本語テキストに対し連番 IDを付与■ ID:1 おはよう■ ID:2 こんにちは■ ID:3 こんばんは○ 開発メンバーは日本語テキストと対応した IDを関連付ける● 課題○ 日本語テキスト実装箇所は多岐に渡るので IDの関連付け作業が大変○ 番号を間違えると誤った翻訳が行われる可能性がある○ 一度IDを割り振ったら変更することは至難10
git管理で発生していたコンフリクト問題● 内容○ 翻訳データはcsv形式で保存しGitHub上で管理● 課題○ 同じcsvファイルを編集することがありコンフリクトが発生していた○ 作業者にはgitのスキルが求められる11
● 内容○ QAチームは翻訳されたテキストを実機上ですべて確認● 課題○ 翻訳漏れが発生した場合の巻き戻し作業が多い○ 翻訳漏れは五月雨に発覚することもある翻訳チェックと巻き戻し作業の負担12
課題を踏まえた対応方針13
課題点● 日本語テキストの抽出作業負担● 連番によるID管理と翻訳間違い● git管理で発生していたコンフリクト問題● 翻訳チェックと巻き戻し作業の負担14
翻訳が必要な日本語テキストを自動抽出● 対応○ ゲーム内で利用しているテキストすべてを自動で抽出できるようにする● 期待○ 手動で日本語テキストを集めていた労力がなくなる○ 翻訳漏れが発生した際の手戻りもなくなる○ QAチームの確認範囲を限定15
課題点● 日本語テキストの抽出作業負担● 連番によるID管理と翻訳間違い● git管理で発生していたコンフリクト問題● 翻訳チェックと巻き戻し作業の負担16
IDを連番から日本語ハッシュ値に変更● 内容○ IDを日本語を元に生成したハッシュ値に変更■ 例:) こんにちは● ID: 1 -> ID: 20427A708C3F6…● 期待○ IDの採番と関連付けのための実装が不要になる○ IDの割り当て間違いによる誤った翻訳が防げる17
課題点● 日本語テキストの抽出作業負担● 連番によるID管理と翻訳間違い● git管理で発生していたコンフリクト問題● 翻訳チェックと巻き戻し作業の負担18
GoogleSpreadSheetを利用● 内容○ 翻訳作業はGoogleSpreadSheetで行う● 期待○ gitスキルが不要になる○ Web公開することで外部サービスとの連携が可能に19
対応方針● 翻訳が必要な日本語テキストを自動抽出● IDを連番から日本語ハッシュ値に変更● GoogleSpreadSheetを利用20
所感・実装コンセプト● 所感○ 日本語の開発完了後から翻訳対応までの作業量が多い○ どのような実装になっているかでその作業量は大幅に変わる● 実装コンセプト○ 日本向けに開発しているメンバーがいつも通り作業をしているだけで多言語対応のための実装も完了している21
● これまでの海外対応状況と課題点・改修方針● システム化のための実装ルール● 翻訳依頼から反映までの作業フロー● 積み残しになっている課題● まとめアジェンダ22
翻訳対象● クライアント (Unity)○ シーン・プレハブ■ TextMeshProなどのコンポーネント■ SerializeField○ ソースコード (C#)○ ScriptableObject● サーバー (PHP, Spanner, Smarty)○ マスタデータ○ yaml○ ユーザーデータ○ WebView23
シーン・プレハブ● 対象箇所○ シーン、プレハブでアタッチしているTextMeshProなどのテキストコンポーネント● 実装ルール○ 翻訳用のコンポーネントをアタッチ■ 翻訳不要でもアタッチ● 抽出方法○ AssetDatabase.FindAssets("t:Scene t:Prefab");○ GameObjectにアタッチされているテキストコンポーネントから翻訳対象テキストを取得● 表示処理○ シーン、プレハブをアクティブにするタイミングで各言語の翻訳テキストに置き換え24
SerializeField● 対象箇所○ public stringや[SerializeField] private stringで作成した変数にインスペクターから入力しているテキスト● 実装ルール○ 使用禁止● 理由○ 翻訳対象の日本語テキストを抽出するのが難しい○ 翻訳処理を通しているかの保証ができない25
ScriptableObject● 対象箇所○ ScriptableObject内に含まれるテキストデータ○ ADVパートのシナリオ管理に利用● 実装ルール○ なし● 抽出方法○ ScriptableObjectファイルをロード後、翻訳対象の日本語テキストを取得● 表示処理○ 言語毎に翻訳された JSONファイルを用意して管理■ story.asset -> story_en-Latn.json,story_ko-Kore.json■ JsonUtility.ToJson();○ 空のScriptableObjectにJSONのデータを反映■ JsonUtility.FromJsonOverwrite();26
ソースコード (C#)● 対象箇所○ ソースコードに直に記述している日本語テキスト● 実装ルール○ 決められたクラス内に定義○ プロパティ形式にして翻訳メソッドを通す○ 決められたクラス以外で定義することは禁止● 抽出方法○ 決められたクラス内に存在する string or string[]を返すプロパティから翻訳対象のテキストを取得● 表示処理○ プロパティ利用時に各言語の翻訳テキストを返却27
マスタデータ● 対象箇所○ Spannerで管理されている全ユーザー共通データ● 実装ルール○ なし● 抽出方法○ テーブルのスキーマ情報から STRING(XX)で定義されているカラムの値を取得● 表示処理○ 言語毎に翻訳済みのマスタテーブルを用意し、利用時に対象テーブルを切り替える■ ItemMst -> ItemMst_en-Latn,ItemMst_ko-Kore28
yaml● 対象箇所○ yamlファイル内に記述しているテキスト● 実装ルール○ なし● 抽出方法○ 正規表現で「ひらがな」「カタカナ」「漢字」を含んだテキストを抽出○ 英語で記述されたテキストも翻訳対象だったケースにどう対応するかは課題■ 例:) HP, MP● 表示処理○ yamlのパース処理後に対象日本語テキストを各言語の翻訳テキストに置き換え○ 置き換えたyamlは言語毎にキャッシュ29
ユーザーデータ● 対象箇所○ データベースにユーザー個別で記録している日本語テキスト● 実装ルール○ 日本語テキストで記録● 抽出方法○ マスタデータやyamlに記載されている日本語テキストの場合は必要なし○ 上記以外の日本語テキストを利用するケースにどう対応するかは課題● 表示処理○ テーブルからデータ取得時に日本語テキストを各言語の翻訳テキストに置き換える30
WebView● 対象箇所○ テンプレートファイル内に直接記述されている日本語テキスト○ テンプレートエンジンを利用してプログラムから埋め込まれている文字列■ マスタデータやyamlに記載されている日本語テキストの場合は必要なし● 実装ルール○ なし● 抽出方法○ テンプレートファイル内の要素を取得 (予定)● 表示処理○ テンプレート内に直接記述されている日本語テキストはロード時に各言語の翻訳テキストへと置き換える(予定)31
● これまでの海外対応状況と課題点・改修方針● システム化のための実装ルール● 翻訳依頼から反映までの作業フロー● 積み残しになっている課題● まとめアジェンダ32
翻訳対象となる日本語テキストの抽出フロー33
翻訳対象となる日本語テキストの抽出フロー34①
翻訳対象となる日本語テキストの抽出フロー35②②
翻訳対象となる日本語テキストの抽出フロー36③③
翻訳対象となる日本語テキストの抽出フロー37④④
Google Spread Sheet38
Google Spread Sheet39
Google Spread Sheet40
Google Spread Sheet41
Google Spread Sheet42
Google Spread Sheet43
翻訳作業後のフロー44
翻訳作業後のフロー45①
翻訳作業後のフロー46②
翻訳作業後のフロー47③
翻訳作業後のフロー48④
翻訳作業後のフロー49⑤
● これまでの海外対応状況と課題点・改修方針● システム化のための実装ルール● 翻訳依頼から反映までの作業フロー● 積み残しになっている課題● まとめアジェンダ50
UI テキストエリアのサイズ問題● 内容○ 言語によってはテキストがエリア内に収まらない問題● 原因○ 想定されるケース、解決方法が多岐にわたりシステム化が難しい● 方針○ 現時点で良い案がないことを周知○ ノウハウが溜まりシステム化できるまでは 1箇所1箇所対応51
「やってはいけないこと」の厳守● 内容○ 開発メンバーが「やってはいけない」を「やってしまってはいないか?」● 原因○ 「やってはいけないこと」の対象範囲が広い○ チェックツールの作成も難しい● 方針○ 現場レベルで各個人に厳守していただくことを口頭でお願い○ 問題ひとつひとうに対して泥臭く対応52
● これまでの海外対応状況と課題点・改修方針● システム化のための実装ルール● 翻訳依頼から反映までの作業フロー● 積み残しになっている課題● まとめアジェンダ53
実装ルール● クライアント (Unity)○ シーンやプレハブには必ず翻訳用のコンポーネントをアタッチ○ テキストは決められたクラスに定義■ プロパティ形式で翻訳処理を通す■ 特定クラス以外以外は使用禁止○ SerializeFieldを使った日本語テキストの利用は禁止● サーバー (PHP, Spanner, Smarty)○ 基本なし。ただし注意点あり。■ ユーザーデータに日本語テキストを保存する場合は日本語テキストのまま■ yamlに定義したテキストは英語のみだと翻訳されないので注意54
今後の展望● システムはまだ発展途上○ ゲームはまだリリースもされていない○ 翻訳チームの要望もまだ組み込めていない○ QAチームの要望もまだ組み込めていない● 実装したい機能○ デバッグツール○ Slack連携55
56