From 40f61285b04ccd9e55e13a345446a5783cd2b88b Mon Sep 17 00:00:00 2001 From: Adam Hooper Date: Fri, 21 Oct 2016 12:09:27 -0400 Subject: [PATCH] use numberFormat callback to format numbers --- README.md | 22 ++++++++++++++++++++++ index.js | 13 ++++++++++--- test/index.js | 13 ++++++++++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2119ee9..3d0e429 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,28 @@ polyglot.t("car", 2); => "2 cars" ``` +If you pass a `numberFormat` _function_ to the constructor, Polyglot will use +it to translate interpolated `Number`s to `String`s. That's useful because +different locales have different rules for formatting numbers: `2,000.56` in +English versus `1 234,56` in French, for instance. + +```js +polyglot = new Polyglot({ + phrases: { num_cars: '%{smart_count} car |||| %{smart_count} cars' }, + numberFormat: new Intl.NumberFormat('en').format // Chrome, Firefox, IE11+, Node 0.12+ with ICU +}) +polyglot.t("num_cars", 2000); // internally, calls options.numberFormat.format(2000) +=> "2,000 cars" +``` + +(A primer on [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) +in Node: Node 0.12+ comes with Intl as long as it's compiled with ICU (which is +the default). By default, the only locale Node supports is en-US. You can add +[full-icu](https://www.npmjs.com/package/full-icu) to your project to support +other locales. Finally, Polyglot accepts a _function_, not an Intl.NumberFormat +instance: if you have a NumberFormat instance, pass its `.format` property to +Polyglot. + If you like, you can provide a default value in case the phrase is missing. Use the special option key "_" to specify a default. diff --git a/index.js b/index.js index 57ba091..e28d9b7 100644 --- a/index.js +++ b/index.js @@ -171,7 +171,7 @@ var defaultTokenRegex = /%\{(.*?)\}/g; // // You should pass in a third argument, the locale, to specify the correct plural type. // It defaults to `'en'` with 2 plural forms. -function transformPhrase(phrase, substitutions, locale, tokenRegex) { +function transformPhrase(phrase, substitutions, locale, tokenRegex, numberFormat) { if (typeof phrase !== 'string') { throw new TypeError('Polyglot.transformPhrase expects argument #1 to be string'); } @@ -197,8 +197,14 @@ function transformPhrase(phrase, substitutions, locale, tokenRegex) { // Interpolate: Creates a `RegExp` object for each interpolation placeholder. result = replace.call(result, interpolationRegex, function (expression, argument) { if (!has(options, argument) || options[argument] == null) { return expression; } + + var replacement = options[argument]; + if (typeof replacement === 'number' && typeof numberFormat === 'function') { + replacement = numberFormat(replacement); + } + // Ensure replacement value is escaped to prevent special $-prefixed regex replace tokens. - return replace.call(options[argument], dollarRegex, dollarBillsYall); + return replace.call(replacement, dollarRegex, dollarBillsYall); }); return result; @@ -214,6 +220,7 @@ function Polyglot(options) { this.onMissingKey = typeof opts.onMissingKey === 'function' ? opts.onMissingKey : allowMissing; this.warn = opts.warn || warn; this.tokenRegex = constructTokenRegex(opts.interpolation); + this.numberFormat = opts.numberFormat || String; } // ### polyglot.locale([locale]) @@ -370,7 +377,7 @@ Polyglot.prototype.t = function (key, options) { result = key; } if (typeof phrase === 'string') { - result = transformPhrase(phrase, opts, this.currentLocale, this.tokenRegex); + result = transformPhrase(phrase, opts, this.currentLocale, this.tokenRegex, this.numberFormat); } return result; }; diff --git a/test/index.js b/test/index.js index 98d8098..93c3568 100644 --- a/test/index.js +++ b/test/index.js @@ -9,7 +9,8 @@ describe('t', function () { hello: 'Hello', hi_name_welcome_to_place: 'Hi, %{name}, welcome to %{place}!', name_your_name_is_name: '%{name}, your name is %{name}!', - empty_string: '' + empty_string: '', + number: '%{number}' }; var polyglot; @@ -156,6 +157,16 @@ describe('t', function () { instance.t(missingKey); }); }); + + it('uses numberFormat', function () { + var instance = new Polyglot({ + phrases: phrases, + // prove we're passed a Number by doing math on it and formatting it + numberFormat: function (n) { return 'x' + (n + 2); } + }); + + expect(instance.t('number', { number: 1234.56 })).to.equal('x1236.56'); + }); }); describe('pluralize', function () {