Skip to content

入门

基于 Vue I18n v11 编写

速查

  • 安装:pnpm add vue-i18n@11
  • 适配版本:Vue 3.0+(v8 已停更,新项目直接上 v11)
  • 入口:createI18n({ legacy: false, locale, fallbackLocale, messages })
  • 注册:app.use(i18n)
  • 模板取值:$t('key') / $d(date) / $n(num)globalInjection 默认开启)
  • Composition:const { t, d, n, locale } = useI18n()
  • 切语言:locale.value = 'en'(响应式自动重渲染)
  • SFC 翻译块:<i18n>{ "en": {...}, "ja": {...} }</i18n>,需 @intlify/unplugin-vue-i18n
  • 懒加载:i18n.global.setLocaleMessage(locale, msg) + 动态 import()

安装

bash
pnpm add vue-i18n@11

版本与 Vue 兼容

Vue I18nVue状态
v11.xVue 3.0+当前主线,长期维护
v10.xVue 3.0+仍可用,建议升级到 v11
v9.xVue 3.0+已停更,迁移到 v10/v11
v8.xVue 2.x已停更(Vue 2 EOL 后不再维护)

旧项目从 v9 迁到 v11 主要看三个 breaking:Legacy API 模式弃用、v-t 自定义指令弃用、tc / $tc 已移除(Legacy 模式)。详见 v11 迁移要点

配置

createI18n() 创建实例,app.use(i18n) 注册到 Vue 应用:

ts
// src/i18n.ts
import { createI18n } from "vue-i18n";

const messages = {
  en: {
    message: {
      hello: "hello world",
    },
  },
  zh: {
    message: {
      hello: "你好,世界",
    },
  },
};

export const i18n = createI18n({
  legacy: false,           // 启用 Composition API 模式(v12 将默认 false)
  locale: "zh",            // 当前语言
  fallbackLocale: "en",    // 兜底语言(key 缺失时回退)
  messages,
});
ts
// src/main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { i18n } from "./i18n";

createApp(App).use(i18n).mount("#app");

Composition API 必须 legacy: false

createI18n 默认 legacy: true(沿用 Vue 2 时代的全局注入模式),此时 useI18n 会抛错。从 v11 起 Legacy API 已被官方标记弃用,新项目应总是显式写 legacy: false,v12 将彻底移除 Legacy 模式。

常用配置项

字段默认值说明
legacytruefalse 启用 Composition API;强烈建议显式设为 false
locale'en-US'当前语言代码
fallbackLocale兜底语言;可传字符串、数组或 { zh: ['en','ja'], default: ['en'] } 这种 fallback 链
messages{}嵌套对象:{ locale: { key: 'value' } }
globalInjectiontrue是否把 $t / $d / $n 注入到所有组件的模板上下文
missingWarntruekey 缺失时是否在控制台告警;上线后可关
fallbackWarntrue触发 fallback 时是否告警
silentTranslationWarnfalsetrue 关闭所有翻译告警

基本用法

模板里取值

vue
<template>
  <p>{{ $t("message.hello") }}</p>            <!-- 翻译 -->
  <p>{{ $d(new Date(), "long") }}</p>          <!-- 日期 -->
  <p>{{ $n(1234.5, "currency") }}</p>          <!-- 数字 -->
</template>

$t / $d / $n 来自 globalInjection: true。如果显式关闭,模板里需用 useI18n() 解构后的 t / d / n

<script setup> 里取值

vue
<script setup lang="ts">
import { useI18n } from "vue-i18n";

const { t, d, n, locale, availableLocales } = useI18n();

function switchTo(lang: string) {
  // locale 是 ref,赋值会触发整棵组件树重渲染
  locale.value = lang;
}
</script>

<template>
  <button @click="switchTo('en')">EN</button>
  <button @click="switchTo('zh')">中文</button>
  <p>{{ t("message.hello") }}</p>
</template>

命名插值与变量

模板用 {name} 占位,调用时第二参传字典:

ts
// messages.en.greeting
"greeting": "Hello, {name}!"
vue
<p>{{ t("greeting", { name: "Vue" }) }}</p>
<!-- Hello, Vue! -->

列表插值用 {0}{1}

ts
"order": "Item {0} costs {1}"
vue
<p>{{ t("order", ["Apple", "$3"]) }}</p>
<!-- Item Apple costs $3 -->

切换语言

直接给 locale.value 赋值即可,所有用到 t() 的组件会自动重渲染:

ts
const { locale } = useI18n();
locale.value = "en";

要把当前语言持久化,常见做法是写 localStorage + 启动时读回:

ts
// 启动时
const saved = localStorage.getItem("locale") ?? navigator.language.split("-")[0];
i18n.global.locale.value = saved;

// 切换时
watch(locale, (v) => localStorage.setItem("locale", v));

一份能跑的最小示例

src/
├── i18n/
│   ├── index.ts           # createI18n 实例
│   └── locales/
│       ├── en.json
│       └── zh.json
├── App.vue
└── main.ts
ts
// src/i18n/index.ts
import { createI18n } from "vue-i18n";
import en from "./locales/en.json";
import zh from "./locales/zh.json";

export const i18n = createI18n({
  legacy: false,
  locale: "zh",
  fallbackLocale: "en",
  messages: { en, zh },
});
json
// src/i18n/locales/zh.json
{
  "message": {
    "hello": "你好,世界"
  }
}
vue
<!-- src/App.vue -->
<script setup lang="ts">
import { useI18n } from "vue-i18n";
const { t, locale } = useI18n();
</script>

<template>
  <select v-model="locale">
    <option value="zh">中文</option>
    <option value="en">English</option>
  </select>
  <h1>{{ t("message.hello") }}</h1>
</template>

下一步