Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

intl-pluralrules

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

intl-pluralrules - npm Package Compare versions

Comparing version 1.0.3 to 1.1.0

factory.js

41

package.json
{
"name": "intl-pluralrules",
"version": "1.0.3",
"version": "1.1.0",
"description": "Intl.PluralRules polyfill",

@@ -17,15 +17,21 @@ "keywords": [

"files": [
"plural-rules.js",
"polyfill.js"
"factory.*",
"plural-rules.*",
"pseudo-number-format.*",
"polyfill.*"
],
"main": "polyfill.js",
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": "> 0.25%, not dead"
}
]
]
"main": "polyfill",
"jest": {
"moduleFileExtensions": [
"mjs",
"js",
"json"
],
"testMatch": [
"**/*.test.mjs"
],
"transform": {
"\\.mjs$": "babel-jest"
},
"transformIgnorePatterns": []
},

@@ -37,3 +43,3 @@ "prettier": {

"dependencies": {
"make-plural": "^4.3.0"
"make-plural": "^6.0.0"
},

@@ -44,6 +50,9 @@ "devDependencies": {

"@babel/preset-env": "^7.4.5",
"jest": "^24.8.0"
"babel-jest": "^24.9.0",
"jest": "^24.9.0"
},
"scripts": {
"build": "babel -d . src/ --ignore '**/*.test.js'",
"build:cjs": "TARGET=cjs babel -d . src/ --ignore '**/*.test.mjs'",
"build:mjs": "babel -d . src/ --ignore '**/*.test.mjs' --keep-file-extension",
"build": "npm run build:mjs && npm run build:cjs",
"prepublishOnly": "npm test && npm run build",

@@ -50,0 +59,0 @@ "test": "jest"

@@ -8,186 +8,30 @@ "use strict";

var _makePlural = _interopRequireDefault(require("make-plural"));
var Plurals = _interopRequireDefault(require("make-plural/plurals"));
var _pluralCategories = _interopRequireDefault(require("make-plural/umd/pluralCategories"));
var Categories = _interopRequireDefault(require("make-plural/pluralCategories"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _factory = _interopRequireDefault(require("./factory"));
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var _pseudoNumberFormat = _interopRequireDefault(require("./pseudo-number-format"));
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
// does not check for duplicate subtags
var isStructurallyValidLanguageTag = function isStructurallyValidLanguageTag(locale) {
return locale.split('-').every(function (subtag) {
return /[a-z0-9]+/i.test(subtag);
});
};
var NumberFormat = (typeof Intl === "undefined" ? "undefined" : _typeof(Intl)) === 'object' && Intl.NumberFormat || _pseudoNumberFormat.default; // make-plural exports are cast with safe-identifier to be valid JS identifiers
var canonicalizeLocaleList = function canonicalizeLocaleList(locales) {
if (!locales) return [];
if (!Array.isArray(locales)) locales = [locales];
var res = {};
for (var i = 0; i < locales.length; ++i) {
var tag = locales[i];
if (tag && _typeof(tag) === 'object') tag = String(tag);
if (typeof tag !== 'string') {
// Requiring tag to be a String or Object means that the Number value
// NaN will not be interpreted as the language tag "nan", which stands
// for Min Nan Chinese.
var msg = "Locales should be strings, ".concat(JSON.stringify(tag), " isn't.");
throw new TypeError(msg);
}
if (tag[0] === '*') continue;
if (!isStructurallyValidLanguageTag(tag)) {
var strTag = JSON.stringify(tag);
var _msg = "The locale ".concat(strTag, " is not a structurally valid BCP 47 language tag.");
throw new RangeError(_msg);
}
res[tag] = true;
}
return Object.keys(res);
var id = function id(lc) {
return lc === 'in' ? '_in' : lc === 'pt-PT' ? 'pt_PT' : lc;
};
var defaultLocale = function defaultLocale() {
return typeof navigator !== 'undefined' && navigator && (navigator.userLanguage || navigator.language) || 'en-US';
var getSelector = function getSelector(lc) {
return Plurals[id(lc)];
};
var findLocale = function findLocale(locale) {
do {
if (_makePlural.default[locale]) return locale;
locale = locale.replace(/-?[^-]*$/, '');
} while (locale);
return null;
var getCategories = function getCategories(lc, ord) {
return Categories[id(lc)][ord ? 'ordinal' : 'cardinal'];
};
var resolveLocale = function resolveLocale(locales) {
var canonicalLocales = canonicalizeLocaleList(locales);
for (var i = 0; i < canonicalLocales.length; ++i) {
var lc = findLocale(canonicalLocales[i]);
if (lc) return lc;
}
return findLocale(defaultLocale());
};
var getType = function getType(type) {
if (!type) return 'cardinal';
if (type === 'cardinal' || type === 'ordinal') return type;
throw new RangeError('Not a valid plural type: ' + JSON.stringify(type));
};
var PluralRules =
/*#__PURE__*/
function () {
_createClass(PluralRules, null, [{
key: "supportedLocalesOf",
value: function supportedLocalesOf(locales) {
return canonicalizeLocaleList(locales).filter(findLocale);
}
}]);
function PluralRules(locales) {
var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, PluralRules);
this._locale = resolveLocale(locales);
this._type = getType(opt.type);
if ((typeof Intl === "undefined" ? "undefined" : _typeof(Intl)) === 'object' && Intl.NumberFormat) {
// make-plural expects latin digits with . decimal separator
this._nf = new Intl.NumberFormat('en', opt);
} else {
var minID = opt.minimumIntegerDigits,
minFD = opt.minimumFractionDigits,
maxFD = opt.maximumFractionDigits,
minSD = opt.minimumSignificantDigits,
maxSD = opt.maximumSignificantDigits;
this._minID = typeof minID === 'number' ? minID : 1;
this._minFD = typeof minFD === 'number' ? minFD : 0;
this._maxFD = typeof maxFD === 'number' ? maxFD : Math.max(this._minFD, 3);
if (typeof minSD === 'number' || typeof maxSD === 'number') {
this._minSD = typeof minSD === 'number' ? minSD : 1;
this._maxSD = typeof maxSD === 'number' ? maxSD : 21;
}
}
}
_createClass(PluralRules, [{
key: "resolvedOptions",
value: function resolvedOptions() {
var nfOpt = this._nf && this._nf.resolvedOptions();
var opt = {
locale: this._locale,
minimumIntegerDigits: nfOpt ? nfOpt.minimumIntegerDigits : this._minID,
minimumFractionDigits: nfOpt ? nfOpt.minimumFractionDigits : this._minFD,
maximumFractionDigits: nfOpt ? nfOpt.maximumFractionDigits : this._maxFD,
pluralCategories: _pluralCategories.default[this._locale][this._type],
type: this._type
};
if (nfOpt && typeof nfOpt.minimumSignificantDigits === 'number') {
opt.minimumSignificantDigits = nfOpt.minimumSignificantDigits;
opt.maximumSignificantDigits = nfOpt.maximumSignificantDigits;
} else if (typeof this._minSD === 'number') {
opt.minimumSignificantDigits = this._minSD;
opt.maximumSignificantDigits = this._maxSD;
}
return opt;
}
}, {
key: "_format",
value: function _format(n) {
if (this._nf) return this._nf.format(n);
if (this._minSD) {
var raw = String(n);
var prec = 0;
for (var i = 0; i < raw.length; ++i) {
var c = raw[i];
if (c >= '0' && c <= '9') ++prec;
}
if (prec < this._minSD) return n.toPrecision(this._minSD);
if (prec > this._maxSD) return n.toPrecision(this._maxSD);
return raw;
}
if (this._minFD > 0) return n.toFixed(this._minFD);
if (this._maxFD === 0) return n.toFixed(0);
return String(n);
}
}, {
key: "select",
value: function select(number) {
if (typeof number !== 'number') number = Number(number);
if (!isFinite(number)) return 'other';
var fmt = this._format(Math.abs(number));
return _makePlural.default[this._locale](fmt, this._type === 'ordinal');
}
}]);
return PluralRules;
}();
exports.default = PluralRules;
var PluralRules = (0, _factory.default)(NumberFormat, getSelector, getCategories);
var _default = PluralRules;
exports.default = _default;
# intl-pluralrules
A spec-compliant polyfill for [Intl.PluralRules]. Particularly useful if you
need proper support for [`minimumFractionDigits`].
A spec-compliant implementation & polyfill for [Intl.PluralRules]. Particularly
useful if you need proper support for [`minimumFractionDigits`], which are only
supported in Chrome 77 & later.

@@ -15,6 +16,6 @@ [intl.pluralrules]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules

## Usage
## Polyfill
To use the polyfill, just import it to make sure that a fully functional
`Intl.PluralRules` is available in your environment:
To use as a polyfill, just import it to ensure that `Intl.PluralRules` is
available in your environment:

@@ -27,5 +28,7 @@ ```js

[multiple locales](https://nodejs.org/api/intl.html), the polyfill will not be
loaded.
loaded. Full support for `minimumFractionDigits` is not checked.
The implementation itself is available as
## Ponyfill
A complete implementation of PluralRules is available as
`intl-pluralrules/plural-rules`, if you'd prefer using it without modifying your

@@ -40,1 +43,51 @@ `Intl` object, or if you wish to use it rather than your environment's own:

```
## Factory
In order to support all available locales, their data needs to be included in
the package. This means that when minified and gzipped, the above-documented
usage adds about 7kB to your application's production size. If this is a
concern, you can use `intl-pluralrules/factory` and [make-plural] to build a
PluralRules class with locale support limited to only what you actually use.
[make-plural]: https://www.npmjs.com/package/make-plural
Thanks to tree-shaking, this example that only supports English and French
minifies & gzips to 1619 bytes. Do note that this size difference is only
apparent with minified production builds.
```js
import getPluralRules from 'intl-pluralrules/factory'
import { en, fr } from 'make-plural/plurals'
import { en as enCat, fr as frCat } from 'make-plural/pluralCategories'
const sel = { en, fr }
const getSelector = lc => sel[lc]
const cat = { en: enCat, fr: frCat }
const getCategories = (lc, ord) => cat[lc][ord ? 'ordinal' : 'cardinal']
const PluralRules = getPluralRules(
Intl.NumberFormat, // Not available in IE 10
getSelector,
getCategories
)
export default PluralRules
```
All arguments of `getPluralRules(NumberFormat, getSelector, getCategories)` are
required.
- `NumberFormat` should be `Intl.NumberFormat`, or a minimal implementation
such as the one available at `intl-pluralrules/pseudo-number-format`. It
should at least support the `"en"` locale and all of the min/max digit count
options.
- `getSelector(lc)` should return a `function(n, ord)` returning the plural
category of `n`, using cardinal plural rules (by default), or ordinal rules if
`ord` is true. `n` may be a number, or the formatted string representation of
a number. This may be called with any user-provided string `lc`, and should
return `undefined` for invalid or unsupported locales.
- `getCategories(lc, ord)` should return the set of available plural categories
for the locale, either for cardinals (by default), or ordinals if `ord` is
true. This function will be called only with values for which `getSelector`
returns a function.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc