Skip to content

组合 API ​

setup 的引入和 Vue 的 组合 API 开启了新的可能性。但为了能够充分发挥 Vue I18n 的全部潜力,我们需要使用一些新函数来替代对 this 的访问。

我们一直在使用与 vue-i18n v8.x 兼容的传统 API 描述 Vue I18n 的功能。现在让我们来看看 Vue I18n 的组合 API useI18n。

基本用法 ​

让我们看看 Vue I18n 组合 API 的基本用法!我们将通过修改 入门 中的代码来学习基本用法。

要在 Vue 3 的 setup 中使用 useI18n,有一件事需要做,即需要将 createI18n 函数的 legacy 选项设置为 false。

以下是向 createI18n 添加 legacy 选项的示例:

js
// ...

const i18n = VueI18n.createI18n({
  legacy: false, // 您必须设置为 `false`,以使用组合 API
  locale: 'ja',
  fallbackLocale: 'en',
  messages: {
    en: {
      message: {
        hello: 'hello world'
      }
    },
    ja: {
      message: {
        hello: '你好,世界'
      }
    }
  }
})

// ...

您可以设置 legacy: false 来允许 Vue I18n 切换 API 模式,从传统 API 模式切换到组合 API 模式。

注意

通过 createI18n 创建的 i18n 实例的以下属性会改变其行为:

  • mode 属性:"legacy" 至 "composition"
  • global 属性:VueI18n 实例至 Composer 实例

现在您已经准备好在 App.vue 组件中使用 useI18n。代码如下所示:

vue
<script setup> 
import { useI18n } from 'vue-i18n'
const { t } = useI18n() 
</script> // [!code ++]

<template>
  <h1>{{ $t("message.hello") }}</h1>
</template>

您必须在 <script setup> 的顶部调用 useI18n。

useI18n 返回一个 Composer 实例。Composer 实例提供了翻译 API,如 t 函数,以及诸如 locale 和 fallbackLocale 等属性,就像 VueI18n 实例一样。有关 Composer 实例的更多信息,请参见 API 参考。

在上面的例子中,useI18n 没有选项,所以它返回一个与全局作用域一起工作的 Composer 实例。因此,它返回一个与全局作用域一起工作的 Composer 实例,这意味着这里通过展开 t 函数引用的本地化消息是 createI18n 中指定的那一个。

您可以在组件模板中使用 t:

vue
<script setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
</script>

<template>
  <h1>{{ $t("message.hello") }}</h1> // [!code --]
  <h1>{{ t("message.hello") }}</h1> // [!code ++]
</template>

输出如下:

vue
<div id="app">
  <h1>你好,世界</h1>
</div>

消息翻译 ​

在传统 API 模式中,消息使用 $t 或 VueI18n 实例的 t 进行翻译。

在组合 API 模式中,消息格式语法与传统 API 模式相同。您可以使用 Composer 实例 t 来翻译消息,如下所示:

vue
<script setup>
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

const { t } = useI18n({
  locale: 'en',
  messages: {
    en: {
      msg: 'hello',
      named: '{msg} world!',
      list: '{0} world!',
      literal: "{'hello'} world!",
      the_world: 'the world',
      dio: 'DIO:',
      linked: '@:dio @:the_world !!!!'
    },
    ja: {
      msg: 'こんにちは',
      named: '{msg} 世界!',
      list: '{0} 世界!',
      literal: "{'こんにちは'} 世界!",
      the_world: 'ザ・ワールド!',
      dio: 'ディオ:',
      linked: '@:dio @:the_world !!!!'
    }
  }
})

const msg = computed(() => t('msg'))
</script>

<template>
  <p>{{ t('named', { msg }) }}</p>
  <p>{{ t('list', [msg]) }}</p>
  <p>{{ t('literal') }}</p>
  <p>{{ t('linked') }}</p>
</template>

有关 t 的更多详细信息,请参见 API 参考

复数形式 ​

