mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-16 09:23:07 +09:00
233 lines
6.7 KiB
JavaScript
233 lines
6.7 KiB
JavaScript
// 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/.
|
|
// ==UserScript==
|
|
// @name Intl.ListFormat Polyfill (minimal)
|
|
// @namespace internal-userscripts
|
|
// @description Provides a minimal Intl.ListFormat implementation for environments without native support.
|
|
// @match *://*/*
|
|
// @grant none
|
|
// @run-at document-start
|
|
// ==/UserScript==
|
|
(function () {
|
|
"use strict";
|
|
|
|
if (typeof Intl !== "object" || typeof Intl.ListFormat === "function") {
|
|
return;
|
|
}
|
|
|
|
var TYPE_VALUES = { conjunction: true, disjunction: true, unit: true };
|
|
var STYLE_VALUES = { long: true, short: true, narrow: true };
|
|
var LOCALE_MATCHER_VALUES = { lookup: true, "best fit": true };
|
|
var PATTERNS = {
|
|
conjunction: {
|
|
long: { pair: " and ", middle: ", ", end: ", and " },
|
|
short: { pair: " & ", middle: ", ", end: ", & " },
|
|
narrow: { pair: ", ", middle: ", ", end: ", " },
|
|
},
|
|
disjunction: {
|
|
long: { pair: " or ", middle: ", ", end: ", or " },
|
|
short: { pair: " or ", middle: ", ", end: ", or " },
|
|
narrow: { pair: " or ", middle: ", ", end: ", or " },
|
|
},
|
|
unit: {
|
|
long: { pair: ", ", middle: ", ", end: ", " },
|
|
short: { pair: ", ", middle: ", ", end: ", " },
|
|
narrow: { pair: " ", middle: " ", end: " " },
|
|
},
|
|
};
|
|
|
|
function canonicalizeLocales(locales) {
|
|
if (typeof Intl.getCanonicalLocales === "function") {
|
|
return Intl.getCanonicalLocales(locales);
|
|
}
|
|
if (locales == null) {
|
|
return [];
|
|
}
|
|
if (Array.isArray(locales)) {
|
|
return locales.map(function (locale) {
|
|
return String(locale);
|
|
});
|
|
}
|
|
return [String(locales)];
|
|
}
|
|
|
|
function defaultLocale() {
|
|
try {
|
|
if (typeof Intl.DateTimeFormat === "function") {
|
|
return Intl.DateTimeFormat().resolvedOptions().locale;
|
|
}
|
|
} catch (e) {}
|
|
if (typeof navigator !== "undefined" && navigator.language) {
|
|
return String(navigator.language);
|
|
}
|
|
return "en-US";
|
|
}
|
|
|
|
function toStringValue(value) {
|
|
if (typeof value === "symbol") {
|
|
throw new TypeError("Cannot convert a Symbol value to a string");
|
|
}
|
|
return String(value);
|
|
}
|
|
|
|
function toStringList(list) {
|
|
if (list == null) {
|
|
throw new TypeError("List argument is required");
|
|
}
|
|
|
|
var result = [];
|
|
if (typeof Symbol !== "undefined" && list[Symbol.iterator] != null) {
|
|
var iterator = list[Symbol.iterator]();
|
|
if (!iterator || typeof iterator.next !== "function") {
|
|
throw new TypeError("List argument must be iterable");
|
|
}
|
|
while (true) {
|
|
var step = iterator.next();
|
|
if (step.done) {
|
|
break;
|
|
}
|
|
result.push(toStringValue(step.value));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Fallback for very old environments without Symbol.iterator.
|
|
if (Array.isArray(list)) {
|
|
for (var i = 0; i < list.length; i++) {
|
|
result.push(toStringValue(list[i]));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
throw new TypeError("List argument must be iterable");
|
|
}
|
|
|
|
function requireListFormatInstance(value) {
|
|
if (
|
|
value == null ||
|
|
(typeof value !== "object" && typeof value !== "function") ||
|
|
!TYPE_VALUES[value._type] ||
|
|
!STYLE_VALUES[value._style]
|
|
) {
|
|
throw new TypeError(
|
|
"Method Intl.ListFormat.prototype called on incompatible receiver",
|
|
);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function buildParts(items, pattern) {
|
|
var parts = [];
|
|
var i = 0;
|
|
var lastIndex = items.length - 1;
|
|
|
|
if (items.length === 0) {
|
|
return parts;
|
|
}
|
|
if (items.length === 1) {
|
|
parts.push({ type: "element", value: items[0] });
|
|
return parts;
|
|
}
|
|
if (items.length === 2) {
|
|
parts.push({ type: "element", value: items[0] });
|
|
parts.push({ type: "literal", value: pattern.pair });
|
|
parts.push({ type: "element", value: items[1] });
|
|
return parts;
|
|
}
|
|
|
|
parts.push({ type: "element", value: items[0] });
|
|
for (i = 1; i < lastIndex; i++) {
|
|
parts.push({ type: "literal", value: pattern.middle });
|
|
parts.push({ type: "element", value: items[i] });
|
|
}
|
|
parts.push({ type: "literal", value: pattern.end });
|
|
parts.push({ type: "element", value: items[lastIndex] });
|
|
return parts;
|
|
}
|
|
|
|
function ListFormat(locales, options) {
|
|
if (!(this instanceof ListFormat)) {
|
|
throw new TypeError("Intl.ListFormat must be called with new");
|
|
}
|
|
|
|
options = options || {};
|
|
var type = options.type == null ? "conjunction" : String(options.type);
|
|
var style = options.style == null ? "long" : String(options.style);
|
|
var localeMatcher =
|
|
options.localeMatcher == null
|
|
? "best fit"
|
|
: String(options.localeMatcher);
|
|
|
|
if (!TYPE_VALUES[type]) {
|
|
throw new RangeError("Invalid type");
|
|
}
|
|
if (!STYLE_VALUES[style]) {
|
|
throw new RangeError("Invalid style");
|
|
}
|
|
if (!LOCALE_MATCHER_VALUES[localeMatcher]) {
|
|
throw new RangeError("Invalid localeMatcher");
|
|
}
|
|
|
|
var localeList = canonicalizeLocales(locales);
|
|
this._locale = localeList.length ? localeList[0] : defaultLocale();
|
|
this._type = type;
|
|
this._style = style;
|
|
}
|
|
|
|
ListFormat.supportedLocalesOf = function (locales, options) {
|
|
if (options != null && typeof options === "object") {
|
|
var localeMatcher = options.localeMatcher;
|
|
if (
|
|
localeMatcher != null &&
|
|
!LOCALE_MATCHER_VALUES[String(localeMatcher)]
|
|
) {
|
|
throw new RangeError("Invalid localeMatcher");
|
|
}
|
|
}
|
|
return canonicalizeLocales(locales);
|
|
};
|
|
|
|
ListFormat.prototype.resolvedOptions = function () {
|
|
var self = requireListFormatInstance(this);
|
|
return {
|
|
locale: self._locale,
|
|
type: self._type,
|
|
style: self._style,
|
|
};
|
|
};
|
|
|
|
ListFormat.prototype.formatToParts = function (list) {
|
|
var self = requireListFormatInstance(this);
|
|
var items = toStringList(list);
|
|
var pattern = PATTERNS[self._type][self._style];
|
|
return buildParts(items, pattern);
|
|
};
|
|
|
|
ListFormat.prototype._format = function (list) {
|
|
var parts = this.formatToParts(list);
|
|
var result = "";
|
|
for (var i = 0; i < parts.length; i++) {
|
|
result += parts[i].value;
|
|
}
|
|
return result;
|
|
};
|
|
|
|
Object.defineProperty(ListFormat.prototype, "format", {
|
|
configurable: true,
|
|
get: function () {
|
|
var self = requireListFormatInstance(this);
|
|
if (!self._boundFormat) {
|
|
self._boundFormat = function (list) {
|
|
return self._format(list);
|
|
};
|
|
}
|
|
return self._boundFormat;
|
|
},
|
|
});
|
|
|
|
Intl.ListFormat = ListFormat;
|
|
try {
|
|
window.__internalUserscriptsIntlListFormatPolyfill = true;
|
|
} catch (e) {}
|
|
})();
|