MeasurementFormatter workaround for missing .unitStyle = .none?

I was trying to write a function that returns a localized string for a weight measurement - but with the option of skipping the unit substring. As in: return "100,1" instead of "100,1kg" but respecting the user's locale.

First thought was: just specify unitStyle = .none but that is not a valid member.
So I came up with this solution which works for pounds and kilos but there sure are other weight / mass units out there... How do I retrieve the user's preferred unit from locale?
Code Block
func formatWeight(weightInKgs value: Double, skipUnit: Bool = false) -> String {
    let weightInKgs = Measurement(value: value, unit: UnitMass.kilograms)
    if !skipUnit {
        let formatter = MeasurementFormatter()
//        if skipUnit {
//            formatter.unitStyle = .none
//        } else {
            formatter.unitStyle = .short
//        }
        formatter.numberFormatter.maximumFractionDigits = 1
        formatter.numberFormatter.minimumFractionDigits = 1
        return formatter.string(from: weightInKgs)
    } else {
        if Locale.current.usesMetricSystem {
            let formatter = NumberFormatter()
            formatter.maximumFractionDigits = 1
            formatter.minimumFractionDigits = 1
            return formatter.string(from: NSNumber(value: weightInKgs.value))!
        } else {
            let weightInLocaleUnit = weightInKgs.converted(to: UnitMass.pounds) //this is not universal
            let formatter = NumberFormatter()
            formatter.maximumFractionDigits = 1
            formatter.minimumFractionDigits = 1
            return formatter.string(from: NSNumber(value: weightInLocaleUnit.value))!
        }
    }
}

Answered by OOPer in 666911022

How do I retrieve the user's preferred unit from locale?

As far as I checked the documentations of Apple, I could not find any APIs to get preferred weight unit.

there sure are other weight / mass units out there

There are only three countries where the metric system is not used: the US, Liberia and Myanmar.
Testing with macOS 11.1 and iOS 14.4 Simulator, only one region "US" uses pounds.
Code Block
extension Locale {
var measurementSystem: String {
(self as NSLocale).object(forKey: NSLocale.Key.measurementSystem) as! String
}
}
func formatWeight(for locale: Locale, weightInKgs: Double) -> String {
let mformatter = MeasurementFormatter()
mformatter.locale = locale
mformatter.unitOptions = .naturalScale
mformatter.unitStyle = .medium
let weight = Measurement(value: weightInKgs, unit: UnitMass.kilograms)
return mformatter.string(from: weight)
}
let localeIds = ["en_US", "es_US", "en_GB", "en_LR", "my_MM", "ja_JP"]
for localId in localeIds {
let locale = Locale(identifier: localId)
print(locale, locale.measurementSystem)
print(locale.regionCode ?? "*region unknown*")
print("Uses Metric System: \(locale.usesMetricSystem)")
print(formatWeight(for: locale, weightInKgs: 100.1))
}

Output:
Code Block
en_US (fixed) U.S.
US
Uses Metric System: false
220.683 lb
es_US (fixed) U.S.
US
Uses Metric System: false
220.683 lb
en_GB (fixed) U.K.
GB
Uses Metric System: true
100.1 kg
en_LR (fixed) U.S.
LR
Uses Metric System: false
100.1 kg
my_MM (fixed) U.S.
MM
Uses Metric System: false
၁၀၀.၁ kg
ja_JP (fixed) Metric
JP
Uses Metric System: true
100.1 kg

(I'm not sure if kg is really preferred in daily life in the UK, but macOS/iOS uses kg for weight/mass when Locale set to en_GB.)

Seems using UnitMass.pounds is universal enough, practically.
Accepted Answer

How do I retrieve the user's preferred unit from locale?

As far as I checked the documentations of Apple, I could not find any APIs to get preferred weight unit.

there sure are other weight / mass units out there

There are only three countries where the metric system is not used: the US, Liberia and Myanmar.
Testing with macOS 11.1 and iOS 14.4 Simulator, only one region "US" uses pounds.
Code Block
extension Locale {
var measurementSystem: String {
(self as NSLocale).object(forKey: NSLocale.Key.measurementSystem) as! String
}
}
func formatWeight(for locale: Locale, weightInKgs: Double) -> String {
let mformatter = MeasurementFormatter()
mformatter.locale = locale
mformatter.unitOptions = .naturalScale
mformatter.unitStyle = .medium
let weight = Measurement(value: weightInKgs, unit: UnitMass.kilograms)
return mformatter.string(from: weight)
}
let localeIds = ["en_US", "es_US", "en_GB", "en_LR", "my_MM", "ja_JP"]
for localId in localeIds {
let locale = Locale(identifier: localId)
print(locale, locale.measurementSystem)
print(locale.regionCode ?? "*region unknown*")
print("Uses Metric System: \(locale.usesMetricSystem)")
print(formatWeight(for: locale, weightInKgs: 100.1))
}

Output:
Code Block
en_US (fixed) U.S.
US
Uses Metric System: false
220.683 lb
es_US (fixed) U.S.
US
Uses Metric System: false
220.683 lb
en_GB (fixed) U.K.
GB
Uses Metric System: true
100.1 kg
en_LR (fixed) U.S.
LR
Uses Metric System: false
100.1 kg
my_MM (fixed) U.S.
MM
Uses Metric System: false
၁၀၀.၁ kg
ja_JP (fixed) Metric
JP
Uses Metric System: true
100.1 kg

(I'm not sure if kg is really preferred in daily life in the UK, but macOS/iOS uses kg for weight/mass when Locale set to en_GB.)

Seems using UnitMass.pounds is universal enough, practically.
Thank you very much for your profound answer!
MeasurementFormatter workaround for missing .unitStyle = .none?
 
 
Q