axiom-localization について
Appleプラットフォームの開発者向けに、ローカライズと国際化を解説するガイドです。XcodeのString Catalog、SwiftUI/UIKit API、複数形、RTLレイアウト、ロケール対応の書式設定、旧形式からの移行を扱います。
主な機能
- 01Xcode String Catalogの管理
- 02SwiftUIとUIKitのローカライズ
- 03複数形とRTLレイアウトへの対応
- 04ロケールに応じた値の書式設定
- 05旧形式のローカライズファイル移行
活用シーン
- 01アプリに複数言語を追加
- 02翻訳漏れや複数形の誤りを調査
- 03アラビア語やヘブライ語のレイアウトに対応
- 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 ナビゲーター
- File → New → File
- 「String Catalog」を選択します
- 名前を付けます(例:
Localizable.xcstrings) - ターゲットに追加します
方法 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(🔴)- ソースコード内で文字列が見つからなくなりました
ワークフロー:
- 開発者が文字列を追加 → New
- 翻訳者が翻訳を追加 → Reviewed
- 開発者が原文を変更 → Needs Review
- 翻訳者が更新 → Reviewed
- 開発者がコードを削除 → 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 のローカライズ
アプリ名や権限などをローカライズします。
Info.plistを選択します- Editor → Add Localization
- 言語ごとに
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:
- Edit Scheme → Run → Options
- Application Language:Arabic / Hebrew
- または: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 への変換
自動移行:
- ナビゲーターで
.stringsファイルを選択します - Editor → Convert to String Catalog を選択します
- Xcode が
.xcstringsを作成し、翻訳を保持します
手動で行う場合:
- 新しい String Catalog を作成します
- プロジェクトをビルドします(Xcode がコードから文字列を抽出します)
- File → Import Localizations(XLIFF)から翻訳を読み込みます
- 古い
.stringsファイルを削除します
.stringsdict の変換
複数形ファイルは自動的に統合されます:
.stringsと.stringsdictを同じ場所に置きます- 変換すると、両方が1つの
.xcstringsに統合されます - 複数形のバリエーションは保持されます
段階的な移行戦略
フェーズ 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 に文字列が表示されない
原因:ビルド設定が有効になっていません。
解決方法:
- Build Settings → 「Use Compiler to Extract Swift Strings」→ Yes
- Clean Build Folder(Cmd+Shift+K)
- プロジェクトをビルドします。
アプリに翻訳が表示されない
原因 1:言語がプロジェクトに追加されていません。
- Project → Info → Localizations → + ボタン
- 対象言語を追加します。
原因 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」が設定されていません。
解決方法:
- Build Settings → 「Localization Prefers String Catalogs」→ Yes
- ローカライズを再度エクスポートします。
生成されたシンボルが表示されない(Xcode 26+)
原因 1:ビルド設定が有効になっていません。
解決方法:
- Build Settings → 「Generate String Catalog Symbols」→ Yes
- Clean Build Folder(Cmd+Shift+K)
- プロジェクトを再ビルドします。
原因 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 にありません。
- 文字列が
.xcstringsファイルにあることを確認します。 - プロジェクトをビルドしてカタログを更新します。
- リファクタリングを再度試します。
原因 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 は、手動で追加した文字列から型安全なシンボルを生成します。
仕組み
- String Catalog で + ボタンを使って文字列を手動で追加します。
- ビルド設定を有効にします:「Generate String Catalog Symbols」(新規プロジェクトではデフォルトで ON)
- 文字列の代わりにシンボルを使用します。
// ✅ 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 はデバイス上のモデルを使用して、ローカライズ可能な文字列のコンテキストコメントを自動生成します。
機能を有効にする
- Xcode Settings → Editing を開きます。
- 「automatically generate string catalog comments」を有効にします。
- コードに追加された新しい文字列には、コメントが自動生成されます。
例
ボタンの文字列に対して、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:文字列の抽出(新規プロジェクトにおすすめ)
手順:
- コードに文字列を直接記述します
- SwiftUI のビュー(
Text、Button)とString(localized:)を使用します - Xcode が文字列を String Catalog に自動的に抽出します
- コメントの自動生成を活用します
メリット:初期設定が簡単で、すぐに始められます
デメリット:文字列の整理を細かく制御できません
// ✅ String extraction workflow
Text("Welcome to WWDC!", comment: "Main welcome message")
ワークフロー 2:生成されたシンボル(複雑さが増した場合におすすめ)
手順:
- String Catalog に文字列を手動で追加します
- 型安全なシンボルを使って参照します
- カスタムテーブルに整理します
メリット:制御性と型安全性が高く、フレームワーク間の保守も容易です
デメリット:事前に String Catalog の構造を計画する必要があります
// ✅ Generated symbols workflow
Text(.welcomeMessage)
| ワークフロー | 最適な用途 | トレードオフ |
|---|---|---|
| 文字列の抽出 | 新規プロジェクト、シンプルなアプリ、プロトタイピング | 自動抽出されますが、整理の自由度は低くなります |
| 生成されたシンボル | 大規模アプリ、フレームワーク、複数チーム | 型安全性と整理のしやすさが得られますが、事前の計画が必要です |
ワークフロー間のリファクタリング
Xcode 26 では、手動で書き換えることなくワークフローを相互に変換できます。
文字列をシンボルに変換する
- コード内の文字列リテラルを右クリックします
- **「Refactor > Convert Strings to Symbols」**を選択します
- 影響を受けるすべての箇所をプレビューします
- 確定する前にシンボル名をカスタマイズします
- テーブル全体または個々の文字列に適用します
例:
// 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