Vue I18n 是 Vue 官方的国际化插件,专为 Vue 应用提供多语言支持 —— 在 CRM 系统中,若需适配海外客户、多语言团队协作、跨境业务场景,Vue I18n 是实现多语言切换的最优解。下面从「核心集成→实战配置→CRM 高频场景→性能优化」全维度讲解,贴合 Vue3 + TS 开发。

一、核心定位(CRM 为什么需要多语言?)

CRM 系统的多语言需求场景:

  1. 跨境业务:如面向东南亚 / 欧美客户的 CRM,需支持中文 / 英文 / 本地语言;
  2. 多语言团队:海外分公司员工使用,界面需适配当地语言;
  3. 合规要求:部分地区要求系统提供本地语言版本;
  4. 自定义语言包:支持客户按需配置行业专属术语(如外贸 CRM 的 “报关单” 多语言翻译)。

Vue I18n 核心优势:

  • 深度适配 Vue3 组合式 API;
  • 支持模板 / 脚本 / 组件内多语言;
  • 按需加载语言包(减小打包体积);
  • 支持变量插值、复数、日期 / 数字格式化(适配 CRM 动态数据)。

二、快速集成(Vue3 + Vite + TS)

1. 安装依赖

bash

运行

# Vue3 对应 vue-i18n@9+
npm install vue-i18n@9 -S
# TS 类型(库自带,无需额外安装)

2. 核心配置(全局初始化)

步骤 1:创建语言包文件

typescript

运行

// src/locales/zh-CN.ts(中文语言包)
export default {
  common: {
    save: '保存',
    cancel: '取消',
    submit: '提交',
    delete: '删除',
    search: '搜索',
    reset: '重置'
  },
  customer: {
    title: '客户管理',
    name: '客户名称',
    phone: '联系电话',
    status: '客户状态',
    active: '活跃',
    inactive: '非活跃',
    pending: '待跟进'
  },
  order: {
    title: '订单管理',
    id: '订单ID',
    amount: '订单金额',
    createTime: '创建时间',
    status: {
      pending: '待付款',
      paid: '已付款',
      completed: '已完成'
    }
  }
};

// src/locales/en-US.ts(英文语言包)
export default {
  common: {
    save: 'Save',
    cancel: 'Cancel',
    submit: 'Submit',
    delete: 'Delete',
    search: 'Search',
    reset: 'Reset'
  },
  customer: {
    title: 'Customer Management',
    name: 'Customer Name',
    phone: 'Phone Number',
    status: 'Customer Status',
    active: 'Active',
    inactive: 'Inactive',
    pending: 'Pending Follow-up'
  },
  order: {
    title: 'Order Management',
    id: 'Order ID',
    amount: 'Order Amount',
    createTime: 'Create Time',
    status: {
      pending: 'Pending Payment',
      paid: 'Paid',
      completed: 'Completed'
    }
  }
};
步骤 2:初始化 Vue I18n

typescript

运行

// src/locales/index.ts
import { createI18n } from 'vue-i18n';
// 导入语言包
import zhCN from './zh-CN';
import enUS from './en-US';

// 定义支持的语言列表
export const LOCALE_LIST = [
  { label: '中文', value: 'zh-CN' },
  { label: 'English', value: 'en-US' }
];

// 默认语言(优先从本地存储读取,否则用浏览器语言)
const defaultLocale = localStorage.getItem('crm-locale') || (navigator.language === 'en-US' ? 'en-US' : 'zh-CN');

// 创建 i18n 实例
const i18n = createI18n({
  legacy: false, // 启用 Composition API 模式(必须!)
  locale: defaultLocale, // 当前语言
  fallbackLocale: 'zh-CN', // 回退语言(当翻译缺失时)
  messages: {
    'zh-CN': zhCN,
    'en-US': enUS
  },
  // 全局格式化数字/日期(可选)
  numberFormats: {
    'zh-CN': {
      currency: { style: 'currency', currency: 'CNY' } // 人民币格式化
    },
    'en-US': {
      currency: { style: 'currency', currency: 'USD' } // 美元格式化
    }
  }
});

export default i18n;
步骤 3:全局注册(main.ts)

typescript

运行

