mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-05 16:12:20 +00:00
1704827d04
Relevant changes: ko: Use correct names for month and hour in Korean (465eaed) Hide unit count if 2 in Arabic (f90d847)
757 lines
22 KiB
JavaScript
757 lines
22 KiB
JavaScript
// HumanizeDuration.js - https://git.io/j0HgmQ
|
||
|
||
// @ts-check
|
||
|
||
/**
|
||
* @typedef {string | ((unitCount: number) => string)} Unit
|
||
*/
|
||
|
||
/**
|
||
* @typedef {("y" | "mo" | "w" | "d" | "h" | "m" | "s" | "ms")} UnitName
|
||
*/
|
||
|
||
/**
|
||
* @typedef {Object} UnitMeasures
|
||
* @prop {number} y
|
||
* @prop {number} mo
|
||
* @prop {number} w
|
||
* @prop {number} d
|
||
* @prop {number} h
|
||
* @prop {number} m
|
||
* @prop {number} s
|
||
* @prop {number} ms
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
* @typedef {[string, string, string, string, string, string, string, string, string, string]} DigitReplacements
|
||
*/
|
||
|
||
/**
|
||
* @typedef {Object} Language
|
||
* @prop {Unit} y
|
||
* @prop {Unit} mo
|
||
* @prop {Unit} w
|
||
* @prop {Unit} d
|
||
* @prop {Unit} h
|
||
* @prop {Unit} m
|
||
* @prop {Unit} s
|
||
* @prop {Unit} ms
|
||
* @prop {string} [decimal]
|
||
* @prop {string} [delimiter]
|
||
* @prop {DigitReplacements} [_digitReplacements]
|
||
* @prop {boolean} [_numberFirst]
|
||
* @prop {boolean} [_hideCountIf2]
|
||
*/
|
||
|
||
/**
|
||
* @typedef {Object} Options
|
||
* @prop {string} [language]
|
||
* @prop {Record<string, Language>} [languages]
|
||
* @prop {string[]} [fallbacks]
|
||
* @prop {string} [delimiter]
|
||
* @prop {string} [spacer]
|
||
* @prop {boolean} [round]
|
||
* @prop {number} [largest]
|
||
* @prop {UnitName[]} [units]
|
||
* @prop {string} [decimal]
|
||
* @prop {string} [conjunction]
|
||
* @prop {number} [maxDecimalPoints]
|
||
* @prop {UnitMeasures} [unitMeasures]
|
||
* @prop {boolean} [serialComma]
|
||
* @prop {DigitReplacements} [digitReplacements]
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
* @typedef {Required<Options>} NormalizedOptions
|
||
*/
|
||
|
||
(function () {
|
||
// Fallback for `Object.assign` if relevant.
|
||
var assign =
|
||
Object.assign ||
|
||
/** @param {...any} destination */
|
||
function (destination) {
|
||
var source;
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
source = arguments[i];
|
||
for (var prop in source) {
|
||
if (has(source, prop)) {
|
||
destination[prop] = source[prop];
|
||
}
|
||
}
|
||
}
|
||
return destination;
|
||
};
|
||
|
||
// Fallback for `Array.isArray` if relevant.
|
||
var isArray =
|
||
Array.isArray ||
|
||
function (arg) {
|
||
return Object.prototype.toString.call(arg) === "[object Array]";
|
||
};
|
||
|
||
// This has to be defined separately because of a bug: we want to alias
|
||
// `gr` and `el` for backwards-compatiblity. In a breaking change, we can
|
||
// remove `gr` entirely.
|
||
// See https://github.com/EvanHahn/HumanizeDuration.js/issues/143 for more.
|
||
var GREEK = language("έ", "μ", "ε", "η", "ώ", "λ", "δ", "χδ", ","); //
|
||
|
||
/**
|
||
* @internal
|
||
* @type {Record<string, Language>}
|
||
*/
|
||
var LANGUAGES = {
|
||
// Afrikaans (Afrikaans)
|
||
af: language("j", "mnd", "w", "d", "u", "m", "s", "ms", ","),
|
||
// አማርኛ (Amharic)
|
||
am: language("ዓ", "ወ", "ሳ", "ቀ", "ሰ", "ደ", "ሰከ", "ሳ", "ሚሊ"),
|
||
//العربية (Arabic) (RTL)
|
||
// https://github.com/EvanHahn/HumanizeDuration.js/issues/221#issuecomment-2119762498
|
||
// year -> ع stands for "عام" or س stands for "سنة"
|
||
// month -> ش stands for "شهر"
|
||
// week -> أ stands for "أسبوع"
|
||
// day -> ي stands for "يوم"
|
||
// hour -> س stands for "ساعة"
|
||
// minute -> د stands for "دقيقة"
|
||
// second -> ث stands for "ثانية"
|
||
ar: assign(language("س", "ش", "أ", "ي", "س", "د", "ث", "م ث", ","), {
|
||
_hideCountIf2: true,
|
||
_digitReplacements: ["۰", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"]
|
||
}),
|
||
// български (Bulgarian)
|
||
bg: language("г", "мес", "с", "д", "ч", "м", "сек", "мс", ","),
|
||
// বাংলা (Bengali)
|
||
bn: language("ব", "ম", "সপ্তা", "দ", "ঘ", "মি", "স", "মি.স"),
|
||
// català (Catalan)
|
||
ca: language("a", "mes", "set", "d", "h", "m", "s", "ms", ","),
|
||
//کوردیی ناوەڕاست (Central Kurdish) (RTL)
|
||
ckb: language("م چ", "چ", "خ", "ک", "ڕ", "ه", "م", "س", "."),
|
||
// čeština (Czech)
|
||
cs: language("r", "měs", "t", "d", "h", "m", "s", "ms", ","),
|
||
// Cymraeg (Welsh)
|
||
cy: language("b", "mis", "wth", "d", "awr", "mun", "eil", "ms"),
|
||
// dansk (Danish)
|
||
da: language("å", "md", "u", "d", "t", "m", "s", "ms", ","),
|
||
// Deutsch (German)
|
||
de: language("J", "mo", "w", "t", "std", "m", "s", "ms", ","),
|
||
// Ελληνικά (Greek)
|
||
el: GREEK,
|
||
// English (English)
|
||
en: language("y", "mo", "w", "d", "h", "m", "s", "ms"),
|
||
// Esperanto (Esperanto)
|
||
eo: language("j", "mo", "se", "t", "h", "m", "s", "ms", ","),
|
||
// español (Spanish)
|
||
es: language("a", "me", "se", "d", "h", "m", "s", "ms", ","),
|
||
// eesti keel (Estonian)
|
||
et: language("a", "k", "n", "p", "t", "m", "s", "ms", ","),
|
||
// euskara (Basque)
|
||
eu: language("u", "h", "a", "e", "o", "m", "s", "ms", ","),
|
||
//فارسی (Farsi/Persian) (RTL)
|
||
fa: language("س", "ما", "ه", "ر", "سا", "دقی", "ثانی", "میلیثانیه"),
|
||
// suomi (Finnish)
|
||
fi: language("v", "kk", "vk", "pv", "t", "m", "s", "ms", ","),
|
||
// føroyskt (Faroese)
|
||
fo: language("á", "má", "v", "d", "t", "m", "s", "ms", ","),
|
||
// français (French)
|
||
fr: language("a", "m", "sem", "j", "h", "m", "s", "ms", ","),
|
||
// Ελληνικά (Greek) (el)
|
||
gr: GREEK,
|
||
//עברית (Hebrew) (RTL)
|
||
he: language("ש׳", "ח׳", "שב׳", "י׳", "שע׳", "ד׳", "שנ׳", "מל׳"),
|
||
// hrvatski (Croatian)
|
||
hr: language("g", "mj", "t", "d", "h", "m", "s", "ms", ","),
|
||
// हिंदी (Hindi)
|
||
hi: language("व", "म", "स", "द", "घ", "मि", "से", "मि.से"),
|
||
// magyar (Hungarian)
|
||
hu: language("é", "h", "hét", "n", "ó", "p", "mp", "ms", ","),
|
||
// Indonesia (Indonesian)
|
||
id: language("t", "b", "mgg", "h", "j", "m", "d", "md"),
|
||
// íslenska (Icelandic)
|
||
is: language("ár", "mán", "v", "d", "k", "m", "s", "ms"),
|
||
// italiano (Italian)
|
||
it: language("a", "me", "se", "g", "h", "m", "s", "ms", ","),
|
||
// 日本語 (Japanese)
|
||
ja: language("年", "月", "週", "日", "時", "分", "秒", "ミリ秒"),
|
||
// ភាសាខ្មែរ (Khmer)
|
||
km: language("ឆ", "ខ", "សប្តា", "ថ", "ម", "ន", "វ", "មវ"),
|
||
// ಕನ್ನಡ (Kannada)
|
||
kn: language("ವ", "ತ", "ವ", "ದ", "ಗಂ", "ನಿ", "ಸೆ", "ಮಿಸೆ"),
|
||
// 한국어 (Korean)
|
||
ko: language("년", "달", "주", "일", "시간", "분", "초", "밀리초"),
|
||
// Kurdî (Kurdish)
|
||
ku: language("sal", "m", "h", "r", "s", "d", "ç", "ms", ","),
|
||
// ລາວ (Lao)
|
||
lo: language("ປ", "ເດ", "ອ", "ວ", "ຊ", "ນທ", "ວິນ", "ມິລິວິນາທີ", ","),
|
||
// lietuvių (Lithuanian)
|
||
lt: language("met", "mėn", "sav", "d", "v", "m", "s", "ms", ","),
|
||
// latviešu (Latvian)
|
||
lv: language("g", "mēn", "n", "d", "st", "m", "s", "ms", ","),
|
||
// македонски (Macedonian)
|
||
mk: language("г", "мес", "н", "д", "ч", "м", "с", "мс", ","),
|
||
// монгол (Mongolian)
|
||
mn: language("ж", "с", "дх", "ө", "ц", "м", "с", "мс"),
|
||
// मराठी (Marathi)
|
||
mr: language("व", "म", "आ", "दि", "त", "मि", "से", "मि.से"),
|
||
// Melayu (Malay)
|
||
ms: language("thn", "bln", "mgg", "hr", "j", "m", "s", "ms"),
|
||
// Nederlands (Dutch)
|
||
nl: language("j", "mnd", "w", "d", "u", "m", "s", "ms", ","),
|
||
// norsk (Norwegian)
|
||
no: language("år", "mnd", "u", "d", "t", "m", "s", "ms", ","),
|
||
// polski (Polish)
|
||
pl: language("r", "mi", "t", "d", "g", "m", "s", "ms", ","),
|
||
// português (Portuguese)
|
||
pt: language("a", "mês", "sem", "d", "h", "m", "s", "ms", ","),
|
||
// română (Romanian) săpt?
|
||
ro: language("a", "l", "să", "z", "h", "m", "s", "ms", ","),
|
||
// русский (Russian)
|
||
ru: language("г", "мес", "н", "д", "ч", "м", "с", "мс", ","),
|
||
// shqip (Albanian) orë? muaj?
|
||
sq: language("v", "mu", "j", "d", "o", "m", "s", "ms", ","),
|
||
// српски (Serbian)
|
||
sr: language("г", "мес", "н", "д", "ч", "м", "с", "мс", ","),
|
||
// தமிழ் (Tamil)
|
||
ta: language("ஆ", "மா", "வ", "நா", "ம", "நி", "வி", "மி.வி"),
|
||
// తెలుగు (Telugu)
|
||
te: language("సం", "నె", "వ", "రో", "గం", "ని", "సె", "మి.సె"), //
|
||
// українська (Ukrainian)
|
||
uk: language("р", "м", "т", "д", "г", "хв", "с", "мс", ","),
|
||
//اردو (Urdu) (RTL)
|
||
ur: language("س", "م", "ہ", "د", "گ", "م", "س", "م س"),
|
||
// slovenčina (Slovak)
|
||
sk: language("r", "mes", "t", "d", "h", "m", "s", "ms", ","),
|
||
// slovenščina (Slovenian)
|
||
sl: language("l", "mes", "t", "d", "ur", "m", "s", "ms", ","),
|
||
// svenska (Swedish)
|
||
sv: language("å", "mån", "v", "d", "h", "m", "s", "ms", ","),
|
||
// Kiswahili (Swahili)
|
||
sw: assign(language("mw", "m", "w", "s", "h", "dk", "s", "ms"), {
|
||
_numberFirst: true
|
||
}),
|
||
// Türkçe (Turkish)
|
||
tr: language("y", "a", "h", "g", "sa", "d", "s", "ms", ","),
|
||
// ไทย (Thai)
|
||
th: language("ปี", "ด", "ส", "ว", "ชม", "น", "วิ", "มิลลิวินาที"),
|
||
// o'zbek (Uzbek)
|
||
uz: language("y", "o", "h", "k", "soa", "m", "s", "ms"),
|
||
// Ўзбек (Кирилл) (Uzbek (Cyrillic))
|
||
uz_CYR: language("й", "о", "х", "к", "соа", "д", "с", "мс"),
|
||
// Tiếng Việt (Vietnamese)
|
||
vi: language("n", "th", "t", "ng", "gi", "p", "g", "ms", ","),
|
||
// 中文 (简体) (Chinese, simplified)
|
||
zh_CN: language("年", "月", "周", "天", "时", "分", "秒", "毫秒"),
|
||
// 中文 (繁體) (Chinese, traditional)
|
||
zh_TW: language("年", "月", "週", "天", "時", "分", "秒", "毫秒")
|
||
};
|
||
|
||
/**
|
||
* Helper function for creating language definitions.
|
||
*
|
||
* @internal
|
||
* @param {Unit} y
|
||
* @param {Unit} mo
|
||
* @param {Unit} w
|
||
* @param {Unit} d
|
||
* @param {Unit} h
|
||
* @param {Unit} m
|
||
* @param {Unit} s
|
||
* @param {Unit} ms
|
||
* @param {string} [decimal]
|
||
* @returns {Language}
|
||
*/
|
||
function language(y, mo, w, d, h, m, s, ms, decimal) {
|
||
/** @type {Language} */
|
||
var result = { y: y, mo: mo, w: w, d: d, h: h, m: m, s: s, ms: ms };
|
||
if (typeof decimal !== "undefined") {
|
||
result.decimal = decimal;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Helper function for Arabic.
|
||
*
|
||
* @internal
|
||
* @param {number} c
|
||
* @returns {0 | 1 | 2}
|
||
*/
|
||
// function getArabicForm(c) {
|
||
// if (c === 2) {
|
||
// return 1;
|
||
// }
|
||
// if (c > 2 && c < 11) {
|
||
// return 2;
|
||
// }
|
||
// return 0;
|
||
// }
|
||
|
||
/**
|
||
* Helper function for Polish.
|
||
*
|
||
* @internal
|
||
* @param {number} c
|
||
* @returns {0 | 1 | 2 | 3}
|
||
*/
|
||
// function getPolishForm(c) {
|
||
// if (c === 1) {
|
||
// return 0;
|
||
// }
|
||
// if (Math.floor(c) !== c) {
|
||
// return 1;
|
||
// }
|
||
// if (c % 10 >= 2 && c % 10 <= 4 && !(c % 100 > 10 && c % 100 < 20)) {
|
||
// return 2;
|
||
// }
|
||
// return 3;
|
||
// }
|
||
|
||
/**
|
||
* Helper function for Slavic languages.
|
||
*
|
||
* @internal
|
||
* @param {number} c
|
||
* @returns {0 | 1 | 2 | 3}
|
||
*/
|
||
// function getSlavicForm(c) {
|
||
// if (Math.floor(c) !== c) {
|
||
// return 2;
|
||
// }
|
||
// if (
|
||
// (c % 100 >= 5 && c % 100 <= 20) ||
|
||
// (c % 10 >= 5 && c % 10 <= 9) ||
|
||
// c % 10 === 0
|
||
// ) {
|
||
// return 0;
|
||
// }
|
||
// if (c % 10 === 1) {
|
||
// return 1;
|
||
// }
|
||
// if (c > 1) {
|
||
// return 2;
|
||
// }
|
||
// return 0;
|
||
// }
|
||
|
||
/**
|
||
* Helper function for Czech or Slovak.
|
||
*
|
||
* @internal
|
||
* @param {number} c
|
||
* @returns {0 | 1 | 2 | 3}
|
||
*/
|
||
// function getCzechOrSlovakForm(c) {
|
||
// if (c === 1) {
|
||
// return 0;
|
||
// }
|
||
// if (Math.floor(c) !== c) {
|
||
// return 1;
|
||
// }
|
||
// if (c % 10 >= 2 && c % 10 <= 4 && c % 100 < 10) {
|
||
// return 2;
|
||
// }
|
||
// return 3;
|
||
// }
|
||
|
||
/**
|
||
* Helper function for Lithuanian.
|
||
*
|
||
* @internal
|
||
* @param {number} c
|
||
* @returns {0 | 1 | 2}
|
||
*/
|
||
// function getLithuanianForm(c) {
|
||
// if (c === 1 || (c % 10 === 1 && c % 100 > 20)) {
|
||
// return 0;
|
||
// }
|
||
// if (
|
||
// Math.floor(c) !== c ||
|
||
// (c % 10 >= 2 && c % 100 > 20) ||
|
||
// (c % 10 >= 2 && c % 100 < 10)
|
||
// ) {
|
||
// return 1;
|
||
// }
|
||
// return 2;
|
||
// }
|
||
|
||
/**
|
||
* Helper function for Latvian.
|
||
*
|
||
* @internal
|
||
* @param {number} c
|
||
* @returns {boolean}
|
||
*/
|
||
// function getLatvianForm(c) {
|
||
// return c % 10 === 1 && c % 100 !== 11;
|
||
// }
|
||
|
||
/**
|
||
* @internal
|
||
* @template T
|
||
* @param {T} obj
|
||
* @param {keyof T} key
|
||
* @returns {boolean}
|
||
*/
|
||
function has(obj, key) {
|
||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
* @param {Pick<Required<Options>, "language" | "fallbacks" | "languages">} options
|
||
* @throws {Error} Throws an error if language is not found.
|
||
* @returns {Language}
|
||
*/
|
||
function getLanguage(options) {
|
||
var possibleLanguages = [options.language];
|
||
|
||
if (has(options, "fallbacks")) {
|
||
if (isArray(options.fallbacks) && options.fallbacks.length) {
|
||
possibleLanguages = possibleLanguages.concat(options.fallbacks);
|
||
} else {
|
||
throw new Error("fallbacks must be an array with at least one element");
|
||
}
|
||
}
|
||
|
||
for (var i = 0; i < possibleLanguages.length; i++) {
|
||
var languageToTry = possibleLanguages[i];
|
||
if (has(options.languages, languageToTry)) {
|
||
return options.languages[languageToTry];
|
||
}
|
||
if (has(LANGUAGES, languageToTry)) {
|
||
return LANGUAGES[languageToTry];
|
||
}
|
||
}
|
||
|
||
throw new Error("No language found.");
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
* @param {Piece} piece
|
||
* @param {Language} language
|
||
* @param {Pick<Required<Options>, "decimal" | "spacer" | "maxDecimalPoints" | "digitReplacements">} options
|
||
*/
|
||
function renderPiece(piece, language, options) {
|
||
var unitName = piece.unitName;
|
||
var unitCount = piece.unitCount;
|
||
|
||
var spacer = options.spacer;
|
||
var maxDecimalPoints = options.maxDecimalPoints;
|
||
|
||
/** @type {string} */
|
||
var decimal;
|
||
if (has(options, "decimal")) {
|
||
decimal = options.decimal;
|
||
} else if (has(language, "decimal")) {
|
||
decimal = language.decimal;
|
||
} else {
|
||
decimal = ".";
|
||
}
|
||
|
||
/** @type {undefined | DigitReplacements} */
|
||
var digitReplacements;
|
||
if ("digitReplacements" in options) {
|
||
digitReplacements = options.digitReplacements;
|
||
} else if ("_digitReplacements" in language) {
|
||
digitReplacements = language._digitReplacements;
|
||
}
|
||
|
||
/** @type {string} */
|
||
var formattedCount;
|
||
var normalizedUnitCount =
|
||
maxDecimalPoints === void 0
|
||
? unitCount
|
||
: Math.floor(unitCount * Math.pow(10, maxDecimalPoints)) /
|
||
Math.pow(10, maxDecimalPoints);
|
||
var countStr = normalizedUnitCount.toString();
|
||
|
||
if (language._hideCountIf2 && unitCount === 2) {
|
||
formattedCount = "";
|
||
spacer = "";
|
||
} else {
|
||
if (digitReplacements) {
|
||
formattedCount = "";
|
||
for (var i = 0; i < countStr.length; i++) {
|
||
var char = countStr[i];
|
||
if (char === ".") {
|
||
formattedCount += decimal;
|
||
} else {
|
||
// @ts-ignore because `char` should always be 0-9 at this point.
|
||
formattedCount += digitReplacements[char];
|
||
}
|
||
}
|
||
} else {
|
||
formattedCount = countStr.replace(".", decimal);
|
||
}
|
||
}
|
||
|
||
var languageWord = language[unitName];
|
||
var word;
|
||
if (typeof languageWord === "function") {
|
||
word = languageWord(unitCount);
|
||
} else {
|
||
word = languageWord;
|
||
}
|
||
|
||
if (language._numberFirst) {
|
||
return word + spacer + formattedCount;
|
||
}
|
||
return formattedCount + spacer + word;
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
* @typedef {Object} Piece
|
||
* @prop {UnitName} unitName
|
||
* @prop {number} unitCount
|
||
*/
|
||
|
||
/**
|
||
* @internal
|
||
* @param {number} ms
|
||
* @param {Pick<Required<Options>, "units" | "unitMeasures" | "largest" | "round">} options
|
||
* @returns {Piece[]}
|
||
*/
|
||
function getPieces(ms, options) {
|
||
/** @type {UnitName} */
|
||
var unitName;
|
||
|
||
/** @type {number} */
|
||
var i;
|
||
|
||
/** @type {number} */
|
||
var unitCount;
|
||
|
||
/** @type {number} */
|
||
var msRemaining;
|
||
|
||
var units = options.units;
|
||
var unitMeasures = options.unitMeasures;
|
||
var largest = "largest" in options ? options.largest : Infinity;
|
||
|
||
if (!units.length) return [];
|
||
|
||
// Get the counts for each unit. Doesn't round or truncate anything.
|
||
// For example, might create an object like `{ y: 7, m: 6, w: 0, d: 5, h: 23.99 }`.
|
||
/** @type {Partial<Record<UnitName, number>>} */
|
||
var unitCounts = {};
|
||
msRemaining = ms;
|
||
for (i = 0; i < units.length; i++) {
|
||
unitName = units[i];
|
||
var unitMs = unitMeasures[unitName];
|
||
|
||
var isLast = i === units.length - 1;
|
||
unitCount = isLast
|
||
? msRemaining / unitMs
|
||
: Math.floor(msRemaining / unitMs);
|
||
unitCounts[unitName] = unitCount;
|
||
|
||
msRemaining -= unitCount * unitMs;
|
||
}
|
||
|
||
if (options.round) {
|
||
// Update counts based on the `largest` option.
|
||
// For example, if `largest === 2` and `unitCount` is `{ y: 7, m: 6, w: 0, d: 5, h: 23.99 }`,
|
||
// updates to something like `{ y: 7, m: 6.2 }`.
|
||
var unitsRemainingBeforeRound = largest;
|
||
for (i = 0; i < units.length; i++) {
|
||
unitName = units[i];
|
||
unitCount = unitCounts[unitName];
|
||
|
||
if (unitCount === 0) continue;
|
||
|
||
unitsRemainingBeforeRound--;
|
||
|
||
// "Take" the rest of the units into this one.
|
||
if (unitsRemainingBeforeRound === 0) {
|
||
for (var j = i + 1; j < units.length; j++) {
|
||
var smallerUnitName = units[j];
|
||
var smallerUnitCount = unitCounts[smallerUnitName];
|
||
unitCounts[unitName] +=
|
||
(smallerUnitCount * unitMeasures[smallerUnitName]) /
|
||
unitMeasures[unitName];
|
||
unitCounts[smallerUnitName] = 0;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Round the last piece (which should be the only non-integer).
|
||
//
|
||
// This can be a little tricky if the last piece "bubbles up" to a larger
|
||
// unit. For example, "3 days, 23.99 hours" should be rounded to "4 days".
|
||
// It can also require multiple passes. For example, "6 days, 23.99 hours"
|
||
// should become "1 week".
|
||
for (i = units.length - 1; i >= 0; i--) {
|
||
unitName = units[i];
|
||
unitCount = unitCounts[unitName];
|
||
|
||
if (unitCount === 0) continue;
|
||
|
||
var rounded = Math.round(unitCount);
|
||
unitCounts[unitName] = rounded;
|
||
|
||
if (i === 0) break;
|
||
|
||
var previousUnitName = units[i - 1];
|
||
var previousUnitMs = unitMeasures[previousUnitName];
|
||
var amountOfPreviousUnit = Math.floor(
|
||
(rounded * unitMeasures[unitName]) / previousUnitMs
|
||
);
|
||
if (amountOfPreviousUnit) {
|
||
unitCounts[previousUnitName] += amountOfPreviousUnit;
|
||
unitCounts[unitName] = 0;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/** @type {Piece[]} */
|
||
var result = [];
|
||
for (i = 0; i < units.length && result.length < largest; i++) {
|
||
unitName = units[i];
|
||
unitCount = unitCounts[unitName];
|
||
if (unitCount) {
|
||
result.push({ unitName: unitName, unitCount: unitCount });
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @internal
|
||
* @param {Piece[]} pieces
|
||
* @param {Pick<Required<Options>, "units" | "language" | "languages" | "fallbacks" | "delimiter" | "spacer" | "decimal" | "conjunction" | "maxDecimalPoints" | "serialComma" | "digitReplacements">} options
|
||
* @returns {string}
|
||
*/
|
||
function formatPieces(pieces, options) {
|
||
var language = getLanguage(options);
|
||
|
||
if (!pieces.length) {
|
||
var units = options.units;
|
||
var smallestUnitName = units[units.length - 1];
|
||
return renderPiece(
|
||
{ unitName: smallestUnitName, unitCount: 0 },
|
||
language,
|
||
options
|
||
);
|
||
}
|
||
|
||
var conjunction = options.conjunction;
|
||
var serialComma = options.serialComma;
|
||
|
||
var delimiter;
|
||
if (has(options, "delimiter")) {
|
||
delimiter = options.delimiter;
|
||
} else if (has(language, "delimiter")) {
|
||
delimiter = language.delimiter;
|
||
} else {
|
||
delimiter = " ";
|
||
}
|
||
|
||
/** @type {string[]} */
|
||
var renderedPieces = [];
|
||
for (var i = 0; i < pieces.length; i++) {
|
||
renderedPieces.push(renderPiece(pieces[i], language, options));
|
||
}
|
||
|
||
if (!conjunction || pieces.length === 1) {
|
||
return renderedPieces.join(delimiter);
|
||
}
|
||
|
||
if (pieces.length === 2) {
|
||
return renderedPieces.join(conjunction);
|
||
}
|
||
|
||
return (
|
||
renderedPieces.slice(0, -1).join(delimiter) +
|
||
(serialComma ? "," : "") +
|
||
conjunction +
|
||
renderedPieces.slice(-1)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Create a humanizer, which lets you change the default options.
|
||
*
|
||
* @param {Options} [passedOptions]
|
||
*/
|
||
function humanizer(passedOptions) {
|
||
/**
|
||
* @param {number} ms
|
||
* @param {Options} [humanizerOptions]
|
||
* @returns {string}
|
||
*/
|
||
var result = function humanizer(ms, humanizerOptions) {
|
||
// Make sure we have a positive number.
|
||
//
|
||
// Has the nice side-effect of converting things to numbers. For example,
|
||
// converts `"123"` and `Number(123)` to `123`.
|
||
ms = Math.abs(ms);
|
||
|
||
var options = assign({}, result, humanizerOptions || {});
|
||
|
||
var pieces = getPieces(ms, options);
|
||
|
||
return formatPieces(pieces, options);
|
||
};
|
||
|
||
return assign(
|
||
result,
|
||
{
|
||
language: "en",
|
||
spacer: "",
|
||
conjunction: "",
|
||
serialComma: true,
|
||
units: ["y", "mo", "w", "d", "h", "m", "s"],
|
||
languages: {},
|
||
round: false,
|
||
unitMeasures: {
|
||
y: 31557600000,
|
||
mo: 2629800000,
|
||
w: 604800000,
|
||
d: 86400000,
|
||
h: 3600000,
|
||
m: 60000,
|
||
s: 1000,
|
||
ms: 1
|
||
}
|
||
},
|
||
passedOptions
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Humanize a duration.
|
||
*
|
||
* This is a wrapper around the default humanizer.
|
||
*/
|
||
var humanizeDuration = assign(humanizer({}), {
|
||
getSupportedLanguages: function getSupportedLanguages() {
|
||
var result = [];
|
||
for (var language in LANGUAGES) {
|
||
if (has(LANGUAGES, language) && language !== "gr") {
|
||
result.push(language);
|
||
}
|
||
}
|
||
return result;
|
||
},
|
||
humanizer: humanizer
|
||
});
|
||
|
||
// @ts-ignore
|
||
if (typeof define === "function" && define.amd) {
|
||
// @ts-ignore
|
||
define(function () {
|
||
return humanizeDuration;
|
||
});
|
||
} else if (typeof module !== "undefined" && module.exports) {
|
||
module.exports = humanizeDuration;
|
||
} else {
|
||
this.humanizeDuration = humanizeDuration;
|
||
}
|
||
})();
|