In this follow-up tutorial, we will extend our previous article “Create Vue.js SPA in Laravel Project – Step-by-Step Guide for Beginners” and add multi-language support to the same project. In this post, you will learn how to set up vue-i18n and build a vue.js spa language switcher i18n feature that changes language instantly—without refreshing the page and without calling backend Laravel translations.
This is a small but very powerful upgrade because users expect multi-language support in real world dashboards, admin panels, POS, SaaS apps, or internal business tools. With vue-i18n, you can fully translate content inside Vue components directly inside frontend.
Table of Contents
Why vue-i18n is the best choice for Vue SPAs
vue-i18n is the official internationalization library for Vue. It is:
- Lightweight
- Works perfect in SPA
- No backend integration required
- Language switching is instant (no request to server)
And the most important:
You can store translations directly inside Vue.
Which is what we want.
Step 1: Check Out the Previous Tutorial First
Before starting this guide, make sure you’ve already completed the setup from the previous post: Create Vue.js SPA in Laravel Project – Step-by-Step Guide for Beginners.
👉 This tutorial builds on top of that project structure, so having it ready will help you continue smoothly.
You can read it here: https://laravelcenter.com/laravel-12-vue-3-session-based-authentication/
Step 2: Install vue-i18n Library
In this step, we install the vue-i18n library which is the main plugin used to power the vue.js spa language switcher i18n feature. vue-i18n provides a simple API for handling multi-language text inside any Vue SPA project.
Official website → https://vue-i18n.intlify.dev/
npm install vue-i18n@nextStep 3: Create translation file
Next, we create a translation file that stores our multi-language strings. These key/value pairs are required to make the vue.js spa language switcher i18n work properly, and this file will later be loaded into Vue when we register the i18n instance.
Create a file /resources/js/i18n.js:
import { createI18n } from 'vue-i18n'
const messages = {
en: {
'home': 'Home',
'blog': 'Blog',
'about us': 'About Us',
'contact us': 'Contact Us',
'message': 'Welcome to Vue.js SPA in Laravel!'
},
kh: {
'home': 'ទំព័រដើម',
'blog': 'ទំព័រប្លុក',
'about us': 'អំពីពួកយើង',
'contact us': 'ទាក់ទងយើង',
'message': 'សូមស្វាគមន៍មកកាន់ Vue.js SPA ក្នុង Laravel!'
},
jp: {
'home': 'ホームページ',
'blog': 'ブログページ',
'about us': '私たちについて',
'contact us': 'お問い合わせ',
'message': 'Laravel の Vue.js SPA へようこそ!'
}
}
const i18n = createI18n({
locale: localStorage.getItem('lang') || 'en',
fallbackLocale: 'en',
legacy: false,
messages
})
export default i18nStep 4: Register i18n in app.js
In this step, we import and configure vue-i18n in the main app.js entry point. This setup allows the vue.js spa language switcher i18n to become active throughout the entire SPA so all components can switch languages instantly.
Open /resources/js/app.js:
import './bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import i18n from './i18n';
createApp(App)
.use(router)
.use(i18n)
.mount('#app');Step 5: Display Translated Text in Vue Component
Now we update one of our Vue page components and use the $t() helper to display translation strings. This is where we confirm that the vue.js spa language switcher i18n is working correctly and the language content updates in real time.
In this step, we will update our existing Vue pages and integrate the translation keys so the text can be switched dynamically.
Home.vue
<template>
<div>
<h2>{{ $t('home') }}</h2>
<p>{{ $t('message') }}</p>
</div>
</template>Blog.vue
<template>
<div>
<h2>{{ $t('blog') }}</h2>
<p>{{ $t('message') }}</p>
</div>
</template>About.vue
<template>
<div>
<h2>{{ $t('about us') }}</h2>
<p>{{ $t('message') }}</p>
</div>
</template>Contact.vue
<template>
<div>
<h2>{{ $t('contact us') }}</h2>
<p>{{ $t('message') }}</p>
</div>
</template>Layout.vue
<template>
<div>
<header
class="text-bg-success d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom">
<div class="col-md-4 mb-2 mb-md-0 d-flex">
<a href="/" class="d-inline-flex link-body-emphasis text-decoration-none">
<strong class="fs-3 ms-2 text-white">Laravel Center</strong>
</a>
<ul class="nav nav-pills col-md-auto mt-2 justify-content-end mb-md-0 ms-md-5">
<li class="nav-item" v-for="availableLocale in availableLocales">
<button @click="setLang(availableLocale)"
:class="['nav-link text-white py-1 px-2 mx-1', { 'active fw-bold bg-dark': locale == availableLocale }]">
{{ availableLocale.toUpperCase() }}
</button>
</li>
</ul>
</div>
<ul class="nav nav-underline col-12 col-md-auto mb-2 justify-content-end mb-md-0">
<li class="nav-item">
<RouterLink to="/" class="nav-link mx-3 text-white" exact-active-class="active">
{{ $t('home') }}
</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/blog" class="nav-link mx-3 text-white" active-class="active">
{{ $t('blog') }}
</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/about" class="nav-link mx-3 text-white" active-class="active">
{{ $t('about us') }}
</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/contact" class="nav-link mx-3 text-white" active-class="active">
{{ $t('contact us') }}
</RouterLink>
</li>
</ul>
</header>
<div class="container mt-5">
<router-view></router-view>
</div>
</div>
</template>
<script setup>
import { useI18n } from 'vue-i18n';
// Get the locale ref and availableLocales from the global scope
const { locale, availableLocales } = useI18n({ useScope: 'global' });
const setLang = (lang) => {
locale.value = lang
localStorage.setItem('lang', lang)
}
</script>Test It
Switch language from the dropdown → the welcome text changes instantly.
This confirms vue-i18n is working correctly in our Vue.js SPA.



Why this is better than Laravel translations for SPA
| Feature | vue-i18n in SPA | Laravel translations |
|---|---|---|
| Page reload required? | ❌ No | ✅ Yes |
| Works offline (PWA) | ✅ Yes | ✅ Yes |
| Setup complexity | Low | Medium |
| Best for Vue-only UI | ✅ Yes | ❌ No |
| SEO friendly? (SPA) | Not needed (JS) | Not relevant |
Since our SPA renders text fully on frontend, vue-i18n is the perfect match.
Conclusion
By following these steps, we successfully implemented the vue.js spa language switcher i18n solution inside our Laravel-based Vue SPA. This upgrade improves user experience and adds real-world value for any multilingual project, dashboard, or frontend application.







