How to use Foundation's new FormatStyle to output spell out number?

The old NumberFormatter let you output in .spellOut style.

But I cannot find this same functionality for the new FormatStyle. I only see .number and .percent.

Can the new FormatStyle do .spellOut format?

Edit: Seems spell out formatting it's not supported. So I create it:

import SwiftUI


protocol NSNumberConvertible {
    /// Create an NSNumber out of this concrete numeric type
    var nsNumber: NSNumber { get }
}

extension Decimal: NSNumberConvertible {
    var nsNumber: NSNumber { self as NSNumber }
}
extension Double: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension Float: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension Int8: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension Int32: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension Int: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension Int64: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension Int16: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}


// all the unsigned type we support
extension UInt8: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension UInt32: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension UInt: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension UInt64: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}
extension UInt16: NSNumberConvertible {
    var nsNumber: NSNumber { NSNumber(value: self) }
}

// Prefab one, is there better way. Can't put this in SpelloutNumberFormatStyle with static computed property
let spelloutNumberFormatter: NumberFormatter = {
    let formatter = NumberFormatter()
    formatter.numberStyle = .spellOut
    return formatter
}()

struct SpelloutNumberFormatStyle<Value: NSNumberConvertible>: FormatStyle {
    func format(_ value: Value) -> String {
        spelloutNumberFormatter.string(from: value.nsNumber)!
    }
}

extension FormatStyle where Self == SpelloutNumberFormatStyle<Decimal> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<Double> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<Float> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<Int8> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<Int32> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<Int> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<Int64> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<Int16> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<UInt8> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<UInt> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<UInt64> {
    static var spellOut: Self { .init() }
}
extension FormatStyle where Self == SpelloutNumberFormatStyle<UInt16> {
    static var spellOut: Self { .init() }
}

Did I do it correctly? Any better way?

Maybe it's not implemented yet? I can see a relevantly named DescriptiveNumberFormatConfiguration.Presentation.spellOut but don't see any public API that it can be used with.

I traverse back up a couple of levels and look around. I don't know what DescriptiveNumberFormatConfiguration are used for. Wonder what these things are?

DescriptiveNumberFormatConfiguration.Presentation.spellOut really not used anywhere as of now? Can any "insider" confirm?

DescriptiveNumberFormatConfiguration.Presentation.spellOut really
not used anywhere as of now?

It’s used internally by the byte count formatter:

var fs = ByteCountFormatStyle.byteCount(style: .file)
let s0a = "Downloaded: \(0.formatted(fs))"
print(s0a)
// Downloaded: Zero kB
fs.spellsOutZero = false
let s0b = "Downloaded: \(0.formatted(fs))"
print(s0b)
// Downloaded: 0 bytes

I don’t know if there’s any other way to invoke it.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

2 Likes