Xcode 26 以降では、String Catalog で Swift アクセサーを生成し、手入力のローカライズキーを置き換えられます。このガイドでは、小さな Mac アプリの選択内容の概要を型付きプロパティと関数に移行し、コンパイラが実際に何を保護するのかを確認します。

ここで扱うタスクは意図的に範囲を絞っています。ウィンドウの見出しと、2つの整数の件数を含む概要を表示します。ラベルと値はすべてサンプルです。カタログの契約を作成し、SwiftUI に接続して、コンパイラの診断と画面上の出力の両方を検証します。

ローカライズアクセサーがコンパイル時に検査される仕組み

Apple は Xcode 26 で、String Catalog のネイティブなシンボル生成を導入しました。プレースホルダーのないエントリーは静的プロパティを生成し、プレースホルダーのあるエントリーは型付きパラメーターを持つ関数を生成します。どちらも LocalizedStringResource を返します。新しい Xcode 26 プロジェクトでは生成がデフォルトで有効になっていますが、既存のプロジェクトではビルド設定を有効にする必要がある場合があります。コードに沿って進める: Xcode でローカライズを探る

役に立つ変化は呼び出し側にあります。文字列リテラルなら、Swift の宣言を参照せずに検索キーを記述できます。生成されたアクセサーは存在が必須のメンバーを参照し、生成された関数はシグネチャに合った引数を要求します。これらの仕様から、メンバーのスペルミスや互換性のない引数はコンパイラエラーになるという実用上の帰結が得られます。

この保護には明確な範囲があります。Swift が検査できるのは、アクセサーが存在することと、引数が適合することです。文言が意図したインターフェースを表しているか、2つの有効な整数引数が正しい件数を示しているかは判断できません。アクセサーは、メッセージに対する検査可能なプログラミングインターフェースとして扱ってください。

小さな Mac アプリとメッセージの契約を用意する

Xcode 26 以降を使い、macOS の SwiftUI アプリターゲットを用意します。この例では、デプロイメントターゲットを macOS 15 以降に設定します。基盤となる LocalizedStringResource 型は macOS 13 から利用できます。この例でより新しいターゲットを指定するのは前提条件としての選択であり、その型の最小バージョンを示すものではありません。リソースは、必要になるまで検索を遅らせられるローカライズ可能なテキストを表します。LocalizedStringResource

File > New > File from Template からカタログを追加します。Resource の下にある String Catalog を選び、名前を Workbench にして、アプリターゲットに含めます。Apple の説明では、各カタログは1つのテーブルを表します。この例では、2つのメッセージをまとめるために別のテーブルを使います。String Catalog を使ったテキストのローカライズとバリエーション

プロジェクトエディタで Build Settings を開き、Generate String で絞り込み、ターゲットの有効な構成で Generate String Catalog Symbols を Yes に設定します。これは、古いプロジェクト向けに公式に案内されている切り替え項目です。コードで生成されたローカライズ可能なシンボルを使う

Workbench.xcstrings で英語のソースローカリゼーションを選択します。カタログエディタのツールバーにある + ボタンを使い、次の2つのエントリーを追加します。コメントには、引数の役割を含め、メッセージの意味を定義します。

キー 英語のソース値 コメント
TITLE Selection overview 選択内容の概要の上に表示する見出し。
SUBTITLE %1$(selectedCount)lld selected; %2$(availableCount)lld available 選択内容の概要。selectedCount は選択数、availableCount は選択済み項目を含む全項目数。

SUBTITLE では、Xcode の補完メニューを使って各プレースホルダーを入力できます。% と入力し、整数のプレースホルダーを選んで、名前を selectedCount または availableCount にします。Apple の説明では、これらのフォーマット指定子に対する名前付き変数と生成パラメーターがサポートされています。各エントリーを選択し、Attributes インスペクタで Generate Swift Symbol と Example Usages を確認してください。コードで生成されたローカライズ可能なシンボルを使う

