通貨フォーマットで notation を扱えるようにする
Support notation when formatting currencies
このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら↗。
01 何が問題だったのか
Foundation の FormatStyle には、数値やパーセントを大きな桁でコンパクトに表示するための notation 指定があります。たとえば 1,500,000 を 1.5M と表示するには次のように書けます。
let count = 1_500_000
let result = count.formatted(.number.notation(.compactName))
assert(result == "1.5M")
しかし、これと同じ仕組みを通貨フォーマット(.currency(code:))に対して指定する手段がありませんでした。たとえば「$1,500,000.59 ではなく $1.5M のようにコンパクトに表示したい」というケースでは、数値と通貨記号を別々にフォーマットして組み立て直す必要があり、ロケールに応じた通貨記号の位置や区切り方を扱う上でも余計な手間がかかっていました。
ICU 側のフォーマッタはすでに通貨でも notation を扱えるため、Swift から指定する経路だけが欠けている状態でした。
02 どのように解決されるのか
通貨用の各 FormatStyle に、数値やパーセント版と同じ形の notation(_:) モディファイアが追加されます。対応するのは次の 3 つの通貨フォーマットスタイルで、いずれも FoundationPreview 0.4 以降で利用できます。
IntegerFormatStyle.CurrencyFloatingPointFormatStyle.CurrencyDecimal.FormatStyle.Currency
extension IntegerFormatStyle.Currency {
@available(FoundationPreview 0.4, *)
public func notation(_ notation: Configuration.Notation) -> Self
}
extension FloatingPointFormatStyle.Currency {
@available(FoundationPreview 0.4, *)
public func notation(_ notation: Configuration.Notation) -> Self
}
extension Decimal.FormatStyle.Currency {
@available(FoundationPreview 0.4, *)
public func notation(_ notation: Configuration.Notation) -> Self
}
引数の型は CurrencyFormatStyleConfiguration.Notation ですが、これは数値フォーマット用の NumberFormatStyleConfiguration.Notation の typealias として定義されます。そのため、数値フォーマットで使えていた notation はすべてそのまま通貨フォーマットでも使えます。
extension CurrencyFormatStyleConfiguration {
@available(FoundationPreview 0.4, *)
public typealias Notation = NumberFormatStyleConfiguration.Notation
}
利用側からは、数値フォーマットと同じ感覚で通貨フォーマットに notation を組み合わせるだけです。
let price = Decimal(1_500_000.59)
let result = price.formatted(.currency(code: "USD").notation(.compactName))
assert(result == "$1.5M")
通貨記号の位置や区切り方はロケールに応じて ICU 側が処理するため、利用側は notation を指定するだけで、$1.5M のようなコンパクトな通貨表示を得られます。