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 函数,以及诸如 localefallbackLocale 等属性,就像 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 设置为 messagesdatetimeFormatsnumberFormats 一起设置 useScope: 'global’它们将被合并到全局作用域中。也就是说,它们将由全局作用域 Composer 实例的 messagesdatetimeFormastsnumberFormats 管理。

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

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

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

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

注意

vue-i18n v9.2-beta.34 及更高版本,默认情况下 globalInjectiontrue

这允许 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 应用程序中。

如果您使用一次后停止使用,必须将模板中使用的属性或函数更改为使用 useI18nuseScope: '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 自定义块作为语言环境消息的语言环境资源,它将与 useI18nmessages 选项指定的语言环境消息合并。

以下是如何使用 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 自定义块和 useI18nmessages 选项分离,但在本地作用域中,资源消息在 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

注意

如果您不想从全局作用域继承语言环境,useI18ninheritLocale 选项必须为 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