ios-localization について
Appleプラットフォームのアプリ開発者向けのローカライズと国際化のガイドです。String Catalog、文字列型の使い分け、ロケール対応の書式設定、RTLレイアウト、テスト方法を扱います。
主な機能
- 01String Catalogと生成シンボル
- 02ローカライズ文字列型の選択
- 03補間と複数形処理
- 04ロケール対応の書式設定
- 05RTLレイアウトへの対応
- 06ローカライズのテスト項目
活用シーン
- 01新しいアプリ文字列をString Catalogへ移行
- 02ビュー、サービス、システムUI向けの文字列型を選択
- 03ロケールに応じた日付、通貨、単位の表示
- 04長いテキストやRTL言語でレイアウトを確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill ios-localizationインストール後、Claude Code で/ios-localizationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/formatstyle-locale.mdstring-catalogs.md詳細
iOS のローカライズと国際化
String Catalog、最新の文字列型、ロケールに応じた書式設定、右から左へのレイアウトを使って、Apple プラットフォーム向けアプリをローカライズします。
目次
- String Catalog と生成されるシンボル
- 文字列型 -- 選択ガイド
- ローカライズされた文字列での文字列補間
- 複数形
- FormatStyle -- ロケールに応じた書式設定
- 右から左(RTL)へのレイアウト
- よくある間違い
- ローカライズのレビュー用チェックリスト
- 参考資料
String Catalog と生成されるシンボル
String Catalog は、Xcode 15 以降で新たにローカライズを行う際に推奨されるワークフローです。ローカライズ可能な文字列、複数形のルール、デバイスごとのバリエーションを、ビジュアルエディタを備えた Xcode 管理の JSON ファイルにまとめて管理できます。移行中は従来の .strings ファイルや .stringsdict ファイルと併用できますが、新しい Swift および SwiftUI のコードでは String Catalog を標準として使用してください。
自動抽出の仕組み:
Xcode はビルドのたびに、次のパターンをスキャンします。
// SwiftUI -- automatically extracted (LocalizedStringKey)
Text("Welcome back") // key: "Welcome back"
Label("Settings", systemImage: "gear")
Button("Save") { }
Toggle("Dark Mode", isOn: $dark)
// Programmatic -- automatically extracted
String(localized: "No items found")
LocalizedStringResource("Order placed")
// Plain String: not extracted or localized
let msg = "Hello"
Xcode は見つかったキーを String Catalog に自動で追加します。エディタで翻訳を Needs Review、Translated、または Stale としてマークします。
String Catalog の詳しいワークフロー、移行方法、テスト戦略については、references/string-catalogs.md を参照してください。
生成されるシンボルは、String Catalog に対する Xcode 26 の型付きアクセサーレイヤーです。 カタログが Xcode 15 で利用可能であることに変わりはありません。
有効化: Build Settings > Localization > Generate String Catalog Symbols → Yes(新しい Xcode 26 プロジェクトではデフォルトで有効)。カタログ形式バージョン 1.1 が必要です。
ワークフロー: String Catalog エディタの(+)ボタンからキーを手動で追加します。手動で追加したキーでは、Generate Swift Symbol のチェックボックスがデフォルトで有効です。自動抽出されたキーも、Refactor > Convert Strings to Symbols から生成シンボルを有効にできます。生成シンボルを使う文字列には、安定した手動キーを使用してください。API に公開する文字列には、ソースの文言から生成されるキーを使わないでください。文言を編集すると生成される識別子が変わり、呼び出し箇所にも変更が発生する可能性があります。
// Generated from key "room_available" in Localizable.xcstrings
Text(.roomAvailable)
// Parameterized key "landmarks_count" with %1$(count)lld
Text(.landmarksCount(count: 42))
// Non-default table "Booking.xcstrings"
Text(.Booking.confirmBookingCta)
Xcode はキーをキャメルケースにしてシンボル名を導出します。例:settings.notifications.toggle → .settingsNotificationsToggle。Refactor > Convert Strings to Symbols から、既存の抽出済み文字列をシンボルに変換できます(元に戻すことも可能です)。
生成されるシンボルは internal です。モジュール間でアクセスするには、公開するラッパー拡張を作成してください。複数のモジュールを扱うより複雑な構成では、代わりに xcstrings-tool を使用してください。
生成シンボルの詳しいリファレンス(抽出状態、シンボルの導出ルール、モジュール間での利用パターン)については、references/string-catalogs.md を参照してください。
文字列型 -- 選択ガイド
| コンテキスト | 型 | 理由 |
|---|---|---|
| SwiftUI ビューのテキスト | LocalizedStringKey(暗黙的) | SwiftUI が検索を行います |
| ビューモデル、サービス、エラー | String(localized:) | その場で String に解決します |
| App Intents、ウィジェット、表示が遅延されるシステム UI | LocalizedStringResource | 表示されるまでローカライズ情報を保持します |
| ユーザー向けではないログや分析 | 通常の String | ローカライズは不要です |
LocalizedStringKey(SwiftUI のデフォルト)
SwiftUI ビューは、テキストパラメーターに LocalizedStringKey を受け取ります。文字列リテラルは暗黙的に変換されるため、追加の作業は必要ありません。
Text("Welcome back")
Button("Delete") { deleteItem() }
文字列を SwiftUI ビューのイニシャライザーに直接渡す場合は、LocalizedStringKey を使用してください。ほとんどの場合、LocalizedStringKey を手動で生成する必要はありません。
String(localized:) -- 最新の NSLocalizedString 代替
SwiftUI ビューのイニシャライザーの外でローカライズされた文字列を使う場合に使用します。通常の String を返します。リテラル/補間イニシャライザーは iOS 15 以降で利用でき、LocalizedStringResource の解決は iOS 16 以降で利用できます。
let title = String(localized: "Welcome back")
let msg = String(localized: "error.network",
defaultValue: "Check your internet connection")
Swift パッケージのローカライズに失敗した場合は、バンドルのデバッグを行う前に、以下のリソースチェックリストを提示してください。
Package.swiftでdefaultLocalizationが宣言されている。- ターゲットの
resourcesリストで、カタログの場所が.process("Resources")のように処理されている。 Localizable.xcstringsが、実際にその処理対象のターゲットリソースパス内にある。 これらを確認してから、bundle: .moduleまたはText(..., bundle: .module)を使って検索をデバッグしてください。
既存の NSLocalizedString のリテラルキーは、引き続き Xcode のツールでエクスポートまたは移行できますが、新しい Swift コードでは String(localized:)、SwiftUI のリテラル、LocalizedStringResource、または生成されたシンボルを優先してください。
LocalizedStringResource -- 解決せずにローカライズ情報を渡す
文字列をローカライズ可能な値として後で解決するために保持する必要がある場合、特に App Intents、ウィジェット、通知、生成されたローカライズ可能なシンボル、LocalizedStringResource を直接受け取るシステム API で使用します。コードで解決済みの文字列をすぐに使う必要がある場合は、String(localized:) を使用してください。iOS 16 以降で利用できます。
struct OrderCoffeeIntent: AppIntent {
static var title: LocalizedStringResource = "Order Coffee"
}
func showAlert(title: LocalizedStringResource, message: LocalizedStringResource) {
let resolved = String(localized: title)
}
ローカライズされた文字列の文字列補間
ローカライズされた文字列内の補間値は、翻訳者が並べ替えられる位置引数になります。
// English: "Welcome, Alice! You have 3 new messages."
// German: "Willkommen, Alice! Sie haben 3 neue Nachrichten."
// Japanese: "Alice さん、新しいメッセージが 3 件あります。"
let text = String(localized: "Welcome, \(name)! You have \(count) new messages.")
String Catalog では、翻訳者が並べ替えられる %@ と %lld のプレースホルダーとして表示されます。
- 英語:
"Welcome, %@! You have %lld new messages." - 日本語:
"%@さん、新しいメッセージが%lld件あります。"
型安全な文字列補間(フォーマット指定子より推奨):
// Interpolation provides type safety
String(localized: "Score: \(score, format: .number)")
String(localized: "Due: \(date, format: .dateTime.month().day())")
複数形
String Catalog は、.stringsdict の XML を必要とせず、複数形をネイティブに処理します。
String Catalog での設定
ローカライズされた文字列に整数の補間が含まれている場合、Xcode はそれを検出し、String Catalog エディタで複数形のバリエーションを提示します。各 CLDR 複数形カテゴリーの翻訳を入力してください。
| カテゴリー | 英語の例 | アラビア語の例 |
|---|---|---|
| zero | (使用しません) | 0個の項目 |
| one | 1 item | 1個の項目 |
| two | (使用しません) | 2個の項目(二数形) |
| few | (使用しません) | 3~10個の項目 |
| many | (使用しません) | 11~99個の項目 |
| other | 2個以上の項目 | 100個以上の項目 |
英語で使われるのは one と other のみです。アラビア語では6種類すべてを使います。フォールバックとして、必ず other を入力してください。
// Code -- single interpolation triggers plural support
Text("\(unreadCount) unread messages")
// String Catalog entries (English):
// one: "%lld unread message"
// other: "%lld unread messages"
デバイスごとのバリエーション
String Catalog は、デバイスごとのテキスト(iPhone、iPad、Mac)に対応しています。
// In String Catalog editor, enable "Vary by Device" for a key
// iPhone: "Tap to continue"
// iPad: "Tap or click to continue"
// Mac: "Click to continue"
周囲の語を値の数や性に応じて活用させる必要がある場合は、Foundation の自動文法一致マークアップを使用してください。翻訳者が扱えるよう、活用対象となるフレーズ全体を保持してください。自動文法一致を参照してください。
FormatStyle -- ロケール対応のフォーマット
ユーザーに表示するフォーマットをハードコードしないでください。FormatStyle を使用し、en_US、de_DE、ar_SA、ja_JP など、異なるロケールで出力をテストしてください。
問題が数値、日付、通貨、単位、名前、リスト、暦、区切り文字、ロケールのプレビュー/テストなど、ロケールに応じたユーザー向け表示に関する場合、FormatStyle のガイダンスは ios-localization が担当します。カスタム FormatStyle、ParseableFormatStyle、解析、Date.IntervalFormatStyle、URL.FormatStyle、再利用可能なフォーマッター API の設計については、swift-formatstyle に振り分けてください。実装が明示的に求められていない限り、ios-localization のアドバイスはロケールのリスクとテストに絞ってください。
日付
let now = Date.now
// Preset styles
now.formatted(date: .long, time: .shortened)
// US: "January 15, 2026 at 3:30 PM"
// DE: "15. Januar 2026 um 15:30"
// JP: "2026年1月15日 15:30"
// Component-based
now.formatted(.dateTime.month(.wide).day().year())
// US: "January 15, 2026"
// In SwiftUI
Text(now, format: .dateTime.month().day().year())
数値
let count = 1234567
count.formatted() // "1,234,567" (US) / "1.234.567" (DE)
count.formatted(.number.precision(.fractionLength(2)))
count.formatted(.percent) // For 0.85 -> "85%" (US) / "85 %" (FR)
// Currency
let price = Decimal(29.99)
price.formatted(.currency(code: "USD")) // "$29.99" (US) / "29,99 $US" (FR)
price.formatted(.currency(code: "EUR")) // "29,99 EUR" (DE)
計測値
let distance = Measurement(value: 5, unit: UnitLength.kilometers)
distance.formatted(.measurement(width: .wide))
// US: "3.1 miles" (auto-converts!) / DE: "5 Kilometer"
let temp = Measurement(value: 22, unit: UnitTemperature.celsius)
temp.formatted(.measurement(width: .abbreviated))
// US: "72 F" (auto-converts!) / FR: "22 C"
期間、名前、リスト、カスタムスタイル、バリエーションのマトリックス、より詳細な RTL テストについては、references/formatstyle-locale.md を読み込んでください。
右から左(RTL)へのレイアウト
SwiftUI は RTL 言語(アラビア語、ヘブライ語、ウルドゥー語、ペルシア語)のレイアウトを自動的に反転します。ほとんどのビューで変更は不要です。
SwiftUI が自動的にミラーリングするもの
HStackの子要素は順序が逆になります.leading/.trailingの配置とパディングは左右が入れ替わりますNavigationStackの戻るボタンは末尾の端に移動しますListの開示インジケーターは反転します- テキストの配置は読み方向に従います
手動での対応が必要なもの
// Testing RTL in previews
MyView()
.environment(\.layoutDirection, .rightToLeft)
.environment(\.locale, Locale(identifier: "ar"))
// Images that should mirror (directional arrows, progress indicators)
Image(systemName: "chevron.right")
.flipsForRightToLeftLayoutDirection(true)
// Images that should NOT mirror: logos, photos, clocks, music notes
// Forced LTR for specific content (phone numbers, code)
Text("+1 (555) 123-4567")
.environment(\.layoutDirection, .leftToRight)
レイアウトのルール
- 推奨:
.leading/.trailingを使用します。RTL では自動的に反転します - 非推奨:
.left/.rightは使用しません。固定されているため、RTL でレイアウトが崩れます - 推奨:
HStack/VStackを使用します。レイアウト方向に従います - 非推奨:方向に応じた位置指定に、絶対値の
offset(x:)を使用しません
よくある間違い
非推奨:幅が固定されたレイアウトを使用する
// WRONG -- German text is ~30% longer than English
Text(title).frame(width: 120)
推奨:柔軟なレイアウトを使用する
// CORRECT
Text(title).fixedSize(horizontal: false, vertical: true)
// Or use VStack/wrapping that accommodates expansion
非推奨:疑似ローカライズのテストを省略する
英語だけでテストすると、文字切れ、レイアウト、RTL のバグが見つかりません。
推奨:最低限、ドイツ語(長文)とアラビア語(RTL)でテストする
デバイスのロケールを変更せずに、Xcode のスキーム設定でアプリの言語を上書きできます。
レビューチェックリスト
- ユーザーに表示されるすべての文字列がローカライズを使用している(SwiftUI では
LocalizedStringKey、またはString(localized:)) - ユーザーに表示されるテキストを文字列結合で作成していない
- 日付と数値でハードコードされた形式ではなく
FormatStyleを使用している - 複数形は String Catalog の複数形バリアントで処理している(手動の if/else ではない)
- レイアウトで
.left/.rightではなく.leading/.trailingを使用している - 長いテキスト(ドイツ語)と RTL(アラビア語)で UI をテストしている
- String Catalog にすべての対象言語が含まれている
- RTL でのミラーリングが必要な画像で
.flipsForRightToLeftLayoutDirection(true)を使用している - App Intents とウィジェットで
LocalizedStringResourceを使用している - 新しいコードで
NSLocalizedStringを使用していない - 曖昧なキーにコメント(翻訳者向けのコンテキスト)を付けている
- Dynamic Type に合わせて拡大する必要がある間隔に
@ScaledMetricを使用している - 通貨の書式設定でロケールの既定値ではなく、明示的な通貨コードを使用している
- 疑似ローカライズをテストしている(アクセント付き、右から左、2 倍の長さ)
- 手動管理のキーで、キーに英語のテキストではなく、安定したシンボル形式の名前を使用している
- 手動管理のキーがあるターゲットで Generate String Catalog Symbols を有効にしている
- ローカライズされた文字列の型が Sendable であることを確認している。ロケール変更時の UI 更新には @MainActor を使用する
参考資料
- FormatStyle のパターン:references/formatstyle-locale.md
- String Catalog ガイド:references/string-catalogs.md