mcpField
A
axiom-localization

axiom-localization

github.com/charleswiltgen開発1.2k178 回インストール今日更新
リポジトリ

axiom-localization について

Appleプラットフォームの開発者向けに、ローカライズと国際化を解説するガイドです。XcodeのString Catalog、SwiftUI/UIKit API、複数形、RTLレイアウト、ロケール対応の書式設定、旧形式からの移行を扱います。

主な機能

  1. 01Xcode String Catalogの管理
  2. 02SwiftUIとUIKitのローカライズ
  3. 03複数形とRTLレイアウトへの対応
  4. 04ロケールに応じた値の書式設定
  5. 05旧形式のローカライズファイル移行

活用シーン

  1. 01アプリに複数言語を追加
  2. 02翻訳漏れや複数形の誤りを調査
  3. 03アラビア語やヘブライ語のレイアウトに対応
  4. 04.stringsファイルを.xcstringsへ移行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-localization

インストール後、Claude Code で/axiom-localizationを入力して読み込まれたか確認します。

詳細

ローカライズと国際化

String Catalogs を使用したアプリのローカライズに関する包括的なガイドです。Apple Design Award のインクルージョン部門の受賞作は、優れた RTL(右から左)サポートとともに、常に複数の言語に対応しています。

概要

String Catalogs(.xcstrings)は、アプリのローカライズを管理するための Xcode 15 の統合形式です。従来の .strings ファイルと .stringsdict ファイルに代わる、保守や差分の確認、翻訳ワークフローとの統合が容易な、単一の JSON ベース形式です。

このスキルでは、String Catalogs、SwiftUI/UIKit のローカライズ API、複数形の処理、RTL サポート、ロケールに応じた書式設定、従来の形式からの移行方法について説明します。

このスキルを使用する場面

  • Xcode 15 以降で String Catalogs を設定する
  • SwiftUI および UIKit アプリをローカライズする
  • 複数形を適切に処理する(多くの言語で重要です)
  • RTL 言語(アラビア語、ヘブライ語)に対応する
  • ロケールに応じて日付、数値、通貨を書式設定する
  • 従来の .strings/.stringsdict ファイルから移行する
  • App Shortcuts と App Intents をローカライズできるよう準備する
  • 翻訳の欠落や誤った複数形をデバッグする

システム要件

  • String Catalogs(.xcstrings)には Xcode 15 以降
  • 自動シンボル生成、#bundle マクロ、AI を活用したコメント生成には Xcode 26 以降
  • LocalizedStringResource には iOS 15 以降
  • App Shortcuts のローカライズには iOS 16 以降
  • それ以前の iOS バージョンでは、従来の .strings ファイルを使用します

パート 1:String Catalogs(WWDC 2023/10155)

String Catalog の作成

方法 1:Xcode ナビゲーター

  1. File → New → File
  2. 「String Catalog」を選択します
  3. 名前を付けます(例:Localizable.xcstrings)
  4. ターゲットに追加します

方法 2:自動抽出

Xcode 15 では、次の場所から文字列を自動的に抽出できます。

  • SwiftUI ビュー(Text、Label、Button 内の文字列リテラル)
  • Swift コード(String(localized:))
  • Objective-C(NSLocalizedString)
  • C(CFCopyLocalizedString)
  • Interface Builder ファイル(.storyboard、.xib)
  • Info.plist の値
  • App Shortcuts のフレーズ

必要なビルド設定:

  • 「Use Compiler to Extract Swift Strings」 → Yes
  • 「Localization Prefers String Catalogs」 → Yes
String Catalog の構造

各エントリーには次の項目があります。

  • キー:一意の識別子(デフォルト:英語の文字列)
  • デフォルト値:翻訳がない場合のフォールバック
  • コメント:翻訳者向けの文脈情報
  • String Table:整理用のコンテナ(デフォルト:「Localizable」)

.xcstrings の JSON の例:

{
  "sourceLanguage" : "en",
  "strings" : {
    "Thanks for shopping with us!" : {
      "comment" : "Label above checkout button",
      "localizations" : {
        "en" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "Thanks for shopping with us!"
          }
        },
        "es" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "¡Gracias por comprar con nosotros!"
          }
        }
      }
    }
  },
  "version" : "1.0"
}
翻訳の状態

