You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When running xi18n command on my application, that imports my library i get the following error:
ERROR: Unexpected value 'SharedModule in /Users/****/Code/my-app/dist/@shared/lib/shared.module.d.ts' imported by the module 'CoreModule in /Users/****/Code/my-app/libs/my-core/src/lib/core.module.ts'. Please add a @NgModule annotation.
But this is only happening when my lib is pre-build with Ivy option set to true, otherwise everything is fine.
A clear and concise description of the problem...
🔬 Minimal Reproduction
ng new my-app
ng g lib my-lib
build my-lib
import my-lib into my-apps module
run ng xi18n for my-app
🔥 Exception or Error
`ERROR: Unexpected value 'SharedModule in /Users/****/Code/my-app/dist/@shared/lib/shared.module.d.ts' imported by the module 'CoreModule in /Users/****/Code/my-app/libs/my-core/src/lib/core.module.ts'. Please add a @NgModule annotation.`
@alan-agius4 that's what i'm doing now. however, after reading docs about i18n working fine with Ivy i expected it to work fine in both, libs and apps.
btw. can we expect the fix to ship in final 9.0.0 version?
Hello,
It would be appreciated if we had a banner, at the top of this page, saying it doesn't work yet with Ivy... with a link to the issue to check the state of it.
Hello,
Me again ;-)
I tried the the latest 10-RC3 version and it still doesn't work... I was enthusiastic to use the official $localize service rather than ngx-translate (which is really great BTW), but I will go back to it.
Also, discovering the way to use $localize, it seems very strange to me to compile an app version by language. To me it breaks the principle of an app... switching language shouldn't mean reloading an app. I read also that we could load the xlf files in runtime, but with Ivy only, and it doesn't seem to be really ready... But as we can't compile a project with a lib with Ivy...
So, two possibilities : I've missed something, possible, this framework is deeply impressive and so powerful at many points, Or there is something the angular team should communicate in a more precise way in order to help everyone. Just saying it's not ready yet, we plan to solve in the 10 version, not the 9 etc.
Thank you to the Angular Team, driving such a project is very hard, but I feel that sometimes, it lacks a transparent communication.
Keep up the great work !
Hi @BenLune - I understand your frustration with this and I am sorry that we have not communicated clearly enough what is going on. I have tried to explain the situation in the various issues that have come up, but I can see that this is hard for developers to find when their project is not working as expected.
The documentation for i18n is currently being updated and I will see if we can get an info box that explains that, right now, the extraction mechanism is based on ViewEngine compiler, which is not able to cope with some code syntax shapes that the Ivy compiler can handle.
Regarding the use of $localize. I am sorry that you are frustrated by this. We have purposefully not documented this since for v9 and v10 it is an internal implementation device which was not ready to be used directly in Angular applications. I am afraid that there have been a number of blog postings and other comments where this has been talked abut as a new Ivy feature, which has confused the message.
Indeed using $localize in your own application code effectively works, but as is mentioned in numerous issues, which I have tried to respond to, there is currently no way to automatically extract these messages into translation files. This means that those people who have been trying to use this "internal" feature have felt disappointed. This was never our intention and why we did not publicly document this feature.
The fact that the current message extraction fails in certain cases is indeed a bug, which will be fixed by the new Ivy based message extractor, which I am actively working on. It has been my 2nd highest priority after ensuring that our compatibility compiler (ngcc) is working correctly, which has a large impact on all Ivy projects.
Finally, I would like to clear up the translation strategy that the Angular framework is offering here. Terms like "runtime translation" are ambiguous and mean different things to different people:
There are multiple pieces in the Angular translation offering:
$localize
This (currently internal) tool is a "tag handler" that can be applied to back-ticked strings to "mark" them as translatable. How that happens is dependent upon the project setup:
runtime translation
If we do no "translation inlining" during compilation then we must provide an implementation of this tag handler (by adding import '@angular/localize/init'; to your application). This handler will be executed every time the $localize tagged back-ticked string is evaluated.
By default this implementation is just a pass-through function that does not modify the text of the message. But if you were to load up some translations, by calling the (still internal) loadTranslations() function the implementation of $localize will actually replace the original text with the translated text.
What this means in practice is that in your own application code you could use $localize and as long as your code re-evaluates the back-ticked strings at the appropriate time you could indeed change the translations (i.e. the language) at runtime. But see below about why this doesn't work for translations in templates...
compile-time inlining
In many cases we do not want to be doing the work of translating the messages at runtime so we have in place (via the CLI tool, and also a standalone binary localize-translate) tooling that will actually parse through the built JS source code and replace any instance of a $localize back-ticked string with a new back-ticked string, which has the $localize tag handler removed and all the text replaced with the translated text.
The result of this is code that no longer has any reference to $localize which keeps the code small and fast, and means we no longer need to have the $localize implementation mentioned above in the distributable code downloaded to the browser. All of this results in performance benefits across the board for the application.
Obviously, in this case, we must generate a separate copy of the source code for each language that your project supports, and there is no option to change language at runtime. The CLI is optimised to make this happen as fast as possible, by only running the translation as the last part of the build pipe-line avoiding having to run the earlier parts of the build multiple times for each language.
i18n in Angular templates
Everything about $localize above is internal. Currently the only publcly supported way to internationalise your application is via i18n tags. Here I want to clear up the Angular approach to i18n in the templates and why we believe it is not effective to enable the language in templates to be changed at runtime.
Previously, in the View Engine compiler, we would always inline the chosen language at the point the component template is compiled. This is extremely early in the build pipeline and resulted in long builds where we had to run the complete pipeline for each language. Now that we have the option of using $localize for this purpose, which can be inlined much later in the pipeline, the Ivy compiler takes a different approach.
In the Ivy compiler, we translate the i18n tags in the templates into back-ticked string that are tagged with $localize. This means that we can delay the inlining of the translations until later in the build. The result of Ivy template compilation is a "template function" that contains Ivy rendering instructions and also references variables that hold the result of evaluating tagged back-ticked message strings. These message strings contain additional markers (�) that are used by the Ivy runtime to interleave interpolations {{...}} and actual HTML elements within the translated message. This is necessary because we support ICU messages that can contain both.
At runtime the Ivy rendering instructions will process the translated message string and process the special markers breaking up the string and inserting pieces of it into the correct place in the DOM.
In order to support changing the language of these translated messages at runtime we would need two support two things:
some method to tell template functions that their translated messages have changed
for the template function to be able to reprocess the new translated messages and move DOM elements around without breaking the bindings of data to the DOM.
While it is theoretically feasible (I think) to achieve this, we feel that it has negative impact:
it makes the Ivy rendering runtime much more complicated and therefore more likely to contain unwanted behaviour (bugs!) - and there may even be cases where this re-rendering is simply not possible without blowing away the entire component (and all of it children etc) which is effectively like reloading the page.
the size of the framework code is increased solely to support a very small number (we believe) of use cases.
the cost of tracking the changes to the language (and so the messages) will impact on the runtime speed of Angular in general.
Because of this the design of i18n tags in templates precludes changing the language during normal application execution. I have spoken to a number of developers about runtime language replacement. The initial reaction is often one of "this is an essential feature" but when we dig into the practical benefits there have been very few (if any) scenarios where a reload of the site is not acceptable. For the kind of message translation that most applications require users tend to choose one language to work in for the life of the application.
There are some scenarios where language is used in a more dynamic way. Perhaps a call centre application where the user needs to be given responses in the language of the caller. But this is not really about localisation of the application itself, it is part of the business rules - for example in when changing language for the caller, you would not expect the language of the menus or action buttons to change.
Finally, it might be worth considering that $localize, when it finally becomes public, could provide an application developer with a way to change some aspects of language at runtime without reloading. It would involve re-evaluating the back-ticked strings as needed - and the application developer can have control over that - but the application would then be responsible for getting these updated strings into the rendered DOM (perhaps via Pipes or Directives).
But for the foreseeable future there are no plans to support such dynamic language updates via the i18n tag mechanism in Angular templates.
I hope that this helps to clear up some of the confusion around $localize and I hope that I can get the new Ivy extraction tooling merged and released before the end of June so that you can get past the issues of the current ViewEngine extraction tooling. Please keep an eye on my PR for this to see the progress: #32912 : i18n - extraction tooling.
Reacted by Julian Kühnel, Alan Agius, Tom Seldon, Minko Gechev, BenLune, Jonathan Adamit, Adrien Crivelli and Aleksei Lebedev
Pete,
In your example you talk about the "reload of the site". Working with Angular (before Flex, Flash, Director), I don't feel like creating sites but applications ;-) We are using Angular to build multi-languages applications with Drupal as backend. Languages management is one of the challenges we have (the other one to use the router with urls coming from Drupal, managed by contributors, and of course, translatable). As we create PWAs, it's quite strange for me to reload the app just to switch language.
But sure, I understand the huge challenges doing it in runtime or build time.
To me, the great advantage of the $localize workflow is to tag the translatable tags, and get magically, the xlf file ready for translation. With $localize it seems possible to get translated string from Typescript or from templates (a Pipe can be done for that).
But still no runtime language switch without having to restart the application...
We use ngx-translate in our applications just for interface terms, not the contents, which are coming from Drupal. So when we switch language, we just ask the content in the right language to Drupal.
We use angular for the frontend experience, but also for the frontend of the backend, sometimes mixing both. Then the ability, especially for the contributors to quickly change languages, and check if everything is ok, is really comfortable. And I think, the more it is easy to check the contents of an application, cross language, the more we have the feeling to master the contents and to get a strong application.
Finally, we may put our application interface terms in Drupal and load them runtime, maybe with a static export embedded in the application, then updated in IndexedDB when there is network.
Let's share our experiences !
Thanks again !
PS : I think that if angular.io was a multi-language application with a CMS behind it, it would be a great lab ;-)
Thanks for the additional feedback @BenLune - it is really helpful in guiding the design of the i18n features.
As we create PWAs, it's quite strange for me to reload the app just to switch language.
I would be really interested in some metrics of how often users switch language in your PWAs.
Then the ability, especially for the contributors to quickly change languages, and check if everything is ok, is really comfortable.
If I understand this correctly your are talking about some kind of "preview" in the backend of what the front end content will look like, yes? If so then I would not expect the backend user to want to change the actual language of the backend app. Instead they would just change the language of the preview, yes? In this case, I would imagine having the previous in some kind of iframe, which can be reloaded when you switch preview language, while the actual backend app itself remains in a single language. Am I misunderstanding the workflow here?
Finally, we may put our application interface terms in Drupal and load them runtime, maybe with a static export embedded in the application, then updated in IndexedDB when there is network.
This can actually be achieved with the $localize design right now. In fact I believe that https://www.locl.app/ has support, wrapped around $localize to do just this. The basic idea is that you do "runtime" merging of translations at the point the application loads - where the translated messages can be downloaded on-the-fly (or accessed from a local DB) before the application boots. (This is rather than inlining the translations at compile-time.)
So if I understand correctly I can't upgrade to 9.x.x ?
Because I import a local library, and even with enableIvy set to false it won't work.
And it won't work until it's fixed in v10?
I got a little sidetracked by the discussion about runtime-rendering.
For those searching ; i found out that tsconfig.lib.json didn't set enablyIvy to false for my lib!
Which when setting all to false did the trick.
Okay so we've upgraded to 9.1 by now, with the library and everything set to enableIvy false and it works :).
Sidenote though; because of the old ViewEngine I had to revert deleting all entryComponent-settings. It's is deprecated in 9, however the old ViewEngine still requires them and gives errors if dynamic components don't exist in entryComponents.
Activity
alan-agius4 commentedon Dec 9, 2019
Can you try to build the library in prod mode prior to running
ng xi18n?i18n extraction still uses parts of the legacy compiler which require a library to be compiled using View Engine.
romko391 commentedon Dec 9, 2019
@alan-agius4 that's what i'm doing now. however, after reading docs about i18n working fine with Ivy i expected it to work fine in both, libs and apps.
btw. can we expect the fix to ship in final
9.0.0version?alan-agius4 commentedon Dec 9, 2019
We are targeting a fix for this in 9.1.0. There is already a draft PR in the framework side angular/angular#32912
23 remaining items
BenLune commentedon Jun 10, 2020
Hello,
It would be appreciated if we had a banner, at the top of this page, saying it doesn't work yet with Ivy... with a link to the issue to check the state of it.
BenLune commentedon Jun 11, 2020
Hello,
Me again ;-)
I tried the the latest 10-RC3 version and it still doesn't work... I was enthusiastic to use the official $localize service rather than ngx-translate (which is really great BTW), but I will go back to it.
Also, discovering the way to use $localize, it seems very strange to me to compile an app version by language. To me it breaks the principle of an app... switching language shouldn't mean reloading an app. I read also that we could load the xlf files in runtime, but with Ivy only, and it doesn't seem to be really ready... But as we can't compile a project with a lib with Ivy...
So, two possibilities : I've missed something, possible, this framework is deeply impressive and so powerful at many points, Or there is something the angular team should communicate in a more precise way in order to help everyone. Just saying it's not ready yet, we plan to solve in the 10 version, not the 9 etc.
Thank you to the Angular Team, driving such a project is very hard, but I feel that sometimes, it lacks a transparent communication.
Keep up the great work !
petebacondarwin commentedon Jun 11, 2020
Hi @BenLune - I understand your frustration with this and I am sorry that we have not communicated clearly enough what is going on. I have tried to explain the situation in the various issues that have come up, but I can see that this is hard for developers to find when their project is not working as expected.
The documentation for i18n is currently being updated and I will see if we can get an info box that explains that, right now, the extraction mechanism is based on ViewEngine compiler, which is not able to cope with some code syntax shapes that the Ivy compiler can handle.
Regarding the use of
$localize. I am sorry that you are frustrated by this. We have purposefully not documented this since for v9 and v10 it is an internal implementation device which was not ready to be used directly in Angular applications. I am afraid that there have been a number of blog postings and other comments where this has been talked abut as a new Ivy feature, which has confused the message.Indeed using
$localizein your own application code effectively works, but as is mentioned in numerous issues, which I have tried to respond to, there is currently no way to automatically extract these messages into translation files. This means that those people who have been trying to use this "internal" feature have felt disappointed. This was never our intention and why we did not publicly document this feature.The fact that the current message extraction fails in certain cases is indeed a bug, which will be fixed by the new Ivy based message extractor, which I am actively working on. It has been my 2nd highest priority after ensuring that our compatibility compiler (ngcc) is working correctly, which has a large impact on all Ivy projects.
Finally, I would like to clear up the translation strategy that the Angular framework is offering here. Terms like "runtime translation" are ambiguous and mean different things to different people:
There are multiple pieces in the Angular translation offering:
$localize
This (currently internal) tool is a "tag handler" that can be applied to back-ticked strings to "mark" them as translatable. How that happens is dependent upon the project setup:
runtime translation
If we do no "translation inlining" during compilation then we must provide an implementation of this tag handler (by adding
import '@angular/localize/init';to your application). This handler will be executed every time the$localizetagged back-ticked string is evaluated.By default this implementation is just a pass-through function that does not modify the text of the message. But if you were to load up some translations, by calling the (still internal)
loadTranslations()function the implementation of$localizewill actually replace the original text with the translated text.What this means in practice is that in your own application code you could use
$localizeand as long as your code re-evaluates the back-ticked strings at the appropriate time you could indeed change the translations (i.e. the language) at runtime. But see below about why this doesn't work for translations in templates...compile-time inlining
In many cases we do not want to be doing the work of translating the messages at runtime so we have in place (via the CLI tool, and also a standalone binary
localize-translate) tooling that will actually parse through the built JS source code and replace any instance of a$localizeback-ticked string with a new back-ticked string, which has the$localizetag handler removed and all the text replaced with the translated text.The result of this is code that no longer has any reference to
$localizewhich keeps the code small and fast, and means we no longer need to have the$localizeimplementation mentioned above in the distributable code downloaded to the browser. All of this results in performance benefits across the board for the application.Obviously, in this case, we must generate a separate copy of the source code for each language that your project supports, and there is no option to change language at runtime. The CLI is optimised to make this happen as fast as possible, by only running the translation as the last part of the build pipe-line avoiding having to run the earlier parts of the build multiple times for each language.
i18n in Angular templates
Everything about
$localizeabove is internal. Currently the only publcly supported way to internationalise your application is viai18ntags. Here I want to clear up the Angular approach to i18n in the templates and why we believe it is not effective to enable the language in templates to be changed at runtime.Previously, in the View Engine compiler, we would always inline the chosen language at the point the component template is compiled. This is extremely early in the build pipeline and resulted in long builds where we had to run the complete pipeline for each language. Now that we have the option of using
$localizefor this purpose, which can be inlined much later in the pipeline, the Ivy compiler takes a different approach.In the Ivy compiler, we translate the
i18ntags in the templates into back-ticked string that are tagged with$localize. This means that we can delay the inlining of the translations until later in the build. The result of Ivy template compilation is a "template function" that contains Ivy rendering instructions and also references variables that hold the result of evaluating tagged back-ticked message strings. These message strings contain additional markers (�) that are used by the Ivy runtime to interleave interpolations{{...}}and actual HTML elements within the translated message. This is necessary because we support ICU messages that can contain both.At runtime the Ivy rendering instructions will process the translated message string and process the special markers breaking up the string and inserting pieces of it into the correct place in the DOM.
In order to support changing the language of these translated messages at runtime we would need two support two things:
While it is theoretically feasible (I think) to achieve this, we feel that it has negative impact:
Because of this the design of
i18ntags in templates precludes changing the language during normal application execution. I have spoken to a number of developers about runtime language replacement. The initial reaction is often one of "this is an essential feature" but when we dig into the practical benefits there have been very few (if any) scenarios where a reload of the site is not acceptable. For the kind of message translation that most applications require users tend to choose one language to work in for the life of the application.There are some scenarios where language is used in a more dynamic way. Perhaps a call centre application where the user needs to be given responses in the language of the caller. But this is not really about localisation of the application itself, it is part of the business rules - for example in when changing language for the caller, you would not expect the language of the menus or action buttons to change.
Finally, it might be worth considering that
$localize, when it finally becomes public, could provide an application developer with a way to change some aspects of language at runtime without reloading. It would involve re-evaluating the back-ticked strings as needed - and the application developer can have control over that - but the application would then be responsible for getting these updated strings into the rendered DOM (perhaps via Pipes or Directives).But for the foreseeable future there are no plans to support such dynamic language updates via the
i18ntag mechanism in Angular templates.I hope that this helps to clear up some of the confusion around
$localizeand I hope that I can get the new Ivy extraction tooling merged and released before the end of June so that you can get past the issues of the current ViewEngine extraction tooling. Please keep an eye on my PR for this to see the progress: #32912 : i18n - extraction tooling.BenLune commentedon Jun 12, 2020
Thank you very much Pete for these rich informations for all of us !
BenLune commentedon Jun 12, 2020
Pete,
In your example you talk about the "reload of the site". Working with Angular (before Flex, Flash, Director), I don't feel like creating sites but applications ;-) We are using Angular to build multi-languages applications with Drupal as backend. Languages management is one of the challenges we have (the other one to use the router with urls coming from Drupal, managed by contributors, and of course, translatable). As we create PWAs, it's quite strange for me to reload the app just to switch language.
But sure, I understand the huge challenges doing it in runtime or build time.
To me, the great advantage of the $localize workflow is to tag the translatable tags, and get magically, the xlf file ready for translation. With $localize it seems possible to get translated string from Typescript or from templates (a Pipe can be done for that).
But still no runtime language switch without having to restart the application...
We use ngx-translate in our applications just for interface terms, not the contents, which are coming from Drupal. So when we switch language, we just ask the content in the right language to Drupal.
We use angular for the frontend experience, but also for the frontend of the backend, sometimes mixing both. Then the ability, especially for the contributors to quickly change languages, and check if everything is ok, is really comfortable. And I think, the more it is easy to check the contents of an application, cross language, the more we have the feeling to master the contents and to get a strong application.
Finally, we may put our application interface terms in Drupal and load them runtime, maybe with a static export embedded in the application, then updated in IndexedDB when there is network.
Let's share our experiences !
Thanks again !
PS : I think that if angular.io was a multi-language application with a CMS behind it, it would be a great lab ;-)
petebacondarwin commentedon Jun 17, 2020
Thanks for the additional feedback @BenLune - it is really helpful in guiding the design of the i18n features.
I would be really interested in some metrics of how often users switch language in your PWAs.
If I understand this correctly your are talking about some kind of "preview" in the backend of what the front end content will look like, yes? If so then I would not expect the backend user to want to change the actual language of the backend app. Instead they would just change the language of the preview, yes? In this case, I would imagine having the previous in some kind of iframe, which can be reloaded when you switch preview language, while the actual backend app itself remains in a single language. Am I misunderstanding the workflow here?
This can actually be achieved with the
$localizedesign right now. In fact I believe that https://www.locl.app/ has support, wrapped around$localizeto do just this. The basic idea is that you do "runtime" merging of translations at the point the application loads - where the translated messages can be downloaded on-the-fly (or accessed from a local DB) before the application boots. (This is rather than inlining the translations at compile-time.)CN91 commentedon Aug 6, 2020
So if I understand correctly I can't upgrade to 9.x.x ?
Because I import a local library, and even with enableIvy set to false it won't work.
And it won't work until it's fixed in v10?
I got a little sidetracked by the discussion about runtime-rendering.
For those searching ; i found out that tsconfig.lib.json didn't set enablyIvy to false for my lib!
Which when setting all to false did the trick.
PowerKiKi commentedon Aug 7, 2020
If your library is built with enableIvy set to false, then you can upgrade to Angular 10.0 (independently of the project enableIvy flag).
If your library is built with enableIvy set to true, then you have to wait for Angular 10.1
CN91 commentedon Aug 10, 2020
Okay so we've upgraded to 9.1 by now, with the library and everything set to enableIvy false and it works :).
Sidenote though; because of the old ViewEngine I had to revert deleting all entryComponent-settings. It's is deprecated in 9, however the old ViewEngine still requires them and gives errors if dynamic components don't exist in entryComponents.
Revert "Publish lib built with Ivy"
jonyadamit commentedon Sep 13, 2020
After upgrading to 10.1, and using --ivy switch, everything works as expected.
alan-agius4 commentedon Sep 13, 2020
Closing as per above comment.
If the problem persists after upgrading kindly open a new issue.
Thanks.
angular-automatic-lock-bot commentedon Oct 14, 2020
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.