Skip to content

Commit a60ab57

Browse files
TimothyGuMylesBorins
authored andcommitted
deps: cherry-pick 6989b3f6d7 from V8 upstream
Original commit message: Fix default Intl language tag handling With certain ICU data bundles (such as the Node.js "small-icu"), %GetDefaultICULocale() may return a more specific language tag (e.g. "en-US") than what's available (e.g. "en"). In those cases, consider the more specific language tag supported. This CL also resolves the following Node.js issue: nodejs#15223 Bug: v8:7024 Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng Change-Id: Ifda0776b3418734d5caa8af4e50c17cda95add73 Reviewed-on: https://chromium-review.googlesource.com/668350 Commit-Queue: Daniel Ehrenberg <[email protected]> Reviewed-by: Daniel Ehrenberg <[email protected]> Cr-Commit-Position: refs/heads/master@{nodejs#52716} PR-URL: nodejs#20826 Fixes: nodejs#15223 Refs: v8/v8@6989b3f Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent f781758 commit a60ab57

12 files changed

+119
-46
lines changed

common.gypi

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
# Reset this number to 0 on major V8 upgrades.
2929
# Increment by one for each non-official patch applied to deps/v8.
30-
'v8_embedder_string': '-node.6',
30+
'v8_embedder_string': '-node.7',
3131

3232
# Enable disassembler for `--print-code` v8 options
3333
'v8_enable_disassembler': 1,

deps/v8/src/js/intl.js

