nuxt.jsvue-i18nvite

how to import a json file using vite dynamicly


I am using vue-i18n in a Nuxtjs project, and I want to import my locale files with vite dynamicly.

when I am using webpack, those code run well

plugins/i18n.js

import Vue from 'vue';
import VueI18n from 'vue-i18n';
import config from '@/config';

Vue.use(VueI18n);

let messages = Object;

config.locale.available.forEach(locale => {
    messages[locale] = require(`~/locales/${locale}.json`);
});

export default ({ app, store }) => {
    app.i18n = new VueI18n({
        locale: store.state.locale.locale,
        messages: messages
    });
}

I got that there is no require() in vitejs, also the glob-import feature of vitejs

  1. So I tried like this below first:
let messages = Object,
    languages = import.meta.glob('../locales/*.json'); // => languages = {} (languages only get {} value)

config.locale.available.forEach(locale => {
    messages[locale] = languages[`../locales/${locale}.json`];
});

But the languages only got {} value.

  1. Then I tried to use import()
let messages = Object,
    translate = lang => () => import(`@/locales/${lang}.json`).then(i => i.default || i);

config.locale.available.forEach(locale => {
    messages[locale] = translate(locale);
});

no errors in both terminal and console, but no locale file has been loaded correctly.


only if I import() one by one, the issue will disappear:

import en from '@/locales/en.json';
import fr from '@/locales/fr.json';
import ja from '@/locales/ja.json';

let messages = Object;

messages['en'] = en;
messages['fr'] = fr;
messages['ja'] = ja;

CodeSandbox

But, how to import it dynamicly?

I googled it, but helped little. Greate thank for anyone help!


Solution

  • So, I think I figured out something based on @LiuQixuan's answer on GitHub.

    //Importing your data 
    const data = import.meta.glob('../locales/*.json')
    
    //Ref helps with promises I think. I'm sure there are more elegant ways.
    const imp = ref([{}])
    
    // From https://github.com/vitejs/vite/issues/77
    // by LiuQixuan commented on Jun 20
    
    for (const path in data) {
        data[path]().then((mod) => { 
            imp.value.push(mod)
        })
    }
    

    From there, I iterated through the imp.values, then I can call each file in a loop, grabbing the data with:

    JSON.parse(JSON.stringify(**Your data**))
    

    My example Vue HTML was this:

        <div v-for="(module,i) in imp" :key="i">
              <div v-for="(data,j) in module" :key="j">
    
                //at this point you can read it fully with {{ data }}
    
                <div v-for="(jsonText, k) in JSON.parse(JSON.stringify(data))" :key=k">
                  {{ jsonText.text }}
                  <div v-for="insideJson in jsonText" :key="insideJson">
                    {{ insideJson.yourtext }}
                  </div>
                </div>
              </div>
         </div>
    

    With that, I could access every object in the file. You have other needs I think, but this proves that you can access each file without independent imports.

    I know this is a little rough. I used the Stringify parse because the data was always returning as never, so I couldn't directly access. I'm sure there is a more elegant solution, but this is what I figured out.

    I was originally trying to import images dynamically, after figuring it out, I then applied the method to your issue.

    For anyone wondering on dynamic multi-image import from folder, use:

    new URL(*, import.meta.url)
    

    As in, like before, but with the addition:

        for (const path in modules) {
          modules[path]().then(() => {
            //*************
            const imgURL = new URL(path, import.meta.url)
            //*************
            gallery.value.push(imgURL)
          })
        }
        //Then reference that gallery.value in your :src