Skip to content
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

v9: ng add @angular/localize doesn't fix error #16890

Closed
julkue opened this issue Feb 7, 2020 · 17 comments · Fixed by #16925
Closed

v9: ng add @angular/localize doesn't fix error #16890

julkue opened this issue Feb 7, 2020 · 17 comments · Fixed by #16925

Comments

@julkue
Copy link

julkue commented Feb 7, 2020

🐞 bug report

Affected Package

The issue is caused by package @angular/localize

Is this a regression?

Yes, the previous version in which this bug was not present was: Angular v8

Description

After running ng update @angular/core @angular/cli on an Angular v8 application the ng serve command ran without errors, but I've seen the following error in the browser console

Error: It looks like your application or one of its dependencies is using i18n.
Angular 9 introduced a global `$localize()` function that needs to be loaded.
Please run `ng add @angular/localize` from the Angular CLI.
(For non-CLI projects, add `import '@angular/localize/init';` to your polyfills.ts file)

as described in the migration guide.

Therefore I've executed ng add @angular/localize like described. But:

  1. This only adds the package @angular/localize to package.json, but doesn't add the import statement
/******************************************************************
 * Load `$localize` - used if i18n tags appear in Angular templates.
 */
import '@angular/localize/init';
  1. Even when manually adding the above mentioned import statement to the polyfills.ts file the error isn't fixed - even after restarting ng serve. I'm still seeing the issue and don't know to resolve it, since I've followed the migration guide.

🔥 Exception or Error

000072

🌍 Your Environment

Angular Version before updating:


Angular CLI: 8.3.23
Node: 12.13.1
OS: win32 x64
Angular: 8.2.14
... animations, common, compiler, compiler-cli, core, elements
... forms, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.803.23
@angular-devkit/build-angular     0.803.23
@angular-devkit/build-optimizer   0.803.23
@angular-devkit/build-webpack     0.803.23
@angular-devkit/core              8.3.23
@angular-devkit/schematics        8.3.23
@angular/cli                      8.3.23
@ngtools/webpack                  8.3.23
@schematics/angular               8.3.23
@schematics/update                0.803.23
rxjs                              6.5.4
typescript                        3.5.3
webpack                           4.39.2

Angular Version after updating:


Angular CLI: 9.0.1
Node: 12.13.1
OS: win32 x64

Angular: 9.0.0
... animations, common, compiler, compiler-cli, core, elements
... forms, language-service, localize, platform-browser
... platform-browser-dynamic, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.900.1
@angular-devkit/build-angular     0.900.1
@angular-devkit/build-optimizer   0.900.1
@angular-devkit/build-webpack     0.900.1
@angular-devkit/core              9.0.1
@angular-devkit/schematics        9.0.1
@angular/cli                      9.0.1
@ngtools/webpack                  9.0.1
@schematics/angular               9.0.1
@schematics/update                0.900.1
rxjs                              6.5.4
typescript                        3.7.5
webpack                           4.41.2
@wartab
Copy link

wartab commented Feb 7, 2020

I had the same issue, I had to run it twice for it to add it.

@julkue
Copy link
Author

julkue commented Feb 7, 2020

@wardbell Thanks for answering. But was the issue resolved for you, once the import statement was available? Because as mentioned in the description, for me it's not resolved even when adding it manually.

@AndrewKushnir
Copy link

Hi @julmot, thanks for reporting the issue. Could you please provide a small repro (in a form of Github repo), so that we can perform further investigation? Thank you.

@julkue
Copy link
Author

julkue commented Feb 7, 2020

@andreaswissel Thanks for your reply.

Luckily I could indeed reproduce it in a minimal repo. I've removed everything that is unnecessary from a real life application where I've encountered the issue. There might be some fragments in the angular.json file that are unnecessary for this issue, but I thought it might be helpful to share the entire file.

Please head over to the following repository:

https://github.com/julmot/angular-localize-error

NOTE: As you can see in the 4 available commits I've created one commit for:

  • The initial setup of the project
  • The upgrade to Angular v9 using ng update @angular/core @angular/cli
  • The installation of @angular/localize using ng add @angular/localize
  • Manual adding the import statement

