isomorphic500 icon indicating copy to clipboard operation
isomorphic500 copied to clipboard

IntlUtils.loadLocaleData seems like it could be improved

Open robink opened this issue 9 years ago • 11 comments

I'm not a very big fan of this part: https://github.com/gpbl/isomorphic500/blob/master/src/utils/IntlUtils.js#L64-L107

When I add a locale to one of my webapps, I love to simply have to create a new locale file, like en.js, declare it as being available in my config file, like dev.js, and that's it.

What is being done in loadLocaleData seems to go against the DRY principle.

I've tried to refactor the switch using dynamic requires but webpack is now complaining about it. Any thoughts?

robink avatar May 28 '15 21:05 robink

I agree with you @robink, I couldn't find a better solution.

The problem here is to download locale data only for the user's language before rendering the app.

With this script we can group and require-ensure them in small chunks. I'm not sure it is possible to automatize this thing. Also, some granularity is needed because often english is loaded by default (e.g. Intl, moment.js). And also the Intl polyfill. So maybe instead of simplifying we would make things even more complex.

I've tried to refactor the switch using dynamic requires but webpack is now complaining about it.

Dynamic requires wouldn't work because webpack cannot know what to put inside them. Which error did you get?

An alternative may be to not use webpack and try a more custom way, maybe using a fetchr service or, why not, a store. I'm open for new ideas :-)

gpbl avatar May 28 '15 22:05 gpbl

I'm also interested in this topic. Looks like only one way of doing that is to share translation data on the REST end-point and download it on the server/client side with fetchr.

dmitry avatar May 29 '15 17:05 dmitry

@dmitry thanks for joining in :-) What do you mean for translation data ?

We need:

  1. "messages" (as in the react-int jargon): translated strings used in the interface
  2. "locale data": content used by external modules such as react-intl or moment.js or other libs

In my implementation, "messages" are already fetched server-side and dehydrated in the IntlStore. I consider this part solid and closed.

The weak part is the way IntlUtils is loading the "locale data" for the i18n-enabled modules used in the website. In the current implementation, webpack is creating and then injecting an external script (a "chunk") that is downloaded and executed on the client. The script will augments react-intl and intl, so that they can understand the user's locale. Basically, it is a client-side, async require.

The bad part is that we need to hand-write the modules to be required, for each language. If we'd write a fetchr service, we'd end up with a solution similar to what webpack is already doing: creating a chunk, loaded async, injected to the browser. So i'm not 100% sure skipping webpack is a good solution.

As alternative, chunks could be set in the webpack config:

 entry: {
    main: "./client.js",

    // define chunks required for i18n, 
    "i18n-it": ["intl/locale-data/jsonp/it", "react-intl/dist/locale-data/it"],
    "i18n-es": ["intl/locale-data/jsonp/es", "react-intl/dist/locale-data/es"],
    "i18n-en": [] // default for both intl and react-intl, no need to load anything in this chunk
  }

then, a fetchr service could read the content of those chunks (maybe accessing the webpack stats json) and somewhere we could <script>-inject it before rendering the app.

However, it would not be enough, as we need to discern browsers not supporting Intl or having Intl without the required locale. So we would need:

 entry: {
    main: "./client.js",

    // define chunks required for intl, 
    "i18n-it": ["react-intl/dist/locale-data/it"],
    "i18n-it-with-intl": ["intl/locale-data/jsonp/it", "react-intl/dist/locale-data/it"],
    "i18n-es": ["react-intl/dist/locale-data/es"],
    "i18n-es-with-intl": ["react-intl/dist/locale-data/es"],
    "i18n-en": [], // default for both intl and react-intl, so no need to load anything in this chunk
    "i18n-en-with-intl": []
 }

It does get more complex. I still believe the IntlUtils (as now) is easier to understand, since it is just one, verbose script, instead of a hidden config working magically with a fetchr service.

... or I'm just overthinking the problem. Other ideas?

gpbl avatar May 29 '15 20:05 gpbl

We could make a webpack plugin loading a set of locales. The plugin should receive an array of the scripts to be included for each language. It could work with react-intl, intl, moment or any other library locale data sets

gpbl avatar Jul 15 '15 06:07 gpbl

@gpbl Thank you for providing this awesome repository. I made a loader that does exactly what you need to reduce IntlUtils to a minimum. See https://github.com/danilobuerger/react-intl-loader

danilobuerger avatar Apr 13 '16 18:04 danilobuerger

woah @danilobuerger you rock!! Does it even work with react-intl 2.0?

gpbl avatar Apr 13 '16 19:04 gpbl

@gpbl yes, only with 2.0 as it requires the addLocaleData and i didn't bother with switching between those.

danilobuerger avatar Apr 13 '16 19:04 danilobuerger

But i guess if you need to support 1.x as well, it would be a very simple case to just check if addLocaleData exists... i could implement that if needed

danilobuerger avatar Apr 13 '16 19:04 danilobuerger

@danilobuerger Awesome ! Well done! No i don't think is worth having it working on react-intl 1.0. Sure I'd like to have the time to update this repo 💦😄

gpbl avatar Apr 13 '16 19:04 gpbl

@gpbl if you do, you should also consider redux, would reduce a lot of additional boilerplate related to intl

danilobuerger avatar Apr 13 '16 19:04 danilobuerger

👍 see redux500 – still work in progress: I'm just finished migrating a flux app to redux and i've got much more experience with it.

gpbl avatar Apr 13 '16 20:04 gpbl