Xcodeで未使用のローカライズキーを削除する際は、Staleエントリをレビュー候補として扱います。削除する前に実行時のキー構築を確認し、必要な動的メッセージは手動管理エントリとして保持し、クリーンアップ後に影響を受けるMacアプリの画面をテストします。

このガイドは、String Catalogを使うSwiftUI製Macアプリを保守する開発者向けです。作業はカタログのクリーンアップ1件です。ラベルや、アプリに引き続き表示される数に関するメッセージを保ちながら、削除できるメッセージを特定します。以下の判断材料では、抽出時の証拠と実行時の動作を分けて考えます。

staleなローカライズキーとは、実際には何を意味しますか?

Xcodeはビルド時にローカライズ可能な文字列を検出します。Appleによると、抽出の対象は現在のスキームとプラットフォームです。以前に抽出された文字列が見つからなくなると、翻訳されていないエントリはXcodeによって自動的に削除されることがあります。翻訳があるエントリは残り、Stale状態になります。この状態は、Xcodeがコード内にその文字列を見つけられなくなったことを意味します。Appleは、その文字列が不要になったことを確認した場合に限り、削除するよう明示しています。String Catalogを確認する

実務上は、ソースコード内に参照が見つからないことをきっかけに調査を始めます。panel.compactを完全一致で検索すれば、リテラルの参照を見つけられます。しかし、コードがpanel.と選択されたモードを結合してキーを作っているかどうかまでは分かりません。候補のキーと、検索キーを生成するコードの両方を確認してください。

各候補について、次のレビュー表を使ってください。これは、文書化された抽出範囲から導いた判断材料であり、Xcodeの追加機能ではありません。

レビューで見つかった証拠 判断 次の対応
削除済みの画面だけが使用しており、実行時にキーを生成するコードも残っていない 候補を削除 エントリを削除し、ビルドして変更を確認する
実行時のコードがこの正確なキーを生成する可能性がある 保持 手動管理で保持するか、参照を明示的なローカライズ可能リテラルに置き換える
別のターゲットまたはビルド条件で、まだキーが参照されている 保持 該当する構成をビルドして確認する
別のテーブルに似た名前のキーがある 個別に調査 各参照で使われるテーブルとリソースバンドルを確認する
使用箇所は見つからないが、キーを生成するコードが不明 保留 削除を判断する前に、キー生成元を追跡する

Xcodeで有用なベースラインを作成するには?

まず、カタログの復元可能なコピーを保存するか、現在の状態をコミットします。次に、プロジェクトを開き、レビューするMac用スキームを選択します。対象のインターフェースにメッセージを提供しうるターゲットと条件付き構成を記録し、レビュー対象の範囲を明確にします。

プロジェクトナビゲータでカタログを選択し、Product > Buildを選びます。Appleの説明によると、ビルドによってローカライズ可能なソーステキストからString Catalogが作成、更新されます。カタログを選択した状態でEditor > Assistantを選び、キーを選択してソース位置を確認します。カタログからソースへ移動することもできます。String Catalogを使ったテキストのローカライズとバリエーション

想定したSwiftの文字列が見つからない場合は、ターゲットのUse Compiler to Extract Swift Stringsビルド設定が有効になっているか確認します。Appleは、コンパイラによる抽出の前提条件としてこの設定を説明しています。抽出が不完全なカタログは、何を削除するか判断するためのベースラインとして適していません。SwiftUIアプリをローカライズする

各候補について、キー、カタログ、想定される使用箇所、判断を記録します。まずキーを完全一致で検索し、次にその変わらないプレフィックスと、関連するローカライズ用ラッパーを検索します。それらのラッパーに値を渡すモデルの値や、同梱された検索データも調べます。別のターゲットやコンパイル条件によって含まれるソースが変わる場合は、該当するビルドも繰り返します。

2つのエントリが同じテキストを表示するからといって、判断をまとめないでください。AppleのローカライズAPIではテーブル名を指定でき、アプリのメインバンドル外にあるリソースには別のバンドルが必要な場合があります。別のエントリを代替として扱う前に、参照先のテーブルとバンドルを追跡してください。アプリのテキストを翻訳に備える

動的に参照されるメッセージを保つには?

Appleは、キーが動的に構築される文字列について、手動管理の方法を明示しています。必要なエントリを選び、インスペクタで手動管理に設定します。このようなエントリは、ビルド後のローカライズ同期でXcodeによる更新や削除の対象になりません。動的なエントリが見つからない場合は、カタログのプラスボタンを使って手動で文字列を追加する方法もAppleが紹介しています。String Catalogを確認する

手動管理には明示的な保守ルールが必要です。有効なキーを選択するコードやデータのそばに記録し、カタログのコメントで用途を説明します。後で対応モードを削除した場合は、その手動エントリも確認してください。自動抽出によってクリーンアップされることはありません。

SwiftUIが実際に検索を行うか確認する

String変数をTextに渡すと、ローカライズせずにそのまま表示されます。変数を検索キーとして使うには、そこからLocalizedStringKeyを作る方法をAppleが説明しています。リテラルをTextに直接渡すと、自動的にローカライズの経路が使われます。これらのオーバーロードはソース言語で同じ出力を表示することがありますが、動作は異なります。LocalizedStringKey

次の完全なデモアプリでは、実行時に選択するキーと、補間する数を分けています。Xcode 15以降、macOS 13をデプロイメントターゲットとする使い捨てのSwiftUI製Macアプリプロジェクトで、生成されたアプリ宣言をこのコードに置き換えてください。@main宣言は1つだけ残します。文書化されたAPIに照らして確認済みですが、ここではSwiftツールチェーンが利用できなかったためコンパイルしていません。

import SwiftUI

