I’m using prerender-spa-plugin
in order to prerender certain pages so I get better SEO from my Vue app.
My goal is to transform the way I’m currently using Vue-i18n
, so I can base it on url param /lang
. Examples: /en/home
or /nl/home
. With this, I would be able to pre-render depending on the language.
I created a prefixer function that adds to every parent route the optional param /:lang?
. Here it is:
const withPrefix = (prefix: string, routes: RouteConfig[]): RouteConfig[] => routes.map((route): RouteConfig => {
// Avoiding mutations
const clonedRoute = { ...route };
// Every route except for '/'
if (clonedRoute.path !== '/') {
clonedRoute.path = prefix + clonedRoute.path;
}
return clonedRoute;
});
In Vue templates, I’m using:
<router-link :to="`/account`">
So I’m trying to manipulate the redirect to the next page according to the lang
param.
First approach
The most logical one is (inside Router’s beforeEach
):
const { lang } = to.params;
const redirectTo = lang ? to.fullPath : `${fullToLang}${to.fullPath}`;
if (from.fullPath !== redirectTo) {
next({ path: redirectTo });
} else {
next();
}
But it enters in an endless loop because from is always the same.
Second approach
Using Router
‘s base
property.
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import HelloWorld from "./components/HelloWorld";
import Test from "./components/Test";
Vue.config.productionTip = false;
Vue.use(VueRouter);
const router = new VueRouter({
mode: "history",
base: "/en",
routes: [
{
path: ":lang?/",
component: HelloWorld,
beforeEnter: (to, from, next) => {
console.log(1);
next();
}
},
{
path: "/:lang?/nope",
component: Test,
beforeEnter: (to, from, next) => {
console.log(2);
next();
}
},
{
path: "/:lang?/*",
beforeEnter: (to, from, next) => {
console.log(to);
next("/nope");
}
}
]
});
new Vue({
render: h => h(App),
router
}).$mount("#app");
Or better, live:
https://codesandbox.io/embed/vue-template-0bwr9
But, I don’t understand why it’s redirecting to /en/nope
only if the url is not found on the routes (last case). And more, would I have to create a new Router
instance each time I want to change base
?
Third approach
Wrapper component for router-link
injecting :to
based on this.$route.params.lang
.
This would do it for navigation after the app is loaded but not at the first refresh/initialization.
So, how should I resolve this?
~ Solution ~
So yeah, first approach was the correct way to go but I missunderstood how Router behaves with next
and redirects
. The condition should be checking the to
not the from
.
const redirectTo = lang ? to.fullPath : `${fullToLang}${to.fullPath}`;
if (to.fullPath !== redirectTo) {
// Change language at i18n
loadLanguageAsync(toLang as Language);
next({ path: redirectTo });
return;
}
2
Answers
I am not entirely sure what you are asking. But I assume you want to prefix your navigations with the current language param (../en/..) if they do not already have one?
You could resolve this with a
beforeEach()
hook and only redirecting if there is nolang
param present.If that’s not what you want please clarify and I’ll edit my answer
Something like this? The assumption is that the new path starts
/[lang]/...
as a note – there are still errors when routing e.g.
/:lang/bar
->/foo/bar