【问题标题】:vue-i18n lazy loading is loading all localesvue-i18n 延迟加载正在加载所有语言环境
【发布时间】:2021-02-12 08:20:02
【问题描述】:

我正在尝试为 vue-i18n 实现延迟加载,我正在按照 https://kazupon.github.io/vue-i18n/guide/lazy-loading.html 的说明进行操作。

但是导入的行为并不符合我的预期。我希望它仅在调用时加载文件,但是当页面刷新时,即使未执行导入,它也会下载与模式“@i18n/messages/*.js”匹配的所有文件。代码中存在该行这一事实足以加载所有包。

import(/* webpackChunkName: "lang-[request]" */ `@/i18n/messages/${lang}.js`)

我错过了什么?

我正在使用 vue-cli。

【问题讨论】:

  • 你有什么运气吗?我也有同样的问题
  • @tom_h 我没有找到解决方法,但找到了解决方法。看我的回答。

标签: vue.js webpack vue-cli vue-i18n


【解决方案1】:

我无法指示 webpack 使用文档中的语法单独打包每个文件,但发现以下解决方法并不理想,但对我有用。

我正在替换文档中的 loadLanguageAsync(lang) 方法:

export function loadLanguageAsync(lang) {
    // If the same language
    if (i18n.locale === lang) {
        return Promise.resolve(setI18nLanguage(lang))
    }

    // If the language was already loaded
    if (loadedLanguages.includes(lang)) {
        return Promise.resolve(setI18nLanguage(lang))
    }

    // If the language hasn't been loaded yet
    return import(/* webpackChunkName: "lang-[request]" */ `@/i18n/messages/${lang}.js`).then(
        messages => {
        i18n.setLocaleMessage(lang, messages.default)
        loadedLanguages.push(lang)
        return setI18nLanguage(lang)
    }
)

有了这个:

export async function loadLanguageAsync(lang) {
    // If the same language
    if (i18n.locale === lang) {
        return Promise.resolve(setI18nLanguage(lang))
    }

    // If the language was already loaded
    if (loadedLanguages.includes(lang)) {
        return Promise.resolve(setI18nLanguage(lang))
    }

    // If the language hasn't been loaded yet
    let messages = null;
    switch (lang) {
        case 'en':
            messages = await import(/* webpackChunkName: "i18n-en" */ `@/i18n/messages/en.js`)
            break;
        case 'fr':
            messages = await import(/* webpackChunkName: "i18n-fr" */ `@/i18n/messages/fr.js`)
            break;
        case 'de':
            messages = await import(/* webpackChunkName: "i18n-de" */ `@/i18n/messages/de.js`)
            break;
    }
    if (messages != null) {
        i18n.setLocaleMessage(lang, messages.default)
        loadedLanguages.push(lang)
        return setI18nLanguage(lang)
    }
}

【讨论】:

  • 谢谢,确实有效。仅供参考,这似乎与 webpackChunkName 选项有关,删除它确实对我有用,但是你失去了重命名 i18n 块的能力。对我来说不是破坏交易,但有点烦人。
【解决方案2】:

由于这一直困扰着我一段时间,我现在刚刚解决了这里是我的 延迟加载解决方案(使用 vuetypescript强>)。从 4.5 - 7 mb 到 2.6 mb。我延迟加载并且不预取语言。

vue.config.js

   ...
   chainWebpack: config => {
    // remove the prefetch plugin
    // config.plugins.delete("prefetch");

    // or:
    // modify its options:
    config.plugin("prefetch").tap(options => {
      options[0].fileBlacklist = options[0].fileBlacklist || [];
      options[0].fileBlacklist.push(/lang(.)+?\.js$/);
      options[0].fileBlacklist.push(/lang(.)+?\.js.map$/);
      return options;
    });
  },
  ...

更新

如果使用 vue cli pages 这是一个更动态的预取选择器

vue.config.js

   ...
   chainWebpack: config => {
    // remove the prefetch plugin
    // config.plugins.delete("prefetch");

    // or:
    // modify its options:
    if (config && config.plugins && config.plugins.store) {
      const pluginKeys = Array.from(config.plugins.store.keys());

      const prefetchKeys = pluginKeys.filter(x => x.indexOf("prefetch") != -1);

      prefetchKeys.forEach(key => {
        if (config.plugins.has(key)) {
           config.plugin(key).tap(options => {
              options[0].fileBlacklist = options[0].fileBlacklist || [];
              options[0].fileBlacklist.push(/lang(.)+?\.js$/);
              options[0].fileBlacklist.push(/lang(.)+?\.js.map$/);
              return options;
           });
        }
      }
    }
  },
  ...

i18n.ts

import Vue from "vue";
import VueI18n from "vue-i18n";
import { LanguageList } from "@/types/languages";

import messages from "@/locales/en_US.json";

Vue.use(VueI18n);

export const i18n = new VueI18n({
  locale:
    process.env.VUE_APP_I18N_LOCALE ||
    "en_US",
  silentTranslationWarn: true,
  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || "en_US",
  messages: { en_US: messages }
});

const loadedLanguages = ["en_US"]; // our default language that is preloaded

export function setI18nLanguage(lang: string, load = true) {
  if (load) {
    /* eslint-disable @typescript-eslint/no-use-before-define */
    loadLanguageAsync(lang).then(() => {
      return lang;
    });
  } else {
    i18n.locale = lang;
    // axios.defaults.headers.common['Accept-Language'] = lang
    (document.querySelector("html") as HTMLElement).setAttribute("lang", lang);
    return lang;
  }
}

export function loadLanguageAsync(lang: string) {
  if (
    i18n.locale !== lang ||
    (!loadedLanguages.includes(lang) && LanguageList.find(l => l.code == lang))
  ) {
    if (!loadedLanguages.includes(lang)) {
      return import(
        /* webpackChunkName: "lang-[request]" */ `@/locales/${lang}`
      ).then(msgs => {
        debugger;
        console.log(msgs.default);
        i18n.setLocaleMessage(lang, msgs);
        loadedLanguages.push(lang);
        return setI18nLanguage(lang);
      });
    }
    return Promise.resolve(setI18nLanguage(lang, false));
  }
  return Promise.resolve(setI18nLanguage(lang, false));
}

App.vue

<script>
import {setI18nLanguage } from "@/i18n";
...
beforeMount() {
   setI18nLanguage(i18n.locale);
}
...
</script>

main.ts

...
import { i18n } from "@/i18n";
...

new Vue({
  router,
  store,
  i18n,
  render: h => h(App)
}).$mount("#app");

languages.ts

export interface LanguageI {
  code: string;
  language: string;
  english: string;
}

export const LanguageList: LanguageI[] = [
  { code: "en_US", language: "English", english: "English" },
//...
];

【讨论】:

  • 这很有效,谢谢。我需要禁用预取的唯一一点是在我的动态导入中添加一个以lang 开头的chunkName,并将options[0].fileBlacklist.push(/lang*/); 行添加到黑名单中。干杯!
猜你喜欢
  • 1970-01-01
  • 2022-06-20
  • 2023-04-07
  • 1970-01-01
  • 2019-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
相关资源
最近更新 更多