import { createApp } from 'vue';
import App from './App.vue';
import i18n from './locales';

const app = createApp(App);
app.use(i18n); // 注册 i18n
app.mount('#app');

三、CRM 实战用法(核心场景)

场景 1:模板中使用多语言(最常用)

直接用 $tt 函数(Composition API)渲染多语言文本:

vue

<template>
  <!-- 基础翻译 -->
  <div class="page-header">
    <h1>{{ t('customer.title') }}</h1>
    <button>{{ t('common.save') }}</button>
  </div>

  <!-- 嵌套翻译(订单状态) -->
  <table>
    <tr v-for="order in orderList" :key="order.id">
      <td>{{ order.id }}</td>
      <td>{{ t(`order.status.${order.status}`) }}</td>
      <td>{{ t('common.delete') }}</td>
    </tr>
  </table>

  <!-- 变量插值(动态内容) -->
  <div>{{ t('common.notice', { count: unreadCount }) }}</div>
</template>

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

// 组合式 API 引入 t 函数
const { t } = useI18n();
// 动态数据
const unreadCount = ref(5);
const orderList = ref([
  { id: 'ORD001', status: 'pending' },
  { id: 'ORD002', status: 'paid' }
]);
</script>

场景 2:脚本中使用多语言

在请求、逻辑处理中使用多语言(如提示文案):

vue

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

const { t } = useI18n();

// 保存客户逻辑
const saveCustomer = async () => {
  try {
    await api.saveCustomer();
    ElMessage.success(t('common.saveSuccess')); // 多语言提示
  } catch (err) {
    ElMessage.error(t('common.saveFailed'));
  }
};
</script>

场景 3:语言切换组件(CRM 全局功能)

封装语言切换下拉框,切换后保存到本地存储:

vue

<template>
  <el-select
    v-model="currentLocale"
    class="locale-select"
    @change="handleLocaleChange"
  >
    <el-option
      v-for="item in LOCALE_LIST"
      :key="item.value"
      :label="item.label"
      :value="item.value"
    />
  </el-select>
</template>

<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { LOCALE_LIST } from '@/locales';

const { locale } = useI18n();
// 当前语言(双向绑定)
const currentLocale = ref(locale.value);

// 切换语言
const handleLocaleChange = (val: string) => {
  locale.value = val; // 更新 i18n 语言
  localStorage.setItem('crm-locale', val); // 保存到本地存储
  // 可选:刷新页面(如需立即生效所有组件)
  // window.location.reload();
};
</script>

场景 4:动态变量 & 复数处理(CRM 统计场景)

适配 “1 条记录”“2 条记录” 等复数场景,或动态插入变量:

typescript

运行

// 先在语言包中定义复数模板
// zh-CN.ts
{
  "common": {
    "recordCount": "共 {count} 条记录",
    "notification": "你有 {count} 条未读消息 |||| 你有 {count} 条未读消息" // 复数格式(|||| 分隔)
  }
}

// en-US.ts
{
  "common": {
    "recordCount": "Total {count} records",
    "notification": "You have {count} unread message |||| You have {count} unread messages"
  }
}

// 组件中使用
const { t } = useI18n();
console.log(t('common.recordCount', { count: 10 })); // 共 10 条记录
console.log(t('common.notification', { count: 1 })); // 你有 1 条未读消息
console.log(t('common.notification', { count: 5 })); // 你有 5 条未读消息

场景 5:数字 / 日期格式化(CRM 金额 / 时间)

利用 Vue I18n 内置的格式化能力,适配不同语言的数字 / 日期格式:

vue

<template>
  <!-- 金额格式化(人民币/美元) -->
  <p>{{ $n(order.amount, 'currency') }}</p>
  <!-- 日期格式化 -->
  <p>{{ $d(order.createTime, 'short') }}</p>
</template>

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

const { n, d } = useI18n();
// 脚本中使用
const formatAmount = (amount: number) => {
  return n(amount, 'currency');
};
</script>

// 配置日期格式化(locales/index.ts)
const i18n = createI18n({
  // ...其他配置
  datetimeFormats: {
    'zh-CN': {
      short: { year: 'numeric', month: '2-digit', day: '2-digit' } // 2026-03-20
    },
    'en-US': {
      short: { month: '2-digit', day: '2-digit', year: 'numeric' } // 03/20/2026
    }
  }
});

