vue.js 无法在Pinia Store中使用国际化插件i18n

k7fdbhmy  于 2023-06-24  发布在  Vue.js
关注(0)|答案(5)|浏览(482)
import { useToast } from "vue-toastification";
import { useI18n } from "vue-i18n";

export default function useToastMsg(message, type) {

  const { t } = useI18n();
  const toast = useToast()

  if (type == "success") {
    return toast.success(t(`${message}`))
  } else if (type == "error") {
    return toast.error(t(`${message}`))
  }

}

我正在尝试在操作发生后在商店中使用此功能。store.js import useToast from "@/composables/toast"
作用功能:
useToast("submit", "success")
错误信息:Uncaught (in promise) SyntaxError: Must be called at the top of a设置function
我该如何解决这个问题?

ig9co6j1

ig9co6j11#

这让我有些头疼。但最终我还是想出了一个简单的解决方案。
第一步:初始化i18n,如下所示:

/* /utils/i18n.ts */

import { createI18n } from 'vue-i18n';
import messages from 'src/i18n';

const instance = createI18n({
    locale: 'en-US',
    messages,
});

export default instance;

export const i18n = instance.global;

步骤2:将上面的i18n示例添加到Vue应用程序中,如下所示:

import { createApp } from 'vue';
import i18nInstance from '/utils/i18n.ts'

const app = createApp({
  // something vue options here ...
})

app.use(i18nInstance)
app.mount('#app')

这就是你目前为止的i18n设置。现在,当你想在pinia中使用它时,你可以这样做:

import { defineStore } from 'pinia';
import { i18n } from '/utils/i18n';

const useStore = defineStore({
  id: 'StoreApp',
  state: () => {},
  getters: {
    getSomeTranslatedString() => i18n.t('String to be translated')
  },
  actions: {}
});

export default useStore;
lskq00tm

lskq00tm2#

useI18n()只能在setup()函数的顶部使用,因为它需要使用Composition API的inject()
解决方法是将$t()传递到useToastMsg()

// composables/toast.js
export default function useToastMsg(t, message, type) {
  //...
  return toast.success(t(`${message}`))
}
<template>
  <button @click="sayHello($t)">{{ $t('action.hello') }}</button>
</template>

<script>
import { defineComponent } from 'vue'
import { useStore } from '@/store'
import { mapActions } from 'pinia'

export default defineComponent({
  methods: {
    ...mapActions(useStore, ['sayHello']),
  },
})
</script>

demo

xsuvu9jc

xsuvu9jc3#

在store中定义一个包含i18n示例变量,并定义一个getter来访问它:

...
import { defineStore } from 'pinia';
import { Composer } from 'vue-i18n'; // WHEN USING TYPESCRIPT
...
const useStore = defineStore('store', {
  state: () =>
    ({
      $i18n: {}, // <== HERE
      ...
    }),
  getters: {
    // JS VERSION
    i18n() {
      return this.$i18n.global;
    },
    // TS VERSION
    i18n(): Composer {
      return this.$i18n.global as Composer;
    },
  },
  actions: ....
})

在某个地方,最好在应用程序初始化期间,在pinia创建之后,创建i18n,然后分配其示例:

import { createI18n } from 'vue-i18n';
import { createPinia } from 'pinia';
...
// init Pinia
const pinia = createPinia();
app.use(pinia);
const store = useStore();

// init i18n
const i18n = createI18n({...})

// assign instance
store.$i18n = i18n;

那么商店中的任何地方都可以使用i18n示例:

...
const useStore = defineStore('store', {
  state: ...
  getters: ...
  actions: {
    saySomething(): {
      toast.success(this.i18n.t('it works!')) // USE this.i18n
    }
  }
})
llycmphe

llycmphe4#

从我的Angular 来看,最好提供整个Vue应用程序的链接来存储。它不需要任何费用,因为它只是链接到对象。对于Vue 3.x,这是官方的方式-属性app是链接到您的应用程序,我们可以通过pinia插件为Vue 2.x做同样的事情
src/main.js Vue初始化:

new Vue({
    el: '#app',
    i18n,
    router,
    pinia,

    // ... other Vue plugins

    beforeCreate() {
        // provide Vue to pinia context
        pinia.use((context: PiniaPluginContext) => {
            context.store.app = this;
        });
    },
    render: (h) => h(App),
});

src/index.d.ts让TypeScript知道这个属性:

import Vue from 'vue';
import 'pinia';

declare module 'pinia' {
    export interface PiniaCustomProperties {
        // provide Vue instance to store
        app: Vue,
    }
}

示例-从pinia操作访问:

export const useLaunchStore = defineStore('launchStore', {
    // ... other properties like state, getters and e.t.c

    actions: {
        launch() {
            // access to router
            this.app.$router.push({ name: 'launch' });
            // access to i18n
            console.log('->', this.app.$t('actions.launch'));
        },
    },
});
wkftcu5l

wkftcu5l5#

如果您使用的是Nuxt 3,例如想在商店更改时更新语言。您可以观察pinia状态的变化,并在组件中执行setLocale(或其他任何内容)。最好是始终存在的一个,例如App.vue或布局(例如layouts/default.vue

// either App.vue or a layout (e.g. layouts/default.vue)

<script setup lang="ts">
const { setLocale } = useI18n();
const settingsStore = useSettingsStore();
const { languageSettings } = storeToRefs(settingsStore);

watch(
    () => languageSettings.value.languageCode,
    (value) => setLocale(value),
);

</script>

我找到了其他解决hacky/mess的方法,所以这个要干净得多。

相关问题