As you can see in the 3rd commit, the import statement is not generated automatically. And even with manually adding the import statement – it's still resulting in the same error in the browser console.

Run $ npm start after $ npm install and head over to the browser console to see the error.

@petebacondarwin
Copy link
Contributor

So the problem is that when you specify a specific locale for a CLI build it will actually replace the @angular/localize/init file with a new file called empty.js. This is because "normally" you will be building with aot: true and then running the compile time translation of $localize calls, which means that there will be no run-time calls to $localizeleft in the code. (In that case the@angular/localize/init` is redundant and so not needed, which is why it is replaced to ensure it is not added unnecessarily to the bundle).

You can see this by stepping into the code and looking at polyfills.js file, which contains the following:

/* harmony import */ var _angular_localize_init__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/localize/init */ "./node_modules/@angular-devkit/build-angular/src/utils/empty.js");
/* harmony import */ var _angular_localize_init__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_angular_localize_init__WEBPACK_IMPORTED_MODULE_1__);

I think the correct solution to this issue is for the CLI to avoid replacing the @angular/localize/init with empty.js if the build is not using AOT? What do you think @clydin? In the meantime, I am transferring to the CLI repo as this is not a framework issue.

@clydin
Copy link
Member

clydin commented Feb 9, 2020

There appears to be several different elements involved in this situation.

In regards to the reproduction (thank you for a minimal reproduction), some of the Angular CLI migrations are not performed on the configuration file due to the usage of a third party builder. The Angular CLI does not know how to interpret the options and behavior of a third-party builder. As a result, third-party builders may need to be updated separately (either manually or via migrations if provided by the builder) to allow them to function properly with Angular 9.0 and/or align them with 9.0 best practices.

Starting with Angular 9.0, Ahead of Time (AOT) compilation is enabled for both development and production configurations. The new compiler provides significant performance improvements for AOT. AOT also provides improved error and diagnostic reporting at build time and is now recommended for use in development.

The use of the third-party builder is also the reason ng add @angular/localize does not augment the polyfills file. With a third-party builder present, it is not currently possible to accurately locate a polyfills TypeScript file to augment. (When using a third-party builder, there might not be one to augment or it could be JSON or even some type of template).

As to the situation of using localization in combination with JIT mode, there are also several concerns to consider. One is the localize polyfill. The current behavior can definitely be changed to account for JIT usage. However, I think the larger concern is user expectations of attempting to use localization with JIT. Currently without AOT enabled, the translations present in the application will not be translated to the locale specified and will instead remain in the source locale. For locales with defined translations, I think a build warning may be useful to indicate the expected outcome of such a build.

@julkue
Copy link
Author

julkue commented Feb 9, 2020

Hello @petarblazevski and @clydin,

Thanks for your feedback!

I have just two questions concerning your answers:

third party builder

Which builder do you mean, xliffmerge? If so, I'm confused, because this builder is completely separate and I've not enhanced or manipulated any of the built-in builders, just configured them. Because of that and because this also has to be run separately, I don't understand why this could break Angular's migration?

I think the correct solution to this issue is for the CLI to avoid replacing the @angular/localize/init with empty.js if the build is not using AOT?

What would be necessary to workaround the solution until an official fix, and would there be necessary changes for it to work with an official fix?

Thanks in advance!

@clydin
Copy link
Member

clydin commented Feb 10, 2020

@angular-builders/custom-webpack:browser is a third-party builder. It appears that it is only being used to add support for importing graphql files? If so, an alternative that should remove the need to customize the underlying webpack configuration would be to explicitly reference the graphql webpack loader in the import statements (something like import query from 'graphql-tag/loader!./query.graphql';).

As to the localize issue, the easiest way to fix the issue would be to enable AOT. Always using AOT is now the recommended best practice. This also has the advantage of creating translated builds in development mode including when using ng serve. Please note however that while ng build now has the capability to generate all locale variants of an application in a single build, ng serve can currently only be used with a single locale at a time.

@julkue
Copy link
Author

julkue commented Feb 10, 2020

@clydin Thank you very much for your answer.

It appears that it is only being used to add support for importing graphql files?

Indeed, in the example repository that's true. However, as this is only a minimal example I've removed the other reason why I've needed to extend Angular's webpack configuration: To configure alias paths. I'm importing a shared components library that we're using component-wide and this component library uses the shared-components alias (namespace). To support this, I have to make this alias available in my Angular application too. If there's a reason to also configure Webpack alias with some built-in Angular feature, I'm happy to remove this!

As to the localize issue, the easiest way to fix the issue would be to enable AOT

I have to confess, I'm now even more confused 😄
You're right, I enabled aot everywhere and it seems to work. But it also seems to work even without the import '@angular/localize/init';. I know the difference between aot and jit (maybe not in detail) but I don't understand why this fixed the issue. Do you have a link or something that describes why this fixed the issue?

However, now I could migrate to Angular v9. Thank you! 🎆

@clydin
Copy link
Member

clydin commented Feb 11, 2020

TypeScript's path mapping can be used as a replacement for resolve.alias. For the Angular CLI, path mapping affects all TS and JS files processed by Webpack.

@angular/localize/init provides an implementation of the $localize global. The new localization processing in the Angular compiler transforms template i18n into calls to this global. The CLI's new localization processing then transforms these calls into the actual translated text for the specified locale(s). As a result, an AOT compiled and localized application should not contain any calls to $localize and not need the implementation provided by @angular/localize/init. This process also has the advantage of only requiring one full application build. The locale specific application variants can be created during post-processing. You can find additional information regarding the new process in the Angular documentation here.

dgp1130 pushed a commit that referenced this issue Feb 11, 2020
@julkue
Copy link
Author

julkue commented Feb 13, 2020

Thanks @clydin for fixing this issue.

In terms of removing @angular-builders/custom-webpack:browser in favor of @angular-devkit/build-angular:browser. I've tested your suggestion and it seems to be fine for TypeScript only alias paths, but I need to have the alias path mainly in the context of SCSS to inherit/configure shared components from a node module. To not have the need to specify the entire node_module path in every single Angular componet, I still have to use the custom wepback builder, I'm afraid. Otherwise this leads to:

SassError: Can't find stylesheet to import.

So, if I understood you correctly the migration in ng update isn't able to migrate anything when using this builder?

@clydin
Copy link
Member

clydin commented Feb 19, 2020

@julmot Can you provide an example of the stylesheet usage? Are you using @import in a sass file or referencing a stylesheet in the component metadata or maybe something else entirely?

For @import usage, there is the stylePreprocessorOptions object option that contains the includePaths option. This option is an array of paths that will be used by each stylesheet preprocessor to first search for imported stylesheets. This option is passed directly to the preprocessor so it has the advantage of being webpack/bundler agnostic.

@julkue
Copy link
Author

julkue commented Feb 19, 2020

@clydin Thanks for your reply.

Yes you're right and I'm already using it to import a file "_common.scss" from the styles folder that Angular CLI genereates, using @import "common". However, unfortunately this doesn't help me with the shared components library. Because I'm importing it trough something like @import "~shared-components/components/common/address/address"; and I'll have to use this explicit alias rather than just an include path as file names can be the same – and are the same already sometimes, like _common.scss. In case I can't specify that alias I'll have to depend on a custom webpack config it seems.

@petebacondarwin
Copy link
Contributor

@debender495 - it is difficult to say from your stack trace but I am confident that your error is not related to this issue. Please create a new issue with a reproduction of your problem, which we can then investigate.

@debender495
Copy link

debender495 commented Mar 17, 2020

@petebacondarwin created an issue, but unfortunately it's closed without any resolution.

ng test fails in angular 9
#17235

@shaikh-nazish
Copy link

The best way to do this is by using Angular CLI:
You just have to run the following command in terminal:
ng add @angular/localize
It will automatically install packages and will also add the import statement in polyfills.ts file.
The import statement is:
import '@angular/localize/init';

If you don't want to go through the CLI approach then you can manually enter the import statement in the polyfills.ts file.
Also you have to do one more step is to add the below line in package.json under dependencies tag.
"dependencies":{
...
"@angular/localize":"^9.1.0",
...
}

@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators May 2, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.