Loading translation files asynchronously with angular-translate and Webpack
Hello all,
I am developing a component based angular 1.5+ application. Since I am using Webpack to build, I want to make full of use of it and I want to load asynchronously translations files split in chuncks.
In order to make chuncks out of your code, you should can dynamic System.import
import
syntax (details). If you are not familiar with this concept I suggest you to read the documentation about code splitting.
Moreover I want to use angular-translate which normally works with static assets served locally or via url.
How can I tell angular-translate to load my assets via import
?
First we should define an angular-translate custom loader and make it the default one. See this example:
import angular from 'angular';
import angularTranslate from 'angular-translate';
import asyncLoaderService from './async-loader.service';
export default angular
.module('app', [
angularTranslate
])
.service('asyncLoader', asyncLoaderService)
.config($translateProvider => {
// configures staticFilesLoader
$translateProvider.useLoader('asyncLoader');
// load 'en' table on startup
$translateProvider.preferredLanguage('en');
$translateProvider.useSanitizeValueStrategy(null);
})
.name;
PS: If you are not familiar with this syntax then check out Todd Motto’s AngularJS styleguide (ES2015).
Then let’s define the asyncLoaderService
where we will use a dynamic import
to load our translations.
export default class asyncLoaderService {
constructor() {
return options => {
const locale = options.key;
/*
* Dynamic chunk import with Webpack
* import returns a Promise
*
* See: https://webpack.js.org/guides/code-splitting-import/#usage-with-babel
*/
return import(`./i18n/${locale}.js`)
.then(module => module.default);
};
}
}
This service loads static .js
files based on the locale
you are requesting. Webpack is smart so it will look in the ./i18n/
path for those files and produce chuncks out of them without any additional configuration.
Finally you just need to tell angular-translate which language to use, now and after the user had some interactions involving changing it. I can imagine for example a language switcher component with this two methods inside its controller:
class LanguageSwitcherController {
constructor($translate) {
// stick the angular-translate provider into the controller
this.$translate = $translate;
}
// this can be invoked by a select changing the language
handleChange(newLocale) {
this.$translate.use(newLocale);
}
$onInit() {
this.handleChange('en'); // set the default locale
}
}
Let’s see what’s the content of ./i18n/en.js
:
const requireContext = require.context('../app', true, /i18n\/en\.json$/);
const translations = {};
requireContext.keys().forEach(filePath => {
Object.assign(translations, requireContext(filePath));
});
export default translations;
Angular-translate expects a javascript object or an object with a combination of key and values. This script will load every i18n/en.json
file inside my project recursively and merge them together. For example I can have translations on everyone of my components
app/component-a/i18n/en.json app/component-b/i18n/en.json app/i18n/en.json
and have them loaded in a single object by the ./i18n/en.js
script.
To conclude this is the architecture I used to implement i18n localization using angular-translate and Webpack in an angularjs component based application. The final result is a performant application which loads localization contents only when demanded.
No comments yet.