Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to abbreviate large numbers in a i18n-friendly way?

I want to "abbreviate" large numbers to make them human-readable, using abbreviations that are idiomatic for a given locale. For example, the number 16512 would become:

  • "16.5k" for en-US ("k" is short for the Metric prefix "thousand", as in "kilometer")
  • "16,5тыс." for ru ("тыс." is short for "тысяча", meaning "thousand" in Russian)

I'm not sure what to call this procedure I'm describing.

Ruby on Rails has something similar to what I'm looking for called #number_to_human, but it's not quite right -- it would return "16.5 Thousand" in my example above. I'm interested in abbreviations (and perhaps not all locales round things to the nearest thousand), not merely making strings human-readable.

I'd be especially interested in a solution that works for JavaScript, but even the name of this procedure would be a huge help!

like image 567
ucarion Avatar asked Jan 12 '17 04:01

ucarion


1 Answers

Answering my own question:

The procedure I'm describing is known as compact number formatting. There are two variants: short ("16.5K") and long ("16.5 Thousand"). The Unicode Common Locale Data Repository (CLDR) provides number-formatting patterns for compact numbers in each locale: http://cldr.unicode.org/translation/number-patterns#TOC-Short-Numbers

For JavaScript, there is a (stalled) ECMA proposal to add a compact option to the Intl.NumberFormat API: https://github.com/tc39/ecma402/issues/37

Luckily for Ruby and JS programmers, Twitter has an NPM package called twitter_cldr (documentation is here and here). Usage looks like this:

const TwitterCldr = require('twitter_cldr');

function printNumbers(localeName) {
    const locale = TwitterCldr.load(localeName);
    const formatter = new locale.ShortDecimalFormatter();

    const numbers = [123, 1231, 12312, 123123, 1231231, 12312312, 123123123];
    return numbers.map(n => formatter.format(n, { precision: 1 }));
}

console.log(printNumbers('en'));
// [ '123.0', '1.2K', '12.3K', '123.1K', '1.2M', '12.3M', '123.1M' ]
console.log(printNumbers('ru'));
// [ '123,0', '1,2 тыс.', '12,3 тыс.', '123,1 тыс.', '1,2 млн', '12,3 млн', 123,1 млн' ]
console.log(printNumbers('ja'));
// [ '123.0', '1.2千', '1.2万', '12.3万', '123.1万', '1231.2万', '1.2億' ]

Note that in Japan, people wouldn't say "12.3 Million", they'd say "1231.2 Ten-Thousand". Add that to the list of falsehoods programmers assume about the world!

like image 112
ucarion Avatar answered Nov 13 '22 20:11

ucarion