Xcode は翻訳ごとに状態を追跡します。

  • New(⚪)- 文字列がまだ翻訳されていません
  • Needs Review(🟡)- 原文が変更され、翻訳が古くなっている可能性があります
  • Reviewed(✅)- 翻訳が承認され、最新の状態です
  • Stale(🔴)- ソースコード内で文字列が見つからなくなりました

ワークフロー:

  1. 開発者が文字列を追加 → New
  2. 翻訳者が翻訳を追加 → Reviewed
  3. 開発者が原文を変更 → Needs Review
  4. 翻訳者が更新 → Reviewed
  5. 開発者がコードを削除 → Stale

パート 2:SwiftUI のローカライズ

LocalizedStringKey(自動)

String パラメーターを持つ SwiftUI ビューは、自動的にローカライズに対応します。

// ✅ Automatically localizable
Text("Welcome to WWDC!")
Label("Thanks for shopping with us!", systemImage: "bag")
Button("Checkout") { }

// Xcode extracts these strings to String Catalog

仕組み:SwiftUI は内部で LocalizedStringKey を使用し、String Catalogs 内の文字列を検索します。

コメント付きの String(localized:)

Swift コード内で明示的にローカライズする場合:

// Basic
let title = String(localized: "Welcome to WWDC!")

// With comment for translators
let title = String(localized: "Welcome to WWDC!",
                   comment: "Notification banner title")

// With custom table
let title = String(localized: "Welcome to WWDC!",
                   table: "WWDCNotifications",
                   comment: "Notification banner title")

// With default value (key ≠ English text)
let title = String(localized: "WWDC_NOTIFICATION_TITLE",
                   defaultValue: "Welcome to WWDC!",
                   comment: "Notification banner title")

ベストプラクティス:翻訳者に文脈を伝えるため、必ず comment を含めてください。

LocalizedStringResource(遅延ローカライズ)

ローカライズ可能な文字列を別の関数に渡す場合:

import Foundation

struct CardView: View {
    let title: LocalizedStringResource
    let subtitle: LocalizedStringResource

    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 10.0)
            VStack {
                Text(title)      // Resolved at render time
                Text(subtitle)
            }
            .padding()
        }
    }
}

// Usage
CardView(
    title: "Recent Purchases",
    subtitle: "Items you've ordered in the past week."
)

主な違い:LocalizedStringResource は使用されるまで検索を遅延するため、カスタムビューを完全にローカライズ可能にできます。

Markdown を使った AttributedString
// Markdown formatting is preserved across localizations
let subtitle = AttributedString(localized: "**Bold** and _italic_ text")

パート 3:UIKit と Foundation

NSLocalizedString マクロ
// Basic
let title = NSLocalizedString("Recent Purchases", comment: "Button Title")

// With table
let title = NSLocalizedString("Recent Purchases",
                             tableName: "Shopping",
                             comment: "Button Title")

// With bundle
let title = NSLocalizedString("Recent Purchases",
                             tableName: nil,
                             bundle: .main,
                             value: "",
                             comment: "Button Title")
Bundle.localizedString
let customBundle = Bundle(for: MyFramework.self)
let text = customBundle.localizedString(forKey: "Welcome",
                                        value: nil,
                                        table: "MyFramework")
カスタムマクロ
// Objective-C
#define MyLocalizedString(key, comment) \
    [myBundle localizedStringForKey:key value:nil table:nil]
Info.plist のローカライズ

アプリ名や権限などをローカライズします。

  1. Info.plist を選択します
  2. Editor → Add Localization
  3. 言語ごとに InfoPlist.strings を作成します。
// InfoPlist.strings (Spanish)
"CFBundleName" = "Mi Aplicación";
"NSCameraUsageDescription" = "La app necesita acceso a la cámara para tomar fotos.";

パート 4:複数形

言語によって複数形のルールは異なります。

  • 英語:2種類(単数、その他)
  • ロシア語:3種類(単数、少数、複数)
  • ポーランド語:3種類(単数、少数、その他)
  • アラビア語:6種類(ゼロ、単数、双数、少数、複数、その他)
SwiftUI での複数形の処理
// Xcode automatically creates plural variations
Text("\(count) items")

// With custom formatting
Text("\(visitorCount) Recent Visitors")

String Catalog 内:

