Comments (182)
Strong +1 for including Intl
support out-of-the-box in Hermes, having just encountered this limitation ourselves!
At the moment the lack of Intl
support on Android RN is a major source of inconsistency in behaviour between iOS and Android. On iOS Intl
'just works' as expected, but not so on Android, where you're stuck trying to find some workable solution to restore parity in behaviour on the two platforms. On iOS, Number.prototype.toLocaleString()
for formatting numbers and currency values all work as expected, as does Date.prototype.toLocaleString()
for dates, and all the Intl
API...
The lack of Intl
support on Android's out-of-the-box JSC was one significant hurdle we encountered in enabling our iOS-first RN app for Android. As many folks have said, the pollyfills just don't work well enough and feel like an unsatisfactory hack.
For our investment app, date/time and currency formatting are the primary drivers, though relative time rules, plural rules, and list formats would all undeniably help offer a more polished user experience.
Needing to include a custom JSC build on Android is non-trivial and really shouldn't be necessary for such a fundamental piece of functionality!
If Hermes is worried about size, some RN config to optionally exclude Intl
support for those (rare?) apps that don't need it might be a way forward. Surely these days most commercial quality apps need to reliably present localised time & date or numeric/currency values?
If Hermes did fully support Intl
, switching from the existing JSC would be a no-brainer for us. On the other hand, no support means we would perhaps be better off with a JSC build that does support it?? Feels like a problem that Hermes needs an answer to, one way or the other.
I18n certainly is darn complicated, which is precisely why it's so important that the platform itself offers first-class support for Intl
out of the box! Even on Android.
from hermes.
Its main use cases (most popular function it has) to the RN community
Enabling I18n for apps regarding:
- Date / Time Formats
- Relative Time Formats
- List Formats
- Number (also Currency) Formats
- Plural Rules
Any important libraries that depend on it
https://github.com/formatjs/react-intl (> 10K Stars)
https://github.com/moment/luxon (> 8K Stars)
What alternatives exist (is there a JS-only way to implement it?)
As pointed out by @fbartho, polyfilling doesn't work properly. Every other solution is incomplete at least regarding locale rules around the world.
but I think it was related to ICU's binary size
If it is just about binary size, it could be done like JSC: a variant with Intl.
See https://github.com/react-native-community/jsc-android-buildscripts/#international-variant
and that it is not part of the normal EcmaScript JS spec
However, lots of functions that are part of the ECMAScript 2015, are dependent on Intl to function "properly", or at least need a locale aware implementation anyway. For example:
20.3.4.39 Date.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] )
An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the Date.prototype.toLocaleString method as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of the toLocaleString method is used.This function returns a String value. The contents of the String are implementation-dependent, but are intended to represent the Date in the current time zone in a convenient, human-readable form that corresponds to the conventions of the host environmentβs current locale.
from hermes.
An update on plans for Intl support. Our primary motivation for building Intl support is to make Hermes usable as a replacement for JSC for the most apps on Android.
Currently, the android community build of JSC doesn't support all of ECMA 402. In particular, the only properties of Intl which it supports are getCanonicalLocales, Collator, NumberFormat, DateTimeFormat, and PluralNames. The latter was only relatively recently implemented in JSC. In addition, DateTimeFormat.formatRange/formatRangeToParts are not implemented by JSC.
Given the history of Intl JSC, we will plan initially to implement getCanonicalLocales, Collator, NumberFormat, and DateTimeFormat, excluding the range methods. Later, we can add more functionality as needed.
If anybody knows of RN app which uses any other Intl APIs, please comment and tag me. Thanks!
from hermes.
Intl is super important for us, and unfortunately, it's a blocker for my team. The Polyfills we tried before switching to jsc-intl weren't complete (they allowed compilation/basic testing, but didn't work in actual localized environments).
Is there a plan for when Intl might be discussed again for the Hermes Engine?
from hermes.
Intl is a major concern for all the apps I have ever worked on. Today we're using react-intl
which is one of the most popular React libraries for handling intl. As stated before, there are no polyfills that work properly on Android right now.
I'd be curious if someone could tell us what Facebook uses to handle intl in their React Native apps? Specifically for number and date formatting.
from hermes.
Sorry about the delayed response here. Internally at Facebook we use fbt
, with its own specific translation assets handling, and translation dictionary shipped with the app binary. fbt was open sourced a while back, and fortunately we have RN android variant in OSS now.
See:
https://github.com/facebookincubator/fbt
https://github.com/facebookincubator/fbt/tree/master/packages/fbt-rn-android-native
https://github.com/facebookincubator/fbt/tree/rn-demo-app
The published version currently builds for Android but AFAIK there is nothing preventing porting to iOS.
On the subject of Intl support: we would like to have it in Hermes, but it isn't our top priority, since, as described above, we don't use it internally. We welcome help from the community in implementing it.
from hermes.
EDIT: I found that Chrome Status shares data publicly on the usage of these APIs. I have gathered and ordered that data for the Intl APIs in this comment.
Additional anecdotal data is probably not as helpful now.
We are revisiting Intl
support on Hermes and need your help figuring out which functions to prioritize. There are a ton of Intl
APIs and I'd bet that only a handful of them are the most critical functions blocking Hermes adoption.
Please help us understand the particular function calls that are blocking your ability to use Hermes. For example, I've seen Number.prototype.toLocaleString()
mentioned twice in this thread. That's the kind of specific example I'm looking for. "Relative Time Formats" is too vague. I'm sure there are many more functions that would be really nice to have but aren't as critical. Please mention them, but separately so I can track that.
Intl functions blocking usage of Hermes:
Number.prototype.toLocaleString()
Date.prototype.toLocaleString
Date.prototype.toLocaleTimeString
Intl.DateTimeFormat().resolvedOptions
Intl.DateTimeFormat().format()
(specific options)Intl.NumberFormat().format()
(specific options)Intl.RelativeTimeFormat().format()
String.prototype.localeCompare
Also, I saw a mention of the react-intl project. Can someone go through that and identify what Intl
functions it uses and share those here?
Thanks!
from hermes.
Big thanks to this thread, Hermes is great but we need support for Intl
which most fundamental part of any app.
from hermes.
One thing to add: Intl works perfectly out of box on iOS as it has to use its V8 (oops!) JavaScriptCore engine which already integrates this. So I find it strange why we're trying to back off from Intl support as this would just confuse RN developers with the iOS and Android feature gap.
from hermes.
Hello, I'm the maintainer of react-intl
& formatjs
& also a delegate on TC39/ECMA-402. We got quite a few requests to support non-traditional JS engines that don't have Intl
, and sounds like hermes
is 1 of those. There're no hierarchy of which Intl APIs are more important/popular from my perspective because most implementations either use libicu
or has native bindings that wraps around icu4j
/icu4c
.
On top of that the standards are evolving. formatjs
has polyfills for stage-3 APIs like Unified NumberFormat which allows you to format units like 5 feet
or compact notation like 1 thousand
. What you'd gain from native implementation in hermes vs polyfill would basically means hermes would have to package w/ CLDR data (& follow its upgrade cadence as well). That's a non-trivial amount of bytes.
Performance-wise I don't see a huge advantage unless you're handling subsecond re-rendering.
The other reason why it's hard to pick and choose 2, 3 or 4 APIs to support is because if you look at the spec, they share a lot of abstract operations & CLDR data. For example, you typically always have to start with locale negotiation, which is the process to match what the user asks for, and what data you have. None of the browsers package ALL of CLDR so this is especially important. From there you start figuring out CLDR dataset(s) based on the API and then join them together to produce the best-effort
output (that's right, ECMA-402 is best effort & not correct).
If I were to rank, the sequence you basically need would be something like:
Intl.Locale
because you need locale negotiation, whether public or abstractIntl.DateTimeFormat
because you need 2 datasets: CLDR for pattern & IANA for timezone so it might help a lot of people to not have to polyfill those giant datasets.Intl.PluralRules
because it's very foundational, even toNumberFormat
(to determine things like1 dollar
vs2 dollars
)Intl.NumberFormat
because it's an important primitiveIntl.RelativeTimeFormat
is cherry-on-top.
The class of problem involving string like Collation
algorithm is fairly separate and not necessarily required.
Happy to chat more :)
from hermes.
How does facebook handle Intl in their apps when using Hermes?
from hermes.
I'm currently using the following polyfills for Hermes:
- intl (https://github.com/andyearnshaw/Intl.js)
- @formatjs/intl-pluralrules (https://github.com/formatjs/formatjs/tree/master/packages/intl-pluralrules)
- @formatjs/intl-relativetimeformat (https://github.com/formatjs/formatjs/tree/master/packages/intl-relativetimeformat)
I'm using https://lingui.js.org/ as a higher level abstraction over intl apis.
I don't have anything blocking usage of hermes since it works fine with these polyfills. First thing would be to try and remove usage of the intl polyfill, this one actually implements a lot of apis, the list is available here https://github.com/andyearnshaw/Intl.js#implemented.
Here are some Intl apis I use either directly or through lingui-js:
- Intl.NumberFormat for currency formatting.
- Intl.DateTimeFormat for date formatting.
- Intl.RelativeTimeFormat for relative date formatting (x days ago).
from hermes.
Microsoft is staffing up people to work on the Intl implementations that @mhorowitz mentioned live in https://github.com/facebook/hermes/tree/master/lib/Platform/Intl
from hermes.
FWIW we just released Intl.DateTimeFormat ES2021 polyfill so basically all the Intl APIs are polyfills except Intl.Collator
https://formatjs.io/docs/polyfills
from hermes.
if you look over in the Pull Requests tab, you can see that this work is progressing. I'm excited to see it happening!
Great! I see that several of these were recently resolved. π
from hermes.
As @danilobuerger clearly states, there is no complete and reliable JS-only solution to this. For I18n apps Intl
is needed. It adds to binary size, but as I understand it that's because I18n is so darn complicated with so many edge-cases.
from hermes.
We ended up using react-native-v8 which provides similar performance benefit like Hermes but has full intl support.
from hermes.
@gpawlik A couple weeks ago I landed the framework to bridge between JS to C++ to Java for the APIs I mentioned above. Most of the code lives under https://github.com/facebook/hermes/tree/master/lib/Platform/Intl. This isn't yet very usable, as the changes to build using CMake have not yet landed. We'll be working on that soon.
Once that happens, we need real implementations of the Java API there in terms of the Android ICU library. We have had a community member express intent to work on this, but I cannot speak for their plans directly. Of course, PRs are always welcome!
from hermes.
That's a great point @TheTimeWalker -- this is a "platform compatibility issue" where iOS & Android's JavaScript engines differ. (Nit: iOS uses the JavaScriptCore engine rather than the V8 engine, but your point is the same).
I guess the key question is: What is this project's driving mandate with regards to differences between iOS & Android? -- Presumably the expectation is that there shouldn't be significant framework-level differences? Especially not in things that can't be polyfilled-well.
Unfortunately, the existing Polyfills in this case are insufficient. React-Native developers targeting more than one language will be stuck on jsc-intl unless this feature is provided by Hermes!
from hermes.
I use Luxon and it uses Intl apis quite a bit. I assume lots of other people also use Luxon for handling dates and timezones and other things.
Luxon uses or supports at least these Intl methods:
Intl.RelativeTimeFormat
(constructor)Intl.RelativeTimeFormat.prototype.format
Intl.RelativeTimeFormat.prototype.formatToParts
Intl.DateTimeFormat
(constructor)Intl.DateTimeFormat.prototype.formatToParts
Intl.DateTimeFormat.prototype.format
Intl.DateTimeFormat.prototype.resolvedOptions
Date.prototype.toLocaleString
from hermes.
@TheSavior
I believe we are specifically interested in DateTime and TimeZone related ones such as
- Date.prototype.toLocaleString
- Date.prototype.toLocaleTimeString
- Intl.DateTimeFormat().resolvedOptions
- rest of timezone related things
For react-intl it is probably better to start with intl-messageformat as it is most used one.
@fbartho
I believe moment is not actually using Intl.
from hermes.
It looks like the ChromeStatus page has usage numbers for these APIs:
- String.prototype.toLocaleLowerCase() 18.143881%
- Number.prototype.toLocaleString() 15.742356%
- DateTimeFormat 8.755547%
- String.prototype.localeCompare() 8.739834%
- Collator 5.05094%
- NumberFormat 3.182229%
- String.prototype.toLocaleUpperCase() 1.832129%
- Date.prototype.toLocaleString() 1.7049%
- Date.prototype.toLocaleDateString() 1.19445%
- Date.prototype.toLocaleTimeString() 0.796161%
- RelativeTimeFormat 0.165491%
- PluralRules 0.136803%
- ListFormat 0.00172%
- Locale <=0.000001%
This is probably better than any anecdotal data we are going to get here, although I'm still open to anecdotal data. π
from hermes.
I recommend my library users to use the following code (for my date picker library). (Thanks a lot @longlho!)
// in your index.js file
if (!!global.HermesInternal) {
require('@formatjs/intl-getcanonicallocales/polyfill')
require('@formatjs/intl-pluralrules/polyfill')
require('@formatjs/intl-pluralrules/locale-data/nl') // use your language files
require('@formatjs/intl-relativetimeformat/polyfill')
require('@formatjs/intl-relativetimeformat/locale-data/nl') // use your language files
require('@formatjs/intl-listformat/polyfill')
require('@formatjs/intl-listformat/locale-data/nl') // use your language files
require('@formatjs/intl-displaynames/polyfill')
require('@formatjs/intl-displaynames/locale-data/nl') // use your language files
require('@formatjs/intl-numberformat/polyfill')
require('@formatjs/intl-numberformat/locale-data/nl') // use your language files
require('@formatjs/intl-datetimeformat/polyfill')
require('@formatjs/intl-datetimeformat/locale-data/nl') // use your language files
require('@formatjs/intl-datetimeformat/add-all-tz')
require('@formatjs/intl-locale/polyfill')
// https://formatjs.io/docs/polyfills/intl-datetimeformat/#default-timezone
let RNLocalize = require('react-native-localize')
if ('__setDefaultTimeZone' in Intl.DateTimeFormat) {
Intl.DateTimeFormat.__setDefaultTimeZone(RNLocalize.getTimeZone())
}
}
from hermes.
@RichardLindhout if you look over in the Pull Requests tab, you can see that this work is progressing. I'm excited to see it happening!
from hermes.
Our codebase also directly uses
from hermes.
@TheSavior Intl.XFormat apis actually don't really have many functions. AFAIK the usage is pretty much always:
new Intl.XFormat('locale').format(thing)
For example Intl.NumberFormat
:
new Intl.NumberFormat('de-DE').format(number)
Actually I think what you are looking for is which options on the format constructor we want to support first. Here's a list of options that should be supported / I'm using
NumberFormat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat/NumberFormat)
- style: I think all 4 options would be important to have
- currency: needed for currency support
- currencyDisplay
- minimumFractionDigits
- maximumFractionDigits
DateTimeFormat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/DateTimeFormat)
- dateStyle
- timeStyle
- hour12
- weekday, year, month, day, hour, minute, second
RelativeTimeFormat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/RelativeTimeFormat)
This one doesn't have much options so I guess everything.
from hermes.
If you gotta do it, I'd personally recommend stage-4 of ES2020 because right now there's no way to monkey-patch Intl APIs from ES2015 to, say ES2019, so having old support is kinda worse than no support you'd always lag behind MDN docs. Right now stage-3 polyfills are basically the full implementation.
from hermes.
FWIW we just released Intl.DateTimeFormat ES2021 polyfill so basically all the Intl APIs are polyfills except
Intl.Collator
formatjs.io/docs/polyfills
Hi, I tried using your polyfill to use hermes on my RN app but I cannot get it working
I keep getting Property 'Intl' doesn't exist, js engine : hermes
I don't think I missed a step though
Could you help me on the matter ? Hermes would be a huge boost on my app
from hermes.
@RichardLindhout Thanks, it's good to know there are workarounds while we work on Intl.
I'm curious, what's the size impact of the JS polyfills on the app? What if someone wants multiple languages?
from hermes.
So to clarify I'm talking about this: https://formatjs.io/docs/polyfills/intl-relativetimeformat#dynamic-import--capability-detection
I'm not super familiar with how RN does bundling. What I meant is you can still ship w/ ALL locales, just don't load them ALL at once or it'll definitely OOM.
The core polyfill are typically small (~20 - 40KB unminified). Locale data for ALL locales are quite large
API | Size (unminified) |
---|---|
Intl.getCanonicalLocales | 0 |
Intl.Locale | 0 |
Intl.PluralRules | 848K |
Intl.NumberFormat | 22M |
Intl.DateTimeFormat | 22M CLDR + 420K IANA TZ |
Intl.RelativeTimeFormat | 3.4M |
Intl.ListFormat | 2.2M |
Intl.DisplayNames | 15M |
So total unminified unzipped is around 85M. Now I did a quick gzip on ru
which is typically the largest & most complex locale and compression shaves it down by ~83% so ballpark 14M gzipped? There are 543 locales so you can do the math π
Now this is not apple to apple bc JSC (WebKit) is notorious for being behind on Intl APIs, so tbh I don't what's included in JSC with Intl variant. There's a high chance if u use JSC w/ Intl u'd still need polyfills (e.g https://caniuse.com/#search=relativetimeformat or Intl.NumberFormat
ES2020)
from hermes.
That's if you package 543 locales, which, I don't think you should or need to, 6MB worth of CLDR data would be 250 locales, which, I still don't think you should or need to support π
Supporting another locale (aside from the framework & data to do so) requires operation & QA as they don't always appear the same way (think of bidi, truncation, different calendar like buddhist, different numbering system like tibet...). I haven't seen any app that supports more than a handful.
The polyfill approach has worked well for the web from what I've seen and that has a much stricter size & runtime constraint than native (e.g ECMA402 spent a lot of time discussing which unit
are sanctioned to be part of spec bc of size).
That said, I'm not familiar with the RN ecosystem so just my 2c.
from hermes.
Hi,
We also need the support of Intl in hermes.
from hermes.
Hey folks,
Is that any workaround suggested for Number.prototype.toLocaleString()
while they don't implement Intl
?
We broke our minds for some weeks with this bug because when we were using the debug mode in React Native, the Number.prototype.toLocaleString()
works, I think because it uses my browser engine to run JavaScript, but as soon we assemble the app or turnOff the debug mode, Number.prototype.toLocaleString()
starts to no work.
from hermes.
@OtacilioN -- On my team we're still using org.webkit:android-jsc-intl:r245459
until Hermes supports Intl
(we would love to use Hermes for Android Performance reasons!!) Not to give you useless advice, but that's what I recommend.
And I ran into exactly the same debug-time issues with some other features including Proxy (also missing in Hermes, #33), before that was updated to be available on android-jsc. I feel your pain!
from hermes.
@longlho I started looking into this, and I have a generic question. ECMA 402 is written in terms of CLDR data, but icu and icu4j are written in terms of higher-level abstractions, which in turn use CLDR data underneath. So, the APIs have strong parallels, but spec compliance is not clear. For example, if implemented new Intl.NumberFormat(...).format(number));
by using com.ibm.icu.number.NumberFormatter
and it's associated classes, would this be a proper implementation? Or am I going to run into gaps and inconsistencies? Is test262/test/intl402
detailed enough to provide confidence?
from hermes.
Is there any progress this? Is it possible to prioritize on this critical feature?
Recently highly popular react-native-reanimated library introduced new version 2 based on Turbomodules.
Now it supports on Android only Hermes engine (no JSC support yet, no recent plans). At the same time Hermes doesn't support Intl, which is highly popular in i18n (react-intl).
This leads to blocking on Intl support feature. Developers can't update their apps to Reanimated V2.
from hermes.
I typically recommend dynamically polyfill locale on demand. For intl-numberformat you'll likely OOM if you load everything. Note that Chrome doesn't even ship with all locales.
from hermes.
I think the main issue with the polyfill approach and supporting a large number of locales is that currently RN doesn't have good support for code splitting and loading bundles at runtime, which I'm pretty sure is how you can scale intl polyfills on the web.
from hermes.
Hermes is mainly a C++ library. It doesn't control how JS is packaged or loaded.
It sounds like your suggestions are potentially relevant for React Native, if someone wanted to contribute it.
For now, our strategy for Hermes is to have the Intl APIs call into the Java android.icu APIs, so we can ship only the necessary glue between them. I think this is more sustainable in the long run, although it might not get the functionality into the VM as quickly.
from hermes.
Is DateTimeFormat already supported?
None of Intl is supported yet, but it's being worked on.
from hermes.
It will help us prioritize work on Intl
if we know the following things:
- Its main use cases (most popular function it has) to the RN community
- Any important libraries that depend on it
- What alternatives exist (is there a JS-only way to implement it?)
I don't remember the exact conversation we had about Intl
, but I think it was related to ICU's binary size, and that it is not part of the normal EcmaScript JS spec.
@avp or @ridiculousfish have more context on this
from hermes.
@dulinriley is there any more information that you need in order to prioritise this issue?
from hermes.
I'm not entirely sure how to search react-intl
for "particular function calls" that need to be supported. I'm trying to join their slack to figure that out.
In addition to react-intl, a super popular library is MomentJS -- https://momentjs.com & its sub library moment-timezone https://momentjs.com/timezone/
Moment has a CI testing various browsers/environments, so maybe you can add hermes to that list, and then get an enumeration of the methods that are missing / fail tests?
from hermes.
Hey @longlho, thanks for the response. We are definitely worried and want to do everything we can to avoid increasing the size of the binary substantially. Our current thinking is that the implementations of these APIs in Hermes would internally use the native Android APIs so that we wouldn't have to include that CLDR data. Does that seem feasible with your understanding?
from hermes.
The other thing to note is that NumberFormat
/DateTimeFormat
in ES2015 is different from ES2017 & ES2020 π. The tendency of ECMA-402 right now is to add more things to options
instead of new APIs.
from hermes.
yeah test262 should be enough. Browsers all use icu4c
under the hood so I think it should be fine for you guys (e.g V8 https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/objects/js-number-format.h)
from hermes.
@mhorowitz would you be able to give us an update on the progress please?
from hermes.
@likern https://github.com/longlho/hermes-intl-demo
from hermes.
@RichardLindhout The gradle files says JSC with Intl support is 6mb larger, per architecture. There is no such thing as an international version of JSI.
I was asking about the size of formatjs polyfills exactly because I was interested in the size impact. Based on what @longlho says, it sounds like adding all languages will blow out your memory, so that's not a good option. But this doesn't tell me even what a single language plus the base polyfills costs in app size.
@longlho when you say "polyfill locale on demand" do you mean add it to your application when people ask for different locales? Since an RN app ships with its JS bundle, I'm not sure what else this might mean.
from hermes.
Yup that's right, but as i said you don't need to support 200, or even 100 locales
from hermes.
As I mentioned, Hermes doesn't implement import
yet, so it's doing none of what's in the spec :-) I said we're outside of my domain because I don't personally know anything about our implementation plans or strategy for import
. Someone else is working on that.
My message above is attempting to describe the status quo of the current behavior of Hermes as the engine for React Native, where whatever import
does, it's entirely out of Hermes's control. Startup performance is one of our primary metrics, so I imagine we're doing things as lazily as possible.
from hermes.
from hermes.
Yeah, we had some bugs related to proxy too, fortunately, checked the code of the lib that we were using, and made a pull request to not use proxy when is not supported, actually, the usage of proxy was not really necessary in the lib.
Unfortunately, we made the decision of migrating to Hermes a couple of months ago and getting back to JSC could be really painful now. I could not imagine that an engine created by facebook would not support localization. π’
from hermes.
@patrickkempff I don't think they use it in their apps.
from hermes.
@dlebedynskyi thanks, from my quick searching it looks like IntlMessageFormat isn't part of a finalized spec. Am I looking in the wrong place?
from hermes.
@janicduplessis, it looks like the Intl APIs you list are a collection of multiple functions. Do you know which functions in those APIs you use? The more specific the better here :)
from hermes.
Thanks @janicduplessis @jozan, updated
from hermes.
@TheSavior Would it be feasible for this Intl
support to be built on top of JSI interfaces such that other JS engines with JSI implementations (beyond Hermes) can take advantage of this?
from hermes.
@TheSavior I think another thing to consider is the binary size impact of each Intl api.
from hermes.
Not to mention CLDR data compression in and of itself is a whole problem set, because of how locale fallback works (e.g en-GB
-> en-001
-> en
) so yeah, the increase in size won't be trivial.
We're having debate in ECMA-402 during Unified NumberFormat on what unit data to package, which is why the spec only has 6 sanctioned units. It's definitely a point of contention.
from hermes.
Hey @longlho, thanks for the response. We are definitely worried and want to do everything we can to avoid increasing the size of the binary substantially. Our current thinking is that the implementations of these APIs in Hermes would internally use the native Android APIs so that we wouldn't have to include that CLDR data. Does that seem feasible with your understanding?
Yes that's definitely feasible. Android does package icu4j
AFAIK.
from hermes.
Cool, phew. π
This is why we are trying to figure out which APIs are the most critical to support. The Hermes implementations will require finagling the Android APIs to match the JS spec. We'd like to unblock the majority of people by prioritizing the common APIs first
from hermes.
I was thinking we could strip unused locales but this is even better, I like this approach.
from hermes.
If that's your approach I think you'd basically need DateTimeFormat
& NumberFormat
as the bare minimums (to be on par w/ IE11 π). Intl.PluralRules
& Intl.RelativeTimeFormat
are fairly small & new. PluralRules
are mostly useful in the context of MessageFormat and rarely used raw.
from hermes.
Even passing through to icu, there's still a lot of APIs. Even if we have to do it all, it is useful to know what to prioritize and do first.
from hermes.
Yea when talking about XFormat
apis it would be useful to know which options are used the most (see #23 (comment)). Or just focus on ES2015 options first.
from hermes.
Forgot another thing: have you guys run hermes through test262 yet? Intl API abstract ops rely on several building blocks within the core JS spec (ECMA262) to produce a spec-compliant output (e.g things like digit truncation, rounding & BigDecimal
...). Therefore it's pretty important for a JS engine to pass test262 π
from hermes.
We run hermes through test262 on a continuous basis, but we skip parts we know we don't implement, like Intl.
from hermes.
Ok cool that's good to hear π
from hermes.
You're looking for https://formatjs.io/docs/polyfills/intl-datetimeformat/#requirements
For Hermes it's likely you need everything in the dep chain https://formatjs.io/docs/polyfills so Intl.getCanonicalLocales
, Intl.PluralRules
, Intl.NumberFormat
& Intl.DateTimeFormat
from hermes.
@longlho I've installed all polyfills, didn't work for me. I see this error:
[Tue Jun 23 2020 23:42:49.868] ERROR ReferenceError: Property 'Intl' doesn't exist, js engine: hermes
from hermes.
from hermes.
from hermes.
from hermes.
I recreated my i18n code based on your repo https://github.com/likern/hermes-intl-demo. Looks like on expo and ejected expo it's working fine.
If I find the source of this error I let you know.
from hermes.
@likern It's working fine because you don't have Hermes enabled: https://github.com/likern/hermes-intl-demo/blob/master/android/app/build.gradle#L80.
from hermes.
In my case I needed at least the following polyfills to make the DateFormatting working
import '@formatjs/intl-getcanonicallocales/polyfill'
import '@formatjs/intl-pluralrules/polyfill'
import '@formatjs/intl-pluralrules/locale-data/nl'
import '@formatjs/intl-numberformat/polyfill'
import '@formatjs/intl-numberformat/locale-data/nl'
import '@formatjs/intl-datetimeformat/polyfill'
import '@formatjs/intl-datetimeformat/locale-data/nl'
from hermes.
For the multilanguage version of JSI it's 6 MB stated in the build.gradle for all locales.
I don't know what's the impact of of formatjs but I think it's a lot less since we can pick the languages needed and even if you added all languages I don't think it would be 6MB.
Maybe ask @longlho on this since he is a maintainer of formatjs.
It would be nice if we could specify which languages to bundle with Hermes to keep the selling point of small binaries (if it comes as close to the 6mb of the international JSI π)
from hermes.
For reference this is likely the list of locales Chrome supports: https://src.chromium.org/viewvc/chrome/trunk/src/third_party/cld/languages/internal/languages.cc
from hermes.
@RichardLindhout The gradle files says JSC with Intl support is 6mb larger, per architecture. There is no such thing as an international version of JSI.
I was asking about the size of formatjs polyfills exactly because I was interested in the size impact. Based on what @longlho says, it sounds like adding all languages will blow out your memory, so that's not a good option. But this doesn't tell me even what a single language plus the base polyfills costs in app size.
@longlho when you say "polyfill locale on demand" do you mean add it to your application when people ask for different locales? Since an RN app ships with its JS bundle, I'm not sure what else this might mean.
I think we can't lazy load yet in RN but it would improve startup time and prevent OOM when you have a lot of locales e.g. something like this (https://github.com/microsoft/react-native-lazy-index)
There is no such thing as an international version of JSI.
I did mean JSC :-D ->
/**
* The preferred build flavor of JavaScriptCore.
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
from hermes.
FWIW, current RN's jsc-android used ICU from Chromium.
Chromium maintains their locale list for android at https://chromium.googlesource.com/chromium/deps/icu.git/+/master/filters/android.json.
Different jsc-android version may use different ICU version,
here I am posting the latest Chromium list.
from hermes.
That doesn't look right. That's a language list, not locale list and they are different (e.g en vs en-GB)
from hermes.
Oops, it was locale list before but changed to filter by language after this CL
from hermes.
hmm I don't know enough about chromium lang filter to understand what the change entails.
from hermes.
how RN does bundling
RN apps include all the JS in the app which comes from the store. So even if you loaded stuff as needed, your android store app with hermes + all languages would include 14mb of Intl data. This is a significant fraction of the size of most single-ABI apps. This is why we've been trying to avoid a polyfill approach.
from hermes.
It would be really nice if we could force the locales which are needed in the app/build.gradle
file.
It would also be nice if it would load the provided locales dynamically based on the Intl usage so it would not be in RAM.
E.g English user would never have the Dutch locales in ram.
But maybe that's the case by default I'm not that familiar with how engines or ram bundles work.
from hermes.
Yeah I agree that's the better long term solution. Does Hermes implement dynamic import
though? That's basically the backbone of code splitting.
from hermes.
Does Hermes implement dynamic import though?
Not yet. It's in progress at https://github.com/facebook/hermes/blob/master/doc/Features.md
from hermes.
Ok looks like those 2 combined should be future-proofing Intl
or any future ES spec changes/polyfill interop. Polyfills are also used to correct buggy native implementations AND unsupported locales which has a fairly long release cycle as well you already mentioned.
from hermes.
import is itself polyfilled, so people can still use it for those purposes. They just can't do it dynamically.
from hermes.
@mhorowitz can you provide more details?
from hermes.
@longlho About what exactly? the import polyfill?
from hermes.
The can't do it dynamically
part? Does that mean static import
works but not dynamic import
?
from hermes.
We're a bit out of my domain here. I know you can use import
in a React Native application's JavaScript. I believe, but I'm not sure, that this is managed by the metro bundler. What I do know is that from the perspective of Hermes, the JavaScript is precompiled at build time to a single bytecode file, which is included in the APK. Then at runtime, the bytecode file is mmapped into memory and processed by Hermes. This process is designed to be very fast at runtime, which is one of Hermes's startup performance advantages.
Because all the JavaScript is baked into a single mmapped bytecode file, it's not even obvious what dynamic means. Bytecode which hasn't been executed or data which hasn't been referenced may not even be in RAM, because pages in the mmapped file are only read on demand by the operating system.
from hermes.
By dynamic I mean the procedure described in the spec. Now the spec doesn't enforce I/O
or the fact that the Module Record
actually has to be dynamically loaded so it could be static anw. However in the interest of performance, it ideally should be dynamically loaded & evaluated from a JS engine perspective, otherwise you might get a slew of bug reports filed. In this scenario Hermes might have to re-evaluate its loading strategy. Anw sorry for digressing from the initial topic of this thread but I don't see a separate GH issue for dynamic import
support π’
from hermes.
It would be cool if Hermes could use the underlying native implementations of date so the bundle size would not grow at all for Intl support. In JavascriptCore in iOS Intl works without growing the bundle size. But I guess that won't be an options as Hermes would need to implement the Intl api for every platform.
from hermes.
I did a small bit of researching on formatting dates using Intl
and iOS's NSDateFormatter
that I quickly summarized in this tweet: https://twitter.com/vonovak/status/1296454407484256257
I think there is a chance that using Intl
, it might be impossible to get the same date formatting iOS would use in date pickers and other places in the system and other apps, so a RN app using Int
would display dates a little different from what would be desirable if one really cares about date formatting. A workaround would be making calls across the bridge to get a date formatted (not practical) or create a <Text />
component equivalent that would be used to render dates only (not straightforward).
Apologies if you find this a little off the topic π
from hermes.
I personally find that a bit hard to believe since they're all backed by libicu
from hermes.
With Turbomodules asking the native OS what the date format would maybe be just as fast as using a polyfill. Would be interesting because that way no big bundle sizes are required
from hermes.
Is DateTimeFormat already supported?
from hermes.
Related Issues (20)
- WeakRef support HOT 8
- Hermes should throw an exception when implicitly convert Int to BigInt HOT 5
- simplifyBinOp in InstSimplify generates wrong result HOT 3
- The generator function's body is executed incorrectly when the next() method is not called HOT 1
- [Feature Request] Hello World application for JavaScript Http Server
- Async arrow functions are not supported, making 'show source' unusable inside them HOT 6
- An issues with with statements HOT 1
- Hermes should throw an exception when BigInts use unsigned shift HOT 2
- Hermes should throw an exception when Maxium BigInt size exceed HOT 1
- simplifySwitchInst in SimplifyCFG ignores negative zero HOT 1
- iOS App submission will require a privacy manifest and signature HOT 6
- Possible memory leak HOT 30
- Compile failure with optimized ASan builds HOT 4
- Thread 6: "Exception NSException * "Unhandled JS Exception: Error: invalid host, js engine: hermes" HOT 32
- Parser: improve error message when await is used in non-async functions or instead of async
- JSRangeErrorException setting maximumFractionDigits to 0 with Intl.NumberFormat currency style HOT 1
- Unreachable in ES6 is reachable. HOT 1
- Update documentation on using custom Hermes builds HOT 3
- Building Static Hermes on Windows HOT 4
- Problems finding libraries with fresh compile under windows HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hermes.