Launch argument "-AppleLocale en_US" doesn't change measurement system(units) to "US" on MacOs

We used Locale::usesMetricSystem to distinguish between metric and Imperial(US) measurement systems. We set "-AppleLocale en_US" as launch argument for App in UITests but usesMetricSystem still returns true in case user's locale are not equal to "US" in System Preferences -> Language and Region -> Region.

Here is a demo project to illustrate the issue: https://github.com/yuri-qualtie/UseMetricSystemDemo

Precondition: Change user region to not US(for example Australia) in System Preferences -> Language and Region -> Region

We expect that code:
Code Block
print(Locale.current.usesMetricSystem)

prints false when -AppleLocale en_US is set but actual result is true

Probably there is alternative way how to change measurement system via launch arguments or App's settings in Xcode?
Answered by DTS Engineer in 671734022
Try this [1]:

Code Block
-AppleLocale en_US -AppleMetricUnits <false/> -AppleMeasurementUnits Inches


There are two things to note here:
  • These preferences keys are not considered API. It’s fine to use them for tests and so on, but you should not ship code that relies on them. Rather, continue to use Locale APIs like usesMetricSystem.

  • Apropos usesMetricSystem, be aware that we no longer use a strict Boolean value here. The popup now shows three values (Metric, US, UK) reflected in NSLocaleMeasurementSystem. I believe NSMeasurementFormatter will do the right thing here, but it’s not something I’ve dug into in detail.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Weirdly, if you’re testing this in a command-line tool (rather than app), you have to initialise the UserDefaults system before you get the locale. So this code:

Code Block
_ = UserDefaults.standard
let loc = Locale.current
print(loc)


prints en_US but, if you drop the first line, it prints your current locale (en_GB in my case).
Try this [1]:

Code Block
-AppleLocale en_US -AppleMetricUnits <false/> -AppleMeasurementUnits Inches


There are two things to note here:
  • These preferences keys are not considered API. It’s fine to use them for tests and so on, but you should not ship code that relies on them. Rather, continue to use Locale APIs like usesMetricSystem.

  • Apropos usesMetricSystem, be aware that we no longer use a strict Boolean value here. The popup now shows three values (Metric, US, UK) reflected in NSLocaleMeasurementSystem. I believe NSMeasurementFormatter will do the right thing here, but it’s not something I’ve dug into in detail.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Weirdly, if you’re testing this in a command-line tool (rather than app), you have to initialise the UserDefaults system before you get the locale. So this code:

Code Block
_ = UserDefaults.standard
let loc = Locale.current
print(loc)


prints en_US but, if you drop the first line, it prints your current locale (en_GB in my case).
Accepted Answer
Quinn, thank you for reply!

I've just tried
Code Block
-AppleLocale en_US -AppleMetricUnits <false/> -AppleMeasurementUnits Inches

but unfortunately it doesn't help.

I've updated my example project at https://github.com/yuri-qualtie/UseMetricSystemDemo in case you want take a look.

  • We definitely won't use these arguments in production code. It's just for UITests

  • I put some simple code example with print but actually I test in the example App by following code:

Code Block
struct ContentView: View {
    var body: some View {
        VStack {
            Text("Current Locale: \(Locale.current.regionCode!)")
            Text("Curren Locale uses metric system: " + "\(Locale.current.usesMetricSystem)")
                .padding()
            Text("US Locale: \(Locale(identifier: "en_US").regionCode!)")
            Text("US uses metric system: " + "\(Locale(identifier: "en_US").usesMetricSystem)")
                .padding()
        }
    }
}


So I always see:
Code Block
Current Locale: US
Curren Locale uses metric system: true
US Locale: US
US uses metric system: false

Your project is reporting false in both cases for me. I’m testing with Xcode 12.4 on macOS 11.2.3 with my Mac’s region set to United Kingdom (I also tried Australia, just in case it was specific to the oddball UK measurement system).

What does your configuration look like?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
My region - Russia and Measurement units: Metric.

I’m testing with Xcode 12.4 on macOS 11.2.3 with my Mac’s region set to United Kingdom (I also tried Australia, just in case it was specific to the oddball UK measurement system).

Could you please click "Advanced..." at Language & Region Preferences and change Measurement units to "Metric". It looks like that AppleLocale or AppleMetricUnits doesn't override measurement units

My region - Russia and Measurement units: Metric.

I tried that, and things still work.