@main
struct CatalogReviewDemoApp: App {
    var body: some Scene {
        WindowGroup {
            CatalogReviewView()
        }
    }
}

struct CatalogReviewView: View {
    @State private var compact = true
    @State private var itemCount = 2

    private var selectedKey: String {
        "panel." + (compact ? "compact" : "expanded")
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Toggle("Compact layout", isOn: $compact)

            Text(LocalizedStringKey(selectedKey))

            Text("\(itemCount) items",
                 comment: "Number of items in the sample panel.")

            Button("Add item") {
                itemCount += 1
            }
        }
        .padding()
        .frame(minWidth: 320)
    }
}

Localizable.xcstringsをアプリのターゲットに追加します。panel.compactとpanel.expandedのエントリを手動管理に設定し、ソース値をそれぞれCompact panelとExpanded panelにします。プロジェクトをビルドして、リテラルのメッセージを抽出します。明示的なLocalizedStringKey変換は実行時の検索を要求しますが、構築される可能性のあるすべてのキーをリテラルとして抽出器に示すものではありません。

選択肢が少数で有限なら、各分岐に明示的なローカライズ可能リテラルを使い、キーの構築をやめる方法も検討してください。メッセージをコンポーネント間で受け渡すカスタムインターフェースには、テーブル、コメント、デフォルト値などのローカライズ情報を保持するLocalizedStringResourceをAppleが推奨しています。サポートするメッセージ全体を最も確認しやすい表現を選んでください。アプリのテキストを翻訳に備える

変わる数は、変わるキーとどう違うのですか?

デモでは、レイアウトを選ぶとアプリが検索するメッセージキーが変わります。itemCountを変更すると、1つのローカライズ可能なメッセージに渡す引数が変わります。SwiftUIでは補間によって埋め込み値がローカライズ用のフォーマットプレースホルダーに変換され、実行時の描画で値が入ります。SwiftUIアプリをローカライズする

そのため、2 items、3 items、4 itemsという表示ラベルごとに別のキーを用意する必要はありません。例をビルドし、抽出された数のメッセージを見つけ、そのキーをControlキーを押しながらクリックしてVary by Pluralを選びます。ソース言語が英語の場合は、Xcodeが示す整数プレースホルダーを使って、Oneに%lld item、Otherに%lld itemsを入力します。Appleは、この数に関するメッセージのワークフローと、他のサポート対象ローカライズ用に適切な複数形バリエーションを追加する方法を説明しています。String Catalogを使ったテキストのローカライズとバリエーション

クリーンアップ中は、バリエーションを含む数のメッセージ全体を確認してください。ソースコードに4 itemsのような表示文が見当たらなくても、基になる補間メッセージが使われているかどうかは分かりません。同様に、数のテンプレートを残しても、同じパネルに表示されるというだけで無関係な動的キーが保持されるわけではありません。

クリーンアップで実際に削除すべきエントリはどれですか?

例として、24件の候補をレビューする場合を考えます。以下の数は架空の例を示すもので、実際のプロジェクトで測定した結果ではありません。

レビュー結果 エントリ数 対応
唯一の使用箇所が削除済みのパネルにあった 9 パネルと参照データがなくなったことを確認してから削除
実行時の選択でキーを引き続き使用できる 8 保持し、手動管理であることを記録
別のターゲットまたは条件付きビルドに参照がある 5 保持し、そのビルド範囲を確認
キーの由来が未解決 2 調査が終わるまで保留
レビュー合計 24 削除候補は9件

この計算によってクリーンアップの判断を監査できます。24件をレビューしても、24件すべてを削除するわけではありません。削除候補の9件それぞれについて、削除された使用箇所と確認した実行時の参照経路を示す短い理由を残します。動的な8件については、許可するキーの一覧を記録し、次回のレビューで同じ判断を繰り返せるようにします。

確認済みの候補だけを削除し、カタログの差分を確認します。無関係な複数形やデバイスのバリエーションを消さず、意図したキーと関連する翻訳が変更に含まれていることを確認します。該当する構成を再ビルドします。削除したキーが抽出によって戻ってきた場合は、再度削除する前に使用箇所を見直します。

Macで保持したメッセージを確認するには?

Product > Scheme > Edit Schemeを開き、Runを選択してOptionsを開きます。App Languageからサポート対象のローカライズを選び、エディタを閉じてMacの実行先で起動します。Appleは、ローカライズしたビルドをテストするためのスキーム設定を説明しています。アプリがサポートするローカライズごとに繰り返します。アプリ実行時にローカライズをテストする

デモの両方のレイアウトを含め、許可された動的な選択肢をすべて試します。識別子ではなく、期待するカタログの値がアプリに表示されることを確認します。数のメッセージについては、0、1、2、12などのサンプル値を確認し、サポート対象のローカライズで必要な追加の複数形カテゴリも確認します。サンプルの初期値を変えれば、これらの値をテストできます。

保持したメッセージの表示がおかしい場合は、カタログを変更する前に、正確なキー、テーブル、バンドル、Textイニシャライザを確認します。Appleの新しい生成シンボルのワークフローを使うと、手動リソースを参照しやすくなる場合もあります。Xcode 26ではString Catalogのシンボル生成が導入され、既存プロジェクトではGenerate String Catalog Symbolsで有効にできます。これは任意のリファクタリング方法であり、参照されていない手動リソースが未使用である証拠にはなりません。コードを使って学ぶ:Xcodeでローカライズを試す

最後に、理由を説明できる小さな削除対象と、保持した動的メッセージの記録を残します。残ったエントリに特定できる使用箇所があり、実行時に選択されるキーとフォーマット済みの数のメッセージがMacのインターフェースで引き続き機能するカタログが、望ましい結果です。

参考資料