在组合 API 模式中,消息的复数形式保持与传统 API 模式相同的语法,但使用 Composer 实例的 t 进行翻译:

vue
<script setup>
import { useI18n } from 'vue-i18n'

const { t } = useI18n({
  locale: 'en',
  messages: {
    en: {
      car: 'car | cars',
      apple: 'no apples | one apple | {count} apples',
      banana: 'no bananas | {n} banana | {n} bananas'
    }
  }
})
</script>

<template>
  <h2>Car:</h2>
  <p>{{ t('car', 1) }}</p>
  <p>{{ t('car', 2) }}</p>
  <h2>Apple:</h2>
  <p>{{ t('apple', 0) }}</p>
  <p>{{ t('apple', 1) }}</p>
  <p>{{ t('apple', { count: 10 }, 10) }}</p>
  <p>{{ t('apple', 10) }}</p>
  <h2>Banana:</h2>
  <p>{{ t('banana', { n: 1 }, 1) }}</p>
  <p>{{ t('banana', 1) }}</p>
  <p>{{ t('banana', { n: 'too many' }, 100) }}</p>
</template>

注意

在组合 API 模式中,复数翻译已集成到 t 中。

日期时间格式化 ​

在传统 API 模式中,日期时间值使用 $d 或 VueI18n 实例的 d 进行格式化。

在组合 API 模式中,使用 Composer 实例的 d 进行格式化:

vue
<script setup>
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'

const { t, d } = useI18n({
  locale: 'en-US',
  messages: {
    'en-US': {
      current: 'Current Datetime'
    }
  },
  datetimeFormats: {
    'en-US': {
      long: {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit'
      }
    }
  }
})

const now = ref(new Date())
</script>

<template>
  <p>{{ t('current') }}: {{ d(now, 'long') }}</p>
</template>

有关 d 的更多详细信息,请参见 API 参考

数字格式化 ​

在传统 API 模式中,数字值使用 $n 或 VueI18n 实例的 n 进行格式化。

在组合 API 模式中,使用 Composer 实例的 n 进行格式化:

vue
<script setup>
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'

const { t, n } = useI18n({
  locale: 'en-US',
  messages: {
    'en-US': {
      money: 'Money'
    }
  },
  numberFormats: {
    'en-US': {
      currency: {
        style: 'currency',
        currency: 'USD'
      }
    }
  }
})

const money = ref(1000)
</script>

<template>
  <p>{{ t('money') }}: {{ n(money, 'currency') }}</p>
</template>

有关 n 的更多详细信息,请参见 API 参考

全局作用域 ​

在组合 API 模式中,当使用 createI18n 创建 i18n 实例时会创建全局作用域,与传统 API 模式类似。

传统 API 模式中 i18n 实例的 global 属性是 VueI18n 实例,而在组合 API 模式中,您可以引用 Composer 实例。

有两种方式可以在组件中引用全局作用域 Composer 实例。

显式使用 useI18n ​

正如我们所解释的,在 useI18n 中是一种方式。

ts
import { useI18n } from 'vue-i18n'

const { t } = useI18n({ useScope: 'global' })

// 在这里做一些事情...

以上代码将 useI18n 选项设置为 useScope: 'global',这使得 useI18n 能够返回一个可以通过 i18n 实例 global 属性访问的 Composer 实例。Composer 实例是全局作用域。

然后您可以使用从 Composer 实例公开的函数和属性进行组合。

注意

如果您将 useI18n 设置为 messages、datetimeFormats 和 numberFormats 一起设置 useScope: 'global’,它们将被合并到全局作用域中。也就是说,它们将由全局作用域 Composer 实例的 messages、datetimeFormasts 和 numberFormats 管理。

此外,如果在 i18n 自定义块中指定了 global(例如 <i18n global>{ … }</i18n>),则在块中定义的语言环境消息将与全局作用域合并。

隐式通过注入的属性和函数 ​

另一种引用全局作用域 Composer 实例的方式是通过隐式注入到组件中的属性和函数。

