i18n-polyfill
i18n-polyfill copied to clipboard
AOT bundle files
We have been using the angular-cli ng xi18n
for our project with much success. I just setup our system to use the runtime I18n
service and was able to get it working in both JIT for development server and the AOT for our released code.
On thing I ran into was that I noticed the main bundle size grew dramatically. After looking at it I found that our entire xlf file was embedded in the javascript adding over 500K. Currently our project only has a couple of runtime translations so 99% of the embedded file is only used at compile time.
I realize that this project is a temporary solution until this feature is incorporated into the existing translation stuff, but I had a few questions:
- Is there any plans to optimize the AOT compile so that it only extracts the translations required at runtime and stores them in the bundle.
- Will the storage format of the AOT translations be changed to something smaller like a Object or Map so the xlf file only needs to be processed during the build.
Hello, I'm not planning on adding new features or optimizations to this library, because like you said it's only a temporary solution. That being said, the same issues will arise with the official Angular i18n solution. How come your xlf file is 500k?!! That seems huge! I guess that uglify cannot compress xml like it can compress js... I'm been trying to convince our team to support some kind of json format for a long time now, it would indeed fix the issue of having to ship a lot of serializer code to decode the xml. It would also probably reduce the size a bit, json is less verbose than xml. You could probably try to switch to xmb/xtb, it's a lot less verbose than xliff (xml) too, maybe that would help? As for the first point it wouldn't be possible for Angular i18n because both the service and the template translations will be handled at runtime.
Our project has around 300 translated strings for english and french the raw xlf files are around 250K. After investigating the bundled code further it appears that it is saving the english and french file in the bundle even though we are building the bundle once for english and once for french as described in the documentation.
One way to reduce the size is during the load operation it could remove the context-group
tag before embedding the files in the in the bundle.
I've been looking into this some more and have made a few observations, I wonder if you could comment on if we are doing something wrong with our setup.
In our current setup we make no reference to TRANSLATIONS
in our main.ts
nor our app.module.ts
. When we build our release versions we do: ng build --prod --base-href /en --deploy-url /en --i18n-file=src/i18n/messages.en.xlf --i18n-format=xlf --locale=en"
for each language we support. The resulting bundle files do not contain the xliff file but all the templates are translated correctly. Passing the similar arguments to the ng serve
command doesn't do any translations, which we were willing to accept. If we add TRANSLATIONS
to the main.ts
then translations also work with ng serve
, but doing this will embed the xliff file in the bundles.
Now trying to use the i18n-polyfill
we have had to setup TRANSLATIONS
in the app.module.ts
so that the I18n
service would work. Doings this also causes the xlf files to be embedded in the bundles.
So to summerize it appears that:
- For JIT build, template translations require the
TRANSLATIONS
are provided in themain.ts
- For JIT and AOT build, I18n service requires the
TRANSLATIONS
are provided in theapp.module.ts
- If
TRANSLATIONS
are provided inmain.ts
orapp.module.ts
then the xliff file is embeded in the AOT bundle.
Yes that's correct. The reason is that this is an external library, not part of the framework itself. When Angular is built, it will replace texts in the templates, but not in the service (since it's just another external lib for the compiler).
When runtime i18n lands in the framework for Angular v7, then the built-in service will use the same translations for code and templates.
Thank you for all the information, I had one last confirmation question.
So when v7 releases will it be possible to do ng build --prod --i18n-file=...
and have it work without specifying any TRANSLATIONS
provider or embedding the entire XLF file in the main bundle.
Came here to ask the same thing. Actually it's much worse for us.
The XLIFF 1.2 is 340kb and our bundle grew from 1.8mb to 3.6mb (doubled). Thought there was something wrong when I saw the XLIFF actually embedded into my bundle but see that it's expected :(
Created 2x bundles (english and french) and I can see both messages(en).xlf and messages(fr).xlf are both embedded in both bundles.
Our build command looks like:
./node_modules/.bin/ng "build" "--app=mysite" "--environment=prod" "--i18n-file=src/mysite/locale/messages(en).xlf" "--locale=en" "--missing-translation=ignore" "--output-path=dist/mysite/en" "--prod" "--base-href=/en/" "--deploy-url=/en/"
Bundle looks like:
webpackJsonp(["main"],{"+1m/":function(t,e){t.exports='<?xml version="1.0"?>\n<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">\n <file source-language="af" datatype="plaintext" original="ng2.template" target-language="en-US">\n <body>\n <trans-unit id="5e6548eb9cbb0467c307b4079bc989cd21f44355" datatype="html">\n <source>This field is required</source><target>This field is required</target>\n <context-group purpose="location">\n <context context-type="sourcefile">../app/shared/form-errors/form-errors.component.ts</context>\n <context context-type="linenumber">4</context>\n </context-group>\n </trans-unit>\n <trans-unit id="bab5e4d5a5641055b05160f8cdc95de7a2289140" datatype="html">\n <source>This field must be an email</source>
Was expecting a JSON map like:
{
"5e6548eb9cbb0467c307b4079bc989cd21f44355": "This field is required"
}
Later down the line I see this in my bundle as well. Maybe these could be directly replaced with i18n being a NOOP?
this.required=this.i18n("This field is required")
So I guess a couple of things:
- Is it normal that my single-language bundle includes 2 languages?
- I guess we don't need to store
context-group
ornote
and extra metadata likeequiv-text
. We'll clean those manually but is there any idea to automate it? (created a script to removecontext-group
tags and XLF went from 340 to 170kb) - If
trans-unit
has a unique ID can I also delete thesource
tags (drops from 170 -> 119kb. Minify also drops it further to 94kb) - 99% of our translations are template driven and there's probably like... 20 strings which are translated in TS. Could we loop through our XML and leave only those dynamically translated?
- Wouldn't XML parsing in JavaScript be really heavy and unperformant?
- JSON would be a billion times smaller than XML :)
Maybe after all of the post-processing, 94kb extra within the bundle would be an acceptable trade-off for all the savings generated from reducing HTML
@intellix about a script to remove <context-group>
, do you have it? Is it available on this repo? My XLF file has about 300 strings, and removing them manually will be a big pain
in jetbrain ide's it's quite simple to replace all context-groups with a regex search => "
This is the regex for the vscode, in case someone is interested in reducing the bundle size:
<context-group[\n\s\S]*?</context-group>
You can remove other tags by replacing context-group
with the tag name
@cngarkar Basically the same as i already commented. But also to mention, with angular 9 use the newly written i18n tools and it's no longer necessary to use the i18n polyfill
Thanks @dyingangel666, that was helpful. For others on how to use $localize to use translation in ts, this post can be useful: https://blog.ninja-squad.com/2019/12/10/angular-localize/