+59-30
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,11 @@ var AVAILABLE_LOCALES = {
152152
*/
153153
var DEFAULT_ICU_LOCALE = UNDEFINED;
154154

155-
function GetDefaultICULocaleJS(service) {
155+
function GetDefaultICULocaleJS() {
156156
if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) {
157157
DEFAULT_ICU_LOCALE = %GetDefaultICULocale();
158158
}
159-
// Check that this is a valid default for this service,
160-
// otherwise fall back to "und"
161-
// TODO(littledan,jshin): AvailableLocalesOf sometimes excludes locales
162-
// which don't require tailoring, but work fine with root data. Look into
163-
// exposing this fact in ICU or the way Chrome bundles data.
164-
return (IS_UNDEFINED(service) ||
165-
HAS_OWN_PROPERTY(getAvailableLocalesOf(service), DEFAULT_ICU_LOCALE))
166-
? DEFAULT_ICU_LOCALE : "und";
159+
return DEFAULT_ICU_LOCALE;
167160
}
168161

169162
/**
@@ -434,6 +427,48 @@ function resolveLocale(service, requestedLocales, options) {
434427
}
435428

436429

430+
/**
431+
* Look up the longest non-empty prefix of |locale| that is an element of
432+
* |availableLocales|. Returns undefined when the |locale| is completely
433+
* unsupported by |availableLocales|.
434+
*/
435+
function bestAvailableLocale(availableLocales, locale) {
436+
do {
437+
if (!IS_UNDEFINED(availableLocales[locale])) {
438+
return locale;
439+
}
440+
// Truncate locale if possible.
441+
var pos = %StringLastIndexOf(locale, '-');
442+
if (pos === -1) {
443+
break;
444+
}
445+
locale = %_Call(StringSubstring, locale, 0, pos);
446+
} while (true);
447+
448+
return UNDEFINED;
449+
}
450+
451+
452+
/**
453+
* Try to match any mutation of |requestedLocale| against |availableLocales|.
454+
*/
455+
function attemptSingleLookup(availableLocales, requestedLocale) {
456+
// Remove all extensions.
457+
var noExtensionsLocale = %RegExpInternalReplace(
458+
GetAnyExtensionRE(), requestedLocale, '');
459+
var availableLocale = bestAvailableLocale(
460+
availableLocales, requestedLocale);
461+
if (!IS_UNDEFINED(availableLocale)) {
462+
// Return the resolved locale and extension.
463+
var extensionMatch = %regexp_internal_match(
464+
GetUnicodeExtensionRE(), requestedLocale);
465+
var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0];
466+
return {locale: availableLocale, extension: extension};
467+
}
468+
return UNDEFINED;
469+
}
470+
471+
437472
/**
438473
* Returns best matched supported locale and extension info using basic
439474
* lookup algorithm.
@@ -446,31 +481,25 @@ function lookupMatcher(service, requestedLocales) {
446481
var availableLocales = getAvailableLocalesOf(service);
447482

448483
for (var i = 0; i < requestedLocales.length; ++i) {
449-
// Remove all extensions.
450-
var locale = %RegExpInternalReplace(
451-
GetAnyExtensionRE(), requestedLocales[i], '');
452-
do {
453-
if (!IS_UNDEFINED(availableLocales[locale])) {
454-
// Return the resolved locale and extension.
455-
var extensionMatch = %regexp_internal_match(
456-
GetUnicodeExtensionRE(), requestedLocales[i]);
457-
var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0];
458-
return {locale: locale, extension: extension, position: i};
459-
}
460-
// Truncate locale if possible.
461-
var pos = %StringLastIndexOf(locale, '-');
462-
if (pos === -1) {
463-
break;
464-
}
465-
locale = %_Call(StringSubstring, locale, 0, pos);
466-
} while (true);
484+
var result = attemptSingleLookup(availableLocales, requestedLocales[i]);
485+
if (!IS_UNDEFINED(result)) {
486+
return result;
487+
}
488+
}
489+
490+
var defLocale = GetDefaultICULocaleJS();
491+
492+
// While ECMA-402 returns defLocale directly, we have to check if it is
493+
// supported, as such support is not guaranteed.
494+
var result = attemptSingleLookup(availableLocales, defLocale);
495+
if (!IS_UNDEFINED(result)) {
496+
return result;
467497
}
468498

469499
// Didn't find a match, return default.
470500
return {
471-
locale: GetDefaultICULocaleJS(service),
472-
extension: '',
473-
position: -1
501+
locale: 'und',
502+
extension: ''
474503
};
475504
}
476505

deps/v8/test/intl/assert.js

+41
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,16 @@ function assertFalse(value, user_message = '') {
132132
}
133133

134134

135+
/**
136+
* Throws if value is null.
137+
*/
138+
function assertNotNull(value, user_message = '') {
139+
if (value === null) {
140+
fail("not null", value, user_message);
141+
}
142+
}
143+
144+
135145
/**
136146
* Runs code() and asserts that it throws the specified exception.
137147
*/
@@ -189,3 +199,34 @@ function assertInstanceof(obj, type) {
189199
(actualTypeName ? ' but of < ' + actualTypeName + '>' : ''));
190200
}
191201
}
202+
203+
204+
/**
205+
* Split a BCP 47 language tag into locale and extension.
206+
*/
207+
function splitLanguageTag(tag) {
208+
var extRe = /(-[0-9A-Za-z](-[0-9A-Za-z]{2,8})+)+$/;
209+
var match = %regexp_internal_match(extRe, tag);
210+
if (match) {
211+
return { locale: tag.slice(0, match.index), extension: match[0] };
212+
}
213+
214+
return { locale: tag, extension: '' };
215+
}
216+
217+
218+
/**
219+
* Throw if |parent| is not a more general language tag of |child|, nor |child|
220+
* itself, per BCP 47 rules.
221+
*/
222+
function assertLanguageTag(child, parent) {
223+
var childSplit = splitLanguageTag(child);
224+
var parentSplit = splitLanguageTag(parent);
225+
226+
// Do not compare extensions at this moment, as %GetDefaultICULocale()
227+
// doesn't always output something we support.
228+
if (childSplit.locale !== parentSplit.locale &&
229+
!childSplit.locale.startsWith(parentSplit.locale + '-')) {
230+
fail(child, parent, 'language tag comparison');
231+
}
232+
}

deps/v8/test/intl/break-iterator/default-locale.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ assertFalse(options.locale === 'und');
3737
assertFalse(options.locale === '');
3838
assertFalse(options.locale === undefined);
3939

40-
// Then check for equality.
41-
assertEquals(options.locale, %GetDefaultICULocale());
40+
// Then check for legitimacy.
41+
assertLanguageTag(%GetDefaultICULocale(), options.locale);
4242

4343
var iteratorNone = new Intl.v8BreakIterator();
4444
assertEquals(options.locale, iteratorNone.resolvedOptions().locale);