您需要指定 globalInjection: true 与 legacy: false 一起作为 createI18n 的选项,因为默认是禁用的。

注意

vue-i18n v9.2-beta.34 及更高版本,默认情况下 globalInjection 为 true。

这允许 Vue I18n 将以下属性和函数注入到组件中:

  • $i18n:封装了以下全局作用域 Composer 实例属性的对象
    • locale
    • fallbackLocale
    • availableLocales
  • $t:全局作用域的 Composer t 函数
  • $rt:全局作用域的 Composer rt 函数
  • $d:全局作用域的 Composer d 函数
  • $n:全局作用域的 Composer n 函数
  • $tm:全局作用域的 Composer tm 函数

Vue 3 运行时会将组件中设置的 app.config.globalProperties 全局注入组件。因此,上述列出的内容是由 Vue 3 运行时注入的,因此可以在模板中隐式使用。

注意

  • setup 无法看到注入到组件中的这些属性和函数
  • 在传统 API 模式中,一些以 $ 为前缀的 Vue I18n API 被注入,但在组合 API 模式中以 $ 为前缀并注入组件的属性和函数与传统 API 模式不同。

您注意到上述列出的内容都以 $ 为前缀。将它们以前缀 $ 的原因是:

  • setup 不与渲染上下文返回的属性和函数冲突
  • Vue I18n 组合 API 模式的全局作用域可访问标识符

通过这样做,用户意识到它们是特殊的属性和函数。

注意

如果您的 Vue 应用程序不使用本地作用域并且在全局作用域中进行所有 i18n,这非常有用,因为它不需要在每个组件的 setup 中运行 useI18n。然而,这种方式有与全局变量相同性质的问题。应谨慎使用,特别是在大型 Vue 应用程序中。

如果您使用一次后停止使用,必须将模板中使用的属性或函数更改为使用 useI18n 与 useScope: 'global' 选项返回的 setup 上下文中的属性或函数。

本地作用域 ​

在传统 API 模式中,通过为每个组件指定 i18n 组件选项创建 VueI18n 实例。这使 VueI18n 实例管理的本地消息等资源成为只能由目标组件引用的本地作用域。

要在组合 API 模式中启用本地作用域,您需要在 useI18n 中设置选项,这将基于给定的语言环境、语言环境消息等创建新的 Composer 实例。当给出选项时,useI18n 将基于选项指定的语言环境、语言环境消息和其他资源创建并返回一个新的 Composer 实例。

注意

您可以显式指定 useScope: ‘local’ 选项。

以下示例代码:

js
import { useI18n } from 'vue-i18n'

const { t, d, n, tm, locale } = useI18n({
  locale: 'ja-JP',
  fallbackLocale: 'en-US',
  messages: {
    'en-US': {
      // ....
    },
    'ja-JP': {
      // ...
    }
  },
  datetimeFormats: {
    'en-US': {
      // ....
    },
    'ja-JP': {
      // ...
    }
  },
  numberFormats: {
    'en-US': {
      // ....
    },
    'ja-JP': {
      // ...
    }
  }
})

// 在这里做一些事情...

语言环境消息 ​

如果您在 SFC 中使用 i18n 自定义块作为语言环境消息的语言环境资源,它将与 useI18n 的 messages 选项指定的语言环境消息合并。

以下是如何使用 i18n 自定义块和 useI18n 选项的示例:

vue
<script setup>
import { useI18n } from 'vue-i18n'
import en from './en.json'

const { t, availableLocales, getLocaleMessages } = useI18n({
  locale: 'en',
  messages: {
    en
  }
})

availableLocales.forEach(locale => {
  console.log(`${locale} locale messages`, getLocaleMessages(locale))
})
</script>

<i18n locale="ja">
{
  "hello": "こんにちは!"
}
</i18n>

注意

在此示例中,资源定义与 i18n 自定义块和 useI18n 的 messages 选项分离,但在本地作用域中,资源消息在 messages 选项中统一指定以进行管理目的,或在 i18n 自定义块中定义所有资源消息,这是更可取的做法。

