Skip to content

TypeScript 支持

支持的版本

🆕 9.2+

VueI18n 使用资源,包括本地化消息、日期时间格式和数字格式。 特别是,本地化消息可以作为 i18n 资源外部化,如 json 文件,以便与本地化服务协作,并且这些资源可以导入以进行协作。

为了与本地化服务结合实现顺畅的本地化工作流程,您可能希望防止缺失本地化或外部化 i18n 资源的资源定义缺失。 在开发过程中,您可能不希望因使用翻译函数(如 $t)时的键字符串错误而破坏开发者体验。

带模式的类型安全资源

您可以使用 TypeScript 支持带资源模式的类型安全资源。

createI18n 中的类型安全资源

以下是如何为 createI18n 选项中定义的 messages 定义类型安全资源的示例代码。

本地化消息资源:

json
{
  "world": "the world!"
}

应用程序入口点:

ts
import { createI18n } from 'vue-i18n'
import enUS from './locales/en-US.json'

// 将 'en-US' 定义为资源的主模式
type MessageSchema = typeof enUS

const i18n = createI18n<[MessageSchema], 'en-US' | 'ja-JP'>({
  locale: 'en-US',
  messages: {
    'en-US': enUS
  }
})

上述代码从 createI18n 选项中的 messages 指定的 en-US 消息资源定义了一个类型。此定义的类型是使用 VueI18n 处理的消息资源的主模式。这意味着您可以将其定义为应用程序中的单一真理来源资源。您可以通过指定从消息资源配置定义的模式类型作为 createI18n 类型参数的第一个参数来在其他语言环境中定义类型安全的资源。

createI18n 类型参数的第二个参数是要处理的语言环境。通过这个,基于第一个参数中指定的资源类型,对第二个参数中指定的每个语言环境进行类型检查。在上面的代码示例中,en-USja-JP 被指定为主要语言环境,这也指定在 locale 选项中。如果在这种状态下编译 TypeScript,您将得到以下错误来检查 messages 选项中未定义 ja-JP 资源。

sh
$ npx tsc
npx tsc
src/main.ts:11:3 - error TS2741: Property '"ja-JP"' is missing in type '{ 'en-US': { world: string; }; }' but required in type '{ "en-US": { world: string; }; "ja-JP": { world: string; }; }'.

