一、核心功能

  1. 自动化命名空间处理
    通过 namespace 参数自动为翻译键添加命名空间前缀(如 system.title),避免手动拼接路径。

  2. 类型安全的翻译函数
    使用 TypeScript 重载定义 I18nGlobalTranslation,支持不同参数形式:

    t('key')                          // 无动态参数
    t('key', ['动态插值'])            // 列表参数
    t('key', { name: '值' })          // 命名参数
    t('key', 'en', [...])             // 指定语言+参数
    
  3. 兼容性回退
    如果未初始化 i18n 实例,返回基础函数直接输出键名,避免报错。

  4. 模块化翻译管理
    允许组件按需绑定不同命名空间,实现翻译键的模块化分类。


二、使用方法

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') // 直接传递完整路径

三、核心优势

  1. 减少冗余代码
    自动处理命名空间,无需手动拼接键名如 t('system.title'),直接写 t('title')

  2. 类型提示与安全
    TypeScript 类型重载严格检查参数类型,防止传递错误格式的动态值。

  3. 灵活的参数传递
    支持列表、对象、指定语言等多种参数形式,适应不同翻译场景。

  4. 优雅的兼容性
    未初始化 i18n 时回退到安全模式,保证代码不崩溃,键名直接显示。

  5. 模块化维护
    按功能模块划分命名空间(如 userorder),便于协作和后期维护。


四、适用场景

  • 中大型项目需要分模块管理多语言键
  • 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

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