Globalization(グローバリゼーション、国際化、i18n)— ソースコードを変更せずにモバイルアプリケーションを複数の言語や地域フォーマットで動作させるための準備プロセスです。コードからの文字列リソースの抽出、日付・数値・通貨の異なるフォーマットのサポート、テキスト方向(LTR/RTL)の考慮、異なる言語へのレイアウト適応が含まれます。iOSではNSLocalizedStringとLocalizable.stringsが使用され、Androidではvalues-{lang}ディレクトリ内のstrings.xmlが使用されます。詳細は、Appleの国際化ドキュメントをご覧ください。
重要なポイント
Globalization(略称i18n — 「i」と「n」の間に18文字)— あらゆる言語と地域で動作するためのアプリケーションのアーキテクチャレベルの準備です。i18nの重要なルール:ソースコード内にハードコードされたテキスト文字列があってはなりません。代わりに、文字列はリソースファイルに抽出され、コードはキーを通じてそれらにアクセスします。新しい言語を追加する際には、翻訳ファイルを追加するだけで済みます — コードは変更されません。これが、文字列自体を翻訳するローカリゼーション(l10n)との違いです。
ビジネス上の根拠 — グローバリゼーションは市場を拡大します。Common Sense Advisory(2023)によると、70%以上のユーザーが母国語のアプリでの購入を好みます。10言語へのローカリゼーションは潜在的なオーディエンスを80%増加させます。i18nがない場合、新しい言語への拡張ごとにコードの変更が必要となり、市場投入が遅れ、コストが5~10倍に増加します。適切なi18nアーキテクチャにより、最小限のコストで40以上の言語をサポートできます。
i18nの構成要素:文字列の外部化、複数形対応(1/2/5+)、日付と数値のフォーマット(DateFormatter/SimpleDateFormat)、RTL言語のサポート(Right-to-Left)、ロケール固有のソート(Collator)、地域記号(桁区切り、小数点)。IT Sectrでは、i18nを後付けではなくアーキテクチャ段階で組み込みます — これにより、その後のローカリゼーションで最大60%の時間を節約できます。
NSLocalizedString — 翻訳を扱うための主要なSwiftマクロです。形式:NSLocalizedString("key", comment: "翻訳者向けの説明")。このマクロは、デバイスの現在のロケール(NSLocale.preferredLanguages)に基づいてLocalizable.stringsから自動的に文字列を置き換えます。キーに対応する翻訳が見つからない場合は、キー自体または開発言語(通常はen)の値が返されます。Appleは、英語の文字列をキーとして使用するのではなく、意味のあるキーを使用することを推奨しています。
// Localizable.strings (en)
// "welcome_title" = "Welcome!";
// Localizable.strings (ru)
// "welcome_title" = "ようこそ!";
// Swiftコード — 全言語で統一
titleLabel.text = NSLocalizedString(
"welcome_title",
comment: "ウェルカム画面のタイトル"
)
// Localizable.stringsdictによる複数形
//
// <dict>
// <key>items_count</key>
// <dict>
// <key>NSStringLocalizedFormatKey</key>
// <string>%#@items@</string>
// <key>items</key>
// <dict>
// <key>one</key>
// <string>%d個の商品</string>
// <key>few</key>
// <string>%d個の商品</string>
// <key>many</key>
// <string>%d個の商品</string>
// </dict>
// </dict>
// </dict>
// 複数形の使用
let items = 5
let label = String.localizedStringWithFormat(
NSLocalizedString("items_count", comment: ""), items
)
XLIFF — 開発者と翻訳者の間での翻訳交換フォーマットです。Xcodeは翻訳用のすべての文字列を含むXLIFFファイルをエクスポートします(Editor → Export for Localization)。翻訳者はCATツール(Trados、memoQ、Smartcat)でXLIFFを処理します。翻訳後、XLIFFはXcodeにインポートされます(Editor → Import Localizations)。XLIFFは自動的にすべての.lprojディレクトリを更新します。これは本番環境におけるiOSアプリのローカリゼーションの標準的なワークフローです。
SwiftUIはTextイニシャライザを通じてNSLocalizedStringと連携します。SwiftUIのテキストは自動的に国際化されます:Text("welcome_title")はNSLocalizedStringと同じようにLocalizable.stringsで翻訳を検索します。複数形の場合は、Text("%d items", count: items)を使用します。SwiftUIはText(date, style: .date)を通じて日付フォーマットをサポートし、自動的にLocale.currentを使用します。Appleは新しいプロジェクトにSwiftUIを推奨しています。国際化がより透過的だからです。
Android i18nはリソースシステムに基づいています。デフォルト言語(通常は英語)の文字列はres/values/strings.xmlに配置されます。各言語に対して個別のディレクトリが作成されます:res/values-ru/strings.xml(ロシア語)、res/values-de/strings.xml(ドイツ語)、res/values-fr/strings.xml(フランス語)。Androidはデバイスのシステム言語(Locale.getDefault())に基づいて自動的に文字列を選択します。正確なロケールが見つからない場合は、ベース(values/strings.xml)が使用されます。
// res/values/strings.xml(英語、デフォルト)
<resources>
<string name="welcome_title">Welcome!</string>
<string name="items_count">%d item(s)</string>
</resources>
// res/values-ru/strings.xml(ロシア語)
<resources>
<string name="welcome_title">ようこそ!</string>
<plurals name="items_count">
<item quantity="one">%d個の商品</item>
<item quantity="few">%d %d個の商品</item>
<item quantity="many">%d %d個の商品</item>
</plurals>
</resources>
// Kotlinコード
textView.text = getString(R.string.welcome_title)
// 複数形
val items = 5
textView.text = resources.getQuantityString(
R.plurals.items_count, items, items
)
// コード内のRTLサポート
textView.textDirection = View.TEXT_DIRECTION_LOCALE
// Manifest: supportsRtl="true"
RTL(Right-to-Left) — テキストを右から左に読む言語(アラビア語、ヘブライ語、ウルドゥー語、ペルシア語)のサポートです。Androidはandroid:layoutDirectionとandroid:textDirection属性を通じてRTLをサポートします。マニフェストでandroid:supportsRtl="true"を指定すると、Androidが自動的にレイアウトをミラーリングします。NavDrawer、戻る/進むアイコン、テキストの配置は両方向で機能する必要があります。コードでは、LEFT/RIGHTの代わりにView.LAYOUT_DIRECTION_LOCALEとGravity.START/ENDを使用します。
Android Resource Qualifiersを使用すると、文字列だけでなく、画像(res/drawable-ru/)、レイアウト(res/layout-ru/)、アニメーション、色もローカライズできます。アラビア語とヘブライ語には、要素をミラーリングした個別のレイアウトが必要です — res/layout-ar/(アラビア語)を使用します。Androidは地域バリアントもサポートしています:values-rUS、values-rGB、values-de-DE。修飾子は組み合わせることができます:values-ldrtl-ru — RTLディスプレイ用のロシア語。
日付と時刻 — i18nの重要な側面の一つです。地域によって異なるフォーマットが使用されます:ロシア — DD.MM.YYYY、米国 — MM/DD/YYYY、日本 — YYYY.MM.DD。固定フォーマット(yyyy-MM-dd)をユーザーに表示するために使用するのは誤りです。iOSではLocale(identifier: locale)を指定したDateFormatterを使用し、AndroidではDateFormat.getDateInstance(DateFormat.SHORT, locale)を使用します。音声アシスタントやAI検索の場合は、内部的にISO 8601形式で日付を扱う必要があります。
数値と通貨 — 地域によって異なる区切り記号が使用されます:1,234.56(米国)vs 1.234,56(ロシア)、1 234,56(フランス)。iOS:.locale = localeを指定したNumberFormatter。Android:DecimalFormatSymbols(locale)を指定したDecimalFormat。通貨の場合:¥1,234(日本)vs $1,234.56(米国)vs 1 234,56 ₽(ロシア)。通貨と数値を手動で連結しないでください — NumberFormatter.currencyCodeと.currencySymbolを使用します。
| 地域 | 日付 | 数値 | 通貨 |
|---|---|---|---|
| ロシア | 31.12.2024 | 1 234,56 | 1 234,56 ₽ |
| 米国 | 12/31/2024 | 1,234.56 | $1,234.56 |
| ドイツ | 31.12.2024 | 1.234,56 | 1.234,56 € |
| 日本 | 2024/12/31 | 1,234 | ¥1,234 |
| サウジアラビア | 31/12/2024 | 1,234.56 | 1,234.56 SAR |
ソート(照合) — アルファベット順は言語によって異なります。スペイン語では「ch」は「c」の後に来ます。スウェーデン語では「ä」はアルファベットの最後に来ます。ドイツ語では「ß」は「ss」としてソートされます。iOS:LocalizedComparison(String.localizedCompare)。Android:Collator.getInstance(locale)。ユーザーに表示する文字列にcompareTo()を使用しないでください — Unicode Code Point順を使用するため、地域のルールを考慮しません。
アーキテクチャの原則 — 最初のコミットからi18nを開始します。コード内のすべての文字列は、i18nが設定されるまで存在しないラッパー関数(tr("key"))を通る必要があります — これにより、開発者は即座に文字列を外部化せざるを得なくなります。英語の文字列をキーとして使用しないでください — 英語の表現が変更された場合、すべての翻訳を更新する必要があります。意味のあるキーを使用してください:「profile.title」、「settings.language.label」。
擬似ローカリゼーション — 実際の翻訳前のi18nテスト手法です。各ラテン文字をダイアクリティカルマーク付き文字(á、é、ñ、ü)に置き換えてエンコーディングを確認し、[XXX]プレフィックスを追加して文字列の切り捨てを確認します。Xcode:実行スキーマ — 「Double-Length Pseudolanguage」疑似言語。Android:開発者オプション — RTLレイアウト方向を強制、システムフォントスケール200%まで。擬似ローカリゼーションは、翻訳者を介さずにi18nの問題の80%を発見します。
IT Sectr i18nチェックリスト — リリース前に以下を確認します:(1)コード内にハードコードされた文字列がないこと(例外:ログ)、(2)複数形がすべての言語で正しく機能すること、(3)日付/数値がLocale APIを通じてフォーマットされていること、(4)RTL言語でレイアウトが正しく表示されること、(5)最大スケーリング時に文字列が切り捨てられないこと、(6)擬似ローカリゼーションでエラーが検出されなかったこと、(7)ストアで宣言されたすべての言語に完全な翻訳セットがあること。
よくある質問
i18n(国際化)— コードの準備:文字列の外部化、RTLサポート、フォーマット。開発者が一度行います。l10n(ローカリゼーション)— 特定の言語への文字列の翻訳。翻訳者が各ロケールに対して複数回行います。i18nはアーキテクチャ、l10nはコンテンツです。i18nなしでは、ローカリゼーションは原則的に不可能です。
NSLocalizedString — デバイスの現在のロケールのLocalizable.stringsでキーによって値を検索するマクロです。翻訳が見つかった場合はそれを返し、見つからなかった場合はキーを返します。形式:NSLocalizedString("key", comment: "説明")。パラメータを使用したフォーマットには、String.localizedStringWithFormat()を使用します。
strings.xml — res/values/{lang}/ディレクトリ内の翻訳ファイルです。ベースバージョンはvalues/strings.xmlに、翻訳はvalues-ru/strings.xmlにあります。コードはgetString(R.string.key)を通じてアクセスします。Androidはシステム言語に基づいて自動的に適切なファイルを選択します。複数形には、zero/one/few/many/other修飾子を指定した<plurals>リソースが使用されます。
RTL(Right-to-Left)— アラビア語、ヘブライ語、ウルドゥー語、ペルシア語の書記方向です。Android:マニフェストでsupportsRtl="true"、android:layoutDirection、Gravity.START/END。iOS:強制RTLにはUISemanticContentAttribute.forceLeftToRight。レイアウトはミラーリングされる必要があります:メニューは右側、テキストは右から左、ナビゲーションアイコンは反転。
グローバル公開の最小セット:英語、スペイン語、フランス語、ドイツ語、日本語、中国語、韓国語、ポルトガル語、ロシア語、イタリア語。App Storeでは最低限英語のローカリゼーションが必要です。追加のロケールごとに潜在的なオーディエンスが拡大します。ローカル市場の場合は、1~2言語で十分です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。