Vue 3 本地化(i18n@next)实现中的静态资源、URL路径翻译及路由链接问题解决方案咨询
Hey there! Let's tackle these three issues one by one with practical solutions tailored to your Vue 3 + i18n setup:
1. Fix Static Asset Loading with Language Prefixes
The problem happens because relative asset paths get resolved against the current route path (which includes the language prefix). To load assets from the root path every time, use one of these approaches:
Option 1: Use Absolute Paths
Replace relative asset paths with absolute paths starting with / (since your app's base URL is /):
<!-- Before --> <img v-bind:src="assets/images/logo.png" alt="Logo"> <!-- After --> <img src="/assets/images/logo.png" alt="Logo">
Option 2: Use process.env.BASE_URL
If your app might be deployed under a subpath later, use the built-in environment variable to ensure portability:
<img :src="`${process.env.BASE_URL}assets/images/logo.png`" alt="Logo">
Option 3: Configure publicPath in vue.config.js
If you need more control, set the public path explicitly (this ensures all assets are loaded from the root):
// vue.config.js module.exports = { publicPath: process.env.NODE_ENV === 'production' ? '/' : '/' }
2. Localize URL Slugs (e.g., /en/login → /it/accedi)
To translate route slugs alongside content, follow these steps:
Step 1: Add Slug Translations to Your i18n Files
Update your translation JSONs to include route slug mappings:
// lang/translations/en.json { "selectLanguage": "Select Language", "routes": { "home": "", "login": "login", "register": "register" } } // lang/translations/it.json { "selectLanguage": "Seleziona Lingua", "routes": { "home": "", "login": "accedi", "register": "registrati" } }
Step 2: Update Route Configuration
Modify your routes to use dynamic slugs and link them to translation keys via meta:
// router/index.ts const routes: Array<RouteRecordRaw> = [ { path: '/', name: 'root', redirect: `/${process.env.VUE_APP_I18N_LOCALE}/${i18n.global.t('routes.home')}` }, { path: '/:locale', component: App, beforeEnter: (to, from, next) => { const locale = to.params.locale.toString() const supportedLocales = process.env.VUE_APP_I18N_SUPPORTED_LOCALE.split(',') if (!supportedLocales.includes(locale)) return next(`/en/${i18n.global.t('routes.home', { locale: 'en' })}`) if (i18n.global.locale !== locale) { i18n.global.locale = locale } next() }, children: [ { path: ':slug', name: 'home', component: load('Home'), meta: { requiresAuth: false, slugKey: 'routes.home' } }, { path: ':slug', name: 'login', component: load('Auth/Login'), meta: { requiresAuth: false, slugKey: 'routes.login' } }, { path: ':slug', name: 'register', component: load('Auth/Register'), meta: { requiresAuth: false, slugKey: 'routes.register' } } ] } ]
Step 3: Add Route Guard to Match Slugs
Add a global guard to map incoming slugs to the correct route based on the current locale:
// router/index.ts router.beforeEach((to, from, next) => { if (to.params.locale && to.params.slug) { const locale = to.params.locale.toString() const incomingSlug = to.params.slug.toString() // Find the route whose translated slug matches the incoming one const matchedRoute = routes[1].children?.find(route => { return i18n.global.t(route.meta.slugKey, { locale }) === incomingSlug }) if (matchedRoute) { next({ name: matchedRoute.name, params: { locale } }) } else { // Redirect to home if slug is invalid next(`/${locale}/${i18n.global.t('routes.home', { locale })}`) } } else { next() } // Keep your existing auth logic here const { authenticating, user } = useAuth() })
Step 4: Update Language Switcher to Navigate to Localized Slugs
Modify the changeLanguage method to jump to the translated slug of the current route:
<!-- LanguageSwitcher.vue --> <script> export default defineComponent({ // ... existing code methods: { changeLanguage(lang) { const currentRouteName = this.$route.name const translatedSlug = this.$t(`routes.${currentRouteName}`, { locale: lang }) this.$i18n.locale = lang this.$router.replace(`/${lang}/${translatedSlug}`) } } }) </script>
3. Fix router-link to Auto-Add Language Prefix
The issue occurs because you're using hardcoded absolute paths (like /login) instead of leveraging route names. Here's how to fix it:
Option 1: Use Route Names with Params
Always reference routes by their name and pass the current locale as a param:
<!-- Before --> <router-link class="nav-link" to="/login">Login</router-link> <!-- After --> <router-link class="nav-link" :to="{ name: 'login', params: { locale: $i18n.locale } }"> {{ $t('login') }} </router-link>
Option 2: Create a Reusable Localized Router Link
For convenience, build a custom component that automatically injects the current locale:
<!-- components/LocalizedRouterLink.vue --> <template> <router-link :to="getLocalizedRoute"> <slot></slot> </router-link> </template> <script setup> import { useI18n } from 'vue-i18n' const { locale } = useI18n() const props = defineProps({ to: { type: [String, Object], required: true } }) const getLocalizedRoute = () => { if (typeof props.to === 'string') { // Convert string paths (e.g., '/login') to locale-prefixed paths return `/${locale.value}${props.to}` } else { // Add locale to route object params return { ...props.to, params: { locale: locale.value, ...props.to.params } } } } </script>
Register it globally in main.ts:
// main.ts import LocalizedRouterLink from '@/components/LocalizedRouterLink.vue' createApp(App) // ... existing plugins .component('LocalizedRouterLink', LocalizedRouterLink)
Now use it anywhere in your app:
<localized-router-link to="/login">{{ $t('login') }}</localized-router-link> <!-- Or with route name --> <localized-router-link :to="{ name: 'login' }">{{ $t('login') }}</localized-router-link>
内容的提问来源于stack exchange,提问作者sfarzoso