四、性能优化(CRM 大型项目)

1. 按需加载语言包(减小首屏体积)

若语言包较大(如包含大量行业术语),可改为异步加载:

typescript

运行

// src/locales/index.ts
const i18n = createI18n({
  legacy: false,
  locale: 'zh-CN',
  fallbackLocale: 'zh-CN',
  messages: {
    'zh-CN': import('./zh-CN') // 初始只加载中文
  }
});

// 动态加载语言包
export const loadLocale = async (locale: string) => {
  if (!i18n.global.availableLocales.includes(locale)) {
    // 异步导入语言包
    const messages = await import(`./${locale}.ts`);
    i18n.global.setLocaleMessage(locale, messages.default);
  }
  i18n.global.locale.value = locale;
  localStorage.setItem('crm-locale', locale);
};

// 语言切换时调用
// handleLocaleChange = async (val) => {
//   await loadLocale(val);
// };

2. 避免模板中频繁调用 t 函数

频繁调用 t('xxx') 会触发多次翻译解析,可缓存翻译结果:

vue

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

const { t } = useI18n();
// 缓存翻译结果
const translate = computed({
  get() {
    return {
      save: t('common.save'),
      cancel: t('common.cancel')
    };
  }
});
</script>

<template>
  <button>{{ translate.save }}</button>
  <button>{{ translate.cancel }}</button>
</template>

3. 翻译缺失兜底

配置 missingWarn 关闭开发环境警告,自定义缺失翻译处理:

typescript

运行

const i18n = createI18n({
  // ...其他配置
  missingWarn: false, // 关闭缺失翻译警告
  fallbackWarn: false,
  // 自定义缺失翻译处理
  missing: (locale, key) => {
    console.warn(`[i18n] 缺失翻译:${key} (${locale})`);
    return `[${key}]`; // 兜底显示 key
  }
});

五、核心避坑点

1. legacy: false 必须设置

忘记设置 legacy: false 会导致 Composition API(useI18n)无法使用,报 t is not a function 错误。

2. 动态 key 翻译不生效

问题:t(order.status.${status}) 若 status 为动态值,开发环境可能不生效;解决方案:

  • 确保语言包中存在对应 key;
  • 开发环境禁用 vue-i18n 的缓存:i18n.global.setLocaleMessage(locale, messages)

3. 本地存储语言不生效

问题:切换语言后刷新页面,语言还原;解决方案:初始化时优先从 localStorage 读取语言(如配置中的 defaultLocale)。

4. 第三方组件(如 Element Plus)多语言

需单独配置 Element Plus 多语言,与 Vue I18n 联动:

typescript

运行

// main.ts
import ElementPlus from 'element-plus';
import zhCn from 'element-plus/dist/locale/zh-cn.mjs';
import enUs from 'element-plus/dist/locale/en.mjs';
import i18n from './locales';

// 动态切换 Element Plus 语言
const updateElementLocale = (locale: string) => {
  const app = createApp(App);
  app.use(ElementPlus, {
    locale: locale === 'zh-CN' ? zhCn : enUs
  });
};
// 初始化时调用
updateElementLocale(i18n.global.locale.value);
// 语言切换时重新调用

六、总结(CRM 开发最佳实践)

  1. 适用场景
    • 需多语言支持的跨境 CRM、多语言团队协作场景;
    • 纯中文 CRM 无需引入 Vue I18n,完全没必要;
  1. 核心配置
    • 按模块拆分语言包(common/customer/order),便于维护;
    • 语言切换后保存到本地存储,刷新不丢失;
  1. 性能优化
    • 大型 CRM 按需加载语言包,缓存翻译结果;
    • 自定义缺失翻译兜底,避免页面显示空白;
  1. 集成第三方组件
    • 同步 Element Plus 等第三方组件的多语言,保证体验一致。

Vue I18n 是 CRM 多语言场景的 “刚需工具”,但纯中文场景下完全可以不用;若需多语言,按上述配置可快速实现全系统多语言切换,兼顾性能与可维护性。

更多推荐