-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core(i18n): improve Intl polyfill and use it in Util #9584
Conversation
|
||
// Check if global implementation supports a minimum set of locales. | ||
const minimumLocales = ['en', 'es', 'ru', 'zh']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be enough to establish whether Node is full-icu
or not, but happy to add or take away from this minimum list.
if (locale === 'en-XA') locale = 'de'; | ||
|
||
Util.numberDateLocale = locale; | ||
Util.numberFormatter = new Intl.NumberFormat(locale); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more static-ish state is unfortunate, but it seemed wasteful to do new Intl.NumberFormat(Util.numberDateLocale).format(coarseTime)
for each format call...I'm not sure if it matters much
(tsc ensures it's initialized on the class, though, so that's a plus)
expect(lhrEn.audits['render-blocking-resources'].displayValue) | ||
.toEqual('Potential savings of 1,130 ms'); | ||
expect(lhrEs.audits['render-blocking-resources'].displayValue) | ||
.toEqual('Potential savings of 1.130 ms'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is actually formatted by intl-messageformat
, but it's one more check that the number locales are being initialized correctly and it seemed like a missing piece of checking locale swapping
@@ -47,25 +51,40 @@ describe('util helpers', () => { | |||
assert.equal(Util.formatDuration(28 * 60 * 60 * 1000 + 5000), `1${NBSP}d 4${NBSP}h 5${NBSP}s`); | |||
}); | |||
|
|||
// TODO: need ICU support in node on Travis/Appveyor | |||
it.skip('formats based on locale', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- it.skip
🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pretty much LGTM
lighthouse-core/lib/i18n/i18n.js
Outdated
// Node usually doesn't come with the locales we want built-in, so load the polyfill if we can. | ||
// Node without full-icu doesn't come with the locales we want built-in. Load the polyfill if needed. | ||
// See https://nodejs.org/api/intl.html#intl_options_for_building_node_js | ||
// The bundler should remove these dependencies, so this will be a no-op in the browser. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be worth clarifying "no-op".
right now it appears to me that we would override a browser that failed to support those 4 locales with Intl.NumberFormat = undefined
, which would be worse than a no-op. Is it more like All our environments where IntlPolyfill is empty are guaranteed to support these 4 locales, so this will be a no-op
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it shouldn't be possible in Chrome (other browsers never see this code because it's only in the bundle, not in the report) but you never know what Chrome builds are out there and at the least it would be good for the code to make it completely clear it's not possible. I'll fix it.
@@ -9,6 +9,10 @@ const assert = require('assert'); | |||
const Util = require('../../../../report/html/renderer/util.js'); | |||
const sampleResult = require('../../../results/sample_v2.json'); | |||
|
|||
// Require i18n to make sure Intl is polyfilled in Node without full-icu. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe worth noting that this code won't actually be run in node though for a real report but it's OK because browser should support it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. i18n might be getting a bit ridiculous because I'm even losing track now.
@@ -213,7 +212,7 @@ class Util { | |||
*/ | |||
static formatMilliseconds(ms, granularity = 10) { | |||
const coarseTime = Math.round(ms / granularity) * granularity; | |||
return `${coarseTime.toLocaleString(Util.numberDateLocale)}${NBSP}ms`; | |||
return `${Util.numberFormatter.format(coarseTime)}${NBSP}ms`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
fixes part of #7238 (second bullet point)
tl;dr better Intl polyfill guard and switch our Util number formatters to use
Intl
methods. No change to ICU message formatters.Our current polyfill relies only on browserify build ignoring
intl
, which means we're polyfilling even on node that hasfull-icu
. But if we base it just on ifIntl
and (e.g.)Intl.NumberFormat
are defined we won't get locales onsystem-icu
orsmall-icu
where those are defined but only (usually) a single locale is supported.Instead, we can use the approach suggested by
intl-locales-supported
and check if all our needed locales are supported and polyfilling if not. If we take that literally, though, we'll still polyfill because for some reason (TODO:)'no'
and'tl'
aren't included in the latestIntl
release in Chrome/Node.Instead we just check that a representative sample of locales are supported and, if so, count that Intl as up-to-date enough. I adopted the same set of locales that
intl-pluralrules
uses but we could tweak to our own needs.Finally, our
Util.format*()
methods are switched to usenew Intl.NumberFormat().format()
directly instead of indirectly throughNumber.toLocaleString()
. This means that the Intl polyfill will be picked up in Node withoutfull-icu
and anywhere we were using those formatters (mostly in the renderer) will now be formatted. And we can re-enable some long-skip
ped tests.