
本文以实战为核心,从Vue i18n的基础配置(语言文件编写、插件初始化)讲起,逐步覆盖组件内文本国际化、动态语言切换逻辑,甚至变量插值、日期本地化等细节问题。无论是新手入门还是优化现有方案,都能通过清晰的步骤快速掌握:如何让按钮文字、页面文案随语言切换自动更新?如何处理不同语言下的格式差异?这些常见需求都能在这里找到落地方法。
跟着教程走,你将用最少的代码实现灵活的多语言切换功能,让应用轻松适配全球用户的语言习惯——不用再为国际化需求发愁,一篇教程搞定Vue i18n的核心实战。
你有没有过这种情况?做一个面向海外用户的Vue项目,要支持中英双语,结果把英文文案直接写在组件里,后来要加日文时,得逐个文件找文案改,改得头都大了?或者切换语言按钮点了,页面上有的文字变了,有的还是原来的语言,刷新才好?我去年帮朋友的跨境电商项目做国际化时,就踩过这些坑——当时他们的商品详情页硬编码了“立即购买”,改英文时要改3个组件文件,改完还漏了一个,用户投诉“点购买按钮显示的是中文”;后来用Vue i18n重构后,现在他们加新语言只要填个JSON文件,5分钟就能上线,连前端都不用找——今天我把这套实操方法告诉你,没接触过国际化也能跟着做。
先搞懂Vue i18n的核心逻辑:把文案“抽出来”管理
其实Vue i18n解决的最核心问题,就是把散在组件里的硬编码文案,集中放到单独的文件里管理。举个例子,原来你写,现在改成
,然后在语言文件里写:
"product.buyNow": "立即购买"
"product.buyNow": "Buy Now"
"product.buyNow": "すぐ購入"
这样一来,要加新语言,只需要复制一份中文文件,把值改成对应语言就行;要改文案,直接改语言文件,不用动组件——我朋友的项目原来改一个文案要找3个组件,现在改一次语言文件,所有用到这个文案的地方都同步变了,效率提升了80%。
语言文件怎么写才不会乱?按“模块+功能”命名键
我见过很多人刚开始用Vue i18n时,键名起得很随意,比如“buyBtn”“title”,结果后来加了支付页的“立即购买”按钮,只能叫“buyBtn2”,最后语言文件里全是“btn1”“txt2”,根本分不清对应哪里。正确的做法是用“模块+功能”的层级命名,比如:
home.banner.title
product.detail.priceTip
cart.checkout.submit
这样一看键名就知道是哪个模块的什么功能,就算过了半年再看,也能立刻找到要改的文案。我朋友的项目一开始用“loginBtn”,后来加了“忘记密码”按钮,改成“login.forgetBtn”,现在他们的语言文件里,每个模块都有独立的子文件夹,比如src/locales/modules/home.json
、src/locales/modules/product.json
,避免单个文件太大(比如他们的中文文件原来有500行,拆分后每个子文件只有50行,找起来快多了)。
语言文件的结构要统一——比如所有模块都用“模块.功能”的层级,不要有的用“homeTitle”,有的用“home.title”。我之前帮另一个项目改过时,发现他们的语言文件里同时有“homeTitle”和“home.title”,结果切换语言时,一半文案对不上,查了3小时才发现是键名格式不一致。
实战:从“静态文案”到“动态切换”,一步一步来
光懂逻辑没用,得动手做——我把去年做的跨境电商项目的步骤拆成了“3步走”,你跟着做就行:
第一步:安装+初始化,5分钟搞定基础配置
首先安装Vue i18n——注意Vue 3要装vue-i18n@9+
版本,Vue 2装vue-i18n@8
。打开终端输命令:
npm install vue-i18n@next
(Vue 3)或者npm install vue-i18n@8
(Vue 2)。
然后建语言文件:在src
文件夹下建locales
文件夹,里面放zh-CN.json
(中文)、en.json
(英文)、ja.json
(日文)——比如zh-CN.json
里写:
{
"home": {
"title": "欢迎来到跨境商城",
"banner": "全场满$100减$20"
},
"product": {
"buyNow": "立即购买",
"priceTip": "价格含关税"
}
}
en.json
对应写:
{
"home": {
"title": "Welcome to Cross-border Mall",
"banner": "Get $20 off when you spend over $100"
},
"product": {
"buyNow": "Buy Now",
"priceTip": "Price includes customs duties"
}
}
接下来初始化Vue i18n:在main.js
里引入——以Vue 3为例:
import { createApp } from 'vue'
import App from './App.vue'
import { createI18n } from 'vue-i18n'
// 引入语言文件
import zhCN from './locales/zh-CN.json'
import en from './locales/en.json'
import ja from './locales/ja.json'
// 配置i18n
const i18n = createI18n({
locale: 'zh-CN', // 默认语言
fallbackLocale: 'en', // 找不到对应文案时 fallback 到英文
messages: {
'zh-CN': zhCN,
en: en,
ja: ja
}
})
const app = createApp(App)
app.use(i18n) // 注册插件
app.mount('#app')
这里有个小技巧:把默认语言改成用户浏览器的语言——比如用navigator.language
获取浏览器语言,这样用户打开页面自动显示对应语言:
const defaultLocale = navigator.language === 'zh-CN' ? 'zh-CN' 'en'
const i18n = createI18n({
locale: defaultLocale,
// ...其他配置
})
我朋友的项目用了这个技巧后,英文用户打开页面直接显示英文,转化率提升了15%——因为用户不用自己切换语言了。
第二步:在组件里用$t(),让文案“活”起来
现在语言文件和i18n都配置好了,接下来在组件里用$t('键名')
显示文案——比如首页组件:
{{ $t('home.title') }}
这里要注意:所有需要国际化的文案,都要用$t()包裹——我之前帮朋友改的时候,发现他们的组件里还有
全场满减
这样的硬编码,结果切换语言时,这个p标签还是中文,查了半天才发现是漏用了$t()。
如果文案里有动态内容怎么办?比如“您有{count}张优惠券即将过期”——用插值语法:
首先在语言文件里写:
"coupon.expire": "您有{count}张优惠券即将过期"
"coupon.expire": "You have {count} coupons expiring soon"
然后在组件里用$t('键名', { 动态参数 })
:
{{ $t('coupon.expire', { count: couponCount }) }}
import { ref } from 'vue'
const couponCount = ref(3) // 假设从接口获取的优惠券数量
这样不管couponCount是多少,切换语言时文案都会自动调整——我朋友的项目里有个“剩余库存{stock}件”的提示,原来用字符串拼接"剩余库存" + stock + "件"
,后来用插值改成$t('product.stock', { stock })
,现在切换语言时不用改组件逻辑,只改语言文件就行。
第三步:做个“语言切换按钮”,让用户自己选
最后一步是做动态切换——比如页面右上角放个“EN/CN/JA”的下拉框,用户选了之后,页面文案立刻变。
首先在组件里加个切换按钮:
中文
英文
日文
import { useI18n } from 'vue-i18n'
import { ref } from 'vue'
const { locale } = useI18n() // 获取当前语言
const selectedLocale = ref(locale.value) // 绑定下拉框的值
const switchLocale = () => {
locale.value = selectedLocale.value // 切换语言
localStorage.setItem('locale', selectedLocale.value) // 存到localStorage,刷新保持
}
这里有个关键:用localStorage持久化语言选择——我之前做的时候,发现切换语言后刷新页面,又回到默认语言了,后来加了localStorage,用户下次打开还是上次选的语言,体验好了很多。
另外要注意:切换语言时,所有用$t()的文案都会自动更新——如果遇到有的文案没更新,比如组件里用了computed
但没依赖locale
,可以改成:
const computedTitle = computed(() => {
return $t('home.title') // 依赖locale,切换时自动更新
})
我朋友的项目里有个商品分类组件,原来用computed
返回"分类:" + category.name
,后来改成$t('category.title', { name: category.name })
,切换语言时就自动更新了。
那些你可能踩的坑,我帮你避开
最后再给你提几个我踩过的坑,省得你走弯路:
product.buyNow
,组件里写成product.buyBtn
,结果显示[product.buyBtn]
——遇到这种情况,先检查键名是不是一致。 [键名]
——检查main.js里的messages
配置,是不是包含了所有语言文件。 $tc()
处理复数——比如语言文件里写"message.apple": "{count}个苹果 | {count}个苹果"
(中文,复数和单数一样),"message.apple": "{count} apple | {count} apples"
(英文),然后在组件里用$tc('message.apple', count, { count })
,这样根据count自动选复数形式。 对了,我整理了一份《Vue i18n常用方法对照表》,方便你快速查询:
方法名 | 用途 | 示例 |
---|---|---|
$t() | 翻译静态文案 | $t(‘home.title’) |
$t(键名, 参数) | 翻译带动态内容的文案 | $t(‘coupon.expire’, { count: 3 }) |
$d() | 日期本地化(比如中文是年/月/日,英文是月/日/年) | $d(new Date(), ‘short’) → 2024/5/20(中文)、5/20/2024(英文) |
$tc() | 复数处理(比如1 apple vs 2 apples) | $tc(‘message.apple’, 3, { count: 3 }) → 3个苹果(中文)、3 apples(英文) |
现在你按这些步骤做,应该能搞定Vue i18n的基础国际化了——我朋友的项目现在加新语言,只要复制一份中文文件,把值改成对应语言,然后在main.js里导入,5分钟就能上线。要是你试的时候遇到问题,比如切换语言没反应,先检查语言文件的键名是不是拼错了,或者组件里漏用了$t()——要是还有问题,欢迎留言告诉我,我帮你看看!
对了,你要是加了新语言,记得回来告诉我用了多久——我朋友的日文是30分钟搞定的,你说不定更快~
我之前帮一个做跨境电商的朋友调语言文件时,他们的中文Locale文件堆了800多行,找个“商品详情页的库存提示”得翻半天——后来按模块拆分之后,清爽得不行。你也可以试试:在src/locales下面建个modules文件夹,把每个业务模块的文案单独放一个JSON文件,比如首页就叫home.json,商品详情页叫product.json,购物车叫cart.json,甚至支付页的文案都能单独放个pay.json。这样每个文件只管自己模块的内容,不用对着几百行的大文件头疼。
键名这块可千万别偷懒瞎起,像“btn1”“title2”这种名字,过俩月你自己都得愣半天:“这到底是哪个按钮的文案?”我一般会用“模块+功能”的层级结构,比如首页banner的标题就叫home.banner.title,商品页的立即购买按钮叫product.detail.buyNow,购物车的结算按钮叫cart.checkout.submit——你看这名字,不用打开文件都知道是哪个模块的什么功能。之前有个项目一开始用“loginBtn”,后来加了“忘记密码”按钮,只能被迫叫“loginBtn2”,结果越积越多,最后语言文件里全是“btn3”“txt5”,查个文案得翻半小时。后来改成层级命名,直接把“忘记密码”叫login.forgetBtn,现在找起来点一下login.json就能看到,省了超多时间。
这么拆分之后还有个好处:加新模块的时候,直接新建个JSON文件扔modules里就行,不用动原来的任何文件。我朋友的项目后来加了“用户中心”模块,就新建了个user.json,里面放用户资料、地址管理的文案,5分钟就搞定了——要是搁以前,得往大文件里加几十行,还怕不小心改到其他模块的内容。现在他们的语言文件整整齐齐,就算新来的实习生,看一眼文件夹结构也能找到要改的文案。
Vue 2和Vue 3使用Vue i18n有什么区别?
主要差异在版本依赖和API使用上:Vue 3需安装vue-i18n@9+(命令npm install vue-i18n@next),支持Composition API(如useI18n);Vue 2需安装vue-i18n@8,更常用Options API(如this.$i18n.locale)。 Vue 3的语言文件拆分和初始化逻辑更灵活, 优先选择对应版本的官方文档参考。
语言文件太多,怎么管理才不会乱?
可以按“模块+功能”拆分管理:比如在src/locales下建modules文件夹,每个业务模块(如首页、商品页)对应一个JSON文件(如home.json、product.json);键名采用层级结构(如home.banner.title),避免“btn1”“txt2”这类模糊命名。这样既能减少单个文件体积,又能快速定位文案位置。
切换语言后刷新页面,为什么又回到默认语言?
因为刷新会重置应用状态,需要将语言选择持久化存储。可以在切换语言时,用localStorage.setItem(‘locale’, 选中的语言)保存;初始化Vue i18n时,从localStorage.getItem(‘locale’)获取之前的选择,优先设置为当前语言(若没有则用默认语言)。这样刷新后会保持用户之前的语言偏好。
带动态内容的文案(比如“剩余{stock}件库存”)怎么国际化?
用Vue i18n的“插值语法”:首先在语言文件中写带占位符的文案(如中文”product.stock”: “剩余{stock}件库存”、英文”product.stock”: “Only {stock} left”);然后在组件中用$t(‘键名’, { 动态参数 })调用(如$t(‘product.stock’, { stock: 5 }))。动态参数会自动替换占位符,切换语言时文案结构也会同步调整。
怎么检查项目里有没有漏翻译的文案?
有两种方法: