angular / angular

Deliver web apps with confidence 🚀

Home Page:https://angular.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Issues with the ECMAScript Internationalization API

marclaval opened this issue · comments

Running unit tests in non-Chrome browsers raised some doubts about this API which is currently used in the Date and Currency pipes.

To start with, it is not supported in all Safari versions (desktop and mobile) and older browsers:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
http://caniuse.com/#search=intl

Then, on browsers which support it, the result doesn't match what Chrome does.
On Firefox, one of the test fires this 2 years old bug: https://bugzilla.mozilla.org/show_bug.cgi?id=866372
On IE11, most tests are failing due to discrepancies in output (formatting, white space, special chars,etc).

At the end of the day, it seems only reliable in Chrome, but it is also difficult to polyfill.
So, if anyone has a good solution to that, please speak up!

Would this polyfill help? https://github.com/andyearnshaw/Intl.js (probably not)

It sounds to me as if we should drop this API and instead implement some of these ourselves. This would require a design doc as to what we will and will not support.

I think we should completely drop this for beta.

Is there a workaround this so that pipes don't break in Safari?

Moment works ok, here's a gist with a custom pipe: https://gist.github.com/BostjanPisler/9d3048052468b25f7efa

+1 still happing on beta.5

commented

+1 still happing on beta.7

