i18n多语言
安装以及版本
pnpm add vue-i18n@9
配置
i18nFormat.ts
ts
// 配置日期格式化
export const datetimeFormats = {
'en-US': {
short: {
year: 'numeric',
month: 'short',
day: 'numeric',
},
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: 'numeric',
minute: 'numeric',
},
},
'zh-CN': {
short: {
year: 'numeric',
month: 'short',
day: 'numeric',
},
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: 'numeric',
minute: 'numeric',
// 默认是24小时制,如果想显示为12小时制,则进行下面这个属性的设置
// hour12: true,
},
},
}
// 配置数字相关的格式化
export const numberFormats = {
'en-US': {
currency: {
style: 'currency',
currency: 'USD',
},
decimal: {
style: 'decimal',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
},
percent: {
style: 'percent',
useGrouping: false,
},
},
'zh-CN': {
currency: {
style: 'currency',
currency: 'RMB',
},
decimal: {
style: 'decimal',
minimumSignificantDigits: 3,
maximumSignificantDigits: 5,
},
percent: {
style: 'percent',
useGrouping: false,
},
},
}
zh-CN.json
json
{
"test": "测试:新项",
"person": {
"name": "人员姓名"
}
}
index.ts
ts
import zhCN from './lang/shared/zh-CN.json'
import enUS from './lang/shared/en-US.json'
export { datetimeFormats, numberFormats } from './i18nFormat'
export const sharedMessages = {
'zh-CN': zhCN,
'en-US': enUS,
}
i18n.ts
ts
import { nextTick } from 'vue'
import { createI18n } from 'vue-i18n'
import { sharedMessages, datetimeFormats, numberFormats } from '@/i18n/index'
export const i18n = createI18n({
// @ts-ignore
datetimeFormats,
// 当前语言
locale: 'zh-CN',
// 当语言资源不存在时,使用的默认替换语言
fallbackLocale: 'zh-CN',
// 通过composition api方式使用,则需要将legacy设置为false
legacy: false,
messages: sharedMessages,
numberFormats,
})
/**
* 切换语言环境
*
* @param {string} locale 语言标识
*
* @return {[type]} [return description]
*/
export function setI18nLanguage(locale: string) {
if (i18n.mode === 'legacy') {
i18n.global.locale = locale
} else {
// @ts-ignore
i18n.global.locale.value = locale
}
/**
* NOTE:
* If you need to specify the language setting for headers, such as the `fetch` API, set it here.
* The following is an example for axios.
*
* axios.defaults.headers.common['Accept-Language'] = locale
*/
document.documentElement.setAttribute('lang', locale)
}
/**
* 动态加载多语言资源
*
* @param {string} locale 语言标识
*
*/
export async function loadLocaleMessages(locale: string) {
// 这里可以换成axios从服务器加载
const messages = await import(/* webpackChunkName: "locale-[request]" */ `./i18n/lang/${locale}.json`)
// 用新的语言数据覆盖已有的语言数据(要使用哪种自己选择)
// i18n.global.setLocaleMessage(locale, messages.default)
return nextTick()
}
main.ts
ts
import { createApp } from 'vue'
import { setupI18n } from './i18n'
const i18n = setupI18n()
const app = createApp(App)
app.use(i18n)
app.mount('#app')
在 vue 组件(composition API)中使用
vue
<script setup lang="ts">
import { loadLocaleMessages, setI18nLanguage } from '@/i18n'
import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n'
const { t, locale, getLocaleMessage, d, n, availableLocales } = useI18n()
function onClick() {
ElMessage({
message: `${t('operate.add')}-${t('person.name')}`,
type: 'success',
})
}
function onLoadI18nResource(lang: string) {
loadLocaleMessages(lang)
}
function onChangeLang(lang: string) {
setI18nLanguage(lang)
}
</script>
<template>
<el-button @click="onLoadI18nResource('zh-CN')"> 加载额外的中文i18n资源 </el-button>
<el-button @click="onLoadI18nResource('en-US')"> 加载额外的英文i18n资源 </el-button>
<el-button type="primary" @click="onClick">按钮</el-button>
<p>{{ d(new Date(), 'long') }}</p>
<p>{{ d(new Date(), 'short') }}</p>
<p>{{ n(3250.86, 'currency') }}</p>
<p>{{ n(0.99123, 'percent') }}</p>
<p>{{ n(0.99123, 'percent', { minimumFractionDigits: 2 }) }}</p>
<p>{{ n(12.11612345, 'decimal') }}</p>
<p>{{ n(12145281111, 'decimal', 'en-US') }}</p>
<p>当前使用语言:{{ locale }}</p>
<p>可用语言:{{ availableLocales }}</p>
两种语言切换方式:
<h3>方式一</h3>
<div>
<el-button @click="onChangeLang('zh-CN')">切换为中文</el-button>
<el-button @click="onChangeLang('en-US')">切换为英文</el-button>
</div>
<h3>方式二</h3>
<select v-model="locale">
<option v-for="oneLocale in availableLocales" :key="`locale-${oneLocale}`" :value="oneLocale">
{{ oneLocale }}
</option>
</select>
<p>{{ getLocaleMessage('zh-CN') }}</p>
<p>{{ getLocaleMessage('en-US') }}</p>
<p>{{ t('operate.add') }}</p>
<p>{{ t('hello') }}</p>
<p>{{ t('test') }}</p>
<p>{{ t('person.name') }}</p>
{{ $t('operate.add') }}
</template>
<style scoped></style>
特殊字符处理
如下字符在 i18n 中属于特殊字符
{}@$|
处理方式
ts
const messages = {
'zh-CN': {
address: "{account}{'@'}{domain}",
},
}
使用{'和'}对特殊字符串进行包裹。如上面示例中的{'@'}
xml
<p>邮箱: {{ t('address', { account: 'foo', domain: 'domain.com' }) }}</p>
输出结果
xml
<p>邮箱: foo@domain.com</p>
多语言资源值中包含 html 标签的处理
ts
const messages = {
en: {
message: {
hello: '你好 <br> 世界',
},
},
}
如果需要按照 html 标签输出, 则需要使用v-html指令
xml
<p v-html="$t('message.hello')"></p>
输入结果
xml
<p>hello
<!--<br> exists but is rendered as html and not a string-->
world</p>
useScope: 'local'与 useScope: 'global'的区别
不指定useScope值时,默认就是global
INFO
useScope: 'local' 一般用不到,可以不管
ts
useI18n({
useScope: 'local',
})
区别就是当你指定为local时,你必须在当前组件,再另外配置一套 i18n 的配置,该配置只会再这个组件中生效,且该组件也只会使用你在这个组件中声明的配置,而忽略全局的配置。同时,你在这个组件中对i18n组件的修改,都只是对你这个单独的i18n生效,不会影响全局的i18n配置