From 329430e7b9c52de3c8fedfe50f49092a9a0e2662 Mon Sep 17 00:00:00 2001 From: Neil Dhar Date: Tue, 3 Oct 2023 13:29:36 -0700 Subject: [PATCH] Truncate legacy extension keys from default locale on iOS/Mac (#1141) Summary: Pull Request resolved: https://github.com/facebook/hermes/pull/1141 iOS can sometimes return a default locale identifier that contains extensions in the legacy form. Ideally, we should convert these into the new style and respect them, but that isn't trivial to do. We could do also just use the iOS version of the locale without converting it. But this is potentially confusing, since the locale won't follow a format that we actually accept. So in something like: ``` Intl.Collator(Intl.Collator().resolvedOptions.locale) ``` the inner collator and outer collator will have inconsistent behaviour. For now, truncate the extensions so we can at least parse the first part of the identifier and honour it. Closes #1140 Reviewed By: avp Differential Revision: D49870526 fbshipit-source-id: 893c3e1d95009ab6b32b2e2c41ef84855cedf28a --- lib/Platform/Intl/PlatformIntlApple.mm | 21 +++++++++++++------ .../intl/default-locale-legacy-extension.js | 15 +++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 test/hermes/intl/default-locale-legacy-extension.js diff --git a/lib/Platform/Intl/PlatformIntlApple.mm b/lib/Platform/Intl/PlatformIntlApple.mm index 324f6a34972..099499220f5 100644 --- a/lib/Platform/Intl/PlatformIntlApple.mm +++ b/lib/Platform/Intl/PlatformIntlApple.mm @@ -42,6 +42,10 @@ std::replace(u16str.begin(), u16str.end(), u'_', u'-'); // Some locales may still not be properly canonicalized (e.g. en_US_POSIX // should be en-US-posix). + // Note that we do not need to handle legacy extensions here (unlike + // getDefaultLocale), since the documentation for + // availableLocaleIdentifiers states that they will only contain a + // language, country, and script code. if (auto parsed = ParsedLocaleIdentifier::parse(u16str)) vec->push_back(parsed->canonicalize()); } @@ -53,12 +57,17 @@ static const std::u16string *defLocale = new std::u16string([] { // Environment variable used for testing only const char *testLocale = std::getenv("_HERMES_TEST_LOCALE"); - if (testLocale) { - NSString *nsTestLocale = [NSString stringWithUTF8String:testLocale]; - return nsStringToU16String(nsTestLocale); - } - NSString *nsDefLocale = [[NSLocale currentLocale] localeIdentifier]; - auto defLocale = nsStringToU16String(nsDefLocale); + NSString *nsLocale = testLocale + ? [NSString stringWithUTF8String:testLocale] + : [[NSLocale currentLocale] localeIdentifier]; + auto defLocale = nsStringToU16String(nsLocale); + + // The locale identifier may occasionally contain legacy style locale + // extensions. We cannot handle them so remove them before parsing the tag. + size_t delimIdx = defLocale.find(u'@'); + if (delimIdx != std::u16string::npos) + defLocale.resize(delimIdx); + // See the comment in getAvailableLocales. std::replace(defLocale.begin(), defLocale.end(), u'_', u'-'); if (auto parsed = ParsedLocaleIdentifier::parse(defLocale)) diff --git a/test/hermes/intl/default-locale-legacy-extension.js b/test/hermes/intl/default-locale-legacy-extension.js new file mode 100644 index 00000000000..01eaee23635 --- /dev/null +++ b/test/hermes/intl/default-locale-legacy-extension.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// RUN: _HERMES_TEST_LOCALE="en-GB@foo=bar" %hermes %s | %FileCheck --match-full-lines %s +// REQUIRES: intl + +print(Intl.Collator().resolvedOptions().locale); +// CHECK: en-GB + +print(Intl.DateTimeFormat().resolvedOptions().locale); +// CHECK-NEXT: en-GB