意図する契約は、タイトルのプロパティと、2つの Int 値を受け取るサブタイトル関数です。先に進む前に、インスペクタで実際に生成された表記を確認してください。Apple によると、シンボル名にはキーとその値の両方が使われます。以下の例では、Apple の説明にある大文字のキーのパターンに従って、.Workbench.title と .Workbench.subtitle(selectedCount:availableCount:) を使っています。コードに沿って進める: Xcode でローカライズを探る

この契約によって、重要な区別が明確になります。availableCount は選択済みの項目を含みます。このコメントがなければ、呼び出し側は残りの項目数だと解釈しても不思議ではありません。どちらの解釈でも型チェックは通るため、意味を文書化することはアクセサーを役立てるうえで欠かせません。

生成されたアクセサーを使ってウィンドウを完成させる

カタログを作成したら、Product > Build を選びます。テンプレートのアプリ宣言とコンテンツビューを次のプログラムに置き換え、ターゲット内の @main 宣言が1つだけになるようにします。このプログラムにはカタログリソースが必要です。Swift を単独のファイルに貼り付けても、そのアクセサーは生成されません。

import Foundation
import SwiftUI

@main
struct SelectionOverviewApp: App {
    var body: some Scene {
        WindowGroup {
            SelectionOverviewView(
                selectedCount: 3,
                availableCount: 12
            )
        }
    }
}

struct SelectionOverviewView: View {
    let selectedCount: Int
    let availableCount: Int

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text(.Workbench.title)
                .font(.title2)

            Text(
                .Workbench.subtitle(
                    selectedCount: selectedCount,
                    availableCount: availableCount
                )
            )
        }
        .padding(24)
        .frame(minWidth: 360, minHeight: 140)
    }
}

英語のソースローカリゼーションが有効な状態では、例の入力により Selection overview の後に 3 selected; 12 available と表示されるはずです。選択管理のコードを追加せずに引数の配置を確認できるよう、件数は固定しています。

Apple の説明では、生成されたリソースは Text を含む SwiftUI と、Foundation の String(localized:) イニシャライザーで利用できます。既存の Mac インターフェースで解決済みの String が必要な場合は、その境界で生成されたリソースを変換します。コードに沿って進める: Xcode でローカライズを探る

たとえば、カタログを用意した後、同じアプリターゲットに次のヘルパー関数を追加できます。

import Foundation

func selectionSummary(
    selectedCount: Int,
    availableCount: Int
) -> String {
    String(
        localized: .Workbench.subtitle(
            selectedCount: selectedCount,
            availableCount: availableCount
        )
    )
}

独自のインターフェースから LocalizedStringResource を返すと、後で検索できるリソースが保持されます。String を返すと、イニシャライザーの実行時に解決されます。受け取り側のインターフェースに必要なものに応じて選んでください。Apple は Foundation のドキュメントで、この遅延検索と即時検索の違いを説明しています。LocalizedStringResource

例は取得したドキュメントに照らして確認しました。利用可能な環境に Swift 実行ファイルも Xcode もないため、ここではコンパイルしていません。

先頭のドットと引数ラベルが重要な理由

先頭のドットは Swift の暗黙的なメンバー構文です。周囲の文脈から Swift が型を推論できる場合に、型メンバーへのアクセスを省略して記述できます。これは通常の Swift 構文であり、特殊な文字列キー演算子ではありません。式 — 暗黙的メンバー式

生成されたローカライズシンボルでは、デフォルトの Localizable テーブルはメンバーを直接公開し、名前付きテーブルはテーブルの名前空間を導入します。そのため、この例ではメンバー名の前に .Workbench を付けています。Apple はどちらの形式も説明しています。コードで生成されたローカライズ可能なシンボルを使う

selectedCount: と availableCount: のラベルは関数呼び出しに属します。Swift では、呼び出し側に現れる引数ラベルと、関数内で使うパラメーター名を区別します。ラベルが必要なパラメーターでは、呼び出し側がそのラベルを指定する必要があります。関数 — 関数の引数ラベルとパラメーター名