11   messages: {
     ~~~~~~~~

  node_modules/vue-i18n/dist/vue-i18n.d.ts:712:5
    712     messages?: {
            ~~~~~~~~
    The expected type comes from property 'messages' which is declared here on type 'I18nOptions<{ message: { world: string; }; datetime: DateTimeFormat; number: NumberFormat; }, { messages: "en-US"; datetimeFormats: "en-US"; numberFormats: "en-US"; } | { ...; }, ComposerOptions<...> | VueI18nOptions<...>>'

如果您使用 Visual Studio Code 作为编辑器,在运行 TypeScript 编译之前,您可以在编辑器中注意到资源定义遗漏的错误。

VSCode-Type-Error1VSCode-Type-Error2

useI18n 中的类型安全资源

类型安全资源不仅可以用 createI18n 定义,也可以在使用组合式 API 的 useI18n 中按组件分别定义。

除了本地消息外,资源类型定义还可以包括日期时间格式和数字格式。

以下是在 useI18n 中按组件分别定义本地化消息和数字格式类型安全资源的示例代码。

在 Vue 组件中导入的本地化消息:

json
{
  "messages": {
    "hello": "Hello, {name}!"
  }
}

带有类型安全资源的 Vue 组件:

vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import enUS from './en-US.json' // 导入 Vue 组件的本地化消息

// 定义 Vue 组件的消息模式
type MessageSchema = typeof enUS

// 定义 Vue 组件的数字格式模式
type NumberSchema = {
  currency: {
    style: 'currency'
    currencyDisplay: 'symbol'
    currency: string
  }
}

/*
 * 您可以在第一个类型参数中使用对象文字指定您的定义模式
 * 关于类型参数,参见 http://vue-i18n.intlify.dev/api/composition.html#usei18n
 */
const { t, n } = useI18n<{
  message: MessageSchema,
  number: NumberSchema
}, 'en-US'>({
  inheritLocale: true,
  messages: {
    'en-US': enUS
  },
  numberFormats: {
    'en-US': {
      currency: {
        style: 'currency',
        currencyDisplay: 'symbol',
        currency: 'USD'
      }
    }
  }
})
</script>

<template>
  <p>message: {{ t('messages.hello', { name: 'kazupon' }) }}</p>
  <p>currency: {{ n(1000, 'currency') }}</p>
</template>

通过在 useI18n 的第一个类型参数中指定定义的模式,您可以使用 TypeScript 检查本地化消息和数字格式的未定义资源。另外,通过指定第二个类型参数中要定义的语言环境,TypeScript 可以检查未定义的语言环境。

限制

  • 不支持 SFC 中的 i18n 自定义块的类型安全。我们计划在未来支持它。
  • 当前仅支持 JSON 格式。

迄今为止描述的代码作为 示例 可用。让我们检查一下!

类型安全支持的 API

其他 API 支持类型参数,允许您指定资源的模式以进行类型安全的资源操作,例如:

  • getLocaleMessage
  • setLocaleMessage
  • mergeLocaleMessage
  • getDateTimeFormat
  • setDateTimeFormat
  • mergeDateTimeFormat
  • getNumberFormat
  • setNumberFormat
  • mergeNumberFormat

有关更多详细信息,请查看以下 API 文档页面。

资源键补全支持

注意

资源键补全仅在您使用 Visual Studio Code 时可用

除了支持类型安全的资源定义之外,VueI18n 现在在组合式 API 中提供了 td 等 API 来插入资源键。

以下显示了如何在上述本地作用域 Vue 组件中插入资源键的 Visual Studio Code 方法。

VSCode-Resource-Completion

资源键插入支持可以防止翻译缺失。

在您的项目中,您可能有不使用本地作用域而是使用全局作用域的所有内容的 Vue 组件。

对于这种使用情况,您还可以通过在 useI18n 的类型参数中明确指定为全局作用域定义的模式来支持资源键插入。

为全局作用域定义模式:

ts
/**
 * 定义资源模式
 */

import enUS from './en-US.json'

// 将消息模式定义为主消息模式
export type MessageSchema = typeof enUS

// 定义数字格式模式
export type NumberSchema = {
  currency: {
    style: 'currency'
    currencyDisplay: 'symbol'
    currency: string
  }
}

然后,只需导入定义的模式并在 useI18n 中将其用作类型参数,如以下 Vue 组件所示:

vue
<script lang="ts">
import { useI18n } from 'vue-i18n'

// 导入全局作用域的资源模式
import type { MessageSchema, NumberSchema } from '../locales/schema'

const { t, n } = useI18n<{ message: MessageSchema, number: NumberSchema }>({
  useScope: 'global'
})
</script>

<template>
  <p>message: {{ t('hello') }}</p>
  <p>currency: {{ n(1000, 'currency') }}</p>
</template>

结果,您可以使用 VueI18n 提供的 API(如 tn)进行资源键插入。

注意

传统模式以及通过组合式 API 的 globalInjection: true 注入到组件中的 $t$d 等 API 的资源键插入,需要显式指定类型参数。

有关更多详细信息,请查看 API 文档。 https://vue-i18n.intlify.dev/api/injection.html

全局资源模式类型定义

在 VueI18n 中,您可以使用 TypeScript 特性扩展接口来定义全局作用域级别的资源类型。

如果您的项目将所有资源都作为全局作用域使用,那么轻松处理类型安全资源会非常方便。

VueI18n 提供以下接口:

  • DefineLocaleMessage:用于全局定义本地化消息模式的接口
  • DefineDateTimeFormat:用于全局定义日期时间格式模式的接口
  • DefineNumberFormat:用于全局定义数字格式模式的接口

通过使用这些接口和 declare module,您可以定义 VueI18n 的全局模式。

以下是在 d.ts 中定义的全局模式示例:

ts
/**
 * 您需要导入某些接口
 */



declare module 'vue-i18n' {
  // 定义本地化消息模式
  export interface DefineLocaleMessage {
    hello: string
    menu: {
      login: string
    }
    errors: string[]
  }

  // 定义日期时间格式模式
  export interface DefineDateTimeFormat {
    short: {
      hour: 'numeric'
      minute: 'numeric'
      second: 'numeric'
      timeZoneName: 'short'
      timezone: string
    }
  }

  // 定义数字格式模式
  export interface DefineNumberFormat {
    currency: {
      style: 'currency'
      currencyDisplay: 'symbol'
      currency: string
    }
  }
}

通过使用 declare module 和 VueI18n 提供的接口,您可以定义全局资源的模式。

以前,在使用 createI18nuseI18n 与全局作用域资源类型定义时,有必要将每个资源都指定为类型参数。 这样,您就不需要这样做。

以下是以 createI18n 为例:

ts
import { createI18n, type I18nOptions } from 'vue-i18n'

/**
 * 从 json 导入本地化消息资源用于全局作用域
 */
import enUS from './locales/en-US.json'
import jaJP from './locales/ja-JP.json'

const options: I18nOptions = {
  legacy: false,
  locale: 'ja-JP',
  fallbackLocale: 'en-US',
  messages: {
    'en-US': enUS,
    'ja-JP': jaJP
  },
  datetimeFormats: {
    'ja-JP': {
      short: {
        hour: 'numeric',
        minute: 'numeric',
        second: 'numeric',
        timeZoneName: 'short',
        timezone: 'Asia/Tokyo'
      }
    }
  },
  numberFormats: {
    'ja-JP': {
      currency: {
        style: 'currency',
        currencyDisplay: 'symbol',
        currency: 'JPY'
      }
    }
  }
}

/**
 * 使用全局类型定义的 i18n 资源设置 vue-i18n。
 * 如果您在 `*.d.ts` 中定义了 i18n 资源模式,这些将由 TypeScript 检查。
 */
const i18n = createI18n<false, typeof options>(options)

上面 createI18n 的第一个类型参数未指定资源的模式类型。上面只是为 createI18n 创建的 i18n 实例的 global 属性指定类型提示。 (如果为 false,类型为组合式 API 的 Composer 实例,如果为 true,类型为传统 API 的 VueI18n 实例)

createI18n 的第二个类型参数指定选项的类型提示。

在 Vue 组件使用的 useI18n 情况下,看起来像这样:

vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'

// 使用全局作用域
const { t, d, n } = useI18n({
  inheritLocale: true
})
</script>

<template>
  <p>`t` 资源键补全: {{ t('menu.login') }}</p>
  <p>`d` 资源键补全: {{ d(new Date(), 'short') }}</p>
  <p>`n` 资源键补全: {{ n(1000, 'currency') }}</p>
</template>

从上面的代码可以看出,您不需要为 useI18n 的类型参数指定任何内容。您可以不用指定就插入 tdn 等 API 资源键。