This package is a fork of make-plural version 4.

It provided a compiler for CLDR plurals, but it also contained a lot of methods to test them. I stripped the test methods and kept the conversion code to make it smaller.

Usage

import makePlural from "@onigoetz/make-plural";

// Original CLDR data
const pluralRules = {
  "plurals-type-cardinal": {
    en: {
      "pluralRule-count-one": "i = 1 and v = 0 @integer 1",
      "pluralRule-count-other":
        " @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …"
    }
  },
  "plurals-type-ordinal": {
    en: {
      "pluralRule-count-one":
        "n % 10 = 1 and n % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …",
      "pluralRule-count-two":
        "n % 10 = 2 and n % 100 != 12 @integer 2, 22, 32, 42, 52, 62, 72, 82, 102, 1002, …",
      "pluralRule-count-few":
        "n % 10 = 3 and n % 100 != 13 @integer 3, 23, 33, 43, 53, 63, 73, 83, 103, 1003, …",
      "pluralRule-count-other":
        " @integer 0, 4~18, 100, 1000, 10000, 100000, 1000000, …"
    }
  }
};

const pluralGenerator = makePlural(pluralRules["plurals-type-ordinal"]["en"]);

console.log(pluralGenerator(3)) // => few

Size optimization

The original CLDR data is quite verbose and if you can preprocess it, a lot of data can be removed. You can remove anything after @decimal or @integer and the other rule, you can go from :

{
  "plurals-type-cardinal": {
    "en": {
      "pluralRule-count-one": "i = 1 and v = 0 @integer 1",
      "pluralRule-count-other":
        " @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …"
    }
  },
  "plurals-type-ordinal": {
    "en": {
      "pluralRule-count-one":
        "n % 10 = 1 and n % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …",
      "pluralRule-count-two":
        "n % 10 = 2 and n % 100 != 12 @integer 2, 22, 32, 42, 52, 62, 72, 82, 102, 1002, …",
      "pluralRule-count-few":
        "n % 10 = 3 and n % 100 != 13 @integer 3, 23, 33, 43, 53, 63, 73, 83, 103, 1003, …",
      "pluralRule-count-other":
        " @integer 0, 4~18, 100, 1000, 10000, 100000, 1000000, …"
    }
  }
}

to :

{
  "plurals-type-cardinal": {
    "en": {
      "pluralRule-count-one": "i = 1 and v = 0"
    }
  },
  "plurals-type-ordinal": {
    "en": {
      "pluralRule-count-one": "n % 10 = 1 and n % 100 != 11",
      "pluralRule-count-two": "n % 10 = 2 and n % 100 != 12",
      "pluralRule-count-few": "n % 10 = 3 and n % 100 != 13"
    }
  }
}

Efficient pluralGenerator

If you need to create many plural generators, parsing the CLDR data many times isn’t efficient. You can create a small factory function like this:

const pluralRules = {}; // CLDR data
const pluralMemory = {};

function pluralGenerator(locale, type) {
  const key = `${locale}-${type}`;

  if (!pluralMemory.hasOwnProperty(key)) {
    pluralMemory[key] = makePlural(
      pluralRules[`plurals-type-${type}`][locale]
    );
  }

  return pluralMemory[key];
}