vue-i18n icon indicating copy to clipboard operation
vue-i18n copied to clipboard

[Proposal] Modules and lazy loading

Open javiertury opened this issue 5 years ago • 2 comments

First let's build the modules

// houses/lang/en.js

// This is a locale which belongs to the module *houses*
export default {
  messages: {
    // translation keys start at this level
    houses: {
      house: 'casa',
      hall: 'pasillo',
      bath: 'baño',
      ...
    }
  }
}
import en from './en.js';

// This is a module
const houseModule = {
  en: () => import('./houses/lang/en.js'),
  es: () => import('./houses/lang/es.js'),
  // We can also load locales without lazy loading
  de,
  ...
}

When i18n is created, it accepts modules as configuration parameters.

const i18n = new VueI18n({
  locale: 'en',
  fallbackLocale: 'en',
  modules: {
     houses: houseModule,
  }
})

It integrates nicely with vue-router. This router guard for languages, allows you to declare the localeModules meta property to lazily load locales from that module for a particular route.

// routes.js
import houseLangs from './houses/lang/index.js';

const router = new VueRouter({
  routes: [{
    path: '/:lang/houses',
    name: 'houses',
    component: () => import('./components/houses.vue'),
    props: true,
    meta: {
      // Tells route guard to load languages from this module only in this route and its children
      localeModules: {
        houses: houseLangs,
        cars: {
          en: () => import('./cars/lang/en.js'),
          es: () => import('./cars/lang/es.js'),
          ...
        }
      },
    },
    children: [
      ...
    ],
  }],
})

There is a working demo available. Instructions can be found in the repo.

Why modules?

With sharedMessages, components can selectively load the translation keys they need, but they have to load them for all locales, even if many locales are not used.

vue-i18n provides methods to dynamically register locales like setLocaleMessage, which can easily be used to selectively load locales. By default, they provide no structure to break down translation keys into more specific groups.

Modules provide an structure on top of dynamic vue-i18n methods. Modules can be lazy loaded in a similar way to route components and vuex stores. With modules, you can load only the locales that are strictly needed for the modules that are active.

Summary: sharedMessages can selectively load groups of translations keys, vue-i18m methods can selectively load locales, and modules can do both.

Notes

In this example, VueI18n instances should be called with i18n.setLocale(locale) where i18n.locale = locale was previously used. The reason is that setLocale calls async module loaders and returns a promise.

This is not the only possible solution. Another alternative is to listen to i18n.locale changes and trigger language loaders. Then create a method i18n.onReady(callback, onReject) to know when both locale and fallbackLocale are loaded in all languages. I'm just bad at Vue.

javiertury avatar Aug 03 '19 16:08 javiertury

I'm currently building a large application on Vue and being able to load language files dynamically in a modular system for each route is a must. Making it work like modules presented on this proposal make this possible.

Your solution seems like a life-saver, it was just what I was looking for, I will try implement it on my side as well.

Is there any news on such feature being implemented into the plugin?

iomariani avatar Sep 04 '20 01:09 iomariani

Bump, any news on this? React i18n has similar feature.

klausXR avatar Jan 10 '22 17:01 klausXR