{
  "strings" : {
    "%lld Recent Visitors" : {
      "localizations" : {
        "en" : {
          "variations" : {
            "plural" : {
              "one" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld Recent Visitor"
                }
              },
              "other" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld Recent Visitors"
                }
              }
            }
          }
        }
      }
    }
  }
}
XLIFF エクスポート形式

翻訳用にエクスポートする場合(File → Export Localizations):

レガシー形式(stringsdict):

<trans-unit id="/%lld Recent Visitors:dict/NSStringLocalizedFormatKey:dict/:string">
    <source>%#@recentVisitors@</source>
</trans-unit>

<trans-unit id="/%lld Recent Visitors:dict/recentVisitors:dict/one:dict/:string">
    <source>%lld Recent Visitor</source>
    <target>%lld Visitante Recente</target>
</trans-unit>

String Catalog(よりシンプル):

<trans-unit id="%lld Recent Visitors|==|plural.one">
    <source>%lld Recent Visitor</source>
    <target>%lld Visitante Recente</target>
</trans-unit>

<trans-unit id="%lld Recent Visitors|==|plural.other">
    <source>%lld Recent Visitors</source>
    <target>%lld Visitantes Recentes</target>
</trans-unit>
複数形変数を使った置換
// Multiple variables with different plural forms
let message = String(localized: "\(songCount) songs on \(albumCount) albums")

Xcode は、各変数の複数形ごとにバリエーションを作成します。

  • songCount:単数、その他
  • albumCount:単数、その他
  • 組み合わせの合計:2 × 2 = 4 件の翻訳項目

パート 5:デバイスと幅のバリエーション

デバイス固有の文字列

プラットフォームごとに異なるテキストを使用します。

// Same code, different strings per device
Text("Bird Food Shop")

String Catalog のバリエーション:

{
  "Bird Food Shop" : {
    "localizations" : {
      "en" : {
        "variations" : {
          "device" : {
            "applewatch" : {
              "stringUnit" : {
                "value" : "Bird Food"
              }
            },
            "other" : {
              "stringUnit" : {
                "value" : "Bird Food Shop"
              }
            }
          }
        }
      }
    }
  }
}

結果:

  • iPhone/iPad:「鳥の餌ショップ」
  • Apple Watch:「鳥の餌」(小さい画面向けに短縮)
幅のバリエーション

ダイナミックタイプやサイズクラス向け:

Text("Application Settings")

String Catalog では、幅の狭い表示向けに短いテキストを指定できます。


パート 6:RTL のサポート

レイアウトのミラーリング

SwiftUI は RTL 言語向けにレイアウトを自動でミラーリングします。

// ✅ Automatically mirrors for Arabic/Hebrew
HStack {
    Image(systemName: "chevron.right")
    Text("Next")
}

// iPhone (English): [>] Next
// iPhone (Arabic):  Next [<]
Leading/Trailing と Left/Right

常にセマンティックな方向指定を使用してください:

// ✅ Correct - mirrors automatically
.padding(.leading, 16)
.frame(maxWidth: .infinity, alignment: .leading)

// ❌ Wrong - doesn't mirror
.padding(.left, 16)
.frame(maxWidth: .infinity, alignment: .left)
画像とアイコン

反転する画像、反転しない画像を指定します。

// ✅ Directional - mirrors for RTL
Image(systemName: "chevron.forward")

// ✅ Non-directional - never mirrors
Image(systemName: "star.fill")

// Custom images
Image("backButton")
    .flipsForRightToLeftLayoutDirection(true)
RTL モードでのテスト

Xcode の Scheme:

  1. Edit Scheme → Run → Options
  2. Application Language:Arabic / Hebrew
  3. または:App Language → Right-to-Left Pseudolanguage

Simulator: 設定 → 一般 → 言語と地域 → 優先する言語の順序

SwiftUI のプレビュー:

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environment(\.layoutDirection, .rightToLeft)
            .environment(\.locale, Locale(identifier: "ar"))
    }
}

パート 7:ロケールに応じた書式設定

DateFormatter
let formatter = DateFormatter()
formatter.locale = Locale.current  // ✅ Use current locale
formatter.dateStyle = .long
formatter.timeStyle = .short

let dateString = formatter.string(from: Date())

// US: "January 15, 2024 at 3:30 PM"
// France: "15 janvier 2024 à 15:30"
// Japan: "2024年1月15日 15:30"

