Skip to content

I18n

Internationalization of this project is inplemented via Vue I18n v8.x. Vue I18n v9.x only supports Vue 3, but we can bring several important features like Composition API and message format syntax back to Vue 2 by vue-i18n-bridge.

Bundle Tool

Since vue-i18n@v9.x, the locale messages are handled with message compiler, which converts them to javascript functions after compiling in order to improve the performance of the application. With unplugin-vue-i18n, the compilation can be done before importing locale messages by managing them in a file such as .json, so as to exclude i18n message compiler and only leave a Vue I18n runtime in the final production bundle.

I18n Custom Block

With unplugin-vue-i18n, we can add i18n custom block in SFC to avoid putting all messages in global scope:

vue
<template>
  <form>
    <label>{{ t('language') }}</label>
    <select v-model="locale">
      <option value="en">en</option>
      <option value="zh">zh</option>
    </select>
  </form>
  <p>{{ t('hello') }}</p>
</template>

<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t, locale } = useI18n({
  inheritLocale: true,
  useScope: 'local'
})
</script>

<i18n lang="json">
{
  "en": {
    "language": "Language",
    "hello": "hello, world!"
  },
  "zh": {
    "language": "语言",
    "hello": "你好世界!"
  }
}
</i18n>
<template>
  <form>
    <label>{{ t('language') }}</label>
    <select v-model="locale">
      <option value="en">en</option>
      <option value="zh">zh</option>
    </select>
  </form>
  <p>{{ t('hello') }}</p>
</template>

<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t, locale } = useI18n({
  inheritLocale: true,
  useScope: 'local'
})
</script>

<i18n lang="json">
{
  "en": {
    "language": "Language",
    "hello": "hello, world!"
  },
  "zh": {
    "language": "语言",
    "hello": "你好世界!"
  }
}
</i18n>

For more functionalities of unplugin-vue-i18n, you can refer to its documentations.

Why not vite-plugin-i18n?

Because vite-plugin-i18n does not support i18n custom block for Vue 2.6 (I didn't test if it works for Vue 2.7), and it seems that unplugin-vue-i18n has already supercedes the former and will replace it in the future.

Configuration

The configuration of introducing vue-i18n-bridge and unplugin-vue-i18n has already done in this template, but some settings may be worth mentioning here. runtimeOnly should be set to false, as the plugin will point entry of Vue I18n to vue-i18n/dist/vue-i18n.runtime.esm-bundler.js which doesn't exist in Vue I18n v8. We need to manually set alias of vue-i18n-bridge.

ts
// vite.config.ts
export default defineConfig({
  plugins: [
    VueI18n({
      runtimeOnly: false,
      compositionOnly: true,
      fullInstall: false,
      include: [path.resolve(__dirname, 'src/locales/**')],
    }),
    /* other plugins */
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
      'vue-i18n-bridge':
        'vue-i18n-bridge/dist/vue-i18n-bridge.runtime.esm-bundler.js',
    },
  },
// vite.config.ts
export default defineConfig({
  plugins: [
    VueI18n({
      runtimeOnly: false,
      compositionOnly: true,
      fullInstall: false,
      include: [path.resolve(__dirname, 'src/locales/**')],
    }),
    /* other plugins */
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
      'vue-i18n-bridge':
        'vue-i18n-bridge/dist/vue-i18n-bridge.runtime.esm-bundler.js',
    },
  },

Limitation

In this template, we can only use Vue I18n with Composition API, as Vue I18n does not fully support using both Legacy API and Composition API together in a project, which is also not recommended by the author. But you can still use Composition API just like Legacy API in a component defined via Options API:

vue
<script lang="ts">
export default defineComponent(){
  setup(){
    const { t } = useI18n()
    return { t }
  }
  computed:{
    helloWorld(){
      return `Hellow ${t('world')}`
    }
  }
}
</script>
<template>
  <div>{{ t('hi') }}</div>
</template>
<script lang="ts">
export default defineComponent(){
  setup(){
    const { t } = useI18n()
    return { t }
  }
  computed:{
    helloWorld(){
      return `Hellow ${t('world')}`
    }
  }
}
</script>
<template>
  <div>{{ t('hi') }}</div>
</template>

VSCode Extenstion

Here I highly recommend I18n Ally, a VSCode extension which can inline annotations and manage all translations. Note that I18n Ally does not automatically detect unplugin-vue-i18n and enable vue-sfc feature, that's why I add the following settings manually in VSCode workspace settings.

json
{
  "i18n-ally.enabledFrameworks": ["vue-sfc", "vue"],
}
{
  "i18n-ally.enabledFrameworks": ["vue-sfc", "vue"],
}

Released under the MIT License.