-
Notifications
You must be signed in to change notification settings - Fork 74
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
Ideas to slim down the library #37
Comments
Hey 👋 Thanks for your interest in making the lib better (and smaller, which is always better) 🎉 First of all, I think it's important to notice that we're possibly talking about breaking-changes here.
Anyway, thanks again for the interest in helping the lib 😁 |
Example of what I mean: {
"nearby": "Find places near your location",
"kilometer": "{count} {count, plural, =1 {kilometer} other {kilometers}}", could be parsed as import { plural } from 'helpers';
export default {
"nearby": "Find places near your location",
"kilometer": count => `${count} ${plural(count, { 1: "kilometer", other: "kilometers"})}",
} As you can imagine, after minification that code will be import { p } from 'helpers';
export default {
"nearby": "Find places near your location",
"kilometer": v => `${v} ${p(v,{1:"kilometer",other:"kilometers"})}"
} As you see the overhead is typically small. You app has to have a lot of entries with special plurals and stuff for the overhead to surpass the weight of the library. |
I started taking a look into linguijs which is not only much smaller (1.4kb) than If we supposedly switched to lingui, for what I saw we would need/be able to do:
Or, if we want to take another route, we can use the One of the things that is important to decide is what kind of responsibility the lib should have. Do we want to only delegate some methods and configurations to the underlying i18n lib? Or do we doing things at a lower level, i.e what I mentioned about using the parser instead of the ready-to-use formatter? I like having more control of what the lib is doing, but I'm open to feedbacks. |
I also discovered that what I suggested is already possible and done in react-intl: https://github.com/formatjs/react-intl/blob/master/docs/Advanced-Usage.md#pre-parsing-messages It compiles, however, to the AST, which is a bit more verbose than the approach based in functions, and it still requires intl-messageformat (but would spare us from shipping intl-messageformat-parser). I'm going to play a bit more with the idea of compiling translations to either ASTs or functions. |
Yeah, I know! I found your issue on their repo 😆 I'll play around with the compilation step whenever possible, but for now there is #39 😁. Released as Not much, but after removing |
I also did a proof of concept for a babel plugin that takes the translations and converts them into functions: https://github.com/cibernox/babel-plugin-precompile-icu Check the tests, but the tl;dr; is that it knows how to compile things like: export default {
nearby: "Find places near your location",
kilometer: "{count} {count, plural, =1 {kilometer} other {kilometers}}"
}; into import { plural } from "helpers";
export default {
nearby: "Find places near your location",
kilometer: count => `${count} ${plural(count, {1: "kilometer", other: "kilometers"})}`
}; And even things more complex like: export default {
nearby: "Find places near your location",
kilometer: "This year { gender, select,male {he made {count, plural,=0 {no kilometres} one {one kilometre} other {{count} kilometres}}} female {she made {count, plural,=0 {no kilometres} one {one kilometre} other {{count} kilometres}}} other {they made {count, plural,=0 {no kilometres} one {one kilometre} other {{count} kilometres}}}}"
}; into import { select, plural } from "helpers";
export default {
nearby: "Find places near your location",
kilometer: (count, gender) => `This year ${select(gender, {
male: `he made ${plural(count, {
0: "no kilometres",
1: "one kilometre",
other: `${count} kilometres`
})}`,
female: `she made ${plural(count, {
0: "no kilometres",
1: "one kilometre",
other: `${count} kilometres`
})}`,
other: `they made ${plural(count, {
0: "no kilometres",
1: "one kilometre",
other: `${count} kilometres`
})}`
})}`
}; As you see the overhead in size is minimal. Infact, after minification, you save space. And the more complex the message is, the more you save: - "This year { gender, select,male {he made {count, plural,=0 {no kilometres} one {one kilometre} other {{count} kilometres}}} female {she made {count, plural,=0 {no kilometres} one {one kilometre} other {{count} kilometres}}} other {they made {count, plural,=0 {no kilometres} one {one kilometre} other {{count} kilometres}}}}"
+ (c,g)=>`This year ${d(g,{male:`he made ${p(c,{0:"no kilometres",1:"one kilometre",other:`${c} kilometres`})}`,female:`she made ${p(c,{0:"no kilometres",1:"one kilometre",other:`${c} kilometres`})}`,other:`they made ${p(c,{0:"no kilometres",1:"one kilometre",other:`${c} kilometres`})}`})}` For now I only implemented the transformation of The next step would be to implement the helpers that I'm importing that don't yet exist, which is where I'd copy-paste from some existing library like intl-message-format, but implement the functionality as functions that rollup/webpack can tree-shake. |
Now I managed to write a rollup plugin that compiles the json files and imports the helpers from https://github.com/cibernox/icu-helpers Now that the translations are functions that take arguments, the only thing that svelte-i18n would have to do, is exposes methods to register the translations and configure the preferences.
lookupLocation("my.key")({count: 3}) I think we're not too far from that. |
@cibernox That's great! I'm going to check both repos soon 😉 I just created the Edit: Made |
@hmaesta I recently released a library implementing some of this ideas: https://github.com/cibernox/svelte-intl-precompile It has an API that I think it's almost 100% compatible with svelte-i18n. The docs say it's for SvelteKit but it will work on any rollup-based svelte app. If shouldn't occupy more than 2/3 kb after minification and compression. I presented it on a lighting talk in svelte summit a few days ago: https://youtu.be/fnr9XWvjJHw?t=10004 |
Hey @hmaesta and @cibernox (loved the talk 😁!) Unfortunately, this is not something that I can invest much time in right now. I'm open to all kinds of contribution 👀 @cibernox if you're (still) interested in "merging" the libraries, we can think about a v4 for |
This page has been open for 26 days in my computer as a pinned tab, just waiting for the time when I could try @cibernox's approach. 😅 After a little struggle with Rollup, I was able to test it and save ~100 KB. 🎉 Thanks for the help. I hope it can be merged to this repository, since the name is more friendly and already have some audience. |
First of all, thanks for the great library. It worked like a charm for me.
That said, i've noticed that the app is bigger than I expected it to be, around 12KB after gzip. Part of the problem is that svelte has spoiled me when it comes to the size of the bundles, if this was an angular or ember library I wouldn't bat an eye at the size.
However, it couldn't avoid notice that my 17kb gzipped app grew to 29kb app after adding svelte-i18n and ~20 translations, which is a 70% increase.
Just listing some low hanging fruit to make the library smaller, checking if you think it's worth to pursue them. I might help actually.
Right now, the
format
store's value is a function that hastime
,date
,number
,capital
,title
,upper
andlower
properties attached. Because of that, rollup cannot treeshake unused features. If functions for formatting dates, times and numbers were explicit exported, rollup could just remove the unused stuff (for instance, I only format messages and times, not dates nor numbers).Arguably,
capital
,title
,upper
andlower
may not even belong in this library, but I can see how they are convenient.Maybe
getClientLocale
could be something users also explicitly import if they care:intl-messageformat
to compile translations during the build step. That library accounts for 4/5ths of the size of svelte-i18n. If we could compile ahead of time the translations, we could not ship the library at all. We'd have to assess if the compiled JS functions, once uglified, would be bigger than the equivalent strings using the ICU message format. I reckon that they would be slightly bigger, but probably still smaller than shipping the library unless you have thousands of translations the useplural
/select
or interpolations. And since we already have the functions we wouldn't have to usememoize
to cache the slow parsing process.Are you interested in investigating any of the above? The last one fits very well with svelte's compiler philosophy.
The text was updated successfully, but these errors were encountered: