CanonicalizeLocaleList = function (locales) {
        if (typeof locales === "undefined") {
            return [];
        }

        const seen = [];
        const O = typeof locales === "string" ? [locales] : Internal.ToObject(locales);
        const len = Internal.ToLength(O.length);
        let k = 0, i = 0;;

        while (k < len) {
            const Pk = Internal.ToString(k);
            if (Pk in O) {
                const kValue = O[Pk];
                if ((typeof kValue !== "string" && typeof kValue !== "object") || kValue === null) {
                    platform.raiseNeedObjectOrString("locale");
                }

                const tag = Internal.ToString(kValue);
                if (!IsStructurallyValidLanguageTag(tag)) {
                    platform.raiseLocaleNotWellFormed(tag);
                }

                const canonicalizedTag = platform.normalizeLanguageTag(tag);
                if (canonicalizedTag === undefined) {
                    // See comment in platform.normalizeLanguageTag about when this happens
                    platform.raiseLocaleNotWellFormed(tag);
                } else if (_.arrayIndexOf(seen, canonicalizedTag) === -1) {
                    _.defineProperty(seen, i++, {value: canonicalizedTag, enumerable: true, configurable: true, writable: true});
                }
            }

            k += 1;
        }

        return seen;
    }
Given a locale or list of locales, returns a corresponding list where each locale
is guaranteed to be "canonical" (proper capitalization, order, etc.).

ECMA402: #sec-canonicalizelocalelist

@param {String|String[]} locales the user-provided locales to be canonicalized