Comparing version 4.0.0-alpha.9 to 4.0.0-alpha.10
@@ -10,2 +10,5 @@ export { camelCaseKeys } from "./camelCaseKeys"; | ||
export { lookup } from "./lookup"; | ||
export { numberToDelimited } from "./numberToDelimited"; | ||
export { numberToHuman } from "./numberToHuman"; | ||
export { numberToHumanSize } from "./numberToHumanSize"; | ||
export { parseDate } from "./parseDate"; | ||
@@ -16,2 +19,3 @@ export { pluralize } from "./pluralize"; | ||
export { strftime } from "./strftime"; | ||
export { timeAgoInWords } from "./timeAgoInWords"; | ||
//# sourceMappingURL=index.js.map |
@@ -10,9 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
import BigNumber from "bignumber.js"; | ||
import { get, has, set, range, zipObject, sortBy } from "lodash"; | ||
import { get, has, set } from "lodash"; | ||
import { Locales } from "./Locales"; | ||
import { Pluralization } from "./Pluralization"; | ||
import { MissingTranslation } from "./MissingTranslation"; | ||
import { camelCaseKeys, createTranslationOptions, expandRoundMode, formatNumber, inferType, interpolate, isSet, lookup, parseDate, pluralize, propertyFlatList, roundNumber, strftime, } from "./helpers"; | ||
const within = (start, end, actual) => actual >= start && actual <= end; | ||
import { camelCaseKeys, createTranslationOptions, formatNumber, inferType, interpolate, isSet, lookup, numberToDelimited, numberToHuman, numberToHumanSize, parseDate, pluralize, propertyFlatList, strftime, timeAgoInWords, } from "./helpers"; | ||
const DEFAULT_I18N_OPTIONS = { | ||
@@ -31,26 +29,2 @@ defaultLocale: "en", | ||
}; | ||
const STORAGE_UNITS = ["byte", "kb", "mb", "gb", "tb", "pb", "eb"]; | ||
const WORD_CONNECTORS = { | ||
wordsConnector: ", ", | ||
twoWordsConnector: " and ", | ||
lastWordConnector: ", and ", | ||
}; | ||
const DECIMAL_UNITS = { | ||
"0": "unit", | ||
"1": "ten", | ||
"2": "hundred", | ||
"3": "thousand", | ||
"6": "million", | ||
"9": "billion", | ||
"12": "trillion", | ||
"15": "quadrillion", | ||
"-1": "deci", | ||
"-2": "centi", | ||
"-3": "mili", | ||
"-6": "micro", | ||
"-9": "nano", | ||
"-12": "pico", | ||
"-15": "femto", | ||
}; | ||
const INVERTED_DECIMAL_UNITS = zipObject(Object.values(DECIMAL_UNITS), Object.keys(DECIMAL_UNITS).map((key) => parseInt(key, 10))); | ||
export class I18n { | ||
@@ -115,7 +89,2 @@ constructor(translations = {}, options) { | ||
} | ||
numberToCurrency(amount, options = {}) { | ||
options = Object.assign(Object.assign(Object.assign({ unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "." }, this.get("number.format")), this.get("number.currency.format")), options); | ||
options.negativeFormat = options.negativeFormat || `-${options.format}`; | ||
return formatNumber(amount, options); | ||
} | ||
translate(scope, options) { | ||
@@ -185,137 +154,27 @@ options = Object.assign({}, options); | ||
} | ||
numberToCurrency(input, options = {}) { | ||
return formatNumber(input, Object.assign(Object.assign(Object.assign({ unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "." }, this.get("number.format")), this.get("number.currency.format")), options)); | ||
} | ||
numberToPercentage(input, options = {}) { | ||
options = Object.assign(Object.assign({ unit: "%", precision: 3, separator: ".", delimiter: "", format: "%n%" }, camelCaseKeys(lookup(this, "number.percentage.format"))), options); | ||
return formatNumber(input, options); | ||
return formatNumber(input, Object.assign(Object.assign({ unit: "%", precision: 3, separator: ".", delimiter: "", format: "%n%" }, camelCaseKeys(lookup(this, "number.percentage.format"))), options)); | ||
} | ||
numberToHumanSize(numeric, options = {}) { | ||
var _a, _b, _c, _d; | ||
options = Object.assign(Object.assign({ roundMode: "default", delimiter: "", precision: 3, significant: true, stripInsignificantZeros: true }, camelCaseKeys(this.get("number.human.format"))), options); | ||
const roundMode = expandRoundMode(options.roundMode || "default"); | ||
const base = 1024; | ||
const num = new BigNumber(numeric).abs(); | ||
const smallerThanBase = num.lt(base); | ||
let numberToBeFormatted; | ||
const stripInsignificantZeros = (_a = options.stripInsignificantZeros) !== null && _a !== void 0 ? _a : true; | ||
const units = STORAGE_UNITS; | ||
const computeExponent = (numeric, units) => { | ||
const max = units.length - 1; | ||
const exp = new BigNumber(Math.log(numeric.toNumber())) | ||
.div(Math.log(base)) | ||
.integerValue(BigNumber.ROUND_DOWN) | ||
.toNumber(); | ||
return Math.min(max, exp); | ||
}; | ||
const storageUnitKey = () => { | ||
const keyEnd = smallerThanBase ? "byte" : units[exponent]; | ||
return `number.human.storage_units.units.${keyEnd}`; | ||
}; | ||
const exponent = computeExponent(num, units); | ||
if (smallerThanBase) { | ||
numberToBeFormatted = num.integerValue(); | ||
} | ||
else { | ||
numberToBeFormatted = new BigNumber(roundNumber(num.div(Math.pow(base, exponent)), { | ||
significant: (_b = options.significant) !== null && _b !== void 0 ? _b : true, | ||
precision: (_c = options.precision) !== null && _c !== void 0 ? _c : 3, | ||
roundMode: (_d = options.roundMode) !== null && _d !== void 0 ? _d : "default", | ||
})); | ||
} | ||
let precision; | ||
if (inferType(options.precision) === "number") { | ||
precision = options.precision; | ||
} | ||
else { | ||
const significand = numberToBeFormatted.minus(numberToBeFormatted.integerValue()); | ||
if (significand.gte(0.06)) { | ||
precision = 2; | ||
} | ||
else if (significand.gt(0)) { | ||
precision = 1; | ||
} | ||
else { | ||
precision = 0; | ||
} | ||
} | ||
const format = this.translate("number.human.storage_units.format", { | ||
defaultValue: "%n %u", | ||
}); | ||
const unit = this.translate(storageUnitKey(), { | ||
count: num.integerValue().toNumber(), | ||
}); | ||
let formattedNumber = numberToBeFormatted.toFixed(precision, roundMode); | ||
if (stripInsignificantZeros) { | ||
formattedNumber = formattedNumber | ||
.replace(/(\..*?)0+$/, "$1") | ||
.replace(/\.$/, ""); | ||
} | ||
return format.replace("%n", formattedNumber).replace("%u", unit); | ||
numberToHumanSize(input, options = {}) { | ||
return numberToHumanSize(this, input, Object.assign(Object.assign({ roundMode: "default", delimiter: "", precision: 3, significant: true, stripInsignificantZeros: true, units: { | ||
billion: "Billion", | ||
million: "Million", | ||
quadrillion: "Quadrillion", | ||
thousand: "Thousand", | ||
trillion: "Trillion", | ||
unit: "", | ||
} }, camelCaseKeys(this.get("number.human.format"))), options)); | ||
} | ||
numberToHuman(input, options = {}) { | ||
var _a, _b, _c, _d, _e, _f; | ||
options = Object.assign(Object.assign({ delimiter: "", precision: 3, significant: true, stripInsignificantZeros: true, format: "%n %u", units: (_a = this.get("number.human.decimal_units")) === null || _a === void 0 ? void 0 : _a.units }, camelCaseKeys(this.get("number.human.format"))), options); | ||
const roundMode = (_b = options.roundMode) !== null && _b !== void 0 ? _b : "default"; | ||
const precision = (_c = options.precision) !== null && _c !== void 0 ? _c : 3; | ||
const significant = (_d = options.significant) !== null && _d !== void 0 ? _d : true; | ||
const format = (_e = options.format) !== null && _e !== void 0 ? _e : "%n %u"; | ||
const separator = (_f = options.separator) !== null && _f !== void 0 ? _f : "."; | ||
let units; | ||
if (inferType(options.units) === "string") { | ||
units = this.get(options.units); | ||
} | ||
else { | ||
units = options.units; | ||
} | ||
let formattedNumber = roundNumber(new BigNumber(input), { | ||
roundMode, | ||
precision, | ||
significant, | ||
}); | ||
const unitExponents = (units) => sortBy(Object.keys(units).map((name) => INVERTED_DECIMAL_UNITS[name]), (numeric) => numeric * -1); | ||
const calculateExponent = (num, units) => { | ||
const exponent = num.isZero() | ||
? 0 | ||
: Math.floor(Math.log10(num.abs().toNumber())); | ||
return unitExponents(units).find((exp) => exponent >= exp) || 0; | ||
}; | ||
const determineUnit = (units, exponent) => { | ||
const expName = DECIMAL_UNITS[exponent.toString()]; | ||
return units[expName] || ""; | ||
}; | ||
const exponent = calculateExponent(new BigNumber(formattedNumber), units); | ||
const unit = determineUnit(units, exponent); | ||
formattedNumber = roundNumber(new BigNumber(formattedNumber).div(Math.pow(10, exponent)), { | ||
roundMode, | ||
precision, | ||
significant, | ||
}); | ||
if (options.stripInsignificantZeros) { | ||
let [whole, significand] = formattedNumber.split("."); | ||
significand = (significand || "").replace(/0+$/, ""); | ||
formattedNumber = whole; | ||
if (significand) { | ||
formattedNumber += `${separator}${significand}`; | ||
} | ||
} | ||
return format | ||
.replace("%n", formattedNumber || "0") | ||
.replace("%u", unit) | ||
.trim(); | ||
var _a; | ||
return numberToHuman(this, input, Object.assign(Object.assign({ delimiter: "", separator: ".", precision: 3, significant: true, stripInsignificantZeros: true, format: "%n %u", roundMode: "default", units: (_a = this.get("number.human.decimal_units")) === null || _a === void 0 ? void 0 : _a.units }, camelCaseKeys(this.get("number.human.format"))), options)); | ||
} | ||
numberToRounded(input, options) { | ||
options = Object.assign({ unit: "", precision: 3, significant: false, separator: ".", delimiter: "", stripInsignificantZeros: false }, options); | ||
return formatNumber(input, options); | ||
return formatNumber(input, Object.assign({ unit: "", precision: 3, significant: false, separator: ".", delimiter: "", stripInsignificantZeros: false }, options)); | ||
} | ||
numberToDelimited(input, options = {}) { | ||
options = Object.assign({ delimiterPattern: /(\d)(?=(\d\d\d)+(?!\d))/g, delimiter: ",", separator: "." }, options); | ||
const numeric = new BigNumber(input); | ||
if (!numeric.isFinite()) { | ||
return input.toString(); | ||
} | ||
const newOptions = options; | ||
if (!newOptions.delimiterPattern.global) { | ||
throw new Error(`options.delimiterPattern must be a global regular expression; received ${newOptions.delimiterPattern}`); | ||
} | ||
let [left, right] = numeric.toString().split("."); | ||
left = left.replace(newOptions.delimiterPattern, (digitToDelimiter) => `${digitToDelimiter}${newOptions.delimiter}`); | ||
return [left, right].filter(Boolean).join(newOptions.separator); | ||
return numberToDelimited(this, input, Object.assign({ delimiterPattern: /(\d)(?=(\d\d\d)+(?!\d))/g, delimiter: ",", separator: "." }, options)); | ||
} | ||
@@ -361,4 +220,4 @@ withLocale(locale, callback) { | ||
} | ||
toSentence(items, options) { | ||
options = Object.assign(Object.assign(Object.assign({}, WORD_CONNECTORS), camelCaseKeys(lookup(this, "support.array"))), options); | ||
toSentence(items, options = {}) { | ||
const { wordsConnector, twoWordsConnector, lastWordConnector } = Object.assign(Object.assign({ wordsConnector: ", ", twoWordsConnector: " and ", lastWordConnector: ", and " }, camelCaseKeys(lookup(this, "support.array"))), options); | ||
const size = items.length; | ||
@@ -371,7 +230,7 @@ switch (size) { | ||
case 2: | ||
return items.join(options.twoWordsConnector); | ||
return items.join(twoWordsConnector); | ||
default: | ||
return [ | ||
items.slice(0, size - 1).join(options.wordsConnector), | ||
options.lastWordConnector, | ||
items.slice(0, size - 1).join(wordsConnector), | ||
lastWordConnector, | ||
items[size - 1], | ||
@@ -382,90 +241,3 @@ ].join(""); | ||
timeAgoInWords(fromTime, toTime, options = {}) { | ||
const scope = options.scope || "datetime.distance_in_words"; | ||
const t = (name, count = 0) => this.t(name, { count, scope }); | ||
fromTime = parseDate(fromTime); | ||
toTime = parseDate(toTime); | ||
let fromInSeconds = fromTime.getTime() / 1000; | ||
let toInSeconds = toTime.getTime() / 1000; | ||
if (fromInSeconds > toInSeconds) { | ||
[fromTime, toTime, fromInSeconds, toInSeconds] = [ | ||
toTime, | ||
fromTime, | ||
toInSeconds, | ||
fromInSeconds, | ||
]; | ||
} | ||
const distanceInSeconds = Math.round(toInSeconds - fromInSeconds); | ||
const distanceInMinutes = Math.round((toInSeconds - fromInSeconds) / 60); | ||
const distanceInHours = distanceInMinutes / 60; | ||
const distanceInDays = distanceInHours / 24; | ||
const distanceInHoursRounded = Math.round(distanceInMinutes / 60); | ||
const distanceInDaysRounded = Math.round(distanceInDays); | ||
const distanceInMonthsRounded = Math.round(distanceInDaysRounded / 30); | ||
if (within(0, 1, distanceInMinutes)) { | ||
if (!options.includeSeconds) { | ||
return distanceInMinutes === 0 | ||
? t("less_than_x_minutes", 1) | ||
: t("x_minutes", distanceInMinutes); | ||
} | ||
if (within(0, 4, distanceInSeconds)) { | ||
return t("less_than_x_seconds", 5); | ||
} | ||
if (within(5, 9, distanceInSeconds)) { | ||
return t("less_than_x_seconds", 10); | ||
} | ||
if (within(10, 19, distanceInSeconds)) { | ||
return t("less_than_x_seconds", 20); | ||
} | ||
if (within(20, 39, distanceInSeconds)) { | ||
return t("half_a_minute"); | ||
} | ||
if (within(40, 59, distanceInSeconds)) { | ||
return t("less_than_x_minutes", 1); | ||
} | ||
return t("x_minutes", 1); | ||
} | ||
if (within(2, 44, distanceInMinutes)) { | ||
return t("x_minutes", distanceInMinutes); | ||
} | ||
if (within(45, 89, distanceInMinutes)) { | ||
return t("about_x_hours", 1); | ||
} | ||
if (within(90, 1439, distanceInMinutes)) { | ||
return t("about_x_hours", distanceInHoursRounded); | ||
} | ||
if (within(1440, 2519, distanceInMinutes)) { | ||
return t("x_days", 1); | ||
} | ||
if (within(2520, 43199, distanceInMinutes)) { | ||
return t("x_days", distanceInDaysRounded); | ||
} | ||
if (within(43200, 86399, distanceInMinutes)) { | ||
return t("about_x_months", Math.round(distanceInMinutes / 43200)); | ||
} | ||
if (within(86400, 525599, distanceInMinutes)) { | ||
return t("x_months", distanceInMonthsRounded); | ||
} | ||
let fromYear = fromTime.getFullYear(); | ||
if (fromTime.getMonth() + 1 >= 3) { | ||
fromYear += 1; | ||
} | ||
let toYear = toTime.getFullYear(); | ||
if (toTime.getMonth() + 1 < 3) { | ||
toYear -= 1; | ||
} | ||
const leapYears = fromYear > toYear | ||
? 0 | ||
: range(fromYear, toYear).filter((year) => new Date(year, 1, 29).getMonth() == 1).length; | ||
const minutesInYear = 525600; | ||
const minuteOffsetForLeapYear = leapYears * 1440; | ||
const minutesWithOffset = distanceInMinutes - minuteOffsetForLeapYear; | ||
const distanceInYears = Math.trunc(minutesWithOffset / minutesInYear); | ||
const diff = parseFloat((minutesWithOffset / minutesInYear - distanceInYears).toPrecision(3)); | ||
if (diff < 0.25) { | ||
return t("about_x_years", distanceInYears); | ||
} | ||
if (diff < 0.75) { | ||
return t("over_x_years", distanceInYears); | ||
} | ||
return t("almost_x_years", distanceInYears + 1); | ||
return timeAgoInWords(this, fromTime, toTime, options); | ||
} | ||
@@ -472,0 +244,0 @@ onChange(callback) { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.strftime = exports.roundNumber = exports.propertyFlatList = exports.pluralize = exports.parseDate = exports.lookup = exports.isSet = exports.interpolate = exports.inferType = exports.getFullScope = exports.formatNumber = exports.expandRoundMode = exports.createTranslationOptions = exports.camelCaseKeys = void 0; | ||
exports.timeAgoInWords = exports.strftime = exports.roundNumber = exports.propertyFlatList = exports.pluralize = exports.parseDate = exports.numberToHumanSize = exports.numberToHuman = exports.numberToDelimited = exports.lookup = exports.isSet = exports.interpolate = exports.inferType = exports.getFullScope = exports.formatNumber = exports.expandRoundMode = exports.createTranslationOptions = exports.camelCaseKeys = void 0; | ||
var camelCaseKeys_1 = require("./camelCaseKeys"); | ||
@@ -22,2 +22,8 @@ Object.defineProperty(exports, "camelCaseKeys", { enumerable: true, get: function () { return camelCaseKeys_1.camelCaseKeys; } }); | ||
Object.defineProperty(exports, "lookup", { enumerable: true, get: function () { return lookup_1.lookup; } }); | ||
var numberToDelimited_1 = require("./numberToDelimited"); | ||
Object.defineProperty(exports, "numberToDelimited", { enumerable: true, get: function () { return numberToDelimited_1.numberToDelimited; } }); | ||
var numberToHuman_1 = require("./numberToHuman"); | ||
Object.defineProperty(exports, "numberToHuman", { enumerable: true, get: function () { return numberToHuman_1.numberToHuman; } }); | ||
var numberToHumanSize_1 = require("./numberToHumanSize"); | ||
Object.defineProperty(exports, "numberToHumanSize", { enumerable: true, get: function () { return numberToHumanSize_1.numberToHumanSize; } }); | ||
var parseDate_1 = require("./parseDate"); | ||
@@ -33,2 +39,4 @@ Object.defineProperty(exports, "parseDate", { enumerable: true, get: function () { return parseDate_1.parseDate; } }); | ||
Object.defineProperty(exports, "strftime", { enumerable: true, get: function () { return strftime_1.strftime; } }); | ||
var timeAgoInWords_1 = require("./timeAgoInWords"); | ||
Object.defineProperty(exports, "timeAgoInWords", { enumerable: true, get: function () { return timeAgoInWords_1.timeAgoInWords; } }); | ||
//# sourceMappingURL=index.js.map |
@@ -11,8 +11,4 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.I18n = void 0; | ||
const bignumber_js_1 = __importDefault(require("bignumber.js")); | ||
const lodash_1 = require("lodash"); | ||
@@ -23,3 +19,2 @@ const Locales_1 = require("./Locales"); | ||
const helpers_1 = require("./helpers"); | ||
const within = (start, end, actual) => actual >= start && actual <= end; | ||
const DEFAULT_I18N_OPTIONS = { | ||
@@ -38,26 +33,2 @@ defaultLocale: "en", | ||
}; | ||
const STORAGE_UNITS = ["byte", "kb", "mb", "gb", "tb", "pb", "eb"]; | ||
const WORD_CONNECTORS = { | ||
wordsConnector: ", ", | ||
twoWordsConnector: " and ", | ||
lastWordConnector: ", and ", | ||
}; | ||
const DECIMAL_UNITS = { | ||
"0": "unit", | ||
"1": "ten", | ||
"2": "hundred", | ||
"3": "thousand", | ||
"6": "million", | ||
"9": "billion", | ||
"12": "trillion", | ||
"15": "quadrillion", | ||
"-1": "deci", | ||
"-2": "centi", | ||
"-3": "mili", | ||
"-6": "micro", | ||
"-9": "nano", | ||
"-12": "pico", | ||
"-15": "femto", | ||
}; | ||
const INVERTED_DECIMAL_UNITS = lodash_1.zipObject(Object.values(DECIMAL_UNITS), Object.keys(DECIMAL_UNITS).map((key) => parseInt(key, 10))); | ||
class I18n { | ||
@@ -122,7 +93,2 @@ constructor(translations = {}, options) { | ||
} | ||
numberToCurrency(amount, options = {}) { | ||
options = Object.assign(Object.assign(Object.assign({ unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "." }, this.get("number.format")), this.get("number.currency.format")), options); | ||
options.negativeFormat = options.negativeFormat || `-${options.format}`; | ||
return helpers_1.formatNumber(amount, options); | ||
} | ||
translate(scope, options) { | ||
@@ -192,137 +158,27 @@ options = Object.assign({}, options); | ||
} | ||
numberToCurrency(input, options = {}) { | ||
return helpers_1.formatNumber(input, Object.assign(Object.assign(Object.assign({ unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "." }, this.get("number.format")), this.get("number.currency.format")), options)); | ||
} | ||
numberToPercentage(input, options = {}) { | ||
options = Object.assign(Object.assign({ unit: "%", precision: 3, separator: ".", delimiter: "", format: "%n%" }, helpers_1.camelCaseKeys(helpers_1.lookup(this, "number.percentage.format"))), options); | ||
return helpers_1.formatNumber(input, options); | ||
return helpers_1.formatNumber(input, Object.assign(Object.assign({ unit: "%", precision: 3, separator: ".", delimiter: "", format: "%n%" }, helpers_1.camelCaseKeys(helpers_1.lookup(this, "number.percentage.format"))), options)); | ||
} | ||
numberToHumanSize(numeric, options = {}) { | ||
var _a, _b, _c, _d; | ||
options = Object.assign(Object.assign({ roundMode: "default", delimiter: "", precision: 3, significant: true, stripInsignificantZeros: true }, helpers_1.camelCaseKeys(this.get("number.human.format"))), options); | ||
const roundMode = helpers_1.expandRoundMode(options.roundMode || "default"); | ||
const base = 1024; | ||
const num = new bignumber_js_1.default(numeric).abs(); | ||
const smallerThanBase = num.lt(base); | ||
let numberToBeFormatted; | ||
const stripInsignificantZeros = (_a = options.stripInsignificantZeros) !== null && _a !== void 0 ? _a : true; | ||
const units = STORAGE_UNITS; | ||
const computeExponent = (numeric, units) => { | ||
const max = units.length - 1; | ||
const exp = new bignumber_js_1.default(Math.log(numeric.toNumber())) | ||
.div(Math.log(base)) | ||
.integerValue(bignumber_js_1.default.ROUND_DOWN) | ||
.toNumber(); | ||
return Math.min(max, exp); | ||
}; | ||
const storageUnitKey = () => { | ||
const keyEnd = smallerThanBase ? "byte" : units[exponent]; | ||
return `number.human.storage_units.units.${keyEnd}`; | ||
}; | ||
const exponent = computeExponent(num, units); | ||
if (smallerThanBase) { | ||
numberToBeFormatted = num.integerValue(); | ||
} | ||
else { | ||
numberToBeFormatted = new bignumber_js_1.default(helpers_1.roundNumber(num.div(Math.pow(base, exponent)), { | ||
significant: (_b = options.significant) !== null && _b !== void 0 ? _b : true, | ||
precision: (_c = options.precision) !== null && _c !== void 0 ? _c : 3, | ||
roundMode: (_d = options.roundMode) !== null && _d !== void 0 ? _d : "default", | ||
})); | ||
} | ||
let precision; | ||
if (helpers_1.inferType(options.precision) === "number") { | ||
precision = options.precision; | ||
} | ||
else { | ||
const significand = numberToBeFormatted.minus(numberToBeFormatted.integerValue()); | ||
if (significand.gte(0.06)) { | ||
precision = 2; | ||
} | ||
else if (significand.gt(0)) { | ||
precision = 1; | ||
} | ||
else { | ||
precision = 0; | ||
} | ||
} | ||
const format = this.translate("number.human.storage_units.format", { | ||
defaultValue: "%n %u", | ||
}); | ||
const unit = this.translate(storageUnitKey(), { | ||
count: num.integerValue().toNumber(), | ||
}); | ||
let formattedNumber = numberToBeFormatted.toFixed(precision, roundMode); | ||
if (stripInsignificantZeros) { | ||
formattedNumber = formattedNumber | ||
.replace(/(\..*?)0+$/, "$1") | ||
.replace(/\.$/, ""); | ||
} | ||
return format.replace("%n", formattedNumber).replace("%u", unit); | ||
numberToHumanSize(input, options = {}) { | ||
return helpers_1.numberToHumanSize(this, input, Object.assign(Object.assign({ roundMode: "default", delimiter: "", precision: 3, significant: true, stripInsignificantZeros: true, units: { | ||
billion: "Billion", | ||
million: "Million", | ||
quadrillion: "Quadrillion", | ||
thousand: "Thousand", | ||
trillion: "Trillion", | ||
unit: "", | ||
} }, helpers_1.camelCaseKeys(this.get("number.human.format"))), options)); | ||
} | ||
numberToHuman(input, options = {}) { | ||
var _a, _b, _c, _d, _e, _f; | ||
options = Object.assign(Object.assign({ delimiter: "", precision: 3, significant: true, stripInsignificantZeros: true, format: "%n %u", units: (_a = this.get("number.human.decimal_units")) === null || _a === void 0 ? void 0 : _a.units }, helpers_1.camelCaseKeys(this.get("number.human.format"))), options); | ||
const roundMode = (_b = options.roundMode) !== null && _b !== void 0 ? _b : "default"; | ||
const precision = (_c = options.precision) !== null && _c !== void 0 ? _c : 3; | ||
const significant = (_d = options.significant) !== null && _d !== void 0 ? _d : true; | ||
const format = (_e = options.format) !== null && _e !== void 0 ? _e : "%n %u"; | ||
const separator = (_f = options.separator) !== null && _f !== void 0 ? _f : "."; | ||
let units; | ||
if (helpers_1.inferType(options.units) === "string") { | ||
units = this.get(options.units); | ||
} | ||
else { | ||
units = options.units; | ||
} | ||
let formattedNumber = helpers_1.roundNumber(new bignumber_js_1.default(input), { | ||
roundMode, | ||
precision, | ||
significant, | ||
}); | ||
const unitExponents = (units) => lodash_1.sortBy(Object.keys(units).map((name) => INVERTED_DECIMAL_UNITS[name]), (numeric) => numeric * -1); | ||
const calculateExponent = (num, units) => { | ||
const exponent = num.isZero() | ||
? 0 | ||
: Math.floor(Math.log10(num.abs().toNumber())); | ||
return unitExponents(units).find((exp) => exponent >= exp) || 0; | ||
}; | ||
const determineUnit = (units, exponent) => { | ||
const expName = DECIMAL_UNITS[exponent.toString()]; | ||
return units[expName] || ""; | ||
}; | ||
const exponent = calculateExponent(new bignumber_js_1.default(formattedNumber), units); | ||
const unit = determineUnit(units, exponent); | ||
formattedNumber = helpers_1.roundNumber(new bignumber_js_1.default(formattedNumber).div(Math.pow(10, exponent)), { | ||
roundMode, | ||
precision, | ||
significant, | ||
}); | ||
if (options.stripInsignificantZeros) { | ||
let [whole, significand] = formattedNumber.split("."); | ||
significand = (significand || "").replace(/0+$/, ""); | ||
formattedNumber = whole; | ||
if (significand) { | ||
formattedNumber += `${separator}${significand}`; | ||
} | ||
} | ||
return format | ||
.replace("%n", formattedNumber || "0") | ||
.replace("%u", unit) | ||
.trim(); | ||
var _a; | ||
return helpers_1.numberToHuman(this, input, Object.assign(Object.assign({ delimiter: "", separator: ".", precision: 3, significant: true, stripInsignificantZeros: true, format: "%n %u", roundMode: "default", units: (_a = this.get("number.human.decimal_units")) === null || _a === void 0 ? void 0 : _a.units }, helpers_1.camelCaseKeys(this.get("number.human.format"))), options)); | ||
} | ||
numberToRounded(input, options) { | ||
options = Object.assign({ unit: "", precision: 3, significant: false, separator: ".", delimiter: "", stripInsignificantZeros: false }, options); | ||
return helpers_1.formatNumber(input, options); | ||
return helpers_1.formatNumber(input, Object.assign({ unit: "", precision: 3, significant: false, separator: ".", delimiter: "", stripInsignificantZeros: false }, options)); | ||
} | ||
numberToDelimited(input, options = {}) { | ||
options = Object.assign({ delimiterPattern: /(\d)(?=(\d\d\d)+(?!\d))/g, delimiter: ",", separator: "." }, options); | ||
const numeric = new bignumber_js_1.default(input); | ||
if (!numeric.isFinite()) { | ||
return input.toString(); | ||
} | ||
const newOptions = options; | ||
if (!newOptions.delimiterPattern.global) { | ||
throw new Error(`options.delimiterPattern must be a global regular expression; received ${newOptions.delimiterPattern}`); | ||
} | ||
let [left, right] = numeric.toString().split("."); | ||
left = left.replace(newOptions.delimiterPattern, (digitToDelimiter) => `${digitToDelimiter}${newOptions.delimiter}`); | ||
return [left, right].filter(Boolean).join(newOptions.separator); | ||
return helpers_1.numberToDelimited(this, input, Object.assign({ delimiterPattern: /(\d)(?=(\d\d\d)+(?!\d))/g, delimiter: ",", separator: "." }, options)); | ||
} | ||
@@ -368,4 +224,4 @@ withLocale(locale, callback) { | ||
} | ||
toSentence(items, options) { | ||
options = Object.assign(Object.assign(Object.assign({}, WORD_CONNECTORS), helpers_1.camelCaseKeys(helpers_1.lookup(this, "support.array"))), options); | ||
toSentence(items, options = {}) { | ||
const { wordsConnector, twoWordsConnector, lastWordConnector } = Object.assign(Object.assign({ wordsConnector: ", ", twoWordsConnector: " and ", lastWordConnector: ", and " }, helpers_1.camelCaseKeys(helpers_1.lookup(this, "support.array"))), options); | ||
const size = items.length; | ||
@@ -378,7 +234,7 @@ switch (size) { | ||
case 2: | ||
return items.join(options.twoWordsConnector); | ||
return items.join(twoWordsConnector); | ||
default: | ||
return [ | ||
items.slice(0, size - 1).join(options.wordsConnector), | ||
options.lastWordConnector, | ||
items.slice(0, size - 1).join(wordsConnector), | ||
lastWordConnector, | ||
items[size - 1], | ||
@@ -389,90 +245,3 @@ ].join(""); | ||
timeAgoInWords(fromTime, toTime, options = {}) { | ||
const scope = options.scope || "datetime.distance_in_words"; | ||
const t = (name, count = 0) => this.t(name, { count, scope }); | ||
fromTime = helpers_1.parseDate(fromTime); | ||
toTime = helpers_1.parseDate(toTime); | ||
let fromInSeconds = fromTime.getTime() / 1000; | ||
let toInSeconds = toTime.getTime() / 1000; | ||
if (fromInSeconds > toInSeconds) { | ||
[fromTime, toTime, fromInSeconds, toInSeconds] = [ | ||
toTime, | ||
fromTime, | ||
toInSeconds, | ||
fromInSeconds, | ||
]; | ||
} | ||
const distanceInSeconds = Math.round(toInSeconds - fromInSeconds); | ||
const distanceInMinutes = Math.round((toInSeconds - fromInSeconds) / 60); | ||
const distanceInHours = distanceInMinutes / 60; | ||
const distanceInDays = distanceInHours / 24; | ||
const distanceInHoursRounded = Math.round(distanceInMinutes / 60); | ||
const distanceInDaysRounded = Math.round(distanceInDays); | ||
const distanceInMonthsRounded = Math.round(distanceInDaysRounded / 30); | ||
if (within(0, 1, distanceInMinutes)) { | ||
if (!options.includeSeconds) { | ||
return distanceInMinutes === 0 | ||
? t("less_than_x_minutes", 1) | ||
: t("x_minutes", distanceInMinutes); | ||
} | ||
if (within(0, 4, distanceInSeconds)) { | ||
return t("less_than_x_seconds", 5); | ||
} | ||
if (within(5, 9, distanceInSeconds)) { | ||
return t("less_than_x_seconds", 10); | ||
} | ||
if (within(10, 19, distanceInSeconds)) { | ||
return t("less_than_x_seconds", 20); | ||
} | ||
if (within(20, 39, distanceInSeconds)) { | ||
return t("half_a_minute"); | ||
} | ||
if (within(40, 59, distanceInSeconds)) { | ||
return t("less_than_x_minutes", 1); | ||
} | ||
return t("x_minutes", 1); | ||
} | ||
if (within(2, 44, distanceInMinutes)) { | ||
return t("x_minutes", distanceInMinutes); | ||
} | ||
if (within(45, 89, distanceInMinutes)) { | ||
return t("about_x_hours", 1); | ||
} | ||
if (within(90, 1439, distanceInMinutes)) { | ||
return t("about_x_hours", distanceInHoursRounded); | ||
} | ||
if (within(1440, 2519, distanceInMinutes)) { | ||
return t("x_days", 1); | ||
} | ||
if (within(2520, 43199, distanceInMinutes)) { | ||
return t("x_days", distanceInDaysRounded); | ||
} | ||
if (within(43200, 86399, distanceInMinutes)) { | ||
return t("about_x_months", Math.round(distanceInMinutes / 43200)); | ||
} | ||
if (within(86400, 525599, distanceInMinutes)) { | ||
return t("x_months", distanceInMonthsRounded); | ||
} | ||
let fromYear = fromTime.getFullYear(); | ||
if (fromTime.getMonth() + 1 >= 3) { | ||
fromYear += 1; | ||
} | ||
let toYear = toTime.getFullYear(); | ||
if (toTime.getMonth() + 1 < 3) { | ||
toYear -= 1; | ||
} | ||
const leapYears = fromYear > toYear | ||
? 0 | ||
: lodash_1.range(fromYear, toYear).filter((year) => new Date(year, 1, 29).getMonth() == 1).length; | ||
const minutesInYear = 525600; | ||
const minuteOffsetForLeapYear = leapYears * 1440; | ||
const minutesWithOffset = distanceInMinutes - minuteOffsetForLeapYear; | ||
const distanceInYears = Math.trunc(minutesWithOffset / minutesInYear); | ||
const diff = parseFloat((minutesWithOffset / minutesInYear - distanceInYears).toPrecision(3)); | ||
if (diff < 0.25) { | ||
return t("about_x_years", distanceInYears); | ||
} | ||
if (diff < 0.75) { | ||
return t("over_x_years", distanceInYears); | ||
} | ||
return t("almost_x_years", distanceInYears + 1); | ||
return helpers_1.timeAgoInWords(this, fromTime, toTime, options); | ||
} | ||
@@ -479,0 +248,0 @@ onChange(callback) { |
{ | ||
"name": "i18n-js", | ||
"version": "4.0.0-alpha.9", | ||
"version": "4.0.0-alpha.10", | ||
"description": "A small library to provide I18n on JavaScript.", | ||
@@ -45,3 +45,3 @@ "main": "./dist/import/index.js", | ||
"ts-jest": "*", | ||
"typedoc": "*", | ||
"typedoc": "beta", | ||
"typescript": "*", | ||
@@ -48,0 +48,0 @@ "webpack": "*", |
@@ -1,2 +0,2 @@ | ||
import { FormatNumberOptions } from "../../index.d"; | ||
export declare function formatNumber(input: number | string, options: FormatNumberOptions): string; | ||
import { FormatNumberOptions, Numeric } from "../../index.d"; | ||
export declare function formatNumber(input: Numeric, options: FormatNumberOptions): string; |
@@ -10,2 +10,5 @@ export { camelCaseKeys } from "./camelCaseKeys"; | ||
export { lookup } from "./lookup"; | ||
export { numberToDelimited } from "./numberToDelimited"; | ||
export { numberToHuman } from "./numberToHuman"; | ||
export { numberToHumanSize } from "./numberToHumanSize"; | ||
export { parseDate } from "./parseDate"; | ||
@@ -16,1 +19,2 @@ export { pluralize } from "./pluralize"; | ||
export { strftime } from "./strftime"; | ||
export { timeAgoInWords } from "./timeAgoInWords"; |
@@ -1,2 +0,2 @@ | ||
import { DateTime, Dict, I18nOptions, MissingPlaceholderHandler, NullPlaceholderHandler, Numeric, OnChangeHandler, Scope, TimeAgoInWordsOptions, NumberToCurrencyOptions, NumberToRoundedOptions, NumberToPercentageOptions, NumberToDelimitedOptions, NumberToHumanOptions, NumberToHumanSizeOptions, ToSentenceOptions, TranslateOptions } from "../index.d"; | ||
import { DateTime, Dict, I18nOptions, MissingPlaceholderHandler, NullPlaceholderHandler, NumberToCurrencyOptions, NumberToDelimitedOptions, NumberToHumanOptions, NumberToHumanSizeOptions, NumberToPercentageOptions, NumberToRoundedOptions, Numeric, OnChangeHandler, Scope, TimeAgoInWordsOptions, ToSentenceOptions, TranslateOptions } from "../index.d"; | ||
import { Locales } from "./Locales"; | ||
@@ -28,3 +28,2 @@ import { Pluralization } from "./Pluralization"; | ||
set defaultLocale(newLocale: string); | ||
numberToCurrency(amount: Numeric, options?: NumberToCurrencyOptions): string; | ||
translate(scope: Scope, options?: TranslateOptions): string; | ||
@@ -37,6 +36,7 @@ t: (scope: Scope, options?: TranslateOptions | undefined) => string; | ||
toTime(scope: Scope, input: DateTime): string; | ||
numberToPercentage(input: Numeric, options?: NumberToPercentageOptions): string; | ||
numberToHumanSize(numeric: Numeric, options?: NumberToHumanSizeOptions): string; | ||
numberToHuman(input: Numeric, options?: NumberToHumanOptions): string; | ||
numberToRounded(input: Numeric, options?: NumberToRoundedOptions): string; | ||
numberToCurrency(input: Numeric, options?: Partial<NumberToCurrencyOptions>): string; | ||
numberToPercentage(input: Numeric, options?: Partial<NumberToPercentageOptions>): string; | ||
numberToHumanSize(input: Numeric, options?: Partial<NumberToHumanSizeOptions>): string; | ||
numberToHuman(input: Numeric, options?: Partial<NumberToHumanOptions>): string; | ||
numberToRounded(input: Numeric, options?: Partial<NumberToRoundedOptions>): string; | ||
numberToDelimited(input: Numeric, options?: Partial<NumberToDelimitedOptions>): string; | ||
@@ -48,3 +48,3 @@ withLocale(locale: string, callback: () => void): Promise<void>; | ||
}): void; | ||
toSentence(items: any[], options?: ToSentenceOptions): string; | ||
toSentence(items: any[], options?: Partial<ToSentenceOptions>): string; | ||
timeAgoInWords(fromTime: DateTime, toTime: DateTime, options?: TimeAgoInWordsOptions): string; | ||
@@ -51,0 +51,0 @@ distanceOfTimeInWords: (fromTime: DateTime, toTime: DateTime, options?: TimeAgoInWordsOptions) => string; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1213501
135
2799