Receber por email
← Voltar para o catálogo

web-i18n-vue-i18n

Type-safe i18n for Vue 3 Composition API

11estrelas
Atualizado há 7 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add agents-inc/skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/web-i18n-vue-i18n/svg)](https://www.skillteca.com.br/skills/web-i18n-vue-i18n)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

vue-i18n Internationalization Patterns

Quick Guide: Use vue-i18n v11+ for type-safe internationalization in Vue 3. useI18n composable for translations, d() for dates, n() for numbers, i18n-t component for rich text. Set legacy: false for Composition API mode (Legacy API is deprecated in v11, removed in v12).

<critical_requirements>

CRITICAL: Before Using This Skill

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

(You MUST set legacy: false in createI18n for Composition API mode)

(You MUST use a SINGLE useI18n() call per component - destructure all needed functions from one call)

(You MUST await locale message loading before setting locale.value - setting locale before messages are loaded shows raw keys)

(You MUST use named constants for locale codes - NO inline locale strings)

</critical_requirements>

Auto-detection: vue-i18n, useI18n, createI18n, i18n-t, i18n-d, i18n-n, locale detection, pluralization, Vue 3 i18n, Composition API i18n

When to use:

  • Implementing internationalization in Vue 3 applications
  • Rendering localized messages with interpolation and pluralization
  • Formatting dates, numbers, and currency per locale
  • Setting up locale-based routing and lazy loading
  • Building type-safe translation systems with TypeScript

Key patterns covered:

  • Project setup with createI18n and Composition API
  • useI18n composable for messages, dates, numbers
  • Pluralization with pipe syntax and custom rules
  • Component interpolation with i18n-t, i18n-d, i18n-n
  • Lazy loading translations for performance
  • TypeScript integration for type-safe keys

When NOT to use:

  • Simple single-locale applications (skip i18n complexity)
  • Legacy Vue 2 applications (use vue-i18n v8)
  • Non-Vue applications (use framework-specific i18n solution)

Detailed Resources:

  • [examples/core.md](examples/core.md) -- Setup, useI18n, interpolation, pluralization, component interpolation, TypeScript, locale switching
  • [examples/formatting.md](examples/formatting.md) -- DateTime formats, number formats, i18n-d/i18n-n components with scoped slots
  • [examples/lazy-loading.md](examples/lazy-loading.md) -- Dynamic imports, route-based loading, feature splitting, error handling, SSR
  • [reference.md](reference.md) -- Decision frameworks, anti-patterns, checklists, pluralization rules, migration notes

<philosophy>

Philosophy

vue-i18n follows the principle of locale-aware, reactive rendering with support for complex message formatting. Translations are organized as JSON objects, loaded globally or per-component. The Composition API mode (legacy: false) provides a modern, type-safe approach using the useI18n composable.

Core principles:

  1. Composition API first: Use useI18n() composable with legacy: false for modern Vue 3 patterns
  2. Single composable call: Destructure all functions (t, d, n, locale) from ONE useI18n() call
  3. Locale reactivity: Locale changes automatically trigger re-renders via Vue's reactivity system
  4. Message format standard: Use pipe-separated plurals and named interpolation for translator-friendly messages

</philosophy>

<patterns>

Core Patterns

Pattern 1: Project Setup

Set up vue-i18n with Composition API mode using the standard file structure.

File Structure

src/
  i18n/
    index.ts         # Main i18n configuration
    types.ts         # TypeScript type declarations
  locales/
    en.json          # English translations
    ja.json          # Japanese translations
    fr.json          # French translations
main.ts              # App entry with i18n plugin

Configuration

// src/i18n/index.ts
import { createI18n } from "vue-i18n";
import en from "../locales/en.json";

export const SUPPORTED_LOCALES = ["en", "ja", "fr"] as const;
export const DEFAULT_LOCALE = "en";

export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];

