arcgis-maps-sdk-swift-samples icon indicating copy to clipboard operation
arcgis-maps-sdk-swift-samples copied to clipboard

String interpolation in SwiftUI Text doesn't work with system locale correctly

Open yo1995 opened this issue 2 years ago • 5 comments

Text("Z-value: \(model.zValue.formatted(.measurement(width: .narrow).locale(Locale(identifier: "en-CA"))))")

Shows as "Z-value: 70m"

Text("Z-value: \(model.zValue, format: .measurement(width: .narrow).locale(Locale(identifier: "en-CA")))")

Shows as "Z-value: 230'"

yo1995 avatar Apr 12 '23 21:04 yo1995

I suspect it is because SwiftUI views get the locale from the environment. Does this show the expected value?

Text("Z-value: \(model.zValue, format: .measurement(width: .narrow))")
    .environment(\.locale, Locale(identifier: "en-CA"))

philium avatar Apr 12 '23 22:04 philium

Does this show the expected value?

Yes it shows the correct unit as "Z-value: 70m". It kind of makes sense that the priority is measurement string formatting locale > environment locale > measurement value string interpolation format style locale, but still hard to remember.

Simulator Screenshot - iPhone 14 Pro Max - 2023-04-13 at 10 51 05

I set the locale in Simulator as this - locale ID is still "en-US" while the measurement system is changed to Metric. Using the older formatter API, the dimensions are correctly displayed as metric units, while the SwiftUI formatting style, or formatted() are displayed as imperial.

I'll keep digging to see if SwiftUI formatting style APIs support displaying a different measurement system than the locale's default.

yo1995 avatar Apr 13 '23 18:04 yo1995

I'll keep digging to see if SwiftUI formatting style APIs support displaying a different measurement system than the locale's default.

MeasurementFormatUnitUsage.asProvided might be what you're looking for.

philium avatar Apr 13 '23 18:04 philium

On iOS 16 and newer there is Locale.measurementSystem, which sounds like what you want. It can be specified by creating a locale using Locale.init(components:):

var components = Locale.Components(locale: .current)
components.measurementSystem = .metric
let locale = Locale(components: components)

philium avatar Apr 13 '23 18:04 philium

Thanks Phil. This definitely looks like the correct way to go. Though I tested in iOS 16, it doesn't behave as expected. I'll add this issue to iOS 16 and beyond column and take a look in the future.

yo1995 avatar Apr 13 '23 18:04 yo1995