This helped https://www.npmjs.com/package/intl (date pipe).
I've put intl to package.json.:
"dependencies": { "angular2": "2.0.0-beta.7", "intl": "1.1.0",
Run npm install

Added to index.html:
<script src="node_modules/intl/dist/Intl.min.js"></script> <script src="node_modules/intl/locale-data/jsonp/en.js"></script>
And it helped.

Number pipe causing the same issue on beta.7 (safari)

€ {{price | number}}

Safari:
Can't find variable: Intl in [€ {{price | number }}] in YourOrderComponent@....

The solution suggested by karayv has fixed the problem.

+1, beta.7, running into this with unit tests running karma/jasmine on Phantom for both Currency and Date pipes

Ran into same issue on Safari. @karayv thank you for that quick solution, it worked.
I used script tag for now to load the js file.
https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en

still exists in angula2.beta-12 broke both safari and ios emulator.

quick fix

Add this script tag to index.html

<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script>

now it works on both safari and ios

For a pipe usage like {someDate | date:'shortTime'} along with alzalabany solution to add below script:
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script> in index.html,
the output like 9:5 for 9:05, which is bad.

Still happening in angular 2.0.0-beta.15 which comes with ionic 2.0.0-beta.6.
EXCEPTION: ReferenceError: Can't find variable: Intl

+1 @alzalabany's solution helped (all of my dates and currencies are now displaying on mobile) but am missing final digit in date pipe in the minutes column when I use date:"yMdjm". Ex: I get 5/11/2016, 2:0 PM (missing the last 0)

Due andyearnshaw/Intl.js#152 release 1.2 may fix this. Waiting )

Since the start I went the same way as @bostjanpisler, moment for the date issues and numeral.js for currency/number issues, never had a problem since then. Will wait until all this settles before I consider using the built-in pipe again.

Here's a workaround:
Install the internationalization package:

npm install intl@1.1.0 --save

Then add the following lines to your index.html:

`<script src="node_modules/intl/dist/Intl.min.js"></script>

<script src="node_modules/intl/locale-data/jsonp/en.js"></script>`

@yfain problem with missing leading zeroes with date formatter it not solve. This is workaround with the same package from npm registry.

@yfain this will result in a download far larger than you'll need. Using cdn.polyfill.io as indicated above doesn't present this problem.

@awerlang This is true if you can use cdn.

Agreed to @yfain, you cannot simply use CDN in some cases or just prefer full bundle. For example: bundle for cordova mobile application.

@awerlang using of webpack to build intl.js does not get much overcome due exclude all locales from core.

package.json

 "browser": {
    "./locale-data/complete": false,
    "./locale-data/complete.js": false
  }

My build system build from npm package 31К core + ~20-40К per locale
CDN produces the same 55К with gzip to 15К transfer.
It produces empty if browser natively support Intl feature (I think detected through user-agent header. But as you know simply trust user-agent is not the best technique)

@Delagen I don't mean locales, I mean browsers already support parts of Intl, for Chrome the polyfill is empty, for instance. With a static polyfill you pay the price for the lowest supported browser (safari/IE).

@awerlang if your bundles combined and minified, impact will be less than additional request to server for empty data

Hey, Folks,

I am going to close this issue since the fix is to just add the polyfill.

<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script>

We are not planning on doing any more work on this in angular core team.

@mhevery I disagree with this approach. Here is my reasoning. There are already other issues which require custom polyfills, one comes to mind is an IE issues which requires an IE test shim to be deployed. I'm sure there's many more I didn't come across. If we look in the long term it's not efficient to have a bunch of framework features requiring each their own polyfills. And we all know over time that's what would happen if we don't have a generic polyfill handling mechanism. In my opinion, features included in the framework should either work on their own or on all major browser with the framework provided shims or some framework provided mechanism that's managed over time as features are not longer required in polyfills and/or old browser version support is dropped. Otherwise it's heading down the wrong road. This seem to have been the approach taken for that IE shim I was referring to, it was going to be included in es6-shim or whatever else framework provided polyfill not too sure where it's at now.

@user414 if we include the polyfills in core framework than we will penalize all browser, most of which do not need it.

There are two philosophies, Support the least common denominator OR support the future and polyfill the missing pieces on browsers which do not support it.

You can argue for either one, but Angular has chosen former.

@mhevery Sure I can understand that, but then it needs to be consistent. As discussed here

#7390

and specifically in comment

#7390 (comment)

Which refer that code that do not support IE can't be shipped without having the polyfill in the framework. In addition, by the last statistic of all browser mobile+desktop Safari is second behind chrome so definitely any notion of least common denominator would include Safari as well. I'm all for saying we support the least common denominator, but they need to be clearly identified and be applied consistently. From reading the angular documentation it seemed the least common denominator also included Safari. From that thread above and this one I can't see a clear way, even with the least common denominator polyfill strategy, to explain why this one wouldn't be included in the framework while the other one would be.

@user414

Adding

<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script>

will solve your issue.

@mhevery Thanks. However, it doesn't address my previous observation. In that issue

#7390

they could have very well decided to tell people just add

https://github.com/angular/angular/blob/master/modules/angular2/src/testing/shims_for_IE.js

and your problem will be solved. Instead, and I share @wardbell and others opinion and comment, is that even adding one line is not a good option, it is just not acceptable that the framework doesn't work out of the box on whatever is the least common denominator that was chosen which seem to be latest chrome, firefox, IE and Safari. Or at least, that's my understanding of that discussion thread.

Hi @mhevery,

I am happy to include polifills but the suggested fix of <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script> doesn't fix IE10 when using the date pipe.

I get 'ReferenceError: 'Intl' is undefined at DateFormatter.format ...'.

Could you suggest polyfills to get all browsers to work? What do you do at google to get this to work? Also, I ideally need to use a polyfill that is available other than on cdn.

It would also be really helpful if in the documentation (https://angular.io/docs/ts/latest/api/common/DatePipe-class.html) you could state how to get it to work or what the alternative are rather than just say "this pipe uses the Internationalization API. Therefore it is only reliable in Chrome and Opera browsers.".

I really don't want to abandon angular 2 but unless I can find a way to format dates I am going to be under pressure to use another framework.

Any help you could give to get this fixed would be very much appreciated.

Thanks.

Er, why is this issue closed when the problem is still occurring in the release candidate?

You can add me to the chorus of those saying that the "cdn.polyfill.io" solution is not sufficient for all cases. The polyfill CDN is quite slick, it looks at the user agent to return the correct to set of needed fills, which means they automatically get smaller over time. Problematic cases remaining:

  • Lots of folks deploy behind the firewall, don't want to load any assets from an outside CDN.
  • Other folks deploy on the open web, but for various other reasons have chosen not to depend on any external asset sources.
  • Others are shipping desktop apps, to be bundled with electron or whatever, they certainly don't want to depend on a CDN for this one asset.
  • Mobile web apps bundled using phone gap or whatever... same thing, they are looking to include needed JS, not load it from somewhere.

It seems to me that at least from a technical point of view the product should include either dependencies, or some easy to find list of optional-human-managed dependencies, to support whatever set of browsers the product ends up supporting. They should be provided not only in the form of a suggestion to link to a really smart CDN, but also specific instructions on what additional packages to depend on to grab the minimum-ish needed set of code to run correctly with all the core Angular features (including all the shipped pipes) on all of the supported browsers.

@kylecordes

  • Why is adding your own polyfill not sufficient?
  • What do you think we should do on Angular side other then require that you polyfill the browser?

@mhevery Here is my thinking. As I understand the current polyfill situation:

  • core-js or es6-shim similar: There is a dependency declared by angular, shown in QuickStart, and with documentation pointing me to load this JS on the page.
  • Zones: Same.
  • reflect-metadata: Same.
  • Intl: This one is different. There is no dependency declared. The recommendation above is not even to grab a package and declare your own dependency, it is to use a (rather clever) polyfill specific intelligent CDN which hands you what you need depending on your browser, but leaves one with not much to go on, for cases where pointing to an outside CDN is off the table.

So I don't have a crisp answer, but hopefully this question that helps somehow: Why is it sufficient for Intl (which is quite necessary to use built-in features on common browsers) to only recommend that the developer-user find their own polyfill, while for all the other polyfills, angular artifacts (code and documentation) land the developer-user with a working result up front?

@wardbell can we update the documentation on this?

@mhevery I don't know what we should say in that documentation but happy to discuss. My instinct is to dedicate a page to what we know about browser compatibility and the shims that are available ... by browser.

@kylecordes the core-js script in the docs serves a limited purpose: to make the samples work in the most popular browsers during the time that people are learning about Angular. core-js isn't required by Angular. Certain ES6 features are required by Angular and core-js delivers the essential shims for the browsers we target for documentation readers who are trying to make our samples work. Will it be sufficient for all of the browsers that you target? That isn't the question we tried to answer.

With our (the documentation team) more limited goals, the cdn @mhevery suggested might be adequate ... although it would clearly be the wrong answer for a great many production applications and will trigger at least as many complaints about that approach as we field for our current approach.

I don't have an answer that I like at the moment. I have yet to see an answer that I like. We'll keep working at it.

For now ... I'd say ... use our examples as starting place and adjust to suit your needs.

We will work on getting some documentation out around a richer set of choices.

@wardbell If the documentation samples include use of the pipes, is Intl is less necessary than the other polyfills? Alternatively, are the samples intended to work only on Chrome?

Coming across this for the first time, as long as the angular team is happy with the product from a design/performance/maintenance/robustness/usability perspective, AND some document exists somewhere that helps users with the selected design, then it's perfect.

@wardbell 's comment regarding documentation sounds like a great approach to me. I just want to know up-front what my issues will be; to have a deterministic approach. e.g.:

  • What problems can I expect?
  • What does google recommend to overcome?
  • Am I getting this error because I'm doing it the wrong way?
  • Should I just add every shim package I can find?
  • Will solving this problem cause new ones?
  • Does the design leave notable scenarios without a solution?

We all know what it's like to try to follow the multitude of bad patterns out there. Authoritative advice is really a time-saver.

Reading back on this myself, it seems to me that to enable Angular adoption (assuming that it even a goal), the documentation should recommend a polyfill setup for production use in the supported browsers. I think the notion of the documentation including just enough polyfill hint for documentation readers to get through the examples, is both unhelpful and contrary to the notion of a list of supported browsers.

Just to point something out to those polyfilling: use the npm package for now, don't rely on cdn.polyfill.io for Intl, I've run into this (polyfillpolyfill/polyfill-service#697) which is a dupe of this (polyfillpolyfill/polyfill-service#561) all because of this (3rd-Eden/useragent#86)

If you use the cdn your angular app will break if loaded in the FB in-app browser on iOS

For anyone new to Angular 2 just trying to follow docs and tutorials, @andreafdaf's remedy looks like:

npm install --save intl

Then, for English locale, in your index.html under the other "polyfills" you must already have, add:

    <script src="node_modules/intl/dist/Intl.js"></script>
    <script src="node_modules/intl/locale-data/jsonp/en.js"></script>

Yes, do not use the polyfill from CDN.

//These produce a corrupted time format in Safari v9.1.1
new DatePipe().transform(new Date(), "HH:mm");
new DatePipe().transform(new Date(), 'd/M/yyyy, h:mm a');

MomentJS is the best alternative IMHO.

+1. This completely breaks applications on iOS devices. I have replaced all ' | number' pipes with http://numeraljs.com/ until this is resolved.

+1, I just experienced the same in both Safari and Chrome on iPhone 6 using Date pipe. ReferenceError: Can't find variable: Intl.

+1 just experienced this in RC4 on iPhone 6 with safari ReferenceError: Can't find variable: Intl. I suspect this will catch a lot of people.

Let's give some love here:

  • @Mlaval @laskoviymishka (/anyone interested) could you please create an issue / shared doc that lists the issue with the Intl API - should it be the API itself or a specific implementation of it (check for existing bug report in this case). Please no "this API is crappy" but facts. Thanks.
  • @wardbell Do we have something (i.e. a cookbook) for the Intl polyfill ? May be something to add to the upcoming i18n - btw if you want to catch I'll be gone for one week after tonight.

Thank you @vicb for reopening this.

Completely agree with @kylecordes. The "ok guys, our product works great in Chrome" philosophy is just messed up for real world applications. As a lead dev, what should I tell the PO about the app breaking on his Ipad? "Sorry dude, Angular Team didn't think it was important Angular2 works on Ipad". At least, devs should be warned when using this kind of "need-polyfill" components, so they don't feel like complete idiots when app breaks on the demo day because they didn't know it would be tested out on Safari.

If you plan on keeping that philosophy, then prepare your caniuseangular2feature.com.

You might be right however. It might not be Angular2 Core to do this job, maybe it's some external stuff (webpack? compiler?) that should polyfill this feature or throw a warning? But as devs from real world, we need to feel safe using some Angular2 feature won't break the whole application in some browsers because the answer "just test it out yourself and fix it" is definitely not viable: it is as much painful, not developer-friendly and scary.

PS: Sorry if I've been rude in my message. I just love Angular1 & 2 and some quotes here would just be weapons for the pro-React community that I don't want to hear of.

@wembernard agree with you about several points. Imho there is already couple signs to implement own i18n layer like in a1. Since right now there is active development for i18n itself we could extend it and get rid of Intl.Api.
There is open discussion about future of Intl.Api and overall internationalization issues here #10809. We really need to see every point of view for this problem 🐱

There is a polyfill for Intl. And Angular 2 already depends on a lot of them. So just add the Intl polyfill and next year with iOS 11 and macOS 10.13 you can get rid of it as all major browsers will have support for Intl. So it's just a temporary issue.

@DaSchTour Actually NG2 is not depends on Intl.Api so much. Also you need to keep in mind that this api is not allow us to implement some features (see discussion that i pointing) and we have absolute zero control for it.

@laskoviymishka Angular 2 relies on Intl for ALL formatting pipes. It will crash if you try to use the percent formatting pipe in any release flavor of Safari. It will crash if you use the decimal formatting pipe. Pretty much the only pipe that Angular ships with that won't crash the app is the async pipe.

Maybe the formatting pipes that don't need Intl shouldn't try to load Intl, but that just hides the problem. It's an serious dependency, but it doesn't show up until you start taking the rough edges off your prototype.

@laskoviymishka the point of having zero control is the best about it. You just use something that follows a standard. The user can decide with his OS settings how numbers and dates are formatted. There is not need to implement hunderts of different date and number formats that already have been implemented hunderts of times.
I remember your point from another discussion about not involving moment.js. So why implementing something, that is already there.
And for features that are not there, it shouldn't be so hard to create different pipes so that Intl.API and custom features can live together.

@DaSchTour use someone else repo will lead to same problem - lack of control. From my point of view what we had in NG1 for internationalization was a great. So why not use this approach again?

@johnchristopherjones whole angular 2 dependency over Intl.Api concentrated in single place. Actual format pipes (DatePipe and NumberPipes (Decimal Percent and Currency)) is not related to Intl.Api directly, they use internal wrappers (DateFormatter and NumberFormatter). NumberFormatter is pretty naive - just delegate options to Intl.Api method, but DateFormatter is not so naive, and more like ng1 way to handle formatting except the transformer functions.

Just a note, the cdn.polyfill script mentioned above works well for the devices and user agents that the polyfill service supports, however it defaults to not providing the polyfill to 'unrecognised' user agents. This turns out to include certain samsung mobile/tablet browsers (< 4).

The following update to the script should be made so that the polyfill still loads for unrecognised browers:

<script src="https://cdn.polyfill.io/v2/polyfill.js?features=Intl.~locale.en&unknown=polyfill"></script>

https://polyfill.io/v2/docs/api

When I use angular 2 standard data pipe with IE 11 it isn't working.
In console it doesn't show any errors also.

I just tried to use polyfill-service with their Intl.js and locale-data/jsonp/ru-RU.js and didn't work.
Also I tried to use cdn with link ...polyfill.js?features=Intl.~locale.en&unknown=polyfill and also didn't work.

What i missed?

Kinda start thinking that it's more safe to create my own pipe and use inside moment.js or something. Well in reall world most people use IE 9-11 and i don't think something changed in near 5-10 years.

@szykov

  • try with other browsers,
  • try to add intl polyfill,
  • if still not working, attach a plunker.

@vicb thanks for advising but I just fixed an issue. Seems i messed up with an order of loading scripts. First we add polyfills and then only start loading angular libraries. It's very make sense but I kinda messed here because a have loading scripts on a different html pages.

Now my loading libraries part looks like this:

    <!-- 1. Load libraries -->
    <!-- Polyfill(s) for older browsers -->
    <script type="text/javascript" src="~/node_modules/angular2-ie9-shims/shims_for_IE.prod.js"></script>
    <script type="text/javascript" src="~/node_modules/polyfill-service/node_modules/intl/dist/Intl.min.js"></script>
    <script type="text/javascript" src="~/node_modules/polyfill-service/node_modules/intl/locale-data/jsonp/ru-RU.js"></script>

    <script type="text/javascript" src="~/node_modules/core-js/client/shim.min.js"></script>
    <script type="text/javascript" src="~/node_modules/zone.js/dist/zone.min.js"></script>
    <script type="text/javascript" src="~/node_modules/reflect-metadata/Reflect.js"></script>
    <script type="text/javascript" src="~/node_modules/systemjs/dist/system.src.js"></script>
    <!-- 2. Configure SystemJS -->
    <script>System.packageWithIndex = true;</script>
    <script type="text/javascript" src="~/systemjs.config.js"></script>
    <script>
        System.import('app').catch(function (err) { console.error(err); });
    </script>

Also a small note:
Using this link https://cdn.polyfill.io/v2/polyfill.js?features=Intl.~locale.en&unknown=polyfil or
https://cdn.polyfill.io/v2/polyfill.js?features=Intl.~locale.en didn't work for me also because it was alwasy empty in my case when was using IE browser.

Result was something like this:

/* Polyfill service v3.12.1

Just ran into this too. Using 2.0.1 I npm installed intl and then added the following to my polyfill.js

import 'intl/index';
import 'intl/locale-data/jsonp/en.js';

I had the same problem too with ionic2 rc1. After applying the solution above, jit environment is fine, but AOT is still failing.

import 'intl/index';
import 'intl/locale-data/jsonp/en.js';

is NOT working for us unfortunately.

failing example:
{{ entry.value | currency:'USD':true:'1.2-2' }}
{{ item.expiryDate | date:'MM/yy'}}

You guys I made a low-footprint, minimalist, en-US only, date formatting library suitable for a custom pipe. I'm using it until all this gets sorted out.

@simonh1000

Hi Simon, how did you do it, where did you do it? Thank you,.

@webia1 see my earlier answer

@grapemix are you aware of a solution for this? Holy cow i've been going crazy of this... My app has been silently failing and it took me days to figure out what in the world was going on. Trying to use the currency pipe was the problem; what a huge pita.

@joshgarwood not really. If you really in urge and willing to applying temp solution, you can try GaryB432's solution. Or just left the ugly long number like me for a while.

As a temporary fix I created a custom pipe that uses moment.js to format the date:

import { Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';

@Pipe({
  name: 'customdate'
})
export class CustomDatePipe implements PipeTransform {
  transform(value: string, arg: string): string {
     return moment(value).format(arg);
  }
}

So I can use it like this on my views:

{{ myDate | customdate: 'DD/MM/YYYY' }}

This issue accumulated a lot of comments and while we are thankful for all inputs here it is getting harder to see what is actionable here. So @vicb and I went through the entire issue / all comments once again and here is short summary of real issues being raised:

  1. people are not thrilled about using polyffils, which is understandable. Even more so if usage of polyffils is not documented;
  2. there are inconsistencies in Intl API implementations across browsers;
  3. the Intl API is not flexible enough to cover all use-cases

Let's tackle those points one by one.

ad. 1) Yeh, polyffils are pain. The good news is that now we've got documentation on browsers' support and the Intl polyfill is covered alongside other deps: https://angular.io/docs/ts/latest/guide/browser-support.html. Of course documentation is just one aspect of this all and you could still argue that it would be better to not have this dependency and I agree. The reality is, though, that either we use a polyffill or roll our own code? But even if we roll out our own code you will have to include it (so payload will increase, even if we duplicate say 90% of browser's functionality).

ad 2) and 3) So the real question here is this: is the Intl API "broken beyond repair" (in terms of lacking features, bugs, inconsistency across browsers etc.)? I mean, is it broken enough to warrant custom Angular version? I don't think that we've got answer to this question now but we should get one before making any decisions.

Given the above Victor and I are going to look into all the "broken" usages on the Intl API to see if those are fixable (either in browsers or in a polyfill) or not. If we see that the Intl API is broken to the point that there is no much hope for it then we will roll out Angular-specific version. So the focus for the next few days is to review all the real-life issues with the Intl API. There is a great beginning of this work here: #10809.

I'm going to close this issue as a duplicate of #10809 so we can track down all the real-life issues with the Intl API and decide if those are fixable or not.

Including polyfill works like a charm:

Install it with:

  yarn add intl

then include it:

  import 'intl';
  import 'intl/locale-data/jsonp/en.js';
commented

@elgervb — good you mentioned yarn add intl. This was the only way I was able to install intl on Windows machine I've been testing the solution on — for some reason, npm install intl --save failed with fsevents` build failure error. But yarn instruction worked.

Facing the same problem on angular2 final version also. Date pipe is breaking on iOS11 (chrome and safari both). Tried @elgervb 's solution but did not work. Even adding the pollyfill js as said above under index.html did not work. What to do in such case?

commented

@nikhilbhalwankar I've had the same thing happening for me. Only on my iOS device ver 9.3.1. It worked everywhere else. You will find a solution here or, as per @elgervb's answer. You add the import lines in to your .ts file on the page that is having the issues.

Installing npm i intl and npm i intl-locales-supported and then importing them as @elgervb suggested did solve the issue in my case.

import 'intl';
import 'intl/locale-data/jsonp/en.js';

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.