How to bind and load i18n modules at runtime?

I am trying to migrate from RequireJS to Webpack, and I'm not sure if the best way is to process our locale files.

We are currently creating a separate JS file for each locale. These files contain 7+ module definitions for i18n messages, as well as library configurations (such as moment). For example, our da_DK file looks something like this:

(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('../moment')) : typeof define === 'function' && define.amd ? define('moment-locale',['moment'], factory) : factory(global.moment) }(this, function (moment) { 'use strict'; var da = moment.defineLocale('da', { ... }); return da; })); define('messages',[],function(){ var da_messages = { ... }; return da_messages; }); 

At run time, we determine the appropriate language file to download with the rest of our application. Our application code does not know which language is loaded; any locale-dependent modules will do require('moment-locale') and require('messages') .

I want to do something similar with Webpack, but I have not yet found a good way to accomplish this.

I have seen require.context for dynamic needs, but it looks like this will result in combining all possible locales with my application, which I would rather not do.

I also looked into DllPlugin, considering that each locale file could be a "dll", but I noticed that the dll manifest contains certain module names (for example: node_modules / moment / locale / de-at.js), and I think that I need this to be more general, so webpack knows when I require('moment-locale') it should look in this dll.

One of the ways I was able to get this to work was to update the locale code generation code so that it creates an entry for each locale that looks like this:

 module.exports = { 'messages': require('messages'), 'moment-locale': require('moment-locale'), ... }; 

and then in the webpack configuration, I set the library field to the namespace for my application. And then in my webpack config application, I referenced these modules in externals . In other words, when da_DK.js loads, it puts all the modules in the window under the namespace that the application refers to when loading. I would prefer not to use this approach, but this is the only way I have been able to get this to work so far.

Is there any other / better way to accomplish this?

+8
webpack
source share
1 answer

There are several ways to do this. Three possible ways are:

  • Package of all locales in your kit.
  • Make your package lazy loading locale
  • Make individual packages for each locale

Package of all locales in your package

This way you will trade a higher packet size for one less HTTP request. If the locales are small, this could be a route. In all other cases, I would advise him, as this will increase the size of the packet and increase the load.

Make your package lazy loading locales .

To do this, use the Webpacks code-sharing functionality . This way you can create bundle.js , da_DK.js , a sv_SE.js , etc. And use require() / require.ensure to load one of the locale files depending on the logic in bundle.js.

Make separate packages for each locale

Depending on how you negotiate the locale, the best way might be to create separate packages at build time. In other words, create bundle.da_DK.js a bundle.sv_SE.js and so on. If you are performing locale negotiation based on anything available before downloading the package (e.g. /da/ slug in the URL, session settings, etc.), this might be the way.

By doing this, you will: a) Create the smallest package possible and b) get an increase in performance (albeit a small one), since the translation should not be performed at run time. i18n plugin for Webpack helps you create separate packages.

Side note

Moment.js, although it is a really good library, it is not very convenient for Webpack. It will load all locales. Take a look at this topic to change this behavior: stack overflow

+7
source share

All Articles