InertiaJS(Laravel9+Vue3)应用JS中无法设置i18n.locale问题
问题描述
在Laravel9 + Vue3技术栈的InertiaJS应用中集成9.1版本vue-i18n实现国际化功能时,需要在JavaScript逻辑中切换i18n语言环境并同步执行自定义逻辑,但调用$i18n.locale、this.$i18n.locale两种写法均运行失败,错误提示为this.$i18n / $i18n is not defined,无法正常完成语言设置。
原有配置代码
app.js i18n配置段
require('./bootstrap'); import { createApp, h } from 'vue'; import { createI18n } from 'vue-i18n' import { createInertiaApp } from '@inertiajs/inertia-vue3'; import { InertiaProgress } from '@inertiajs/progress'; const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel'; createInertiaApp({ title: (title) => `${title} - ${appName}`, resolve: (name) => require(`./Pages/${name}.vue`), setup({ el, app, props, plugin }) { const i18n = createI18n({ locale: "de", // locale: props.initialPage.props.locale, // 从props读取用户默认语言 fallbackLocale: "en", // 设置兜底语言 messages: loadLocaleMessages(), }); return createApp({ render: () => h(app, props) }) .use(plugin) .use(i18n) .mixin({ methods: { route } }) .mount(el); }, });
Authenticated.vue 语言切换段
<script setup> import {ref, onMounted} from 'vue'; import BreezeDropdown from '@/Components/Dropdown.vue'; import BreezeNavLink from '@/Components/NavLink.vue'; import BreezeResponsiveNavLink from '@/Components/ResponsiveNavLink.vue'; import ProjectVersion from '@/Components/ProjectVersion.vue'; import {Link} from '@inertiajs/inertia-vue3'; import { usePage } from '@inertiajs/inertia-vue3'; import { computed } from 'vue'; function switchLanguage(key){ console.log('switchLanguage to ' + key); this.$i18n.locale = key; // 此处运行报错 } </script> <template> <div v-if="$i18n.locale == 'en'"> <a @click.prevent="switchLanguage('de')" href="#"> Deutsch </a> </div> <div v-if="$i18n.locale == 'de'"> <a @click.prevent="switchLanguage('en')" href="#"> English </a> </div> </template>
报错原因
- 代码使用Vue3的
<script setup>语法,该语法块内不存在组件实例的this上下文,因此this.$i18n无法找到对应对象 - 模板中可以直接使用
$i18n是Vue全局属性的模板透传规则,<script setup>块内不会自动注入该全局变量,直接写$i18n也会触发未定义错误 - 原有i18n实例初始化在
createInertiaApp的setup回调内部,作用域无法被外部组件访问,且未开启vue-i18n 9.x的组合式API支持配置
修复方案
- 调整i18n实例初始化位置,补充必要配置,修改
app.js:
require('./bootstrap'); import { createApp, h } from 'vue'; import { createI18n } from 'vue-i18n' import { createInertiaApp } from '@inertiajs/inertia-vue3'; import { InertiaProgress } from '@inertiajs/progress'; const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel'; // 将i18n实例提升到外层初始化,方便全局导入调用 const i18n = createI18n({ legacy: false, // vue-i18n 9.x 组合式API模式必须开启该配置 locale: "de", fallbackLocale: "en", globalInjection: true, // 开启全局注入,保证模板内原有$i18n、$t写法正常可用 messages: loadLocaleMessages(), }); createInertiaApp({ title: (title) => `${title} - ${appName}`, resolve: (name) => require(`./Pages/${name}.vue`), setup({ el, app, props, plugin }) { // 初始化时优先用后端返回的用户语言配置覆盖默认值 i18n.global.locale.value = props.initialPage.props.locale || 'de'; return createApp({ render: () => h(app, props) }) .use(plugin) .use(i18n) .mixin({ methods: { route } }) .mount(el); }, }); export default i18n; // 导出i18n实例供组件导入使用
提示:更规范的实践是把i18n初始化逻辑单独抽离到
/resources/js/i18n/index.js文件中导出实例,避免从app.js导入时产生循环依赖问题。
- 修改
Authenticated.vue中的语言切换逻辑,直接导入i18n实例修改全局语言配置,无需依赖this:
<script setup> import {ref, onMounted, computed} from 'vue'; import BreezeDropdown from '@/Components/Dropdown.vue'; import BreezeNavLink from '@/Components/NavLink.vue'; import BreezeResponsiveNavLink from '@/Components/ResponsiveNavLink.vue'; import ProjectVersion from '@/Components/ProjectVersion.vue'; import {Link} from '@inertiajs/inertia-vue3'; import { usePage } from '@inertiajs/inertia-vue3'; // 导入初始化完成的i18n实例,路径按项目实际目录结构调整 import i18n from '@/app.js'; // 响应式获取当前语言,供模板渲染使用 const currentLocale = computed(() => i18n.global.locale.value); function switchLanguage(key){ console.log('switchLanguage to ' + key); // 直接修改全局语言配置,legacy:false模式下locale为ref类型,需要修改.value属性 i18n.global.locale.value = key; // 此处可追加需要同步执行的自定义逻辑,比如缓存语言配置到本地、请求后端保存用户语言偏好等 localStorage.setItem('user_locale', key); } </script> <template> <div v-if="currentLocale == 'en'"> <a @click.prevent="switchLanguage('de')" href="#"> Deutsch </a> </div> <div v-if="currentLocale == 'de'"> <a @click.prevent="switchLanguage('en')" href="#"> English </a> </div> </template>
额外优化建议
- 语言持久化:切换语言时将配置存入localStorage,i18n初始化时优先读取本地缓存值,其次读取后端返回的用户偏好,最后使用默认兜底语言,保证刷新页面后语言状态不丢失
- 路由同步:如果需要URL携带语言前缀,可以在切换语言时同步调用Inertia路由跳转方法,把语言参数拼到URL上,更利于SEO
内容的提问来源于stack exchange,提问作者Konrad
相关产品推荐
相关产品推荐

