Xcode 26から、String CatalogのキーからSwiftのシンボルが自動生成されるようになった。String(localized: .settingsTitle)のように、キーを文字列ではなく型として参照できる。
ただし、すべてのキーが対象になるわけではない。条件は3つあり、外側から内側へ入れ子になっている。3つすべてを満たしたキーだけがシンボルになる。
1段目: ターゲットのビルド設定
一番外側にあるのはSTRING_CATALOG_GENERATE_SYMBOLSというビルド設定。参照されるのはカタログを持つターゲットの値で、NOにするとそのターゲットのカタログからは一切生成されない。
注意点がひとつある。この設定はSwiftPMのパッケージターゲットには伝播しない。文言のカタログをパッケージ側に置いている構成では、プロジェクト側をNOにしてもパッケージ内のカタログからは生成され続ける。なお、パッケージ側で生成させるにはPackage.swiftにdefaultLocalizationの宣言が必要だ。これが無いとシンボルは生成されない。パッケージで止めるには、3段目のキー単位の指定を使うことになる。
2段目: そのキーが手動管理かどうか
次の条件は、カタログの各エントリが持つextractionStateが"manual"であること。手動管理のキーだけが対象になる。抽出由来のキー(extracted_with_value、または状態なし)とstaleのキーは対象外だ。
ここが最も引っかかりやすい点だ。コードにString(localized: "Settings.title")と書くと、そのキーはビルド時の抽出でカタログに登録される。この経路で入ったキーは手動管理ではないため、1段目をYESにしていてもシンボルは作られない。「コードに文字列を書いて抽出させる」という一般的なワークフローでは、設定を有効にしても何も増えないということになる。
つまり、生成を決めているのはコードの書き方ではなく、カタログ側のエントリの状態だ。コードを1文字も変更せず、インスペクタのManagedをManuallyに切り替えるだけで、そのキーはシンボル化の対象になる。恩恵を受けるのは、カタログにキーを手で追加しているチーム、あるいは外部ツールでカタログを生成しているチームだ。
3段目: キーごとの個別スイッチ
最後はキーごとのgeneratesSymbol。インスペクタのGenerate Swift Symbolチェックボックスがこれに対応しており、外すとカタログに次のように書き込まれる。
1 | "Settings.title" : { |
未指定なら生成し、falseなら生成しない。指定はこれだけだ。このフラグは、カタログの形式バージョンが1.0でも1.1でも同じように機能する。
ただし、チェックボックスが表示されるのは形式1.1のカタログに限られる。1.0のファイルを開いても項目は現れない。とはいえXcodeで何か操作すればファイルは1.1に更新されるため、GUIから扱う分には意識する必要はない。カタログを機械生成している場合は、1.0のまま手でgeneratesSymbolを記述しても問題なく機能する。
1段目との関係では、外側が優先される。STRING_CATALOG_GENERATE_SYMBOLS = NOのターゲットでキーに"generatesSymbol": trueを明示しても、シンボルは生成されない。キー単位の指定は「全体は有効のまま、一部だけ止める」ためのものと考えるのが正しい。
生成されるもの
3つの条件を満たしたキーは、GeneratedStringSymbols_<テーブル名>.swiftという名前でビルド用ディレクトリに生成され、そのターゲットのコンパイル対象に加わる。中身はLocalizedStringResourceのextensionで、テーブル名が既定のLocalizableであれば型直下、それ以外ならテーブル名のenumに入れ子になる。
1 | nonisolated extension LocalizedStringResource { |
なお、この生成コードはinternal固定でpublicにはできない。モジュールを跨いで参照する構成では利用できないため、導入前に確認しておきたい。
まとめ
シンボルが生成される条件は、外側から順に次の3つ。
- ターゲットのスイッチ(
STRING_CATALOG_GENERATE_SYMBOLS)が有効であること。ただしパッケージターゲットには届かない - そのキーが手動管理(
extractionState: "manual")であること。抽出されたキーは対象外 - そのキーの個別スイッチ(
generatesSymbol)が切られていないこと。外側がNOならtrueにしても覆せない
「設定を有効にしたのに何も生成されない」という場合は、まず2段目を確認するとよい。