日付形式の文字列をハードコードしないでください:

// ❌ Wrong - breaks in other locales
formatter.dateFormat = "MM/dd/yyyy"

// ✅ Correct - adapts to locale
formatter.dateStyle = .short
通貨の NumberFormatter
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .currency

let priceString = formatter.string(from: 29.99)

// US: "$29.99"
// UK: "£29.99"
// Japan: "¥30" (rounds to integer)
// France: "29,99 €" (comma decimal, space before symbol)
MeasurementFormatter
let distance = Measurement(value: 100, unit: UnitLength.meters)

let formatter = MeasurementFormatter()
formatter.locale = Locale.current

let distanceString = formatter.string(from: distance)

// US: "328 ft" (converts to imperial)
// Metric countries: "100 m"
ロケール固有の並べ替え
let names = ["Ångström", "Zebra", "Apple"]

// ✅ Locale-aware sort
let sorted = names.sorted { (lhs, rhs) in
    lhs.localizedStandardCompare(rhs) == .orderedAscending
}

// Sweden: ["Ångström", "Apple", "Zebra"]  (Å comes first in Swedish)
// US: ["Ångström", "Apple", "Zebra"]      (Å treated as A)

パート 8:App Shortcuts のローカライズ

パラメーター付きフレーズ
import AppIntents

struct ShowTopDonutsIntent: AppIntent {
    static var title: LocalizedStringResource = "Show Top Donuts"

    @Parameter(title: "Timeframe")
    var timeframe: Timeframe

    static var parameterSummary: some ParameterSummary {
        Summary("\(.applicationName) Trends for \(\.$timeframe)") {
            \.$timeframe
        }
    }
}

String Catalog は次の項目を自動的に抽出します:

  • インテントのタイトル
  • パラメーター名
  • プレースホルダー付きのフレーズテンプレート

ローカライズされたフレーズ:

English: "Food Truck Trends for this week"
Spanish: "Tendencias de Food Truck para esta semana"
AppShortcutsProvider のローカライズ
struct FoodTruckShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: ShowTopDonutsIntent(),
            phrases: [
                "\(.applicationName) Trends for \(\.$timeframe)",
                "Show trending donuts for \(\.$timeframe) in \(.applicationName)",
                "Give me trends for \(\.$timeframe) in \(.applicationName)"
            ]
        )
    }
}

Xcode は3つすべてのフレーズを String Catalog に抽出し、翻訳できるようにします。


パート 9:レガシー形式からの移行

.strings から .xcstrings への変換

自動移行:

  1. ナビゲーターで .strings ファイルを選択します
  2. Editor → Convert to String Catalog を選択します
  3. Xcode が .xcstrings を作成し、翻訳を保持します

手動で行う場合:

  1. 新しい String Catalog を作成します
  2. プロジェクトをビルドします(Xcode がコードから文字列を抽出します)
  3. File → Import Localizations(XLIFF)から翻訳を読み込みます
  4. 古い .strings ファイルを削除します
.stringsdict の変換

複数形ファイルは自動的に統合されます:

  1. .strings と .stringsdict を同じ場所に置きます
  2. 変換すると、両方が1つの .xcstrings に統合されます
  3. 複数形のバリエーションは保持されます
段階的な移行戦略

フェーズ 1:新しいコードでは String Catalog を使用

  • Localizable.xcstrings を作成します
  • 新しいコードでは String(localized:) を使用します
  • 古いコード用にレガシーの .strings ファイルを残します

フェーズ 2:既存の文字列を移行

  • .strings テーブルを1つずつ変換します
  • 変換のたびに翻訳をテストします
  • 古い NSLocalizedString 呼び出しを使用しているコードを更新します

フェーズ 3:レガシーファイルを削除

  • .strings と .stringsdict ファイルを削除します
  • すべての文字列が String Catalog にあることを確認します
  • App Store に提出します

共存:.strings と .xcstrings は併用できます。Xcode は両方を確認します。


よくある間違い

ハードコードされた文字列
// ❌ Wrong - not localizable
Text("Welcome")
let title = "Settings"

// ✅ Correct - localizable
Text("Welcome")  // SwiftUI auto-localizes
let title = String(localized: "Settings")
ローカライズされた文字列の連結
// ❌ Wrong - word order varies by language
let message = String(localized: "You have") + " \(count) " + String(localized: "items")

