【前端】【i18】【vue】封装i8n的hooks,减少冗余代码,类型提示与安全,优雅的兼容性
通过namespace参数自动为翻译键添加命名空间前缀(如),避免手动拼接路径。使用 TypeScript 重载定义如果未初始化i18n实例,返回基础函数直接输出键名,避免报错。允许组件按需绑定不同命名空间,实现翻译键的模块化分类。
·
一、核心功能
-
自动化命名空间处理
通过namespace参数自动为翻译键添加命名空间前缀(如system.title),避免手动拼接路径。 -
类型安全的翻译函数
使用 TypeScript 重载定义I18nGlobalTranslation,支持不同参数形式:t('key') // 无动态参数 t('key', ['动态插值']) // 列表参数 t('key', { name: '值' }) // 命名参数 t('key', 'en', [...]) // 指定语言+参数 -
兼容性回退
如果未初始化i18n实例,返回基础函数直接输出键名,避免报错。 -
模块化翻译管理
允许组件按需绑定不同命名空间,实现翻译键的模块化分类。
二、使用方法
1. 初始化 i18n
// main.ts
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import { i18n } from './your-hook-file'
const app = createApp(App)
const i18nInstance = createI18n({
locale: 'en',
messages: {
en: {
system: { title: 'System' },
button: { submit: 'Submit' }
}
}
})
app.use(i18nInstance)
i18n = i18nInstance // 关键:将实例挂载到导出的变量
2. 在组件中使用
<script setup>
// 绑定命名空间 'system'
const { t } = useI18n('system')
// 自动解析键名为 'system.title'
t('title') // 输出 'System'
// 动态参数
t('welcome', ['User']) // 假设键对应 'Welcome, {0}'
</script>
3. 直接使用 t 函数(无命名空间)
// 适用于全局或非模块化键
import { t } from './your-hook-file'
t('button.submit') // 直接传递完整路径
三、核心优势
-
减少冗余代码
自动处理命名空间,无需手动拼接键名如t('system.title'),直接写t('title')。 -
类型提示与安全
TypeScript 类型重载严格检查参数类型,防止传递错误格式的动态值。 -
灵活的参数传递
支持列表、对象、指定语言等多种参数形式,适应不同翻译场景。 -
优雅的兼容性
未初始化 i18n 时回退到安全模式,保证代码不崩溃,键名直接显示。 -
模块化维护
按功能模块划分命名空间(如user、order),便于协作和后期维护。
四、适用场景
- 中大型项目需要分模块管理多语言键
- TypeScript 项目追求类型安全
- 需要动态参数插值的国际化需求
- 希望简化传统
vue-i18n模板代码的开发者
通过这种封装,开发者可以更高效、安全地管理多语言资源,同时保持代码的简洁性和可维护性。
i18源码hooks
import { createI18n } from 'vue-i18n'
export let i18n: ReturnType<typeof createI18n>
type I18nGlobalTranslation = {
(key: string): string
(key: string, locale: string): string
(key: string, locale: string, list: unknown[]): string
(key: string, locale: string, named: Record<string, unknown>): string
(key: string, list: unknown[]): string
(key: string, named: Record<string, unknown>): string
}
type I18nTranslationRestParameters = [string, any]
const getKey = (namespace: string | undefined, key: string) => {
if (!namespace) {
return key
}
if (key.startsWith(namespace)) {
return key
}
return `${namespace}.${key}`
}
export const useI18n = (
namespace?: string
): {
t: I18nGlobalTranslation
} => {
const normalFn = {
t: (key: string) => {
return getKey(namespace, key)
}
}
if (!i18n) {
return normalFn
}
const { t, ...methods } = i18n.global
const tFn: I18nGlobalTranslation = (key: string, ...arg: any[]) => {
if (!key) return ''
if (!key.includes('.') && !namespace) return key
return (t as any)(getKey(namespace, key), ...(arg as I18nTranslationRestParameters))
}
return {
...methods,
t: tFn
}
}
export const t = (key: string) => key
更多推荐


所有评论(0)