Git Product home page Git Product logo

Comments (12)

cibernox avatar cibernox commented on May 18, 2024 9

@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

from svelte-i18n.

hmaesta avatar hmaesta commented on May 18, 2024 7

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.

from svelte-i18n.

kaisermann avatar kaisermann commented on May 18, 2024 4

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 svelte-i18n. It would be great to keep the same API and functionalities if possible though.

from svelte-i18n.

cibernox avatar cibernox commented on May 18, 2024 3

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 plural and select, but it won't be complicated to implement similar compilation for the rest of the syntax.

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.

from svelte-i18n.

cibernox avatar cibernox commented on May 18, 2024 2

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.

$t("my.key", { values: { count: 3 } }) should basically do

lookupLocation("my.key")({count: 3})

I think we're not too far from that.

from svelte-i18n.

kaisermann avatar kaisermann commented on May 18, 2024

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.

  • Since I've first built this lib I have thought about those utility methods (title, upper, etc) and never seem to find myself using them and as you said, they're pretty easy to implement. However, I wouldn't say that removing them would reduce that much the size of the library. I'm not against removing them in the future, but would like to hear more feedback about it. It's also possible to add some kind of utility entrypoint, so devs could add them as they please.

  • That's actually how it worked on v1, albeit with a little more boilerplate to set the locale. My mission withv2 was to make the API smaller and simpler. However, it's nothing that a good documentation change couldn't solve. That may actually simplify the call on server.js for sapper builds.

  • Yeah, the big one, but very important indeed. Can you give an example of how you imagine that happening? Do you mean transforming the formatter calls to smaller functions which only need to receive the values to be interpolated? That would happen to all locales that you add/register at build-time? About the size issue, as you stated, I think this approach can generate a lot of weight depending on the size of the project. If and after we define what would be the result of that compilation step, we should make a benchmark to check what weight change we'd have.

Anyway, thanks again for the interest in helping the lib 😁

from svelte-i18n.

cibernox avatar cibernox commented on May 18, 2024

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.

from svelte-i18n.

kaisermann avatar kaisermann commented on May 18, 2024

I started taking a look into linguijs which is not only much smaller (1.4kb) than intl-messageformatter, it better supports compiling the messages at build-step. I didn't went to far, since I don't have much free time right now, but will definitely continue to tackle this 😁

If we supposedly switched to lingui, for what I saw we would need/be able to do:

  • remove deepmerge (800 bytes or so), because it only accepts shallow dictionaries. We can still support deep dictionary definitions and flat them by joining their keys. This would also remove dlv (191 bytes), the object string path parser. We could possibly do this now without being a breaking change anyway 🤔🤔🤔 (done in v2.2.3)

  • probably remove all the logic of finding the fallback locale for a certain locale: en-US to en to the defined fallback. (Can be a big breaking change if lingui behaves differently).

  • lingui provides ready to use tools to ease the message compilation step. Would be nice to not have to implement them.

Or, if we want to take another route, we can use the intl-message-parser (6.5kb vs 8.6kb) instead, which is lighter and prevent some of the unused deps and code paths of intl-messageformat to end up on the lib. Or any other ICU syntax parser which is well maintained and up to date.

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.

from svelte-i18n.

cibernox avatar cibernox commented on May 18, 2024

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.

from svelte-i18n.

kaisermann avatar kaisermann commented on May 18, 2024

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 v2.2.3 🎉

Not much, but after removing dlv and deepmerge we're down from 38.7kb -> 37.1kb minified and 11.4kb -> 10.9kb.

from svelte-i18n.

kaisermann avatar kaisermann commented on May 18, 2024

@cibernox That's great! I'm going to check both repos soon 😉

I just created the v3 branch to start playing with some of the things mentioned here. The first things I changed were removing the casing utilities and separating the date, time and number formatters from the message one: https://github.com/kaisermann/svelte-i18n/pull/40/files#diff-31df54a9a51bd3da26df362832cc1c9fR28. Not sure if $formatDate, $formatNumber, $formatTime are too verbose... 🤔 could be $date, $number, $time, but maybe that's too generic?

Edit:

Made getClientLocale tree-shakeable too on the PR above.

from svelte-i18n.

hmaesta avatar hmaesta commented on May 18, 2024

When running rollup-plugin-analyzer, icu-messageformat-parser is one of the heaviest parts of my bundle.

Screen Shot 2021-05-13 at 18 09 27

A diet would be nice, indeed. Any update here?

from svelte-i18n.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.