i18next-vue と vue-i18n は、Vue.jsアプリケーションで多言語対応(国際化)を実現するための主要なライブラリです。vue-i18n はVue公式チームが開発するVue専用のソリューションであり、Vueのリアクティブシステムと緊密に統合されています。一方、i18next-vue は、フレームワーク非依存の国際化エンジンである i18next のVue向けバインディングで、i18nextの豊富なエコシステムと柔軟性を活用できます。どちらも翻訳キーの管理、動的言語切り替え、フォールバック処理などの基本機能を提供しますが、設計思想や拡張性、学習コストに明確な違いがあります。
Vue.jsアプリケーションで多言語対応を実装するには、i18next-vueとvue-i18nが主要な選択肢です。どちらも成熟した国際化機能を提供しますが、設計思想や統合方法、拡張性に明確な違いがあります。この記事では、実際の開発現場で直面する技術的課題を中心に、両者の違いを深く掘り下げます。
**vue-i18n**はVue.js公式チームによって開発・メンテナンスされているVue専用のi18nライブラリです。Vueのリアクティブシステムと密接に連携し、コンポーネント内での翻訳キーの使用や動的メッセージの更新を自然にサポートします。
// vue-i18n: プラグイン設定
import { createApp } from 'vue';
import { createI18n } from 'vue-i18n';
const i18n = createI18n({
locale: 'ja',
messages: {
ja: { hello: 'こんにちは' },
en: { hello: 'Hello' }
}
});
const app = createApp(App);
app.use(i18n);
app.mount('#app');
**i18next-vue**は、広く使われている国際化フレームワーク i18next のVue向けバインディングです。i18next自体はフレームワーク非依存で、React、Angular、Vanilla JSなど多くの環境で利用されています。そのため、既にi18nextを使っているプロジェクトや、複数のフロントエンド技術を横断して共通のi18n戦略を取りたい場合に適しています。
// i18next-vue: 設定
import { createApp } from 'vue';
import i18next from 'i18next';
import I18NextVue from 'i18next-vue';
i18next.init({
lng: 'ja',
resources: {
ja: { translation: { hello: 'こんにちは' } },
en: { translation: { hello: 'Hello' } }
}
});
const app = createApp(App);
app.use(I18NextVue, { i18next });
app.mount('#app');
**vue-i18n**は $t グローバルメソッドや <i18n-t> コンポーネントを提供し、テンプレート内で直感的に翻訳キーを参照できます。Composition APIを使う場合は useI18n() フックを利用します。
<!-- vue-i18n: Options API -->
<template>
<p>{{ $t('hello') }}</p>
</template>
<script>
export default {
// ...
}
</script>
<!-- vue-i18n: Composition API -->
<template>
<p>{{ t('hello') }}</p>
</template>
<script setup>
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>
**i18next-vue**は $t メソッドをグローバルプロパティとして注入しますが、Composition API向けの専用フックは提供していません。代わりに、i18next のグローバルインスタンスを直接使うか、カスタムフックを作成する必要があります。
<!-- i18next-vue -->
<template>
<p>{{ $t('hello') }}</p>
</template>
<script setup>
// Composition APIでの使用例(カスタムフックなし)
import i18next from 'i18next';
const t = i18next.t;
</script>
大規模アプリでは、翻訳リソースをコード分割して初期バンドルサイズを抑えることが重要です。
**vue-i18n**は defineAsyncComponent や動的インポートと組み合わせて、言語リソースを非同期で読み込むことができます。また、@intlify/unplugin-vue-i18n を使うことで、ビルド時にJSON/YAMLファイルをモジュールとして取り込めます。
// vue-i18n: 非同期言語切り替え
async function changeLocale(locale) {
if (!i18n.global.availableLocales.includes(locale)) {
const messages = await import(`./locales/${locale}.json`);
i18n.global.setLocaleMessage(locale, messages.default);
}
i18n.global.locale = locale;
}
**i18next-vue**はi18nextのバックエンドプラグイン(例:i18next-http-backend)を使って、必要に応じて翻訳ファイルをHTTP経由で取得できます。これにより、初期ロード時に全言語を含める必要がなくなります。
// i18next-vue: HTTP経由での遅延読み込み
import HttpApi from 'i18next-http-backend';
i18next.use(HttpApi).init({
lng: 'ja',
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
});
開発中に翻訳キーの存在確認やフォールバック動作を検証したい場面は多いです。
**vue-i18n**は開発モードで未登録のキーをコンソールに警告出力する機能があり、またVue Devtools拡張機能と連携して現在のロケールや翻訳状態を可視化できます。
// vue.config.jsでDevtoolsサポートを有効化
module.exports = {
chainWebpack: config => {
config.plugin('define').tap(args => {
args[0]['__VUE_I18N_FULL_INSTALL__'] = JSON.stringify(true);
return args;
});
}
};
**i18next-vue**はi18next本体のデバッグモードを有効にすることで、キーの解決過程やフォールバック動作を詳細にトレースできます。
i18next.init({
debug: true, // 開発時のみtrueに
// ...
});
ユーザーが言語を変更した際に、画面全体を再レンダリングせずに翻訳文だけを更新できるかどうかはUXに直結します。
**vue-i18n**はVueのリアクティブシステムと完全に統合されており、i18n.global.locale を変更すると、すべての $t() 呼び出しが自動的に再評価され、DOMが更新されます。
// 言語切り替え(リアクティブ更新)
i18n.global.locale = 'en'; // これだけで全コンポーネントが更新
**i18next-vue**も同様に、i18next.changeLanguage() を呼び出すと、内部でイベントを発行し、バインディングがVueコンポーネントの再レンダリングをトリガーします。
// 言語切り替え
i18next.changeLanguage('en');
ただし、カスタムフックや手動で i18next.t を呼び出している場合、再レンダリングが発生しない可能性があるため注意が必要です。
**vue-i18n**はVueに特化しているため、他のVueプラグイン(例:Vue Routerとの統合)との連携がスムーズです。たとえば、URLのパスに基づいて言語を自動設定するといった高度なユースケースにも対応しやすいです。
**i18next-vue**はi18nextの豊富なエコシステム(300以上のプラグイン)を活用できます。例えば、翻訳管理サービス(Locize、Phraseなど)との統合、複数名前空間の扱い、複雑なフォールバックチェーンなど、企業レベルの要件を満たす柔軟性があります。
| 観点 | vue-i18n | i18next-vue |
|---|---|---|
| Vueとの統合度 | ⭐⭐⭐⭐⭐(公式サポート) | ⭐⭐⭐(サードパーティバインディング) |
| 学習コスト | 低(Vue開発者向けに最適化) | 中(i18nextの概念を理解必要) |
| 拡張性 | Vue内では十分 | 非常に高い(i18nextエコシステム) |
| マルチフレームワーク対応 | ❌ | ✅(React/Angularなどと共通化可能) |
| 遅延読み込み | ビルド時/動的インポート対応 | HTTPバックエンド対応 |
vue-i18nを選ぶべきケース:Vue専用プロジェクトで、シンプルで直感的なAPIと公式サポートを重視する場合。特に中小規模のアプリや、Vue生態系に深く依存するプロジェクトに最適です。
i18next-vueを選ぶべきケース:既にi18nextを使っている、または複数のフロントエンド技術を横断して国際化戦略を統一したい場合。また、高度な翻訳管理やエンタープライズ向け機能(例:翻訳メモリ、機械翻訳連携)が必要な場合にも有利です。
どちらも安定しており、新しいプロジェクトで使って問題ありません。最終的には、チームの技術スタックや長期的なメンテナンス戦略に合わせて選ぶのが賢明です。
i18next-vue は、すでに i18next を他のプロジェクト(React、Angular など)で使用している場合や、複数のフロントエンド技術間で国際化戦略を統一したい場合に最適です。i18next の豊富なプラグインエコシステム(HTTP バックエンド、翻訳管理サービス連携など)を活用したいエンタープライズ向けプロジェクトにも向いています。ただし、Vue 専用の機能やツールとの統合はやや限定的です。
vue-i18n は、Vue.js 専用のプロジェクトでシンプルかつ直感的な国際化を実現したい場合に最適です。Vue 公式チームによるサポートを受けられ、Composition API や Vue Devtools との統合もスムーズです。中小規模のアプリケーションや、Vue 生態系に深く依存するプロジェクトでは、開発体験と保守性の面で大きなメリットがあります。
This library is a simple wrapper for i18next, simplifying its use in Vue 3.
There is also a Vue 2 version of this package.
In the documentation, you can find information on how to upgrade from @panter/vue-i18next, from i18next-vue 3.x or earlier versions.
npm install i18next-vue
import Vue from "vue";
import i18next from "i18next";
import I18NextVue from "i18next-vue";
import App from "./App.vue";
/*const i18nInitialized = */i18next.init({ ... });
createApp(App).use(I18NextVue, { i18next }).mount('#app');
// to wait for loading the translations first, do this instead:
// i18nInitialized.then(() => createApp(App).use(I18NextVue, { i18next }).mount('#app'));
Use the $t translation function, which works like (and uses) the versatile t function from i18next.
There is a full tutorial for setting up i18next-vue. You can check out the live demo version version of it, too.
To learn about more options, check out the full documentation.
Given the i18next translations
i18next.init({
// ...
resources: {
en: {
// language
translation: {
// the default namespace
insurance: "Insurance",
},
},
de: {
// language
translation: {
// the default namespace
insurance: "Versicherung",
},
},
},
});
You can use
<template>
<h1>A test in {{ $i18next.language }}</h1>
<p>{{ $t("insurance") }}</p>
</template>
$t() works both in Options API and Composition API components.
Using the useTranslation() composition function you can access the i18next instance and t() in the setup part, and e.g. get a t() functions for a specific namespace.
<script setup>
import { computed } from "vue";
import { useTranslation } from "i18next-vue";
const { i18next, t } = useTranslation();
const term = computed(() => t("insurance"));
</script>
<template>
<h1>A test in {{ i18next.language }}</h1>
<p>inline: {{ t("insurance") }}</p>
<p>inline with $t: {{ $t("insurance") }}</p>
<p>computed: {{ term }}</p>
</template>
i18next-vue provides a <i18next> translation component, so you can use markup (including Vue components) in translations.
In this example {faq-link} will be replaced by the faq-link slot, i.e. by the router link. You can move {faq-link} around in the translation, so it makes sense for the target language.
i18next.init({
// ...
resources: {
en: {
translation: {
"message": "Open the {faq-link} page."
"faq": "Frequently Asked Questions"
}
},
fr: {
// ...
}
}
})
<template>
<i18next :translation="$t('message')">
<template #faq-link>
<router-link :to="FAQ_ROUTE">
{{ $t("faq") }}
</router-link>
</template>
</i18next>
</template>
Custom slot values may be useful when the default braces ({ and }) are wrongly treated by the
Locize service or don't satisfy other needs.
Use custom values for recognizing start and end of the insertion points of the <i18next>/TranslationComponent
inside the localization term:
// main.js
i18next.init({
// ...
resources: {
en: {
translation: {
"message": "Open the <slot>faq-link</slot> page."
"faq": "FAQ"
}
},
de: {
// ...
}
}
})
app.use(I18NextVue, {
i18next,
slotStart: '<slot>',
slotEnd: '</slot>',
});
<!-- Component.vue -->
<template>
<i18next :translation="$t('message')">
<template #faq-link>
<router-link :to="FAQ_ROUTE">
{{ $t("faq") }}
</router-link>
</template>
</i18next>
</template>