jpskill.com
🛠️ 開発・MCP コミュニティ

web-i18n-vue-i18n

Vue 3 Composition API で国際化対応を行う際に、型安全性を確保し、より安全で効率的な多言語対応のウェブアプリケーション開発を支援するSkill。

📜 元の英語説明(参考)

Type-safe i18n for Vue 3 Composition API

🇯🇵 日本人クリエイター向け解説

一言でいうと

Vue 3 Composition API で国際化対応を行う際に、型安全性を確保し、より安全で効率的な多言語対応のウェブアプリケーション開発を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o web-i18n-vue-i18n.zip https://jpskill.com/download/10289.zip && unzip -o web-i18n-vue-i18n.zip && rm web-i18n-vue-i18n.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10289.zip -OutFile "$d\web-i18n-vue-i18n.zip"; Expand-Archive "$d\web-i18n-vue-i18n.zip" -DestinationPath $d -Force; ri "$d\web-i18n-vue-i18n.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して web-i18n-vue-i18n.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → web-i18n-vue-i18n フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

vue-i18n 国際化パターン

クイックガイド: Vue 3 でタイプセーフな国際化を行うには、vue-i18n v11+ を使用してください。翻訳には useI18n コンポーザブル、日付には d()、数値には n()、リッチテキストには i18n-t コンポーネントを使用します。Composition API モードでは legacy: false を設定します (Legacy API は v11 で非推奨となり、v12 で削除されました)。


<critical_requirements>

重要: この Skill を使用する前に

すべてのコードは、CLAUDE.md のプロジェクト規約に従う必要があります (kebab-case、名前付きエクスポート、インポート順序、import type、名前付き定数)

(Composition API モードでは、createI18nlegacy: false を必ず設定する必要があります)

(コンポーネントごとに SINGLE の useI18n() 呼び出しを使用する必要があります - 必要なすべての関数を 1 つの呼び出しから分割代入してください)

(locale.value を設定する前に、ロケールメッセージのロードを待機する必要があります - メッセージがロードされる前にロケールを設定すると、生のキーが表示されます)

(ロケールコードには名前付き定数を使用する必要があります - インラインのロケール文字列は使用しないでください)

</critical_requirements>


自動検出: vue-i18n, useI18n, createI18n, i18n-t, i18n-d, i18n-n, ロケール検出, 複数形化, Vue 3 i18n, Composition API i18n

いつ使用するか:

  • Vue 3 アプリケーションで国際化を実装する場合
  • 補間と複数形化を使用してローカライズされたメッセージをレンダリングする場合
  • ロケールごとに日付、数値、通貨をフォーマットする場合
  • ロケールベースのルーティングと遅延ロードを設定する場合
  • TypeScript でタイプセーフな翻訳システムを構築する場合

カバーする主要なパターン:

  • createI18n と Composition API を使用したプロジェクトのセットアップ
  • メッセージ、日付、数値のための useI18n コンポーザブル
  • パイプ構文とカスタムルールによる複数形化
  • i18n-t, i18n-d, i18n-n によるコンポーネント補間
  • パフォーマンスのための翻訳の遅延ロード
  • タイプセーフなキーのための TypeScript 統合

いつ使用しないか:

  • シンプルな単一ロケールアプリケーション (i18n の複雑さをスキップ)
  • レガシー Vue 2 アプリケーション (vue-i18n v8 を使用)
  • Vue 以外のアプリケーション (フレームワーク固有の i18n ソリューションを使用)

詳細なリソース:

  • examples/core.md -- セットアップ、useI18n、補間、複数形化、コンポーネント補間、TypeScript、ロケール切り替え
  • examples/formatting.md -- DateTime フォーマット、数値フォーマット、スコープ付きスロットを持つ i18n-d/i18n-n コンポーネント
  • examples/lazy-loading.md -- 動的インポート、ルートベースのロード、機能分割、エラー処理、SSR
  • reference.md -- 意思決定フレームワーク、アンチパターン、チェックリスト、複数形化ルール、移行ノート

<philosophy>

Philosophy

vue-i18n は、複雑なメッセージフォーマットをサポートする ロケール対応のリアクティブレンダリング の原則に従います。翻訳は JSON オブジェクトとして編成され、グローバルまたはコンポーネントごとにロードされます。Composition API モード (legacy: false) は、useI18n コンポーザブルを使用した最新のタイプセーフなアプローチを提供します。