组件共享语言环境消息 ​

在传统 API 模式中,组件使用 sharedMessages 选项共享语言环境消息。

在组合 API 模式中,使用 useI18n 导出的 mergeLocaleMessage。

通用语言环境消息示例:

js
export default {
  en: {
    buttons: {
      save: "Save",
      // ...
    }
  },
  ja: {
    buttons: {
      save: "保存",
      // ...
    }
  }
}

在组件中使用 mergeLocaleMessage:

vue
<script setup>
import { useI18n } from 'vue-i18n'
import commonMessages from './locales/common'

const { t, mergeLocaleMessage } = useI18n({
  locale: 'en',
  messages: {
    en: {
      hello: 'Hello!'
    },
    ja: {
      hello: 'こんにちは!'
    }
  }
})

for (const locale of ['en', 'ja']) {
  mergeLocaleMessage(locale, commonMessages[locale])
}
</script>

语言环境切换 ​

全局作用域 ​

您想要使用 <script setup> 更改语言环境,只需使用 useI18n 获取全局 Composer 并通过实例的 locale 属性更改它。

vue
<script setup>
const { t, locale } = useI18n({ useScope: 'global' })

locale.value = 'en' // 更改!
</script>

您还可以在模板中使用 setup 上下文,可以按如下方式更改:

vue
<select v-model="locale">
  <option value="en">en</option>
  <option value="ja">ja</option>
</select>

当您更改全局作用域的语言环境时,依赖于全局作用域的组件,如 t 翻译 API 可以响应式地工作并将显示消息切换为目标语言环境的消息。

如果您使用 隐式方式,您也可以在模板中使用 $i18n.locale 更改,如下所示:

vue
<select v-model="$i18n.locale">
  <option value="en">en</option>
  <option value="ja">ja</option>
</select>

本地作用域 ​

本地作用域语言环境,即 useI18n 返回的 Composer 实例 locale 属性,从全局作用域继承,就像传统 API 一样。因此,当您在全局作用域更改语言环境时,继承的本地作用域语言环境也会更改。如果您想切换整个应用程序的语言环境,可以使用 useI18n({ useScope: 'global' }) 返回的 locale,或者如果您使用 隐式方式,可以使用 $i18n.locale。

注意

如果您不想从全局作用域继承语言环境,useI18n 的 inheritLocale 选项必须为 false。

注意

对本地作用域的 locale 的更改对全局作用域语言环境没有影响,仅在本地作用域内有效。

VueI18n 实例与 Composer 实例之间的映射 ​

组合 API 中 Composer 实例提供的 API 与 VueI18n 实例提供的 API 非常相似的接口。

备注

内部上,传统 API 模式下的 VueI18n 实例通过包装 Composer 实例来工作。 因此,在组合 API 模式下比在传统 API 模式下性能开销更少。

以下是映射表:

VueI18n 实例Composer 实例
idid
localelocale
fallbackLocalefallbackLocale
availableLocalesavailableLocales
messagesmessages
datetimeFormatsdatetimeFormats
numberFormatsnumberFormats
modifiersmodifiers
missinggetMissingHandler / setMissingHandler
postTranslationgetPostTranslationHandler / setPostTranslationHandler
silentTranslationWarnmissingWarn
silentFallbackWarnfallbackWarn
formatFallbackMessagesfallbackFormat
syncinheritLocale
warnHtmlInMessagewarnHtmlMessage
escapeParameterHtmlescapeParameter
tt
tct
tete
tmtm
getLocaleMessagegetLocaleMessage
setLocaleMessagesetLocaleMessage
mergeLocaleMessagemergeLocaleMessage
dd
getDateTimeFormatgetDateTimeFormat
setDateTimeFormatsetDateTimeFormat
mergeDateTimeFormatmergeDateTimeFormat
nn
getNumberFormatgetNumberFormat
setNumberFormatsetNumberFormat
mergeNumberFormatmergeNumberFormat