export const i18n = createI18n({
  legacy: false, // REQUIRED for Composition API
  locale: DEFAULT_LOCALE,
  fallbackLocale: DEFAULT_LOCALE,
  // globalInjection defaults to true - injects $t, $d, $n into templates
  messages: {
    en,
  },
});

Why good: legacy: false enables Composition API mode, named constants for locales enable type-safe usage, fallbackLocale prevents missing translation errors, globalInjection enables template shorthand (default true since v9.2)

// main.ts
import { createApp } from "vue";
import { i18n } from "./i18n";
import App from "./App.vue";

const app = createApp(App);
app.use(i18n);
app.mount("#app");

Why good: i18n plugin registered once at app root, all components inherit translation capability

Pattern 2: useI18n Composable

Use the useI18n composable in components for translations, formatting, and locale management.

Basic Usage

<script setup lang="ts">
import { useI18n } from "vue-i18n";

// CRITICAL: Single call, destructure all needed functions
const { t, d, n, locale, availableLocales } = useI18n();

const switchLocale = (newLocale: string) => {
  locale.value = newLocale;
};
</script>

<template>
  <h1>{{ t("greeting") }}</h1>
  <p>{{ t("messages.welcome", { name: "Vue" }) }}</p>
  <p>{{ d(new Date(), "long") }}</p>
  <p>{{ n(1000, "currency") }}</p>

  <select :value="locale" @change="switchLocale($event.target.value)">
    <option v-for="loc in availableLocales" :key="loc" :value="loc">
      {{ loc }}
    </option>
  </select>
</template>

Why good: single useI18n call prevents sync issues, locale.value is reactive and triggers re-renders, destructuring provides all needed functions

<!-- BAD - Multiple useI18n calls cause sync issues -->
<script setup lang="ts">
const { t } = useI18n();
const { locale } = useI18n(); // WRONG: Second call!
const { d } = useI18n(); // WRONG: Third call!
</script>

Why bad: multiple useI18n calls create separate instances that may not stay synchronized, leads to subtle bugs

Pattern 3: Message Interpolation

Use named placeholders and linked messages for flexible translations.

Named Interpolation

// locales/en.json
{
  "greeting": "Hello, {name}!",
  "items": "You have {count} items in your cart.",
  "email": "{account}{'@'}{domain}"
}
const { t } = useI18n();

t("greeting", { name: "John" }); // "Hello, John!"
t("items", { count: 5 }); // "You have 5 items in your cart."
t("email", { account: "user", domain: "example.com" }); // "user@example.com"

Why good: named placeholders are explicit and refactorable, literal interpolation ({'@'}) escapes special characters

Linked Messages

{
  "app": {
    "name": "My App"
  },
  "welcome": "Welcome to @:app.name!",
  "brand": "vue i18n",
  "message": {
    "upper": "@.upper:brand",
    "lower": "@.lower:brand",
    "capitalize": "@.capitalize:brand"
  }
}
t("welcome"); // "Welcome to My App!"
t("message.upper"); // "VUE I18N"
t("message.capitalize"); // "Vue i18n"

Why good: linked messages (@:key) avoid duplication, built-in modifiers (upper, lower, capitalize) transform referenced values

Pattern 4: Pluralization

Use pipe-separated syntax for plural forms with automatic {n} and {count} injection.

Basic Plural Syntax

{
  "car": "car | cars",
  "apple": "no apples | one apple | {count} apples",
  "items": "no items | {n} item | {n} items"
}
const { t } = useI18n();

t("car", 1); // "car"
t("car", 2); // "cars"

t("apple", 0); // "no apples"
t("apple", 1); // "one apple"
t("apple", 10); // "10 apples"

t("items", 5); // "5 items"

Why good: pipe syntax is translator-friendly, {n} and {count} are auto-injected with the plural value, three forms handle zero/one/many

Custom Plural Rules

// For lang
Compartilhar X LinkedIn