IntlUtils.loadLocaleData seems like it could be improved
robink opened this issue · 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?
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 :-)
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 thanks for joining in :-) What do you mean for translation data ?
We need:
- "messages" (as in the react-int jargon): translated strings used in the interface
- "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 require
d, 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?
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 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
woah @danilobuerger you rock!! Does it even work with react-intl 2.0?
@gpbl yes, only with 2.0 as it requires the addLocaleData
and i didn't bother with switching between those.
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 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 if you do, you should also consider redux, would reduce a lot of additional boilerplate related to intl