ICU Messages in Vue with vue-i18n

Implement ICU MessageFormat in Vue.js applications using vue-i18n. Covers plural, select, linked messages, and the Composition API integration.

Framework Integration

Detailed Explanation

ICU MessageFormat in Vue.js

vue-i18n is the standard internationalization library for Vue.js applications. While vue-i18n has its own message syntax by default, it supports ICU MessageFormat through the messageCompiler option.

Enabling ICU in vue-i18n

To use ICU MessageFormat syntax with vue-i18n v9+, install the ICU message compiler:

npm install @intlify/message-compiler

Configure in your i18n setup:

import { createI18n } from 'vue-i18n';

const i18n = createI18n({
  locale: 'en',
  messages: {
    en: {
      greeting: 'Hello, {name}!',
      items: '{count, plural, one {# item} other {# items}}',
      pronoun: '{gender, select, male {He} female {She} other {They}}',
    },
    ja: {
      greeting: 'こんにちは、{name}!',
      items: '{count, plural, other {#個のアイテム}}',
      pronoun: '{gender, select, male {彼は} female {彼女は} other {その人は}}',
    },
  },
});

Using in Templates

<template>
  <p>{{ $t('greeting', { name: userName }) }}</p>
  <p>{{ $t('items', { count: itemCount }) }}</p>
</template>

Composition API

import { useI18n } from 'vue-i18n';

export default {
  setup() {
    const { t } = useI18n();
    const message = t('items', { count: 5 });
    return { message };
  },
};

Plural with Select

const messages = {
  en: {
    activity: '{gender, select, male {He} female {She} other {They}} posted {count, plural, one {# photo} other {# photos}}.',
  },
};
<p>{{ $t('activity', { gender: 'female', count: 3 }) }}</p>
<!-- Output: "She posted 3 photos." -->

vue-i18n's Native Plural Syntax vs ICU

vue-i18n has its own plural syntax using pipe separators:

// vue-i18n native syntax
items: 'no items | one item | {count} items'

// ICU MessageFormat syntax
items: '{count, plural, =0 {no items} one {one item} other {# items}}'

ICU syntax is more powerful because it supports:

  • Named plural categories beyond ordinal position
  • Nested messages (select inside plural)
  • Locale-aware category selection via CLDR rules
  • Consistent syntax across all frameworks

Component Interpolation

For messages containing HTML or Vue components:

<i18n-t keypath="tos" tag="p">
  <template #link>
    <a href="/tos">{{ $t('tosLink') }}</a>
  </template>
</i18n-t>

Message Files Organization

src/
  locales/
    en.json    # English messages (ICU format)
    ja.json    # Japanese messages
    de.json    # German messages
  i18n.ts      # vue-i18n configuration

Best Practices

  1. Use JSON files for messages, not inline objects
  2. Provide context comments in your message keys for translators
  3. Test with RTL locales (Arabic, Hebrew) for layout verification
  4. Use the Vue DevTools i18n plugin for debugging message resolution
  5. Enable fallbackWarn: false in production to suppress console warnings

Use Case

Vue.js developers integrating ICU MessageFormat into their internationalization workflow, especially those migrating from vue-i18n's native plural syntax to the more powerful ICU syntax for better multi-language support.

Try It — ICU Message Format Tester

Open full tool