Could you please click "Advanced..." at Language & Region Preferences
and change Measurement units to "Metric".

I tried that as well, and things still work.

At this point I’ve run out of ‘easy’ suggestions. My advice is that you open a DTS tech support incident and I, or one of my colleagues, can investigate this further. Please reference this DevForums thread for context.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
I tried setting my locale to Australia (metric) and setting the -AppleMetricUnits false in the example project and saw that the launch argument had no effect and my Locale.current.usesMetricSystem was still true.

Screenshots and details at https://github.com/yuri-qualtie/UseMetricSystemDemo/issues/1
Quinn, we double checked the issue on different machine. Unfortunately, it still reproducible. Here is a screenshots: https://github.com/yuri-qualtie/UseMetricSystemDemo/issues/1

We submitted DTS with Follow-up: 767934016 and referenced this thread as you suggested.
It looks like -AppleMetricUnits <false/> works as expected. It's important to set <false/> not just false

Quinn, thank you very much for your attentiveness and help!
Quinn, I've marked wrong post as solved answer but can't find a way how to change it. Any way to change?

It's important to set <false/> not just false

Yep.

I've marked wrong post as solved answer but can't find a way how to
change it. Any way to change?

Unfortunately no (not even as an admin). This a common feature request and it’s definitely on the to-do list (I’d post a bug number but I don’t have that handy right now).

What I can do is mark my initial response as Apple Recommended (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

What I can do is mark my initial response as Apple Recommended (-:

Awesome! Thank you
This is very useful for testing: -AppleLocale en_US -AppleMetricUnits <false/> -AppleMeasurementUnits Inches

@eskimo, where we can find documentation about this and other useful flags and launch arguments?
This link comes on top when searching for AppleMetricUnits
https://opensource.apple.com/source/CF/CF-855.17/CFLocale.c.auto.html

Code Block
CFTypeRef pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMetricUnits"));
if (pref) {
us = (kCFBooleanFalse == pref);
done = true;
} else {
pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMeasurementUnits"));
if (pref) {
us = CFEqual(pref, CFSTR("Inches"));
done = true;
}
}

and it seems the code is expecting boolean value for AppleMetricUnits key.

How is <false/> which seems XML becomes a boolean? What is the correct way to pass booleans as launch arguments?

where we can find documentation about this and other useful flags and
launch arguments?

You can’t. Hence my earlier comment that “These preference keys are not considered API.” If you want that to change, you should file an enhancement request describing your requirements. Please post your bug number, just for the record.

How is <false/> which seems XML becomes a boolean?

Because:
  • Modern versions of CF don’t use that exact code, but rather rely on the value being a CFBoolean.

  • The NSArgumentDomain within NSUserDefaults will only yield a CFBoolean if you use this syntax.

I can’t point you to the exact code for this because I didn’t keep a breadcrumb trail (normally I do that when I’m working on a TSI but in this case I did all that work before myurik2 opened their TSI). Oh, and it’s quite possible that this isn’t part of the CF open source at all.

Apropos that, you wrote:

CF-855.17

That open source version of Core Foundation is wildly out of date. Consider this:

Code Block
% sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.7
BuildVersion: 19H15
% strings CoreFoundation | grep CoreFoundation-
@(#)PROGRAM:CoreFoundation PROJECT:CoreFoundation-1677.104


[The same trick doesn’t work on macOS 11 for… well… reasons, but you get the idea.]

To find the most up-to-date open source Core Foundation, look in the swift-corelibs-foundation project. But, as always, you have to take this with a grain of salt. Some Apple open source projects, and this is especially true for Darwin and swift-corelibs-foundation, are not an exact match for the version included in the OS. So it’s fine to read the open source to get a general idea of what’s going on — and I regularly point folks to it here on DevForums — but you have to be sensible about this:
  • Don’t rely on the OS behaving in exactly the same way as the open source.

  • The open source exposes a lot of implementation details. Do not encode these implementation details in a shipping product. They can and will change over time (or even between Apple platforms).

Hence my “not considered API” comment above.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo, unfortunately launch arguments -AppleLocale en_US -AppleMetricUnits <false/> -AppleMeasurementUnits Inches no longer work on macOS Ventura.

Our environment:
macOs 13.0 (22A380).
Xcode 14.0.1 (14A400).

Could you please suggest how we can change locale on macOs 13?

Launch argument "-AppleLocale en_US" doesn't change measurement system(units) to "US" on MacOs
 
 
Q