// ✅ Correct - single localizable string with substitution
let message = String(localized: "You have \(count) items")

誤りである理由:名詞の前に数字を置く言語もあれば、後に置く言語もあります。

複数形の形式が不足している
// ❌ Wrong - grammatically incorrect for many languages
Text("\(count) item(s)")

// ✅ Correct - proper plural handling
Text("\(count) items")  // Xcode creates plural variations
RTL を考慮していない
// ❌ Wrong - breaks in RTL languages
.padding(.left, 20)
HStack {
    backButton
    Spacer()
    title
}

// ✅ Correct - mirrors automatically
.padding(.leading, 20)
HStack {
    backButton  // Appears on right in RTL
    Spacer()
    title
}
日付や数値の形式が不適切
// ❌ Wrong - US-only format
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"

// ✅ Correct - adapts to locale
formatter.dateStyle = .short
formatter.locale = Locale.current
コメントの記載漏れ
// ❌ Wrong - translator has no context
String(localized: "Confirm")

// ✅ Correct - clear context
String(localized: "Confirm", comment: "Button to confirm delete action")

影響:「Confirm」は「確認する」または「承認する」という意味の場合があり、正確に翻訳するには文脈が重要です。


トラブルシューティング

String Catalog に文字列が表示されない

原因:ビルド設定が有効になっていません。

解決方法:

  1. Build Settings → 「Use Compiler to Extract Swift Strings」→ Yes
  2. Clean Build Folder(Cmd+Shift+K)
  3. プロジェクトをビルドします。
アプリに翻訳が表示されない

原因 1:言語がプロジェクトに追加されていません。

  1. Project → Info → Localizations → + ボタン
  2. 対象言語を追加します。

原因 2:文字列に「Stale」のマークが付いています。

  • 古い文字列を削除するか、コードで引き続き使用されていることを確認します。
複数形が正しく表示されない

原因:String Catalog の代わりに String.localizedStringWithFormat を使用しています。

解決方法:String Catalog の自動複数形処理を使用します。

// ✅ Correct
Text("\(count) items")

// ❌ Wrong
Text(String.localizedStringWithFormat(NSLocalizedString("%d items", comment: ""), count))
XLIFF のエクスポートに文字列が含まれない

原因:「Localization Prefers String Catalogs」が設定されていません。

解決方法:

  1. Build Settings → 「Localization Prefers String Catalogs」→ Yes
  2. ローカライズを再度エクスポートします。
生成されたシンボルが表示されない(Xcode 26+)

原因 1:ビルド設定が有効になっていません。

解決方法:

  1. Build Settings → 「Generate String Catalog Symbols」→ Yes
  2. Clean Build Folder(Cmd+Shift+K)
  3. プロジェクトを再ビルドします。

原因 2:文字列がカタログに手動で追加されていません。

解決方法:シンボルは手動で追加した文字列(String Catalog の + ボタン)に対してのみ生成されます。自動抽出された文字列にはシンボルが生成されません。

#bundle マクロが動作しない(Xcode 26+)

原因:構文が間違っているか、インポートが不足しています。

解決方法:

