i18n Key Structure for Vue Applications

How to structure i18n translation keys for Vue.js applications using vue-i18n. Covers component-scoped messages, global vs local translations, SFC i18n blocks, and Nuxt i18n module patterns.

Framework Guide

Detailed Explanation

i18n Key Structure for Vue

Vue applications typically use vue-i18n for internationalization. vue-i18n offers unique features like component-scoped messages and SFC (Single File Component) i18n blocks that influence key organization.

Global Message Structure

{
  "common": {
    "buttons": {
      "submit": "Submit",
      "cancel": "Cancel",
      "save": "Save Changes"
    },
    "labels": {
      "email": "Email",
      "password": "Password"
    }
  },
  "pages": {
    "home": {
      "title": "Welcome to Our App",
      "description": "The best tool for developers"
    }
  }
}

SFC i18n Blocks

Vue's unique feature -- embedding translations directly in components:

<template>
  <div>
    <h1>{{ $t('title') }}</h1>
    <p>{{ $t('description') }}</p>
    <button>{{ $t('common.buttons.submit') }}</button>
  </div>
</template>

<i18n>
{
  "en": {
    "title": "Settings",
    "description": "Manage your account settings"
  },
  "ja": {
    "title": "\u8A2D\u5B9A",
    "description": "\u30A2\u30AB\u30A6\u30F3\u30C8\u8A2D\u5B9A\u3092\u7BA1\u7406"
  }
}
</i18n>

Keys inside <i18n> blocks are scoped to the component. No prefix needed -- title refers to the component's own title key.

Global vs Local Messages

Scope Use For Access Pattern
Global Shared buttons, errors, nav $t('common.buttons.submit')
Local (SFC) Component-specific text $t('title')
Route-level Page-specific content $t('pages.home.title')

Nuxt i18n Module

Nuxt uses @nuxtjs/i18n which adds:

  • Automatic locale detection from URL prefix (/en/, /ja/)
  • Lazy-loaded locale messages per route
  • SEO helpers (hreflang, canonical URLs)
locales/
  en.json     # or split into en/ directory with multiple files
  ja.json

vue-i18n Pluralization

vue-i18n uses pipe-separated values within a single key:

{
  "items": "No items | {count} item | {count} items"
}

Access: $tc('items', count)

This is different from react-i18next which uses separate keys per plural form.

Key Naming Recommendations for Vue

  1. Use dot notation for global keys (common.buttons.submit)
  2. Use simple names for SFC-scoped keys (title, description)
  3. Prefix page-specific global keys with the page name (pages.settings.title)
  4. Keep shared keys in a common or global namespace
  5. Use pipe-separated plural values instead of separate plural keys

Use Case

Vue developers choosing between global messages and SFC i18n blocks need to understand the trade-offs. SFC blocks co-locate translations with components (better DX) but make it harder to manage translations externally (worse for translation agencies). The i18n Key Generator helps Vue developers generate properly structured keys for both approaches.

Try It — i18n Key Generator

Open full tool