コア原則:

  1. Composition API ファースト: 最新の Vue 3 パターンのために legacy: falseuseI18n() コンポーザブルを使用します
  2. 単一のコンポーザブル呼び出し: 1 つの useI18n() 呼び出しからすべての関数 (t, d, n, locale) を分割代入します
  3. ロケールのリアクティビティ: ロケールの変更は、Vue のリアクティビティシステムを介して自動的に再レンダリングをトリガーします
  4. メッセージフォーマット標準: 翻訳者にとって使いやすいメッセージのために、パイプで区切られた複数形と名前付き補間を使用します

</philosophy>


<patterns>

コアパターン

パターン 1: プロジェクトのセットアップ

標準的なファイル構造を使用して、Composition API モードで vue-i18n をセットアップします。

ファイル構造

src/
  i18n/
    index.ts         # メインの i18n 設定
    types.ts         # TypeScript 型宣言
  locales/
    en.json          # 英語の翻訳
    ja.json          # 日本語の翻訳
    fr.json          # フランス語の翻訳
main.ts              # i18n プラグインを使用したアプリのエントリポイント

設定

// 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, // Composition API には必須
  locale: DEFAULT_LOCALE,
  fallbackLocale: DEFAULT_LOCALE,
  // globalInjection はデフォルトで true です - $t, $d, $n をテンプレートに注入します
  messages: {
    en,
  },
});

良い点: legacy: false は Composition API モードを有効にし、ロケールの名前付き定数はタイプセーフな使用を可能にし、fallbackLocale は翻訳エラーの欠落を防ぎ、globalInjection はテンプレートのショートハンドを有効にします (v9.2 以降はデフォルトで true)

// 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");

良い点: i18n プラグインはアプリのルートで一度登録され、すべてのコンポーネントが翻訳機能を継承します


パターン 2: useI18n コンポーザブル

翻訳、フォーマット、ロケール管理のために、コンポーネントで useI18n コンポーザブルを使用します。

基本的な使い方

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

// 重要: 単一の呼び出しで、必要なすべての関数を分割代入します
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>

良い点: 単一の useI18n 呼び出しは同期の問題を防ぎ、locale.value はリアクティブであり、再レンダリングをトリガーし、分割代入は必要なすべての関数を提供します


<!-- 悪い例 - 複数の useI18n 呼び出しは同期の問題を引き起こします -->
<script setup lang="ts">
const { t } = useI18n();
const { locale } = useI18n(); // 間違い: 2 回目の呼び出し!
const { d } = useI18n(); // 間違い: 3 回目の呼び出し!
</