読みやすいラベルは間違いの防止に役立ちますが、ここではどちらの引数も同じ型です。2つの整数値を入れ替えても、Swift としては有効です。そのため、メッセージの契約と表示結果の確認がコンパイラを補います。

意味を損なわず既存のキーを移行する

既存のローカライズ可能な文字列には、Apple がリファクタリングの手順を用意しています。String Catalog でエントリーを選択し、Control キーを押しながらクリックして、Refactor > Convert Strings to Symbols を選びます。プレビューを確認し、必要に応じて提案されたシンボル名やパラメーター名を調整してから、Convert を選択します。コードで生成されたローカライズ可能なシンボルを使う

まずはこのウィンドウの見出しと概要のように、まとまりのあるグループを1つ移行します。プレビューを確定する前に、古いメッセージと新しい契約を比べます。同じテーブルを使っているか、同じインターフェース要素を表しているか、各プレースホルダーに同じ意味を割り当てているかを確認してください。キーの変更によって影響を受ける既存のローカライズ値は、リファクタリングで正しさが証明されたと思い込まずに確認します。

リファクタリングで更新されなかった呼び出し箇所があれば、カタログインスペクタの生成済み使用例を参照し、その参照を明示的に置き換えます。その後、ビルドして結果のテキストを確認します。呼び出し元をすべて把握するまでは、古いエントリーを削除しないでください。

インストール済みの Xcode でネイティブ生成を利用できない場合、この手順にはより新しいツールチェーンが必要です。Apple はローカライズ可能な API から文字列をカタログに抽出する方法もサポートしており、最初の手順として抽出を推奨しています。これは現在もサポートされているローカライズ管理方法ですが、それだけでここで説明した生成アクセサーの契約が得られるわけではありません。コードに沿って進める: Xcode でローカライズを探る

簡単な診断手順で移行を検証する

サンプルのウィンドウで次の確認を行います。これにより、コンパイラによる保護、メッセージの正しさ、リソースの統合を切り分けて確認できます。

  1. 変更していない例をビルドし、正常に動作する基準を確認します。
  2. 一時的にタイトルメンバーのスペルを間違えてビルドします。存在しないメンバーについてコンパイラ診断が表示されるはずです。元に戻します。
  3. サブタイトルが Int を要求する箇所に、一時的に String 値を渡します。ビルドして型の不一致を確認し、その後整数に戻します。
  4. selectedCount を 3 に、availableCount を 12 に設定して実行します。数値が意図した位置に表示されることを確認します。
  5. カタログのタイトル値だけを Current selection に変更して再ビルドし、見出しの表示を確認します。生成されたシグネチャがコードで使用しているものと同じであることも確認します。

メンバーが予期せず見つからない場合は、まずカタログエントリーの生成済み使用例を確認します。次に、生成設定、カタログのターゲット所属、テーブル名を確認します。コンパイラ診断は参照の失敗を示します。これらの確認によって、スペルミスと生成された宣言が利用できない状態を区別しやすくなります。

最後に、実際のインターフェースをテストします。Apple が案内する手順は、Product > Scheme > Edit Scheme を選び、Run > Options で App Language を選択してから実行する方法です。プロジェクトがサポートするローカリゼーションごとに繰り返します。アプリ実行時にローカリゼーションをテストする

レイアウトを早めに確認するには、Xcode の Double-Length Pseudolanguage も利用できます。ローカライズ可能なテキストを長くして、サイズの問題を見つけやすくします。ウィンドウ幅を狭めて概要を確認してください。コンパイルに成功しても、テキストが収まるかどうかは判断できません。ローカリゼーションをテストする

移行が完了すると、各呼び出し箇所は実在する Swift メンバーを使い、各変数には文書化された役割が与えられ、意図したカタログエントリーへの検査可能な経路が保たれます。コンパイラの確認とウィンドウの確認を組み合わせてください。前者はアクセサーの契約を検証し、後者は読者が意図したメッセージを目にすることを確かめます。

参考資料