Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const localeService = Services.locale;
const data = {
filtering: {
"exact match": [
[["en"], ["en"], ["en"]],
[["en-US"], ["en-US"], ["en-US"]],
[["en-Latn-US"], ["en-Latn-US"], ["en-Latn-US"]],
[["en-Latn-US-windows"], ["en-Latn-US-windows"], ["en-Latn-US-windows"]],
[["fr-FR"], ["de", "it", "fr-FR"], ["fr-FR"]],
[
["fr", "pl", "de-DE"],
["pl", "en-US", "de-DE"],
["pl", "de-DE"],
],
],
"available as range": [
[["en-US"], ["en"], ["en"]],
[["en-Latn-US"], ["en-US"], ["en-US"]],
[["en-US-windows"], ["en-US"], ["en-US"]],
[
["fr-CA", "de-DE"],
["fr", "it", "de"],
["fr", "de"],
],
[["ja-JP-windows"], ["ja"], ["ja"]],
[
["en-Latn-GB", "en-Latn-IN"],
["en-IN", "en-GB"],
["en-GB", "en-IN"],
],
],
"should match on likely subtag": [
[["en"], ["en-GB", "de", "en-US"], ["en-US", "en-GB"]],
[
["en"],
["en-Latn-GB", "de", "en-Latn-US"],
["en-Latn-US", "en-Latn-GB"],
],
[["fr"], ["fr-CA", "fr-FR"], ["fr-FR", "fr-CA"]],
[["az-IR"], ["az-Latn", "az-Arab"], ["az-Arab"]],
[["sr-RU"], ["sr-Cyrl", "sr-Latn"], ["sr-Latn"]],
[["sr"], ["sr-Latn", "sr-Cyrl"], ["sr-Cyrl"]],
[["zh-GB"], ["zh-Hans", "zh-Hant"], ["zh-Hant"]],
[["sr", "ru"], ["sr-Latn", "ru"], ["ru"]],
[["sr-RU"], ["sr-Latn-RO", "sr-Cyrl"], ["sr-Latn-RO"]],
],
"should match likelySubtag region over other regions": [
[["en-CA"], ["en-ZA", "en-GB", "en-US"], ["en-US", "en-ZA", "en-GB"]],
],
"should match cross-region": [
[["en"], ["en-US"], ["en-US"]],
[["en-US"], ["en-GB"], ["en-GB"]],
[["en-Latn-US"], ["en-Latn-GB"], ["en-Latn-GB"]],
],
"should match cross-variant": [
[["en-US-linux"], ["en-US-windows"], ["en-US-windows"]],
],
"should prioritize properly": [
// exact match first
[
["en-US"],
["en-US-windows", "en", "en-US"],
["en-US", "en", "en-US-windows"],
],
// available as range second
[["en-Latn-US"], ["en-GB", "en-US"], ["en-US", "en-GB"]],
// likely subtags third
[["en"], ["en-Cyrl-US", "en-Latn-US"], ["en-Latn-US"]],
// variant range fourth
[
["en-US-macos"],
["en-US-windows", "en-GB-macos"],
["en-US-windows", "en-GB-macos"],
],
// regional range fifth
[["en-US-macos"], ["en-GB-windows"], ["en-GB-windows"]],
[["en-US"], ["en-GB", "en"], ["en", "en-GB"]],
[
["fr-CA-macos", "de-DE"],
["de-DE", "fr-FR-windows"],
["fr-FR-windows", "de-DE"],
],
],
"should handle default locale properly": [
[["fr"], ["de", "it"], []],
[["fr"], ["de", "it"], "en-US", ["en-US"]],
[["fr"], ["de", "en-US"], "en-US", ["en-US"]],
[
["fr", "de-DE"],
["de-DE", "fr-CA"],
"en-US",
["fr-CA", "de-DE", "en-US"],
],
],
"should handle all matches on the 1st higher than any on the 2nd": [
[
["fr-CA-macos", "de-DE"],
["de-DE", "fr-FR-windows"],
["fr-FR-windows", "de-DE"],
],
],
"should handle cases and underscores, returning the form given in the 'available' list":
[
[["fr_FR"], ["fr-FR"], ["fr-FR"]],
[["fr_fr"], ["fr-FR"], ["fr-FR"]],
[["fr_Fr"], ["fr-fR"], ["fr-fR"]],
[["fr_lAtN_fr"], ["fr-Latn-FR"], ["fr-Latn-FR"]],
[["fr_FR"], ["fr_FR"], ["fr_FR"]],
[["fr-FR"], ["fr_FR"], ["fr_FR"]],
[["fr_Cyrl_FR_macos"], ["fr_Cyrl_fr-macos"], ["fr_Cyrl_fr-macos"]],
],
"should handle mozilla specific 3-letter variants": [
[
["ja-JP-mac", "de-DE"],
["ja-JP-mac", "de-DE"],
["ja-JP-mac", "de-DE"],
],
],
"should not crash on invalid input": [
[["fą-FŻ"], ["ór_Fń"], []],
[["2"], ["ąóżł"], []],
[[[""]], ["fr-FR"], []],
],
"should not match on invalid input": [[["en"], ["ťŮ"], []]],
},
matching: {
"should match only one per requested": [
[
["fr", "en"],
["en-US", "fr-FR", "en", "fr"],
null,
localeService.langNegStrategyMatching,
["fr", "en"],
],
],
},
lookup: {
"should match only one": [
[
["fr-FR", "en"],
["en-US", "fr-FR", "en", "fr"],
"en-US",
localeService.langNegStrategyLookup,
["fr-FR"],
],
],
},
};
function run_test() {
const nl = localeService.negotiateLanguages;
const json = JSON.stringify;
for (const strategy in data) {
for (const groupName in data[strategy]) {
const group = data[strategy][groupName];
for (const test of group) {
const requested = test[0];
const available = test[1];
const defaultLocale = test.length > 3 ? test[2] : undefined;
const strategyInner = test.length > 4 ? test[3] : undefined;
const supported = test[test.length - 1];
const result = nl(test[0], test[1], defaultLocale, strategyInner);
deepEqual(
result,
supported,
`\nExpected ${json(requested)} * ${json(available)} = ${json(
supported
)}.\n`
);
}
}
}
// Verify that we error out when requested or available is not an array.
for (const [req, avail] in [
[null, ["fr-FR"]],
[undefined, ["fr-FR"]],
[2, ["fr-FR"]],
["fr-FR", ["fr-FR"]],
[["fr-FR"], null],
[["fr-FR"], undefined],
[["fr-FR"], 2],
[["fr-FR"], "fr-FR"],
[[null], []],
[[undefined], []],
[[undefined], [null]],
[[undefined], [undefined]],
[[null], [null]],
[[[]], [[2]]],
]) {
Assert.throws(
() => {
nl(req, avail);
},
err => err.result == Cr.NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY
);
}
}