Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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')
Expand Down
26 changes: 24 additions & 2 deletions pluralize.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
27 changes: 27 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down