/* 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 ); } }