本番で驚かないための、500+キー対応のVue 3 i18nワークフロー
大規模アプリ向けの実践的なVue 3 i18nワークフロー:キー命名、複数形、QAチェック、リリース手順で本番での翻訳抜けを防ぎます。

500以上のi18nキーで何がまずくなるか
アプリが数百の文字列を超えると、最初に壊れるのはたいていVue I18n自体ではありません。壊れるのは一貫性です。人によってキーの付け方が違い、同じ意味の文言が別の名前で重複し、どのメッセージが安全に削除できるか誰も分からなくなります。
翻訳漏れも珍しくなくなります。設定やエラー状態、空の状態、通知など、あまり使われない画面で普通に現れがちです。
翻訳がないと、ユーザーは通常3つの失敗のどれかを目にします:空白のUI(ラベルのないボタン)、生のキー(checkout.pay_nowのように表示)、あるいはページの一部だけ言語が切り替わる奇妙なフォールバック。これらは小さなバグには見えません。アプリが壊れて見えます。
だからこそ、特定のライブラリよりもワークフローが重要になります。ライブラリはあなたが求めた通りに動きます。規模が大きくなると、チームは「完了」の定義で合意できないことがよくあります。
よくある例:開発者が40の新しい文字列を含む新しい「招待」フローを出しました。英語ファイルは更新されたがフランス語ファイルはされていません。ステージングではテスターが英語を使っているため問題が見えません。ところが本番ではフランス語ユーザーが翻訳済と未翻訳の混在を見て、サポートに生キーのスクリーンショットが届きます。
解決策は、翻訳されたUIの「完了」を定義することです。「文字列を追加しただけ」ではダメです。実践的な完了定義には通常次が含まれます:キーが命名ルールに従っている、ロケールのビルドに欠落キー警告がない、複数形や変数が実データで正しく表示される、少なくとも非デフォルトのロケールが一つチェックされている、そしてコピーの変更が追跡され古いキーが残らないようにする、など。
500以上のキーでは、ローカリゼーションをリリースプロセスとして扱うと勝ちます。最後のファイル編集ではなく、日常的なプロセスにすることです。
文字列を増やす前にいくつかルールを決める
数百の文字列を超えると、翻訳作業自体は混乱の主要因ではなくなります。一貫性が最大の問題になります。少数のルールを定めれば、複数人が毎週コピーに触れてもVue 3 i18nワークフローは予測可能になります。
まず「概念(concept)」をどう定義するか決め、一つの真のソースを保ちます。同じUIの考えが5箇所に出るなら(例:「変更を保存」)、キーは1つにします。save、saveChanges、save_update、saveBtnのようにばらばらにしないでください。重複したキーは時間とともに意味がずれて、ユーザーにもその不一致が伝わります。
次にフォーマットをどこで扱うか決めます。チームはしばしば無意識に分けてしまいます:あるメッセージは句読点や大文字小文字を含み、別の場所ではコードが追加します。どちらかを選んで徹底してください。
実用的なデフォルト案:
- 文法、句読点、ユーザー向けのフォーマット(例:「(任意)」)はメッセージに入れる。
- 純粋なデータのフォーマット(日時、通貨、単位)はコード側で行い、その結果をi18nに渡す。
- 名前や数のような可変部分はプレースホルダを使い、文字列連結は避ける。
- メッセージ内のHTMLは特例として明確なルールを持つ(許可するかしないか)。
次に所有権を定義します。誰が新しいキーを追加できるか、誰がベース言語のコピーをレビューするか、誰が他のロケールを承認するかを決めてください。これがないと、文字列は急いで追加されレビューされずに残ります。
最後にフォールバック戦略を選んで文書化します。キーがないときユーザーに何を見せるか:キー名、デフォルトロケールの文言、安全な一般メッセージのどれか。多くのチームは本番ではデフォルトロケールにフォールバックしつつログを取る方法を好みます。ユーザーがブロックされず、問題のシグナルは残るからです。
AppMaster(Vue3のWeb UIと実際のバックエンドコードの例)のようなジェネレータでVue 3アプリを作る場合も、これらのルールは当てはまります。翻訳を「単なる開発用テキスト」として扱わず、プロダクトコンテンツとして扱えば、リリース直前の驚きの大半を避けられます。
読みやすさを保つキー命名規約
数百の文字列を超えると、一貫性が最大の効果を発揮します。ひとつのキー形式を決めましょう(多くのチームはドット区切りのパス、例:billing.invoice.titleを使います)。ドット、スラッシュ、snake_case、ランダムな大文字小文字を混ぜると検索やレビューが遅くなります。
コピーの変更に耐える安定したキーを使ってください。例えば「Please enter your email」のような文全体をキーにするのは、マーケティングが文を変えた瞬間に壊れます。auth.email.requiredやauth.email.invalidのように意図ベースの名前を好みます。
まずプロダクト領域やUIサーフェスでグループ化し、その後目的で整理します。アプリが既に持っているバケツと同じに考えてください:auth、billing、settings、support、dashboard。こうするとロケールファイルの読みやすさが上がり、別の画面で同じ考えが必要になったときの重複が減ります。
各領域内では、一般的なUI要素のための小さなパターンセットを維持します:
- ボタン:
*.actions.save,*.actions.cancel - ラベル:
*.fields.email.label,*.fields.password.label - ヒント/ヘルプ:
*.fields.email.hint - エラー/バリデーション:
*.errors.required,*.errors.invalidFormat - 通知/トースト:
*.notices.saved,*.notices.failed
動的メッセージは「何が変わるか」を示し、「どう変わるか」は示さないでください。可変部分はパラメータにして、可変箇所を含めて意図で名前を付けます。例:billing.invoice.dueInDays に {days} を使う方が、billing.invoice.dueIn3Days のように具体に書くより明確です。
例:orders.summary.itemsCount に {count} を使って件数を渡し、orders.summary.total に {amount} を使うと、コード上でキーを読んだだけでその所在と目的が分かります。最終的なコピーが変わっても意味が通じます。
期待外れのない複数形ルールとメッセージフォーマット
複数形は英語だけを想定すると静かに壊れます。ICUメッセージ構文をいつ使うか、単純なプレースホルダで足りるかを早めに決めてください。
ラベルや短いUIテキストで数によって変わらないもの(例:「Welcome, {name}」)は単純な置換で十分です。一方で数に依存するものはICUを使いましょう。すべての形を一箇所にまとめ、ルールを明示できるからです。
{
"notifications.count": "{count, plural, =0 {No notifications} one {# notification} other {# notifications}}"
}
数を含むメッセージは翻訳しやすく書いてください。完全な文にして数のプレースホルダ(#)を名詞の近くに置くと良いです。コード側で「1件用」と「2件用」を使い回すような抜け道は避けてください。翻訳者は全体の文を見て正しく訳せる必要があります。
少なくとも =0、one、other を想定して書き、0 をどう扱うかを文書化してください。製品によって「0 items」か「No items」か好みが分かれます。スタイルを決めて統一すればUIの印象が安定します。
また、多くの言語が英語ほど単純に「one vs many」にならないことに注意してください。後で新しいロケールを追加するとき、one と other だけでは文法的に不適切になる場合があります。
出荷前に、JSONを見るだけでなくUI上で実際の数値で複数形をテストしてください。よくあるチェックは 0、1、2、5、21 です。これで多くの問題が見つかります。
AppMasterで生成したVue3のWebアプリなどを作る場合は、実際にそのテキストが表示される画面でテストしてください。レイアウトの崩れや文の切れ、うまくない言い回しは画面で初めて見つかることが多いです。
成長に備えたロケールファイルの整理
数百の文字列を超えると、1つの大きな en.json はボトルネックになります。複数人が同じファイルに触り、マージコンフリクトが増え、コピーがどこにあるか見失います。良い構成は、プロダクトが変わってもVue 3 i18nワークフローを安定させます。
推奨構成
2〜5ロケールなら、機能ごとに分けるだけで十分です。各ロケールで同じファイルレイアウトを保てば、キー追加が予測可能になります。
locales/en/common.json,locales/en/auth.json,locales/en/billing.jsonlocales/es/common.json,locales/es/auth.json,locales/es/billing.jsonlocales/index.ts(メッセージを読み込んでマージする)
20以上のロケールでは同じ考えを拡大し、ずれが生じにくくします。英語をソースオブトゥルースとして扱い、すべてのロケールが同じフォルダとファイル名を反映するように強制してください。新しいドメイン(例:notifications)が出たら、たとえ暫定のテキストでもすべてのロケールに存在するべきです。
ドメインで分割するとマージコンフリクトが減ります。二人が別のファイルに文字列を追加すれば干渉しないからです。ドメインはアプリの構成に合わせてください:common、navigation、errors、settings、reports、そして大きな領域は機能フォルダに分けます。
キーの一貫性を保つ
各ファイル内では、ロケール間で同じキー形状を保ってください:同じネスト、同じキー名、違うのはテキストだけ。言語ごとに「創造的」なキーを使うのは避けてください。英語に billing.invoice.status.paid があれば、すべてのロケールに同じキーを置きます。
本当に繰り返し使われるものだけを中央化します:ボタンラベル、一般的なバリデーションエラー、グローバルナビゲーションなど。機能固有のコピーはその機能ドメインの近くに置いてください。「Save」は common の方がよく、「Save payment method」は billing に置く、といった具合です。
長文コンテンツ
長いヘルプテキスト、オンボーディング手順、メールテンプレはすぐに混乱します。いくつかのルール:
- 長文は別ドメイン(例:
helpやonboarding)に入れ、深いネストは避ける。 - 翻訳者が扱いやすいように短い段落に分ける。
- マーケティングやサポートが頻繁に編集するテキストは専用ファイルにして他のファイルの変動を抑える。
- メールは件名と本文を分け、プレースホルダ(名前、日付、金額)を一貫させる。
このセットアップにより変更のレビュー、翻訳作業、リリース直前の穴を減らせます。
文字列追加と出荷のステップバイステップワークフロー
安定したVue 3 i18nワークフローはツールよりも「同じ小さな手順を毎回繰り返す」ことが大事です。新しいUIテキストはキー、デフォルトメッセージ、明確な翻訳ステータスなしに本番へ行ってはいけません。
まずベースロケール(多くは en)にキーを追加します。デフォルト文言はプレースホルダでなく実際のコピーを書いてください。これでプロダクトやQAがレビューしやすくなり、あとで「不明な文字列」が出るのを防げます。
コンポーネントでキーを使うときは、最初からパラメータと複数形ロジックを含めておくと、翻訳者がメッセージの全体像を見られます。
// simple param
$t('billing.invoiceDue', { date: formattedDate })
// plural
$t('files.selected', count, { count })
翻訳が間に合わないなら、キーを欠けたままにしないでください。他のロケールにプレースホルダ翻訳を追加するか、一貫した方法で未完了をマークします(例:値の先頭に TODO: を付ける)。重要なのはアプリが予測可能にレンダリングされ、レビュワーが未完了を見つけられることです。
マージ前に自動チェックを走らせてください。チェックは退屈で厳格で構いません:ロケール間の欠落キー、使われていないキー、プレースホルダ不一致({count}や{date}が抜けている)、サポートする言語に対する無効な複数形、意図しない上書きなど。
最後に、少なくとも一つの非ベースロケールで短いUIチェックを行います。文字数の長くなる言語(ドイツ語やフランス語など)を選ぶとオーバーフローやボタン切れを見つけやすいです。AppMasterで生成されたVue3 UIのように、機能の進化でレイアウトが変わる環境ではこのステップが特に重要です。
これらの手順を、テキストを追加するすべての機能の「完了定義」としてください。
チームが繰り返す一般的なミス
最もローカリゼーションを苦しくするのは、i18nキーを「ただの文字列」と扱うことです。数百のキーを超えると、小さな習慣が本番のバグになります。
意味がズレる、衝突する、誤解を招くキー
タイプミスや大文字小文字の差は欠落テキストの原因になります:checkout.title と Checkout.title が混在すると問題になります。コードレビューでは見落としやすく、フォールバック言語が静かに出荷されます。
別のよくある問題は、同じキーを異なる意味で使うことです。「Open」はサポート画面では「チケットを開く」を意味し、ストアページでは「今開く」を意味するかもしれません。一つのキーを共有すると、どちらかの画面が他言語で間違って表示されます。
単純なルール:キーは一つの意味に一意に対応させる。意味が変わるなら英語が同じであっても新しいキーを作ってください。
「文字列型」の想定によるレイアウト不具合
チームはしばしば句読点やスペース、HTMLを翻訳に埋め込みます。それはある言語ではうまくいきますが、別の言語が別の句読点や語順を必要とすると壊れます。テンプレート側でマークアップを扱い、メッセージはテキストに集中させてください。
モバイルでは問題が隠れがちです。英語で収まるラベルがドイツ語だと3行に折り返したり、タイ語では溢れたりします。画面サイズを一つしかテストしないと見逃します。
よくある落とし穴:英語の語順を前提に変数を挿入する、メッセージを断片的に連結する、長い値(商品名、住所、エラー詳細)をテストしない、欠落キーが英語で「問題ない」ように無音のフォールバックを有効にして出荷する、英語の値だけ編集してキーをコピペする、など。
500以上のキーで落ち着いたVue 3 i18nワークフローを望むなら、キーをAPIの一部として扱ってください:安定して具体的で、他のコードと同様にテストすること。
翻訳漏れを早期に見つけるQA手順
翻訳漏れはアプリが「動く」ため見落とされがちです。キーにフォールバックしたり、間違ったロケールが出たり、空文字が出るだけです。翻訳カバレッジをテストのように扱い、何かが本番に行く前に速やかにフィードバックを得られるようにします。
自動チェック(各PRで実行)
ビルドを失敗させるチェックから始めてください。警告を出すだけでは誰も見ません。
$t('...')やt('...')の使用をスキャンし、使用されているキーがベースロケールに存在するか検証する。- ロケール間のキーセットを比較し、どのロケールかがキーを欠いていれば失敗させる(例外リストは短くしチームが管理する)。
- ロケールファイルに存在するが使われていない孤立キーをフラグにする。
- メッセージ構文(プレースホルダ、ICU/複数形ブロック)を検証する。壊れたメッセージはランタイムでページをクラッシュさせることがある。
- 重複キーや大文字小文字の不一致をエラー扱いにする。
例外リストは短くし、チームが所有するようにしてください。「CIを通るものなら何でも良い」ではダメです。
ランタイムと視覚的チェック(ステージング)
CIがあってもステージングでのネットが欲しいです。本番で実際のユーザーパスが未翻訳の文字列を引き起こすことがあるからです。
ステージングでは欠落翻訳のログ出力をオンにして、修正を早く行えるようにコンテキスト(ロケール、ルート、コンポーネント名、欠落キー)を含めてください。簡単に無視できるようにすると無視されます。騒がしくしてください。
擬似ロケールを追加して簡単なUIパスを回すのも有効です。文字列を伸ばしたりマーカーをつけたりしてレイアウトの問題を目立たせます(例:[!!! 𝗧𝗲𝘅𝘁 𝗲𝘅𝗽𝗮𝗻𝗱𝗲𝗱 !!!])。これでクリップされたボタンや壊れたヘッダ、スペース不足を事前に見つけられます。
最後に、リリース前に主要なフローを2〜3ロケールでスポットチェックします:サインイン、支払い、コア設定、新機能など。この段階で「翻訳はあるがプレースホルダが間違っている」バグを見つけます。
新しい言語の追加と継続的なコピー変更の扱い方
新しい言語を追加する作業を「コピー作業」ではなく小さなプロダクトリリースとして扱うと混乱が減ります。アプリはロケールが不完全でもビルドできるようにしつつ、本番でユーザーに見せる前に穴が明確になるようにします。
新しいロケールを追加するときはまずソースロケール(多くは en)のファイル構成を生成してください。訳すより構造を先に作ること。
- 新しいロケールフォルダ/ファイルを作り、ソースから全キーセットをコピーする。
- 値はTODOプレースホルダでマークして、QAで未完了が見えるようにする。
- 基本的な部分がカバーされるまで言語切替に追加しない。
- 画面ごとのパスを回してレイアウト問題(語長化、折り返し)をチェックする。
翻訳は遅れて到着することが多いので、「部分的」が何を意味するか事前に決めてください。顧客向けの機能ならフィーチャーフラグで機能と文字列を一緒に出すことを考慮してください。どうしても完全訳なしで出すなら、空のラベルより英語フォールバックを選び、ステージングで大きく目立たせてください。
コピー更新はキーを壊す原因です。文言を変えるならキーは安定させてください。キーは正確な文を表すのではなく意図を表すべきです。意味が変わるときにだけキー名を変え、その際は移行を管理してください。
「ゾンビ文字列」を避けるために、キーは意図的に廃止扱いにしてください:廃止予定日と置換を明記し、1リリース周期保ち、参照がゼロになったことを確認してから削除します。
翻訳ノートはキーの近くに置いてください。JSONがコメントを持てないなら、小さな補助ドキュメントやメタデータファイルにメモを保存します(例:「checkout成功画面で使用」)。AppMasterのように複数の人がコピーとUIに触る環境では特に役立ちます。
例:60の新しい文字列を含む機能を出す場合
あるスプリントでチームが同時に3つのことを出します:新しい設定ページ、請求画面、3つのメールテンプレ(領収書、支払い失敗、トライアル終了)。およそ60の新しい文字列で、ここが汚れ始める典型です。
チームはキーを機能ごと、その後サーフェスごとにグループ化することで合意しました。各機能に新しいファイルを作り、どこでも同じパターン feature.area.element に従わせます。
// settings
"settings.profile.title": "Profile",
"settings.security.mfa.enable": "Enable two-factor authentication",
// billing
"billing.plan.current": "Current plan",
"billing.invoice.count": "{count} invoice | {count} invoices",
// email
"email.receipt.subject": "Your receipt",
"email.payment_failed.cta": "Update payment method"
翻訳作業が始まる前に、複数形の文字列は推測でなく実際の値でテストします。billing.invoice.count なら QA は 0、1、2、5 を種データや開発トグルでチェックし、「0 invoice」のようなおかしな結果をつぶします。
QAは次に、欠落キーを見つけやすいフローに絞った検査を行います:SettingsとBillingの各タブを一回ずつ開く、ステージングでテンプレをテストアカウントでトリガーする、非デフォルトロケールでアプリを動かす、ログに欠落翻訳警告が出たらビルドを失敗させる。
このスプリントでQAは請求画面のラベル1つとメール件名1つの欠落を見つけ、リリース前に修正されました。
リリースをブロックするかフォールバックで出すかはシンプルなルールで決めます:ユーザー向け画面とトランザクションメールはブロック、リスクの低い管理者向けテキストは期限付きでデフォルト言語にフォールバック可(ただしチケットと明確な期限付き)。
次のステップと簡単なリリースチェックリスト
Vue 3 i18nワークフローは翻訳をコードのように扱うと安定します:同じ方法で追加し、テストし、スコアを取る。短く具体的な手順を書き、誰でも従えるようにしてください。
リリースチェックリスト(マージ5分前)
- キー:命名パターンに従い、スコープを明確にする(ページ、機能、コンポーネント)。
- 複数形:少なくとも1つの言語で複数形が正しくレンダリングされることを確認する。
- プレースホルダ:変数が全ロケールで存在し同名であり、実データで見栄えを確認する。
- フォールバック:欠落キー時の挙動がポリシーに合っていることを確認する。
- 画面:壊れやすい数画面(テーブル、トースト、モーダル、空状態)をスポットチェックする。
測るべき指標(問題を早めに見つけるため)
いくつかの簡単な数値を選んで定期的に見てください:テスト実行での欠落キー率、非デフォルトロケールの未翻訳文字列数、使われていないキー数(どこにも参照がない文字列)。可能ならリリースごとに追跡して、傾向を見てください。
文字列追加、翻訳更新、検証の手順を正確に書き残してください。短く、キー名と複数形の使用例を含めます。新しい貢献者が説明なしで従えることが目的です。
内部ツールを作るなら、AppMaster(appmaster.io)はVue3のWebアプリとモバイルアプリでUIコピーと翻訳キーを一元管理する実用的な方法です。すべてを一箇所で扱えるため、整合性が保ちやすくなります。
各スプリントで小さなi18nの健康タスクを1つ入れてください:死んだキーを削除する、プレースホルダの不一致を修正する、最近の欠落をレビューする。小さな掃除が本番での緊急翻訳対応を防ぎます。


