swiftformattingfoundationmeasurement

Format distance measurement as either kilometers or imperial miles, not metric miles


I'm trying to format a Measurement<UnitLength> in either kilometers or miles, but not Scandinavian miles if the measurement is > 10 km and the locale is appropriate.

I want to use Swift and Foundation's new .formatted API but have not found the proper documentation to adjust the unit styling.

In short I want to present distance like the following examples:

I'm using the following code in SwiftUI to format the distance text

Text(distance.formatted(.measurement(width: .abbreviated, usage: .road)))

Here's some test code that I'm using to show the issue:

import SwiftUI

struct TestView: View {
    @Environment(\.locale) var locale

    private let distance1 = Measurement(value: 7.04765, unit: UnitLength.kilometers)
    private let distance2 = Measurement(value: 13.4657, unit: UnitLength.kilometers)
    
    var body: some View {
        VStack {
            Text(distance1.formatted(.measurement(width: .abbreviated, usage: .road).locale(locale)))
            Text(distance2.formatted(.measurement(width: .abbreviated, usage: .road).locale(locale)))
        }
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            TestView() // Swedish
                .environment(\.locale, .init(identifier: "sv_SE"))
            TestView() // American English
                .environment(\.locale, .init(identifier: "en_US"))
            TestView() // French
                .environment(\.locale, .init(identifier: "fr_FR"))
        }
        .previewLayout(.sizeThatFits)
        .padding()
    }
}

This code generates the following:


Solution

  • .general instead of .road will give you kilometres or miles according to locale. .asProvided will give you the units defined on the original measurement.

    I think .general gets you closest to what you want, though it may end up giving you metres or yards for non-kilometre ranged values.