deps/v8/test/intl/break-iterator/wellformed-unsupported-locale.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929

3030
var iterator = Intl.v8BreakIterator(['xx']);
3131

32-
assertEquals(iterator.resolvedOptions().locale, %GetDefaultICULocale());
32+
assertLanguageTag(%GetDefaultICULocale(), iterator.resolvedOptions().locale);

deps/v8/test/intl/collator/default-locale.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ assertFalse(options.locale === 'und');
3737
assertFalse(options.locale === '');
3838
assertFalse(options.locale === undefined);
3939

40-
// Then check for equality.
41-
assertEquals(options.locale, %GetDefaultICULocale());
40+
// Then check for legitimacy.
41+
assertLanguageTag(%GetDefaultICULocale(), options.locale);
4242

4343
var collatorNone = new Intl.Collator();
4444
assertEquals(options.locale, collatorNone.resolvedOptions().locale);
@@ -48,5 +48,8 @@ var collatorBraket = new Intl.Collator({});
4848
assertEquals(options.locale, collatorBraket.resolvedOptions().locale);
4949

5050
var collatorWithOptions = new Intl.Collator(undefined, {usage: 'search'});
51-
assertEquals(%GetDefaultICULocale() + '-u-co-search',
52-
collatorWithOptions.resolvedOptions().locale);
51+
assertLanguageTag(%GetDefaultICULocale(),
52+
collatorWithOptions.resolvedOptions().locale);
53+
assertNotNull(
54+
%regexp_internal_match(/-u(-[a-zA-Z]+-[a-zA-Z]+)*-co-search/,
55+
collatorWithOptions.resolvedOptions().locale));

deps/v8/test/intl/collator/wellformed-unsupported-locale.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929

3030
var collator = Intl.Collator(['xx']);
3131

32-
assertEquals(collator.resolvedOptions().locale, %GetDefaultICULocale());
32+
assertLanguageTag(%GetDefaultICULocale(), collator.resolvedOptions().locale);

deps/v8/test/intl/date-format/default-locale.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ assertFalse(options.locale === 'und');
3737
assertFalse(options.locale === '');
3838
assertFalse(options.locale === undefined);
3939

40-
// Then check for equality.
41-
assertEquals(options.locale, %GetDefaultICULocale());
40+
// Then check for legitimacy.
41+
assertLanguageTag(%GetDefaultICULocale(), options.locale);
4242

4343
var dtfNone = new Intl.DateTimeFormat();
4444
assertEquals(options.locale, dtfNone.resolvedOptions().locale);

deps/v8/test/intl/date-format/wellformed-unsupported-locale.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929

3030
var dtf = Intl.DateTimeFormat(['xx']);
3131

32-
assertEquals(dtf.resolvedOptions().locale, %GetDefaultICULocale());
32+
assertLanguageTag(%GetDefaultICULocale(), dtf.resolvedOptions().locale);

deps/v8/test/intl/number-format/default-locale.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ assertFalse(options.locale === 'und');
3737
assertFalse(options.locale === '');
3838
assertFalse(options.locale === undefined);
3939

40-
// Then check for equality.
41-
assertEquals(options.locale, %GetDefaultICULocale());
40+
// Then check for legitimacy.
41+
assertLanguageTag(%GetDefaultICULocale(), options.locale);
4242

4343
var nfNone = new Intl.NumberFormat();
4444
assertEquals(options.locale, nfNone.resolvedOptions().locale);

deps/v8/test/intl/number-format/wellformed-unsupported-locale.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929

3030
var nf = Intl.NumberFormat(['xx']);
3131

32-
assertEquals(nf.resolvedOptions().locale, %GetDefaultICULocale());
32+
assertLanguageTag(%GetDefaultICULocale(), nf.resolvedOptions().locale);

deps/v8/test/mjsunit/regress/regress-6288.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
// DateTimeFormat but not Collation
99

1010
if (this.Intl) {
11-
assertEquals('und', Intl.Collator().resolvedOptions().locale);
11+
assertEquals('pt', Intl.Collator().resolvedOptions().locale);
1212
assertEquals('pt-BR', Intl.DateTimeFormat().resolvedOptions().locale);
1313
}

0 commit comments

Comments
 (0)