目次
シリーズAの頃、ほぼすべてのスタートアップで交わされる会話があります。誰かがアナリティクスを見て、登録者の30%が非英語圏の国から来ていることに気づきます。プロダクトは英語のみです。これらのコホートからの解約は壊滅的です。エンジニアリングリードが言います、「国際化が必要だ」と。
そして見積もりが返ってきます:最低6か月。
その見積もりはほぼ常に正確で、ほぼ常に避けられるものです。
i18nを後付けする本当のコスト
CSA Researchによると、消費者の87%は自分の言語で代替品がある場合、英語のみのプロダクトからは購入しません。ローカリゼーション市場は2023年に62.7億ドルに達し、成長を続けています。これはニッチな数字ではありません——あなたがコードベースにひっそりとインストールした、アドレス可能な市場の上限を表しています。
後付けが高コストな理由は、国際化が技術的に難しいからではありません。i18nを考慮せずにアプリケーションが構築される方法にあります:
- 200のコンポーネントに散らばった文字列リテラル
- 米国の慣習にハードコードされた日付と数値のフォーマット
- 英語テキストに合わせてサイズ設定されたデータベース列
- 一度も検討されなかった右から左へのレイアウト
- 英語の文法的前提を中心に構造化されたコンテンツ
- 単一地域に結び付けられたタイムゾーン処理
これらはそれぞれ、初日に正しく行うのは安価です。しかし、コードベースが40,000行になり、元の前提の上に構築してきた4人のエンジニアがいる18か月目に解きほぐすのは苦痛です。
6か月の見積もりは翻訳を追加するためではありません。i18nを考慮せずに構築されたアプリケーションの部分を監査して書き直すためです。翻訳は作業の20%。残りの80%は考古学です。
実際にはいつ国際化すべきか?
この質問には2つの部分があります:アーキテクチャをi18n対応にするタイミングと、実際に複数の言語をリリースするタイミングです。
アーキテクチャ:常に初日から。
最初からi18n対応で構築するコストは約2時間のセットアップです。何も翻訳しません。翻訳者を採用しません。ただ、扉を閉じない意思決定をするだけです。
- 文字列をハードコードする代わりにリソースファイルに外部化する
- ロケール対応の日付/時刻ライブラリを使用する(Luxon、ロケールサポート付きdate-fns、Temporal)
Intl.NumberFormatをラップする数値フォーマットアプローチを選ぶ- テキスト拡張のためにUIにスペースを確保する(ドイツ語は英語より30%長くなることがある)
- 最初からロケールをユーザー設定として保存する
これは早すぎる最適化ではありません。オーバーエンジニアリングでもありません。変更したい可能性のある設定値に環境変数を使う理由と同じです——特定のニーズを見越しているのではなく、特定の落とし穴を避けているのです。
翻訳のリリース:シグナルを得た後。
初日にフランス語をリリースする必要はありません。準備ができている必要があります。実際に第2言語に投資する決断はデータに基づくべきです:
- ターゲット市場からオーガニックな登録を見ている
- 販売会話で取引を成立させるために必要とされている
- 英語普及率が低い市場に参入している
- 特定言語のカスタマーコホートがより高い率で解約している
そのシグナルが現れたとき、「i18n対応」とは6か月ではなく1週間で第2言語をリリースできることを意味します。
3か月タイムライントラップ
チームが陥るパターンはこうです:i18nが必要だと知っていて、間違いを犯したくないので「適切なi18nプロジェクト」を計画します。3か月と見積もります。その見積もりには以下が含まれます:
- 既存文字列の監査
- 翻訳パイプラインの構築
- 翻訳管理システムの統合
- 翻訳ベンダーとの調整
- すべてのロケールでのQA
プロジェクトが計画中の間、ロードマップは進み続けます。3か月のプロジェクトは機能をリリースしないため、常に優先度が下げられます。最終的に優先されるころには、コードベースが成長したため5か月のプロジェクトになっています。
罠はi18nをビッグバンの移行として扱うことです。代替案は、アーキテクチャから始めて段階的に構築する基盤として扱うことです。
最小限のi18nセットアップ
シードステージのReactまたはNext.jsアプリにおける「i18n対応」が実践でどのように見えるかを示します。セットアップに2時間かかり、翻訳の準備ができるまで継続的なオーバーヘッドはゼロです。
ステップ1:文字列外部化アプローチを選ぶ。
表示文字列をハードコードしないでください。最低限、JSONファイルに入れてください。より良いのは:最初から型付きのソリューションを使用することです。
// 悪い — ハードコードされた文字列
<button>Get started for free</button>
// より良い — 外部化、今は英語のみでも
// messages/en.json
{
"cta.getStarted": "Get started for free"
}
// コンポーネント
const t = useTranslations();
<button>{t('cta.getStarted')}</button>
まだ翻訳プラットフォームは必要ありません。英語のみであっても、ロケールごとに1つのJSONファイルで十分です。インライン文字列の代わりにt()を使う習慣が重要です。
ステップ2:初日からロケール対応フォーマット。
// 悪い — ハードコードされた米国フォーマット
const formatted = `$${price.toFixed(2)}`;
const date = new Date(ts).toLocaleDateString('en-US');
// 良い — ロケール対応
const formatted = new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'USD'
}).format(price);
const date = new Intl.DateTimeFormat(locale, {
dateStyle: 'medium'
}).format(new Date(ts));
後で第2のロケールを追加すると、フォーマットは自動的に機能します。80ファイルにわたるgrep-and-replaceは不要です。
ステップ3:テキスト拡張を考慮してデザインする。
UIに余裕を持たせてください。テキストが長くなっても優雅に対応するCSSを使用してください。テキストコンテナのピクセル固定幅を避けてください。これはデザインでコストゼロですが、ドイツ語をリリースする際のQAで実際のコストを節約します。
ステップ4:ロケールをファーストクラスのユーザー属性として保存する。
1つの言語をリリースしている場合でも、ユーザーモデルにpreferred_localeを保存してください。第2言語を追加すると、既存ユーザーはすでにロケール設定が保存されています。ライブデータの下でスキーマを移行する必要はありません。
スタートアップよくある間違い
「必要になったらi18nを追加する」 必要になる瞬間は、適切に行う時間がない瞬間です。決断を引き起こすシグナル——フランス語を必要とする主要顧客、地域的なgo-to-marketの推進——は常に緊急性を伴って現れます。
カスタム翻訳パイプラインの構築。 翻訳管理は解決済みの問題です。カスタムソリューションは構築に数週間、メンテナンスに数か月かかります。既存のツールを使用してください。
ローカリゼーションを単なる翻訳として扱う。 言語はローカリゼーションの20%です。通貨、日付形式、住所形式、法的要件、RTLサポート、ロケール固有のUX慣習——これらが残りの80%です。壊れたレイアウトの翻訳された文字列は、やはり壊れた体験です。
翻訳者にJSONファイルへの直接アクセスを与える。 人間の翻訳者はJSONを手動で編集すべきではありません。エラー率が高く、フィードバックサイクルが遅いです。文脈、文字数制限、用語の一貫性強制を備えた翻訳作業用に構築されたUIが必要です。
英語の語順が一般化できると仮定する。 JavaScriptの文字列補間で翻訳された文字列を連結すると、異なる文法構造を持つ言語では壊れます。変数を含むものにはICUメッセージフォーマットを使用してください。
// 悪い — 英語の語順を仮定
t('welcome') + ' ' + userName + '!'
// 良い — ICUフォーマット、ロケールはトークンを並べ替えられる
t('welcome', { name: userName })
// en: "Welcome, {name}!"
// ja: "{name}さん、ようこそ!"
意思決定フレームワーク
これを使って現在の状況と次のステップを判断してください:
| ステージ | i18nアーキテクチャ | アクティブな翻訳 |
|---|---|---|
| プロダクト前 | 外部化された文字列、ロケール対応フォーマットをセットアップ | なし |
| PMF前 | 基盤を維持、まだ翻訳しない | なし |
| PMF後、シリーズA前 | 国際的なシグナルが見えたら、上位2言語を翻訳 | 場合による |
| シリーズA以降 | ローカリゼーションをプロダクト要件として扱う | あり |
重要な洞察:アーキテクチャの決断と翻訳の決断は独立しています。アーキテクチャの決断は今行ってください。翻訳の決断はデータが示すときに行ってください。
実践的なチェックリスト
次のコンポーネントを書く前に、これを確認してください:
- 文字列が外部化されている(JSX/テンプレートにハードコードされていない)
- 日付フォーマットはロケール対応APIを使用している
- 数値と通貨フォーマットは
Intl.NumberFormatを使用している - ユーザーモデルに
localeフィールドがある - UIレイアウトが30%長いテキストでテストされている
- 翻訳可能な部分との文字列連結がない
- 変数を含む文字列にICUメッセージフォーマットを使用している
- 複数形が正しく処理されている(単に「s」を追加するだけでなく)
これらすべてをチェックするのに2時間かかります。スケールでいずれかを見逃すと、数週間のコストがかかります。
実践ではどのように見えるか
実際に複数の言語をリリースする準備ができたとき、ワークフローは「考古学的発掘」から「翻訳プロジェクト」に変わります。必要なもの:
- ソース文字列を翻訳者にエクスポートする方法
- 翻訳のレビュープロセス
- コードデプロイなしで文字列を更新するデプロイパイプライン
- 各ユーザーへの適切なロケールのランタイム配信
Better i18nでは、この特定の問題を中心にプラットフォームを構築しました——React、Next.js、Vue、Svelteのための型安全なSDK、翻訳がコードのようにレビューを経るGitベースの翻訳ワークフロー、そして再デプロイなしで翻訳を更新できるCDN配信。価格ページの無料プランは、予算コミットメントなしに基盤を構築したい初期段階のチームのためにサイズ設定されています。技術的な部分がどのように組み合わさるかを確認したい場合は、開発者向けページに全体像があります。
6か月の書き直しは避けられないものではありません。2時間の決断が長すぎるほど先延ばしにされた結果です。