
从0到1搭Vue i18n:别再对着文档发呆了
首先得装对依赖,Vue3要用@next
版本,直接npm install vue-i18n@next
就行——别问我为什么知道,我一开始装了旧版本,结果main.js里引的时候报错,查了半小时才发现版本不对。接下来建个i18n
文件夹,就在src目录下,里面放两个东西:index.js
(用来初始化i18n实例)和langs
文件夹(存各个语言的文本)。
langs里的文件超简单,比如建en.js
(英文)、zh.js
(中文)、ja.js
(日文),每个文件都是键值对结构——按页面或模块分,别把所有文本堆在一个文件里。我朋友一开始就犯了这错,把首页、产品页、订单页的文本全写在zh.js
里,后来要改产品页的“加入购物车”按钮,翻了500行才找到,差点崩溃。现在我教他按模块分,比如zh.js
里写:
export default {
home: {
title: '首页',
banner: '欢迎来到我们的商店',
button: '立即购买'
},
product: {
name: '产品名称',
price: '价格',
addCart: '加入购物车'
}
}
en.js
对应写:
export default {
home: {
title: 'Home',
banner: 'Welcome to Our Store',
button: 'Buy Now'
},
product: {
name: 'Product Name',
price: 'Price',
addCart: 'Add to Cart'
}
}
这样找起来超方便,维护成本直接降一半。
然后写i18n/index.js
,把这些语言包引进去,创建i18n实例:
import { createI18n } from 'vue-i18n'
import zh from './langs/zh.js'
import en from './langs/en.js'
import ja from './langs/ja.js'
const i18n = createI18n({
locale: localStorage.getItem('locale') || 'zh', // 默认中文,优先取localStorage的内容
messages: {
zh,
en,
ja
}
})
export default i18n
最后在main.js
里引入i18n,用app.use(i18n)
——这一步别忘,不然整个项目都用不了$t
方法。
给你列个语言包组织的示例,一看就懂:
文件路径 | 语言 | 内容示例 |
---|---|---|
src/i18n/langs/zh.js | 中文 | { home: { title: ‘首页’, button: ‘立即购买’ } } |
src/i18n/langs/en.js | 英文 | { home: { title: ‘Home’, button: ‘Buy Now’ } } |
src/i18n/langs/ja.js | 日文 | { home: { title: ‘ホーム’, button: ‘すぐ購入’ } } |
配置好之后,在组件里用$t('键名')
就行——比如首页的标题写成{{ $t('home.title') }}
,刷新页面就能看到默认的中文;产品页的“加入购物车”按钮写成{{ $t('product.addCart') }}
,切换语言时会自动变。是不是比想象中简单?
踩过的坑:动态切换和适配那些事儿
接下来是最关键的动态切换——我朋友一开始配置完,做了个下拉框,点了切换英文,结果页面没反应,急得直拍桌子。后来我帮他查,发现他犯了两个错:一是没用到useI18n
的locale
属性,二是组件里还有硬编码的文本。
正确的做法超简单:在需要切换的组件里(比如导航栏的下拉框),先引入useI18n
:import { useI18n } from 'vue-i18n'
,然后const { locale } = useI18n()
——locale
是响应式的,改它的值就能切换语言。比如下拉框的选项是“中文”和“英文”,点“英文”的时候,locale.value = 'en'
,页面上所有用$t
的地方都会自动更新。
对了,要把当前语言存到localStorage
里,不然刷新页面又回到默认中文了——我一般在切换的时候加一句localStorage.setItem('locale', locale.value)
,然后在i18n/index.js
里初始化的时候,把locale
改成localStorage.getItem('locale') || 'zh'
,这样刷新也能保留用户选择的语言。
然后是日期、数字的适配——我朋友的项目里,订单时间显示一直是“2024-10-05”,切换到英文后还是这个格式,明显不对。后来查了Vue i18n文档才知道,要用到formatNumber
和formatDate
方法(Vue i18n官方文档里提到过,“locale是响应式的,改变它会触发所有使用$t或useI18n的组件重新渲染”,链接放这了:Vue i18n官方文档 rel=”nofollow”)。
比如日期格式化,在组件里写{{ $t('date.format', { value: new Date(), format: 'short' }) }}
,然后在语言包里配置date.format
对应的格式:
zh.js
里写:{ date: { format: '{0, date, short}' } }
en.js
里写:{ date: { format: '{0, date, short}' } }
这样切换到英文后,日期会变成“10/5/2024”,符合英文用户的阅读习惯;数字也是一样,比如价格显示,用{{ $t('price.format', { value: 199, format: 'currency' }) }}
,语言包里配置price.format
为{0, number, currency}
,这样英文会显示“$199.00”,中文显示“¥199.00”——是不是超贴心?
还有个小技巧:如果语言包太大,可以用lazy
加载,比如把每个语言包做成异步组件,需要的时候再加载,这样首屏加载速度更快。我朋友的项目后来加了西班牙文,语言包变大,用了lazy加载后,首屏时间从3秒降到了1.5秒,用户体验好了不少。
如果你按这些步骤做了,或者遇到了其他问题——比如语言包太大加载慢,或者嵌套的键怎么写,欢迎在评论区告诉我,我帮你想想办法!
我之前帮朋友调跨境商店的订单页,切换到英文后订单时间还是“2024-10-05”,用户反馈“看着像中国时间,不符合我们的习惯”——这就是没做日期的多语言适配。其实Vue i18n自带了处理这种动态内容的工具,不用额外找插件,就是formatNumber和formatDate这两个方法。你只要在语言包里加对应的配置就行:比如在zh.js里建个common模块,写个date.short的键,值是{0, date, short};en.js里也写一样的键,不用改格式——Vue i18n会自己根据当前语言调整显示。然后在组件里,订单时间别直接写order.createTime,改成{{ $t(‘common.date.short’, { value: order.createTime }) }},这样切换到英文,日期就会变成“10/5/2024”,切换到日文会变成“2024/10/05”,完全不用手动改。我朋友之前就是直接渲染时间字符串,改了之后用户说“终于看着顺了”。
数字和货币的处理更常用,比如产品价格,中文要显示“¥199”,英文要“$199”,总不能每个语言都写一遍价格吧?用Vue i18n的formatNumber就行。你在语言包的common里加个number.price的键,值写成{0, number, currency},然后组件里产品价格写成{{ $t(‘common.number.price’, { value: product.price }) }}——切换语言后,货币符号会自动变,连千分位分隔符都不用管:中文环境下1000会显示“1,000”,英文也是“1,000”,但切换到德语会变成“1.000”,Vue i18n都帮你处理好了。对了,要是你想自定义格式,比如中文要“199元”而不是“¥199”,可以在语言包里改配置:zh.js的common.number.price写成{0, number} + ‘元’?其实更规范的是用Vue i18n的currency选项,比如在zh.js里写{0, number, currency: ‘CNY’, currencyDisplay: ‘name’},这样会显示“199人民币”,en.js里写{0, number, currency: ‘USD’, currencyDisplay: ‘symbol’},就会显示“$199”——我之前帮做美妆店的朋友调过这个,她想让英文站的价格带符号,中文站带“元”字,这么改完刚好符合需求。
还有次帮人调购物车的数量显示,切换到阿拉伯语后数字还是“12”,但阿拉伯用户习惯看“١٢”——这时候只要在i18n的配置里加个locale为“ar”的语言包,然后用formatNumber处理数量,Vue i18n会自动把数字转换成阿拉伯数字形式。你看,这些细节其实不用自己写逻辑,Vue i18n早就考虑到了,只要按它的规则配置,就能省很多事。我之前踩过坑,一开始直接用toLocaleString处理数字,结果切换语言后没反应,后来才知道Vue i18n的format方法是和locale绑定的,比自己写更靠谱。
Vue2和Vue3使用的Vue i18n版本有区别吗?
有区别。Vue3需要安装@next版本的Vue i18n(即npm install vue-i18n@next),而Vue2使用的是旧版本(如vue-i18n@8.x)。如果Vue3项目装了旧版本,会出现引入报错等问题。
为什么语言包要按模块/页面拆分?
按模块/页面拆分语言包(比如home对应首页、product对应产品页),能避免所有文本堆在一个文件里导致的维护困难。比如要修改产品页的“加入购物车”文本,直接找到product模块下的键即可,不用翻几百行代码,大幅降低维护成本。
动态切换语言时页面没反应,可能是什么原因?
常见原因有两个:一是没正确使用useI18n的locale属性(需通过const { locale } = useI18n()获取响应式的locale,修改它的值才会触发更新);二是组件中还有硬编码的文本(比如直接写“首页”而不是$t(‘home.title’)),硬编码内容不会随语言切换更新。
切换语言后刷新页面,为什么又回到默认语言?
因为没将用户选择的语言保存到本地存储(如localStorage)。解决方法是:切换语言时,用localStorage.setItem(‘locale’, 选择的语言)保存;初始化i18n实例时,将locale设置为localStorage.getItem(‘locale’) || ‘默认语言’,这样刷新页面会优先读取本地存储的语言。
Vue i18n怎么处理日期、数字的多语言显示?
可以用Vue i18n的formatNumber和formatDate方法(或对应语法糖)。比如日期显示,在语言包中配置date.format为{0, date, short},组件中用$t(‘date.format’, { value: new Date(), format: ‘short’ }),切换语言后日期格式会自动适配(如中文显示“2024-10-05”,英文显示“10/5/2024”);数字同理,用{0, number, currency}配置货币格式,会自动切换符号(如中文“¥199”、英文“$199”)。