diff --git a/Readme.md b/Readme.md index c000ada..e7cc1fb 100644 --- a/Readme.md +++ b/Readme.md @@ -45,7 +45,7 @@ This module uses a pre-defined list of rules, applied in order, to singularize o * `word: string` The word to pluralize * `count: number` How many of the word exist -* `inclusive: boolean` Whether to prefix with the number (e.g. 3 ducks) +* `inclusive: boolean | Intl.NumberFormat | (amount: number) => string` Whether to prefix with the number (e.g. 3 ducks) Examples: @@ -58,6 +58,24 @@ pluralize('test', 1, true) //=> "1 test" pluralize('test', 5, true) //=> "5 tests" pluralize('蘋果', 2, true) //=> "2 蘋果" +// Example of formatting numbers +pluralize('test', 1.57, amount => amount.toFixed(1)) //=> "1.6 tests" + +const formatter = new Intl.NumberFormat(undefined, { useGrouping: true, maximumFractionDigits: 1 }) +pluralize('test', 1234567.89, formatter) //=> "1,234,567.9 tests" + +// Example with pronouns +for (const count of [1, 2]) { + console.log([ + pluralize('This', count), + pluralize('pretzel', count), + pluralize('is', count), + 'making me thirsty' + ].join(' ')) +} +//=> This pretzel is making me thirsty +//=> These pretzels are making me thirsty + // Example of new plural rule: pluralize.plural('regex') //=> "regexes" pluralize.addPluralRule(/gex$/i, 'gexii') diff --git a/pluralize.js b/pluralize.js index 65dfcd5..5e89017 100644 --- a/pluralize.js +++ b/pluralize.js @@ -164,19 +164,41 @@ }; } + /** + * Returns the formatted number prefix (or an empty string) + * + * @param {number} amount The number to format + * @param {boolean | Intl.NumberFormat | (amount: number) => string} inclusive Whether to prefix with the number (e.g. 3 ducks). Can also be a function that formats the number, or an Intl.NumberFormat instance. + */ + function getNumberPrefix (amount, inclusive) { + if (!inclusive) return ''; + + if (typeof inclusive === 'function') { + const formatted = inclusive(amount); + return formatted !== '' ? formatted + ' ' : ''; + } + + if (inclusive instanceof Intl.NumberFormat) { + const formatted = inclusive.format(amount); + return formatted !== '' ? formatted + ' ' : ''; + } + + return amount + ' '; + } + /** * Pluralize or singularize a word based on the passed in count. * * @param {string} word The word to pluralize * @param {number} count How many of the word exist - * @param {boolean} inclusive Whether to prefix with the number (e.g. 3 ducks) + * @param {boolean | Intl.NumberFormat | (amount: number) => string} inclusive Whether to prefix with the number (e.g. 3 ducks). Can also be a function that formats the number, or an Intl.NumberFormat instance. * @return {string} */ function pluralize (word, count, inclusive) { var pluralized = count === 1 ? pluralize.singular(word) : pluralize.plural(word); - return (inclusive ? count + ' ' : '') + pluralized; + return getNumberPrefix(count, inclusive) + pluralized; } /** diff --git a/test.js b/test.js index fc84d37..960c01e 100644 --- a/test.js +++ b/test.js @@ -782,6 +782,33 @@ describe('pluralize', function () { it('singular words', function () { expect(pluralize('test', 1, true)).to.equal('1 test'); }); + + it('formats using Intl.NumberFormat', function () { + expect(pluralize('test', 1234567.89, new Intl.NumberFormat('en-US', { useGrouping: true, maximumFractionDigits: 1 }))).to.equal('1,234,567.9 tests'); + }); + + it('formats using function', function () { + expect(pluralize('test', 1234567.89, (amount) => amount.toFixed(1))).to.equal('1234567.9 tests'); + }); + + it('formats using function which returns number as is', function () { + expect(pluralize('test', 1234567.89, (amount) => amount)).to.equal('1234567.89 tests'); + }); + + it('excludes extra space when format function returns empty string', function () { + expect(pluralize('test', 1234567.89, () => '')).to.equal('tests'); + }); + + it('excludes extra space when Intl.NumberFormat returns empty string', function () { + // Not sure if it's possible for Intl.NumberFormat to return an empty string + // so just patching it to force one just in case, so we get the test coverage + const formatter = new Intl.NumberFormat(); + Object.defineProperty(formatter, 'format', { + value: () => '' + }); + + expect(pluralize('test', 1234567.89, formatter)).to.equal('tests'); + }); }); describe('adding new rules', function () {