import Foundation  // Required for #bundle
Text("My Collections", bundle: #bundle, comment: "Section title")

.module ではなく #bundle を使用していることを確認してください。

シンボルへのリファクタリングに失敗する(Xcode 26+)

原因 1:文字列が String Catalog にありません。

  1. 文字列が .xcstrings ファイルにあることを確認します。
  2. プロジェクトをビルドしてカタログを更新します。
  3. リファクタリングを再度試します。

原因 2:ビルド設定が有効になっていません。

  • Build Settings で「Generate String Catalog Symbols」を有効にします。
  • クリーンアップして再ビルドします。

Part 10: Xcode 26 のローカライズ機能強化

Xcode 26 では、生成されたシンボルによる型安全なローカライズ、デバイス上の AI を使用したコメントの自動生成、#bundle マクロによる Swift Package のサポート強化が導入されています。WWDC 2025 セッション 225「Explore localization with Xcode」に基づいています。

生成されたシンボル(型安全なローカライズ)

問題点:文字列ベースのローカライズでは、タイプミスがあってもエラーが通知されません。

// ❌ Typo - fails silently at runtime
Text("App.HomeScren.Title")  // Missing 'e' in Screen

解決方法:Xcode 26 は、手動で追加した文字列から型安全なシンボルを生成します。

仕組み
  1. String Catalog で + ボタンを使って文字列を手動で追加します。
  2. ビルド設定を有効にします:「Generate String Catalog Symbols」(新規プロジェクトではデフォルトで ON)
  3. 文字列の代わりにシンボルを使用します。
// ✅ Type-safe - compiler catches typos
Text(.appHomeScreenTitle)
シンボル生成ルール
文字列の種類生成されるシンボルの種類使用例
プレースホルダーなし静的プロパティText(.introductionTitle)
プレースホルダーありラベル付き引数を持つ関数.subtitle(friendsPosts: 42)

主な名前の変換:

  • App.HomeScreen.Title → .appHomeScreenTitle
  • ピリオドは削除され、キャメルケースに変換されます。
  • LocalizedStringResource で使用できます。
コード例
// SwiftUI views
struct ContentView: View {
    var body: some View {
        NavigationStack {
            Text(.introductionTitle)
                .navigationSubtitle(.subtitle(friendsPosts: 42))
        }
    }
}

// Foundation String
let message = String(localized: .curatedCollection)

// Custom views with LocalizedStringResource
struct CollectionDetailEditingView: View {
    let title: LocalizedStringResource

    init(title: LocalizedStringResource) {
        self.title = title
    }

    var body: some View {
        Text(title)
    }
}

CollectionDetailEditingView(title: .editingTitle)

コメントの自動生成

Xcode 26 はデバイス上のモデルを使用して、ローカライズ可能な文字列のコンテキストコメントを自動生成します。

機能を有効にする
  1. Xcode Settings → Editing を開きます。
  2. 「automatically generate string catalog comments」を有効にします。
  3. コードに追加された新しい文字列には、コメントが自動生成されます。
例

ボタンの文字列に対して、Xcode は次のように生成します。

「コレクションの削除をキャンセルするボタンのテキストラベル」

このコンテキストにより、翻訳者は文字列がどこで、どのように使われるかを理解しやすくなります。

XLIFF のエクスポート

自動生成されたコメントは、エクスポートした XLIFF ファイル内で次のように示されます。

<trans-unit id="Grand Canyon" xml:space="preserve">
    <source>Grand Canyon</source>
    <target state="new">Grand Canyon</target>
    <note from="auto-generated">Suggestion for searching landmarks</note>
</trans-unit>

メリット:

  • 翻訳者向けのコンテキストを書く開発者の時間を節約できます。
  • 一貫性のある明確な説明を提供します。
  • 翻訳の品質を向上させます。

Swift Package とフレームワークのローカライズ
問題点

SwiftUI はデフォルトで .main バンドルを使用します。Swift Package とフレームワークでは、それぞれのバンドルを参照する必要があります。

// ❌ Wrong - uses main bundle, strings not found
Text("My Collections", comment: "Section title")
解決策:#bundle マクロ(Xcode 26 で新登場)

#bundle マクロは、現在のターゲットに適したバンドルを自動的に参照します。

// ✅ Correct - automatically uses package/framework bundle
Text("My Collections", bundle: #bundle, comment: "Section title")

主なメリット:

  • メインアプリ、フレームワーク、Swift Packages で使用できます
  • 古い OS バージョンとの後方互換性があります
  • .module バンドルの手動管理が不要になります
カスタムテーブルを使用する場合
// Main app
Text("My Collections",
     tableName: "Discover",
     comment: "Section title")

// Framework or Swift Package
Text("My Collections",
     tableName: "Discover",
     bundle: #bundle,
     comment: "Section title")

カスタムテーブルのシンボルへのアクセス

整理のために複数の String Catalog を使用する場合:

デフォルトの「Localizable」テーブル

シンボルには LocalizedStringResource から直接アクセスできます。

Text(.welcomeMessage)  // From Localizable.xcstrings

注:Xcode はデフォルトの「Localizable」テーブルからシンボルを自動的に解決します。テーブルの明示的な選択はほとんど必要ありません。デバッグ時や特定のカタログのテスト時にのみ使用してください。

カスタムテーブル

シンボルはテーブルの名前空間にネストされます。

// From Discover.xcstrings
Text(Discover.featuredCollection)

// From Settings.xcstrings
Text(Settings.privacyPolicy)

大規模アプリ向けの整理方法:

  • Localizable.xcstrings - アプリのコア文字列
  • FeatureName.xcstrings - 機能固有の文字列(例:オンボーディング、設定、発見)
  • メリット:管理が容易になり、所有範囲が明確になり、XLIFF の整理も改善されます

2 つのローカライズワークフロー

Xcode 26 は、相互に補完する 2 つのワークフローをサポートしています。

ワークフロー 1:文字列の抽出(新規プロジェクトにおすすめ)

手順:

  1. コードに文字列を直接記述します
  2. SwiftUI のビュー(Text、Button)と String(localized:) を使用します
  3. Xcode が文字列を String Catalog に自動的に抽出します
  4. コメントの自動生成を活用します

メリット:初期設定が簡単で、すぐに始められます

デメリット:文字列の整理を細かく制御できません

// ✅ String extraction workflow
Text("Welcome to WWDC!", comment: "Main welcome message")
ワークフロー 2:生成されたシンボル(複雑さが増した場合におすすめ)

手順:

  1. String Catalog に文字列を手動で追加します
  2. 型安全なシンボルを使って参照します
  3. カスタムテーブルに整理します

メリット:制御性と型安全性が高く、フレームワーク間の保守も容易です

デメリット:事前に String Catalog の構造を計画する必要があります

// ✅ Generated symbols workflow
Text(.welcomeMessage)
ワークフロー最適な用途トレードオフ
文字列の抽出新規プロジェクト、シンプルなアプリ、プロトタイピング自動抽出されますが、整理の自由度は低くなります
生成されたシンボル大規模アプリ、フレームワーク、複数チーム型安全性と整理のしやすさが得られますが、事前の計画が必要です

ワークフロー間のリファクタリング

Xcode 26 では、手動で書き換えることなくワークフローを相互に変換できます。

文字列をシンボルに変換する
  1. コード内の文字列リテラルを右クリックします
  2. **「Refactor > Convert Strings to Symbols」**を選択します
  3. 影響を受けるすべての箇所をプレビューします
  4. 確定する前にシンボル名をカスタマイズします
  5. テーブル全体または個々の文字列に適用します

例:

// Before
Text("Welcome to WWDC!", comment: "Main welcome message")

// After refactoring
Text(.welcomeToWWDC)

メリット:

  • String Catalog 全体を一括変換できます
  • 適用前に変更内容をプレビューできます
  • コードを書き換えることなくローカライズを維持できます

実装チェックリスト

Xcode 26 で生成されたシンボルを採用した後、以下を確認してください。

ビルド構成:

  • 「Generate String Catalog Symbols」ビルド設定が有効になっている
  • 「Cannot find 'symbolName' in scope」エラーなしでプロジェクトをビルドできる
  • クリーンビルドが成功する(Cmd+Shift+K、その後 Cmd+B)

String Catalog の設定:

  • 文字列が + ボタンを使ってカタログに手動で追加されている(自動抽出ではない)
  • シンボル名が規則に従っている(キャメルケース、ピリオドなし)
  • カスタムテーブルが機能ごとに整理されている(複数のカタログを使用する場合)

Swift Package との統合:

  • パッケージ内のすべての Text() および String(localized:) 呼び出しで bundle: #bundle を使用している
  • #bundle を使用する箇所で Foundation をインポートしている
  • パッケージ単体および依存関係としてのビルドをテストしている

リファクタリングと移行:

  • サンプル文字列でリファクタリングツールをテストしている
  • 適用前にプレビューで想定どおりの変更が表示された
  • 移行期間中も従来の文字列ベースの呼び出しが引き続き機能する

オプション機能:

  • Xcode Settings → Editing でコメントの自動生成が有効になっている(任意)
  • AI が生成したコメントの正確性をテストしている
  • XLIFF のエクスポートに自動生成されたコメントが含まれている

テスト:

  • SwiftUI プレビューでシンボルが正しく解決される
  • すべての対応言語でローカライズが機能する
  • 最低対応 iOS バージョンでアプリが動作する

リソース

WWDC:2025-225、2023-10155、2022-10110

ドキュメント:/xcode/localization、/xcode/localizing-and-varying-text-with-a-string-catalog

スキル:axiom-app-intents-ref、axiom-hig、axiom-accessibility-diag

コメント