【问题标题】:vue show page after i18n translations loaded from backend从后端加载 i18n 翻译后的 vue 显示页面
【发布时间】:2021-01-06 03:52:35
【问题描述】:

在我的应用程序中,翻译可以由管理员编辑,所以我需要从我的后端预加载它们并在我拥有的 vue 应用程序中进行初始化。所以我发现 vue i18n 包有延迟加载消息的能力 (link) 。但是在他们的示例中,他们已经使用默认(en)消息初始化了 vue,但就我而言,我没有预加载默认消息。所以我想在创建 VueI18n 的新实例时从后端加载消息。

这是i18n.js 文件:

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import {syncGetData} from "@/apiUtil";
import NProgress from 'nprogress'
import './sass/nprogress.scss'

Vue.use(VueI18n)


let loadedLanguages = []

export const i18n = new VueI18n({
  locale: navigator.language.split('-')[0] || process.env.VUE_APP_I18N_LOCALE,
  fallbackLocale: navigator.language.split('-')[0] || process.env.VUE_APP_I18N_LOCALE,
  messages: loadLanguage(navigator.language.split('-')[0] || process.env.VUE_APP_I18N_LOCALE)
})

function setI18nLanguage (lang) {
  i18n.locale = lang
  document.querySelector('html').setAttribute('lang', lang)
  return lang
}

export function loadLanguage(lang) {
  // If the language was already loaded
  if (loadedLanguages.includes(lang)) {
    return Promise.resolve(setI18nLanguage(lang))
  }
  NProgress.start();
  return syncGetData('/api/translations/' + lang)
    .then(function(data) {
      setI18nLanguage(lang)
      loadedLanguages.push(lang)
      return  data;
    })
    .catch(function (error) {
      console.error(error)
    }).finally(function () {
      NProgress.done();
    });
}

这里还有main.js(简体):

import Vue from 'vue'
import App from './App.vue'
import {i18n} from './i18n'
new Vue({
  i18n,
  render: h => h(App)
}).$mount('#app')

翻译的加载工作正常,但 Vue 在加载之前渲染模板,我看到的不是实际的翻译,而是翻译键。我尝试使用v-cloak,但没有帮助。

所以我想要实现的是,当翻译加载用户应该只看到加载栏(我使用NProgress,您可以在i18n.js 中看到用法)并仅在加载翻译后渲染应用程序(可能不是渲染而是初始化)。我得到的是:加载栏和渲染的应用程序都没有实际翻译

提前致谢!

Michal Levý asnwer 之后的更新

现在,i18n.js 看起来像这样:

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import { syncGetData} from "@/apiUtil";
import NProgress from 'nprogress'
import './sass/nprogress.scss'

Vue.use(VueI18n)


let loadedLanguages = [];

export function initI18n() {
  const lang = navigator.language.split('-')[0] || process.env.VUE_APP_I18N_LOCALE

  return syncGetData('/api/translations/' + lang)
    .then(function(data) {
      console.log(data)
      setI18nLanguage(lang)
      loadedLanguages.push(lang)
      return new VueI18n({
        locale: lang,
        fallbackLocale: lang,
        messages: data
      })
    })
    .catch(function (error) {
      console.error(error)
    });
}

function setI18nLanguage (lang) {
  document.querySelector('html').setAttribute('lang', lang)
  return lang
}

export function loadLanguage(lang) {
  // If the language was already loaded
  if (loadedLanguages.includes(lang)) {
    return Promise.resolve(setI18nLanguage(lang))
  }
  NProgress.start();
  return syncGetData('/api/translations/' + lang)
    .then(function(data) {
      setI18nLanguage(lang)
      loadedLanguages.push(lang)
      return  data;
    })
    .catch(function (error) {
      console.error(error)
    }).finally(function () {
      NProgress.done();
    });
}

main.js 是:

import Vue from 'vue'
import App from './App.vue'
import {initI18n} from './i18n'
import NProgress from "nprogress";
import './sass/nprogress.scss'

NProgress.start();
initI18n().then(function(i18n) {
  new Vue({
    i18n,
    render: h => h(App)
  }).$mount('#app')
}).finally(function () {
  NProgress.done();
});

我可以确认现在消息是在 Vue 初始化之前加载的,b-z 在我的App.vue 我有一个console.logmounted 方法:

  mounted() {
    console.log(this.$i18n.messages)
  }

控制台日志的输出是Object { main_title: "Calculation", tab_you: "You", tab_friend: "Your Friend",...},之前是空对象。

<h2 class="title-form">{{ $t('main_title') }}</h2> 仍然呈现main_title 而不是Calculation

【问题讨论】:

    标签: vue.js fetch vue-i18n


    【解决方案1】:

    VueI18n 初始化替换为如下内容:

    export function initI18n() {
      const lang = navigator.language.split('-')[0] || process.env.VUE_APP_I18N_LOCALE
      
      return loadLanguage(lang).then(function(data) {
        return new VueI18n({
          locale: lang,
          fallbackLocale: lang,
          messages: data
        })
      })
    }
    

    main.js

    import Vue from 'vue'
    import App from './App.vue'
    import { initI18n } from './i18n'
    
    initI18n().then(function(i18n) {
      new Vue({
        i18n,
        render: h => h(App)
      }).$mount('#app')
    })
    

    Q 更新后编辑:

    您本地化的format 似乎是错误的。 VueI18 能够同时使用多种语言,因此您所有的翻译键都应该包含在“语言对象”中

    代替:

    { 
      main_title: "Calculation", 
      tab_you: "You", 
      tab_friend: "Your Friend",
      ...
    }
    

    您的 API 应该返回

    { 
      "en": {
        main_title: "Calculation", 
        tab_you: "You", 
        tab_friend: "Your Friend",
        ...
      }
    }
    

    ...其中“en”是语言标识符

    检查你的浏览器控制台,我相信 VueI18n 应该警告丢失键...

    【讨论】:

    • 嗯,看起来你提到的方式应该可以工作,现在它在初始化 Vue 之前加载翻译,但我仍然只看到翻译键,不知道为什么......我赞成你的回答并继续用新的信息/代码更新主要问题
    • 我认为这是您从后端返回的翻译格式的问题。更新了我的答案...
    • 不,我现在返回像这样的对象 gyazo.com/883bc11d044454c4245046bd0104a23a 并且仍然 {{$t('main_title')}} 不起作用,但我可以像这样访问 {{ $i18n.messages.en.main_title }} 以防万一我找不到任何解决方案
    • 顺便问一下问题,获得解决方案,然后更改问题(添加更多问题)而不给予适当的信用是一种方法......(讽刺)
    • 好的,你是对的,拿起你的答案 :) 谢谢!
    猜你喜欢
    • 2019-07-19
    • 2020-10-31
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多