diff --git a/README.md b/README.md index c2d6eac..51c8904 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,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 84e53a8..576eee9 100644 --- a/index.js +++ b/index.js @@ -119,7 +119,7 @@ var tokenRegex = /%\{(.*?)\}/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) { +function transformPhrase(phrase, substitutions, locale, numberFormat) { if (typeof phrase !== 'string') { throw new TypeError('Polyglot.transformPhrase expects argument #1 to be string'); } @@ -144,8 +144,14 @@ function transformPhrase(phrase, substitutions, locale) { // Interpolate: Creates a `RegExp` object for each interpolation placeholder. result = result.replace(tokenRegex, function (expression, argument) { if (!has(options, argument)) { return ''; } + + var replacement = options[argument]; + if (typeof replacement === 'number') { + 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; @@ -157,6 +163,7 @@ function Polyglot(options) { this.phrases = {}; this.extend(opts.phrases || {}); this.currentLocale = opts.locale || 'en'; + this.numberFormat = opts.numberFormat || String; this.allowMissing = !!opts.allowMissing; this.warn = opts.warn || warn; } @@ -165,7 +172,9 @@ function Polyglot(options) { // // Get or set locale. Internally, Polyglot only uses locale for pluralization. Polyglot.prototype.locale = function (newLocale) { - if (newLocale) this.currentLocale = newLocale; + if (newLocale) { + this.currentLocale = newLocale; + } return this.currentLocale; }; @@ -314,7 +323,7 @@ Polyglot.prototype.t = function (key, options) { result = key; } if (typeof phrase === 'string') { - result = transformPhrase(phrase, opts, this.currentLocale); + result = transformPhrase(phrase, opts, this.currentLocale, this.numberFormat); } return result; }; diff --git a/test/index.js b/test/index.js index 055ff1e..ca9bf96 100644 --- a/test/index.js +++ b/test/index.js @@ -8,7 +8,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; @@ -89,6 +90,16 @@ describe('t', function () { expect(instance.t('nav.cta.join_now')).to.equal('Join now!'); expect(instance.t('header.sign_in')).to.equal('Sign In'); }); + + 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 () {