You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js中使用vue-i18n为路由添加本地化前缀的实现方案

实现URL带本地化前缀的最优方案

这个需求我之前在Vue 2项目里落地过,核心是不用把所有路由硬套成/:locale?的子路由,而是通过路由守卫动态处理locale前缀,同时调整i18n和路由的初始化逻辑,解决两者同时初始化的顺序问题。以下是分步实现:

1. 重构Locale工具模块,支持动态获取/设置

首先把你的locale.js从导出固定值改成可复用的工具函数,方便后续动态同步locale:

// @/services/locale.js
import store from '@/vuex/index'

const defaultLocale = 'en_US'
const supportedLocales = ['en_US', 'ru_RU']
// 映射URL短码到完整locale(比如en → en_US)
export const localeShortMap = { en: 'en_US', ru: 'ru_RU' }
export const reverseLocaleMap = { en_US: 'en', ru_RU: 'ru' }

// 获取初始化locale(兼容登录用户/本地存储/默认值)
export function getInitialLocale() {
  let locale
  if (store.getters['auth/authenticated']) {
    locale = store.getters['auth/currentUser'].locale || defaultLocale
  } else {
    locale = localStorage.getItem('locale') || defaultLocale
  }
  // 确保是支持的locale,避免非法值
  return supportedLocales.includes(locale) ? locale : defaultLocale
}

// 同步locale到本地存储(若用户登录可同步到Vuex)
export function setLocale(locale) {
  if (supportedLocales.includes(locale)) {
    localStorage.setItem('locale', locale)
    // 可选:如果用户已登录,更新Vuex中的用户locale
    // if (store.getters['auth/authenticated']) {
    //   store.dispatch('auth/updateUserLocale', locale)
    // }
  }
}

2. 调整i18n初始化,支持动态修改locale

修改i18n.js,让实例可以动态更新locale,同时用新的工具函数获取初始值:

// @/services/i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import { getInitialLocale } from '@/services/locale'

Vue.use(VueI18n)

const fallbackLocale = 'en_US'
export const i18n = new VueI18n({
  locale: getInitialLocale(),
  fallbackLocale,
})

// 加载语言包(可改成异步加载优化性能,见下文)
i18n.setLocaleMessage('ru_RU', require('@/lang/ru_RU.json'))
i18n.setLocaleMessage('en_US', require('@/lang/en_US.json'))

3. 路由守卫处理Locale前缀解析与重定向

这是核心步骤:在路由全局前置守卫里解析URL的locale前缀,同步到i18n,同时自动重定向无前缀的URL到带前缀的版本。修改你的路由配置文件(比如@/router/index.js):

// @/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import { i18n } from '@/services/i18n'
import { getInitialLocale, localeShortMap, reverseLocaleMap, setLocale } from '@/services/locale'

Vue.use(VueRouter)

// 你的原有路由配置不用改,比如:
const routes = [
  { path: '/profile', name: 'Profile', component: () => import('@/views/Profile.vue') },
  { path: '/settings', name: 'Settings', component: () => import('@/views/Settings.vue') },
  // ...其他路由
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
})

// 全局前置守卫处理locale
router.beforeEach((to, from, next) => {
  let targetLocale = to.params.locale

  // 1. 解析URL中的locale参数
  if (targetLocale) {
    // 把短码转换成完整locale(比如en → en_US)
    targetLocale = localeShortMap[targetLocale] || targetLocale
    // 校验是否是支持的locale,不支持则用默认
    if (!localeShortMap[targetLocale] && !Object.values(localeShortMap).includes(targetLocale)) {
      targetLocale = getInitialLocale()
    }
  } else {
    // URL无locale前缀,从本地存储/默认值获取
    targetLocale = getInitialLocale()
  }

  // 2. 同步locale到i18n和本地存储
  if (i18n.locale !== targetLocale) {
    i18n.locale = targetLocale
    setLocale(targetLocale)
  }

  // 3. 重定向无前缀的URL到带前缀的版本
  if (!to.params.locale) {
    const shortLocale = reverseLocaleMap[targetLocale]
    // 保留原URL的query和hash
    return next({
      path: `/${shortLocale}${to.path}`,
      query: to.query,
      hash: to.hash,
      replace: true, // 重定向不留下历史记录
    })
  }

  next()
})

export default router

4. 优化路由链接生成(自动带Locale前缀)

为了避免手动写/en/profile这种路径,自定义一个全局的locale-router-link组件,自动拼接当前locale前缀:

<!-- @/components/LocaleRouterLink.vue -->
<template>
  <router-link :to="localizedTo">
    <slot></slot>
  </router-link>
</template>

<script>
import { reverseLocaleMap } from '@/services/locale'

export default {
  props: ['to'],
  computed: {
    localizedTo() {
      const shortLocale = reverseLocaleMap[this.$i18n.locale]
      if (typeof this.to === 'string') {
        // 处理字符串路径
        return `/${shortLocale}${this.to.startsWith('/') ? this.to : `/${this.to}`}`
      } else {
        // 处理对象形式的路由参数
        return {
          ...this.to,
          path: `/${shortLocale}${(this.to.path || '').startsWith('/') ? this.to.path : `/${this.to.path || ''}`}`,
        }
      }
    },
  },
}
</script>

然后在main.js全局注册:

import LocaleRouterLink from '@/components/LocaleRouterLink.vue'
Vue.component('locale-router-link', LocaleRouterLink)

之后用<locale-router-link to="/profile">我的主页</locale-router-link>就会自动生成当前locale的链接,比如/en/profile或/ru/profile。

可选优化:异步加载语言包

如果语言包体积较大,改成异步加载减少初始包大小:

// @/services/i18n.js 添加异步加载函数
export async function loadLocaleMessages(locale) {
  const messages = await import(`@/lang/${locale}.json`)
  i18n.setLocaleMessage(locale, messages.default)
}

然后在路由守卫里调用:

// router/index.js 中的beforeEach改成异步
router.beforeEach(async (to, from, next) => {
  // ...前面的locale解析逻辑

  // 如果当前locale的语言包未加载,先异步加载
  if (!i18n.getLocaleMessage(targetLocale)) {
    await loadLocaleMessages(targetLocale)
  }

  // ...后面的同步和重定向逻辑
})

内容的提问来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:36:25