This library contains our plugin for Vue.

Installation

npm i -S vue-intl

Usage

Initialize VueIntl plugin with the same IntlConfig documented in @formatjs/intl.

const app = createApp(App)
app.use(
  createIntl({
    locale: 'en',
    defaultLocale: 'en',
    messages: {
      foo: 'bar',
    },
  })
)

From there you can use our APIs in 2 ways:

inject

By specifying inject: {intl: intlKey}, you can use the full IntlFormatters API documented in @formatjs/intl.

Note: intlKey needs to be imported from vue-intl.

Composition API

We also support Vue's Composition API with provideIntl & useIntl.

const Ancestor = {
  setup() {
    provideIntl(
      createIntl({
        locale: 'en',
        defaultLocale: 'en',
        messages: {
          foo: 'Composed',
        },
      })
    )
  },
  render() {
    return h(Descendant)
  },
}

const Descendant = {
  setup() {
    const intl = useIntl()
    return () =>
      h(
        'p',
        {},
        intl.formatMessage({
          id: 'foo',
          defaultMessage: 'Hello',
        })
      )
  },
}

Methods

You can also use our formatters in Vue template by prepending $ like below:

<template>
  <p>{{ $formatNumber(3, {style: 'currency', currency: 'USD'}) }}</p>
</template>

We currently support:

  • $formatMessage
  • $formatDate
  • $formatTime
  • $formatRelativeTime
  • $formatTimeRange
  • $formatDisplayName
  • $formatList

See @formatjs/intl for the full list of API signatures.

Tooling

formatjs toolchain fully supports vue:

Caveats

Using ICU in Vue SFC

Since }} & {{ are special tokens in .vue <template>, this can cause potential conflict with ICU MessageFormat syntax, e.g:

<template>
  <p>
    {{ $formatMessage({ defaultMessage: '{count, selectordinal, offset:1 one {#}
    other {# more}}', }) }}
  </p>
</template>

Notice the {# more}} where it ends with }}. This will cause parsing issue in your vue template. In order to work around this issue, we recommend using space to turn }} into } }.

<template>
  <p>
    {{
      $formatMessage({
        defaultMessage:
          '{count, selectordinal, offset:1 one {#} other {# more} }',
      })
    }}
  </p>
</template>

Typed messages and migration

Version 8 requires TypeScript 5.4 or newer. Message helpers now share the @formatjs/intl contracts. Returned descriptors and catalog entries are readonly; construct a new descriptor instead of mutating one.

import {defineMessage} from 'vue-intl'

const message = defineMessage<{readonly count: number}>(
  {id: 'items', defaultMessage: '{count, number} items'},
  {typed: true}
)
// intl.formatMessage(message, {count: 3})

defineMessages<Contracts>(catalog, {typed: true}) attaches a separate values contract to each catalog entry. Helpers return the original objects at runtime. The generic declares the contract; it does not parse ICU literals.

For formatMessage and $t, the first generic is the values contract and the second is the rich output type. Move an existing output generic to the second position. Without generics, typed descriptors retain their checks; ordinary unregistered descriptors remain permissive. Vue uses its configured VNode output; Svelte uses strings.