3

I'm trying to use Intl with pt-BR locale and I can't get that to work with Node 0.12.

Code:

global.Intl = require('intl/Intl');
require('intl/locale-data/jsonp/pt-BR.js');

var options = { year: 'numeric', month: 'long' };
var dateTimeFormat = new Intl.DateTimeFormat('pt-BR', options);
console.log(dateTimeFormat.format(new Date()));

This code outputs:

May, 2015

I would expect that to be: 'Maio, 2015'.

Then, if I decide to create a new variable, everything works:

Working Code:

global.NewIntl = require('intl/Intl');
require('intl/locale-data/jsonp/pt-BR.js');

var options = { year: 'numeric', month: 'long' };
var dateTimeFormat = new NewIntl.DateTimeFormat('pt-BR', options);
console.log(dateTimeFormat.format(new Date()));

This prints out the expect value. Question: Why the Intl global variable is not being replaced?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Alan Souza
  • 7,475
  • 10
  • 46
  • 68

2 Answers2

1

Because the Intl property of the global object is not writable (testing on Node 0.12.2):

console.log(Object.getOwnPropertyDescriptor(global, 'Intl'));
/*
{ value: {},
  writable: false,
  enumerable: false,
  configurable: false }
*/

Put your code in strict mode and it will throw a more descriptive error when trying to assign to non-writable properties instead of failing silently.

It is also not configurable, so there is no way to fully replace (re-assign) the global.Intl. And this is a good thing: other modules and dependencies may depend on the built-in Intl implementation.

Tampering with the global scope most often results in more headache than it is worth, it is best to keep your packages self-contained. You can just require the polyfill in the files where you need it:

var Intl = require('intl/Intl');
// Note: you only need to require the locale once
require('intl/locale-data/jsonp/pt-BR.js');

var options = { year: 'numeric', month: 'long' };
var dateTimeFormat = new Intl.DateTimeFormat('pt-BR', options);
console.log(dateTimeFormat.format(new Date()));

You can then just add var Intl = require('intl/Intl'); in the files where you need Intl.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
  • Yeah, I fully support your point @Fabrício, but if you look at this object, its value is empty. Do you know why it is empty? So, as of now, I cannot make a call to Intl.__addLocaleData. This is why I tried to replace it with the polyfill. – Alan Souza May 21 '15 at 23:11
  • @AlanSouza it *looks* empty when you `console.log(Intl)` because its properties are not [enumerable](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#Enumerable_attribute). Try `console.log(Object.getOwnPropertyNames(Intl));` to see that the Intl object is actually not empty. `;)` – Fabrício Matté May 21 '15 at 23:15
  • Cool, yeah it is not empty definetly :) But it does not have the __addLocaleData. How to support the pt-BR locale? – Alan Souza May 21 '15 at 23:17
  • I was checking this: https://github.com/joyent/node/wiki/Intl. I'm wondering if the official Node 0.12 has support for all locales by default, or if I have to compile it manually if I want support for that. Any thoughts? – Alan Souza May 21 '15 at 23:27
  • Yep, it looks like you may need to build Node.js from source setting those ICU options. I believe it is easier to just `require()` the polyfill and set up the locales, then just require the polyfill in the files where you need it. – Fabrício Matté May 21 '15 at 23:31
  • Added an example to the answer without tinkering with the global scope. You only need to add `var Intl = require('intl/Intl');` in the files where you need `Intl` then. `=]` – Fabrício Matté May 21 '15 at 23:38
  • 1
    Thanks brother! I'm afraid I can't choose the files where to use the Intl. I'm using the `react-intl` and it seems they don't offer support for that. I will deal with this problem with them directly, but thanks a lot for your help. – Alan Souza May 21 '15 at 23:53
  • No problem. `=]` And yes, their [website's example](http://formatjs.io/react/#install-node) is actually broken in Node 0.12, that is, `global.Intl = require('intl');` will throw an error in strict mode, and fail silently in loose mode. It is worth [opening an issue in their repository](https://github.com/yahoo/react-intl/issues/new). – Fabrício Matté May 22 '15 at 00:08
1

It turns out that replacing only DateTimeFormat and NumberFormat solves the issue:

require('intl/Intl');
require('intl/locale-data/jsonp/pt-BR.js');
Intl.NumberFormat = IntlPolyfill.NumberFormat;
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;

var options = { year: 'numeric', month: 'long' };
var dateTimeFormat = new Intl.DateTimeFormat('pt-BR', options);
console.log(dateTimeFormat.format(new Date()));

Just make sure to load this script before loading react-intl in case you are also using it.

I got this information from here.

Alan Souza
  • 7,475
  • 10
  • 46
  • 68
  • 1
    Note: I'd still advice to not pollute/replace the built-ins unless you really have to -- which I believe to be your case, as you've mentioned to be using react-intl. – Fabrício Matté May 22 '15 at 22:24
  • Good point, I don't want to pollute/replace, but it is my only option. I really don't like that Node 0.12 does not ship with the whole set of locales. I'm building a framework and I don't want all the people that use my framework to build a custom Node to support the locales that I support. I believe it is easier at this point to use the Polyfill. – Alan Souza May 22 '15 at 22:27