(原文はここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

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 -- Setup, useI18n, interpolation, pluralization, component interpolation, TypeScript, locale switching
  • examples/formatting.md -- DateTime formats, number formats, i18n-d/i18n-n components with scoped slots
  • examples/lazy-loading.md -- Dynamic imports, route-based loading, feature splitting, error handling, SSR
  • 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 languages with complex rules (Russian, Arabic, Polish)
const i18n = createI18n({
  legacy: false,
  locale: "ru",
  pluralRules: {
    ru: (choice: number, choicesLength: number) => {
      if (choice === 0) return 0;

      const teen = choice > 10 && choice < 20;
      const endsWithOne = choice % 10 === 1;

      if (!teen && endsWithOne) return 1;
      if (!teen && choice % 10 >= 2 && choice % 10 <= 4) return 2;
      return choicesLength < 4 ? 2 : 3;
    },
  },
  messages: {
    ru: {
      apple: "нет яблок | {n} яблоко | {n} яблока | {n} яблок",
    },
  },
});

Why good: custom pluralRules handle languages with more than two forms, function receives choice count and returns index into plural array


Pattern 5: Component Interpolation

Use i18n-t, i18n-d, and i18n-n components for rich text with Vue components inside translations.

i18n-t for Rich Text

{
  "tos": "I agree to the {terms}.",
  "termsLink": "Terms of Service"
}
<template>
  <i18n-t keypath="tos" tag="p">
    <template #terms>
      <a href="/terms">{{ t("termsLink") }}</a>
    </template>
  </i18n-t>
</template>

Why good: translation string stays translatable, Vue components can be inserted via named slots, tag prop controls wrapper element

i18n-t with Pluralization

{
  "items": "no items | {n} item | {n} items"
}
<template>
  <i18n-t keypath="items" :plural="count" tag="p">
    <template #n>
      <strong>{{ count }}</strong>
    </template>
  </i18n-t>
</template>

<script setup lang="ts">
import { ref } from "vue";
const count = ref(5);
</script>

Why good: plural value passed via :plural prop, #n slot allows styling the number, result: "5 items"

i18n-d and i18n-n for Styled Parts

<template>
  <!-- DateTime with styled parts -->
  <i18n-d :value="date" format="long" tag="time">
    <template #month="{ month }">
      <span class="month">{{ month }}</span>
    </template>
    <template #day="{ day }">
      <span class="day">{{ day }}</span>
    </template>
  </i18n-d>

  <!-- Number with styled parts -->
  <i18n-n :value="price" format="currency" tag="span">
    <template #currency="{ currency }">
      <span class="currency-symbol">{{ currency }}</span>
    </template>
    <template #integer="{ integer }">
      <span class="integer">{{ integer }}</span>
    </template>
  </i18n-n>
</template>

Why good: scoped slots expose formatted parts (month, day, currency, integer), enables fine-grained styling of formatted values


Pattern 6: DateTime and Number Formatting

Configure and use locale-aware formatting for dates, times, and numbers.

DateTime Format Configuration

const datetimeFormats = {
  "en-US": {
    short: {
      year: "numeric",
      month: "short",
      day: "numeric",
    },
    long: {
      year: "numeric",
      month: "long",
      day: "numeric",
      weekday: "long",
      hour: "numeric",
      minute: "numeric",
    },
  },
  "ja-JP": {
    short: {
      year: "numeric",
      month: "short",
      day: "numeric",
    },
    long: {
      year: "numeric",
      month: "long",
      day: "numeric",
      weekday: "long",
      hour: "numeric",
      minute: "numeric",
      hour12: false,
    },
  },
};

const i18n = createI18n({
  legacy: false,
  locale: "en-US",
  datetimeFormats, // Note: camelCase, not dateTimeFormats
});
const { d } = useI18n();

d(new Date(), "short"); // "Apr 19, 2024"
d(new Date(), "long"); // "Friday, April 19, 2024 at 2:30 PM"

Why good: named formats ensure consistency across app, locale-specific formats handle cultural differences (12h vs 24h time)

Number Format Configuration

const numberFormats = {
  "en-US": {
    currency: {
      style: "currency",
      currency: "USD",
      notation: "standard",
    },
    decimal: {
      style: "decimal",
      minimumFractionDigits: 2,
      maximumFractionDigits: 2,
    },
    percent: {
      style: "percent",
      useGrouping: false,
    },
  },
  "ja-JP": {
    currency: {
      style: "currency",
      currency: "JPY",
      useGrouping: true,
      currencyDisplay: "symbol",
    },
  },
};

const i18n = createI18n({
  legacy: false,
  locale: "en-US",
  numberFormats,
});
const { n } = useI18n();

n(10000, "currency"); // "$10,000.00"
n(0.15, "percent"); // "15%"

Why good: Intl.NumberFormat under the hood, handles locale-specific separators and symbols automatically

</patterns>


<integration>

Integration Guide

vue-i18n integrates with Vue's reactivity system for automatic re-renders on locale change.

Locale state guidance:

  • Locale state is managed by vue-i18n -- use locale.value from useI18n to read/write
  • Locale changes are reactive -- all components using t(), d(), n() update automatically
  • globalInjection defaults to true, injecting $t, $d, $n into templates

Locale-based routing: vue-i18n works with navigation guards to load translations before route renders. See examples/lazy-loading.md for patterns.

</integration>


<red_flags>

RED FLAGS

  • Missing legacy: false -- defaults to deprecated Options API mode (removed in v12)
  • Multiple useI18n() calls in same component -- creates separate instances that desync
  • Hardcoded locale strings -- use named constants for type safety
  • Missing fallbackLocale -- missing translations cause visible errors instead of graceful fallback
  • Using v-html with translations -- XSS vulnerability, use <i18n-t> instead
  • String concatenation -- word order varies by language, use complete messages with interpolation
  • Setting locale before messages load -- shows raw keys, always await loading first
  • Using dateTimeFormats instead of datetimeFormats -- the config key uses lowercase 't'
  • Using $tc() -- removed in v11, use t() with count parameter
  • Using v-t directive -- deprecated in v11, removed in v12, use t() or <i18n-t>

Gotchas & Edge Cases:

  • locale.value is a ref -- assign with .value, not direct assignment
  • @:linked.message syntax only works with global scope, not local scope
  • Custom pluralRules function returns an index into the array, not the form itself

See reference.md for full anti-pattern code examples and decision frameworks.

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

All code must follow project conventions in CLAUDE.md

(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)

Failure to follow these rules will break i18n reactivity and cause translation inconsistencies.

</critical_reminders>