From 046998aa4aca093c518c6745d9405817bed0e73c Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Thu, 29 Dec 2022 12:08:42 -0600 Subject: [PATCH 1/3] preserve language tags --- src/impl/locale.js | 10 +++++++--- test/datetime/create.test.js | 6 +++--- test/datetime/format.test.js | 6 ++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/impl/locale.js b/src/impl/locale.js index d3cb34744..407336b57 100644 --- a/src/impl/locale.js +++ b/src/impl/locale.js @@ -75,22 +75,26 @@ function parseLocaleString(localeStr) { return [localeStr]; } else { let options; + let selectedStr; const smaller = localeStr.substring(0, uIndex); try { options = getCachedDTF(localeStr).resolvedOptions(); + selectedStr = localeStr; } catch (e) { options = getCachedDTF(smaller).resolvedOptions(); + selectedStr = smaller; } const { numberingSystem, calendar } = options; - // return the smaller one so that we can append the calendar and numbering overrides to it - return [smaller, numberingSystem, calendar]; + return [selectedStr, numberingSystem, calendar]; } } function intlConfigString(localeStr, numberingSystem, outputCalendar) { if (outputCalendar || numberingSystem) { - localeStr += "-u"; + if (!localeStr.includes("-u-")) { + localeStr += "-u"; + } if (outputCalendar) { localeStr += `-ca-${outputCalendar}`; diff --git a/test/datetime/create.test.js b/test/datetime/create.test.js index 446ad9e6f..c14d13e6e 100644 --- a/test/datetime/create.test.js +++ b/test/datetime/create.test.js @@ -663,7 +663,7 @@ test("DateTime.fromObject accepts a locale", () => { test("DateTime.fromObject accepts a locale with calendar and numbering identifiers", () => { const res = DateTime.fromObject({}, { locale: "be-u-ca-coptic-nu-mong" }); - expect(res.locale).toBe("be"); + expect(res.locale).toBe("be-u-ca-coptic-nu-mong"); expect(res.outputCalendar).toBe("coptic"); expect(res.numberingSystem).toBe("mong"); }); @@ -677,7 +677,7 @@ test("DateTime.fromObject accepts a locale string with weird junk in it", () => } ); - expect(res.locale).toBe("be"); + expect(res.locale).toBe("be-u-ca-coptic-ca-islamic"); // "coptic" is right, but some versions of Node 10 give "gregory" expect(res.outputCalendar === "gregory" || res.outputCalendar === "coptic").toBe(true); @@ -695,7 +695,7 @@ test("DateTime.fromObject overrides the locale string with explicit settings", ( } ); - expect(res.locale).toBe("be"); + expect(res.locale).toBe("be-u-ca-coptic-nu-mong"); expect(res.outputCalendar).toBe("islamic"); expect(res.numberingSystem).toBe("thai"); }); diff --git a/test/datetime/format.test.js b/test/datetime/format.test.js index 823dce354..23dcfd77a 100644 --- a/test/datetime/format.test.js +++ b/test/datetime/format.test.js @@ -415,6 +415,12 @@ test("DateTime#toLocaleString uses locale-appropriate time formats", () => { expect(dt.reconfigure({ locale: "es" }).toLocaleString(DateTime.TIME_24_SIMPLE)).toBe("9:23"); }); +test("DateTime#toLocaleString() respects language tags", () => { + expect(dt.reconfigure({ locale: "en-US-u-hc-h23" }).toLocaleString(DateTime.TIME_SIMPLE)).toBe( + "09:23" + ); +}); + test("DateTime#toLocaleString() accepts a zone even when the zone is set", () => { expect( dt.toLocaleString({ From a986eb10cd0f89ff090505ab1b7e551a624e2947 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Thu, 29 Dec 2022 18:21:59 -0600 Subject: [PATCH 2/3] note test requirements --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b01cdc70f..d1eeb7c73 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ Here are some vague notes on Luxon's design philosophy: ## Building and testing -Building and testing is done through npm scripts. The tests run in Node and require Node 10+ with full-icu support. This is because some of the features available in Luxon (like internationalization and time zones) need that stuff and we test it all. On any platform, if you have Node 10 installed with full-icu, you're good to go; just run npm scripts like `npm run test`. But you probably don't have that, so read on. +Building and testing is done through npm scripts. The tests run in Node and require Node 18 with full-icu support. This is because some of the features available in Luxon (like internationalization and time zones) need that stuff and we test it all. On any platform, if you have Node 18 installed with full-icu, you're good to go; just run `scripts/test`. But you probably don't have that, so read on. ### OSX From 619e8b20ab86af7b5d147bf97428ae7e3fb37357 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Fri, 30 Dec 2022 20:45:29 -0600 Subject: [PATCH 3/3] review --- src/impl/locale.js | 10 +++++++++- test/datetime/create.test.js | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/impl/locale.js b/src/impl/locale.js index 407336b57..eb8c2bea8 100644 --- a/src/impl/locale.js +++ b/src/impl/locale.js @@ -70,17 +70,25 @@ function parseLocaleString(localeStr) { // b) if it does, use Intl to resolve everything // c) if Intl fails, try again without the -u + // private subtags and unicode subtags have ordering requirements, + // and we're not properly parsing this, so just strip out the + // private ones if they exist. + const xIndex = localeStr.indexOf("-x-"); + if (xIndex !== -1) { + localeStr = localeStr.substring(0, xIndex); + } + const uIndex = localeStr.indexOf("-u-"); if (uIndex === -1) { return [localeStr]; } else { let options; let selectedStr; - const smaller = localeStr.substring(0, uIndex); try { options = getCachedDTF(localeStr).resolvedOptions(); selectedStr = localeStr; } catch (e) { + const smaller = localeStr.substring(0, uIndex); options = getCachedDTF(smaller).resolvedOptions(); selectedStr = smaller; } diff --git a/test/datetime/create.test.js b/test/datetime/create.test.js index c14d13e6e..016266a69 100644 --- a/test/datetime/create.test.js +++ b/test/datetime/create.test.js @@ -811,3 +811,18 @@ test("DateTime.fromObject takes a undefined to mean {}", () => { const res = DateTime.fromObject(); expect(res.year).toBe(new Date().getFullYear()); }); + +test("private language subtags don't break unicode subtags", () => { + const res = DateTime.fromObject( + {}, + { + locale: "be-u-ca-coptic-nu-mong-x-twain", + numberingSystem: "thai", + outputCalendar: "islamic", + } + ); + + expect(res.locale).toBe("be-u-ca-coptic-nu-mong"); + expect(res.outputCalendar).toBe("islamic"); + expect(res.numberingSystem).toBe("thai"); +});