swift-formatstyle について
swift-formatstyleは、Swiftの型安全なフォーマットおよび解析APIの選択と確認を支援する開発スキルです。ロケールに応じた表示、SwiftUI連携、複数の代表的なロケールでの出力テストを扱います。
主な機能
- 01組み込みFormatStyle APIの選択
- 02対応するスタイルでの入力解析
- 03Text(_:format:)によるSwiftUI表示
- 04代表的なロケールでの出力確認
- 05組み込みで不足する場合の独自スタイル作成
活用シーン
- 01日付、数値、通貨、計測値のローカライズ
- 02往復解析が必要なユーザー入力の処理
- 03ロケール別の画面表示の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill swift-formatstyleインストール後、Claude Code で/swift-formatstyleを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/formatstyle-recipes.md
詳細
Swift FormatStyle
ユーザー向けの表示には Foundation の型安全な FormatStyle API を使用し、同じ規則で入力を受け付ける必要がある場合は ParseableFormatStyle を使用します。String Catalog、複数形、ローカライズされたコピー、バンドル、RTL レイアウトについては ios-localization を参照してください。テキストを翻訳しない場合でも、フォーマットにはロケールの確認が必要です。
目次
ワークフロー
- 値の意味上の型と、出力が表示専用なのか、解析を通じて元に戻せる必要があるのかを特定します。
- 最も限定的な組み込みスタイルを選び、ワイヤ形式で別のロケールが明示的に必要な場合を除いて、ユーザーの現在のロケールを維持します。
en_US、de_DE、ar_SA、ja_JPなど、代表的なロケールで実際の UI を表示します。- 区切り文字、数字体系、暦、通貨や単位の規則、テキスト方向、レイアウトを確認します。
- 出力または解析に失敗した場合は、スタイルまたは周囲のコピーを修正し、入力フィクスチャを元に戻して、同じロケールの組み合わせで再実行します。
実装で具体的なモディファイア、日付範囲、相対日付、期間パターン、測定値、名前、リスト、バイト数、URL の構成要素の制御が必要な場合は、FormatStyle レシピを読み込みます。
クイックリファレンス
| 値 | デフォルトのスタイル | 重要な制約 |
|---|---|---|
Int、Double | .number | 精度、丸め、桁区切り、表記法、符号は必要な場合にのみ設定します。 |
Decimal | .number、.percent、.currency(code:) | 正確な小数の表示と解析にはこちらを優先します。 |
| 通貨 | .currency(code:) | ISO 4217 コードを渡します。通貨記号をハードコードしないでください。 |
| パーセント | .percent | 入力が小数(0.85)か、整数のパーセント(85)かを確認します。 |
Date | .dateTime、.relative、.interval | 相対表示は通常、文中に埋め込まず、単独で表示します。 |
Duration | .time(pattern:)、.units(allowed:width:) | iOS 16 以降が必要です。簡潔な時計形式にするか、単位をラベル付きで表示するかを選択します。 |
Measurement | .measurement(width:usage:) | usage: はロケールに応じた変換ポリシーを制御します。 |
PersonNameComponents | .name(style:) | 名前の各部分を手動で連結しないでください。 |
| コレクション | .list(type:width:) | 区切り文字や接続詞はロケール規則に任せます。 |
| バイト数 | .byteCount(style:) | ファイル、メモリ、十進法、二進法のどの意味で扱うかを意図的に選びます。 |
URL | .url | iOS 16 以降が必要です。クエリ、ポート、フラグメントの表示は、明示的に有効にした場合のみ行われます。 |
選択と利用可能なバージョン
- iOS 15 以降の新しいコードでは、従来の
NumberFormatter、DateFormatter、DateComponentsFormatterや手動の補間よりもFormatStyleを優先します。 DurationのフォーマットスタイルとURL.FormatStyleには iOS 16 以降が必要です。Date.AnchoredRelativeFormatStyleには iOS 18 以降が必要です。現在の時点ではなく、固定された基準時点からの相対形式でフォーマットします。- 通常の UI では
.locale(...)を省略し、スタイルがユーザーのロケールを継承するようにします。固定ロケールを使用するのは、明示的なプロトコルまたはテストフィクスチャの場合に限ります。 - 相対日付の出力は、それを含む文全体がローカライズされている場合を除き、単独のテキストとして扱います。
ドキュメント:FormatStyle
解析
ユーザーがフォーマット済みの値を編集またはインポートする場合は、対応する解析可能なスタイルを使用します。
let style = Decimal.FormatStyle.Currency(code: "USD")
.locale(Locale(identifier: "en_US"))
let value = try Decimal("$3,500.63", format: style)
let display = value.formatted(style)
上記の固定ロケールが適切なのは、入力の契約で en_US が明示されているためです。通常の UI 入力ではユーザーのロケールを使用し、小数点の区切り文字、通貨記号の位置、暦、数字体系を変えた代表的なケースで、往復変換をテストします。
SwiftUI との統合
書式設定された値は SwiftUI に管理させるため、Text(_:format:) を優先してください。
Text(price, format: .currency(code: currencyCode))
Text(date, format: .dateTime.month().day().year())
Text(duration, format: .units(allowed: [.minutes, .seconds]))
ユーザーに表示する書式設定済みの Text はすべて、ロケールのマトリックス全体で画面を正確にプレビューまたはテストしてください。時刻をリアルタイムで更新する表示では、文字列の更新を手動でスケジュールするのではなく、Text(.now, style: .timer)、Text(.now, style: .relative)、または Text(timerInterval:) を使用してください。
カスタム FormatStyle
組み込みの構成ではドメイン固有の慣例を表現できない場合に限り、カスタムスタイルを作成してください。FormatStyle は Codable と Hashable を拡張します。スタイルは再利用可能な値として保持し、入力を往復変換する必要がある場合にのみ ParseableFormatStyle を追加してください。
struct AbbreviatedCountStyle: FormatStyle {
func format(_ value: Int) -> String {
switch value {
case ..<1_000: "\(value)"
case 1_000..<1_000_000: String(format: "%.1fK", Double(value) / 1_000)
default: String(format: "%.1fM", Double(value) / 1_000_000)
}
}
}
extension FormatStyle where Self == AbbreviatedCountStyle {
static var abbreviatedCount: Self { .init() }
}
カスタムスタイルでも、ロケールとアクセシビリティの確認が必要です。英語の短縮形の接尾辞が、すべてのロケールに適しているとは限りません。
よくある間違い
| 間違い | 修正方法 |
|---|---|
| ビューコードでの手動書式設定や従来のフォーマッターの割り当て | 対応する FormatStyle と Text(_:format:) を使用します。 |
| 通貨記号やロケールのハードコード | ISO 通貨コードを渡し、仕様で指定されていない限りユーザーのロケールを引き継ぎます。 |
| 正確な小数入力に二進浮動小数点数を使用 | Decimal.FormatStyle と対応する解析ストラテジーを使用します。 |
URL.formatted() がすべての構成要素を保持すると想定 | それらの構成要素を表示する必要がある場合に限り、.port(.always)、.query(.always)、または .fragment(.always) を明示的に指定します。 |
| 相対日付の出力を大きな文の中に埋め込む | 単独で使うか、文全体をローカライズします。 |
| 文章に時計形式の期間を使用 | ラベル付きの出力には .units(allowed:width:) を使用します。 |
| 測定値の変換を暗黙のままにする | UI に適した usage: を選択します。 |
| 1 つのロケールだけで抜き取り確認 | 同じ画面の正確な表示を代表的なロケール全体で実行し、失敗を修正して再実行します。 |
レビューチェックリスト
- 意味上の値の型と、表示または解析の要件を特定した
- 慣例を表現できる場合は組み込みの
FormatStyleを使用した - iOS 16+ および iOS 18+ の API の使用箇所で利用可能条件を設定した
- 通貨には ISO 4217 コードを使用し、正確な小数値には
Decimalを使用した - プロトコルで明示的に固定されていない限り、ユーザーのロケールを引き継いだ
- 相対日付のテキストを単独で使用するか、文全体をローカライズした
- URL の構成要素と測定値の
usage:を意図的に指定した - 書式設定された値には SwiftUI の
Text(_:format:)を使用した - 代表的なロケールのマトリックスで、正確な UI 表示と解析の往復変換に合格した
参考資料
- 詳細なレシピとモディファイア:references/formatstyle-recipes.md
- Apple のドキュメント:FormatStyle · ParseableFormatStyle · Date.FormatStyle · Duration.TimeFormatStyle · URL.FormatStyle