When you change the locale the page is reloaded.
If you switch the language when typing a form, or editing something, all your changes are lost (one could prevent that with the provided callbacks, but it's quite a lot of work to do it for all the cases in your app
It's easy to simply change the locale with
this.$i18n.locale = lang
But it doesn't change the current path.
I would be nice if one could pass a second parameter to switchLocalePath to prevent the reload the page, while still modifying the path and changing the locale
switchLocalePath returns only the route name (String), based on the given locale code.
If you want to change the locale on your javascript code:
this.$router.push(this.switchLocalePath(code));
The this.$router.push solution still reloads the page.
Here's how I solved this issue:
switchLang(locale: TAvailableLocales): void {
if (locale === this.$store.state.i18n.locale) {
return;
}
// update store info
this.$store.commit('i18n/i18nSetLocale', locale);
// fetch new locale file
import(`../lang/${locale}`).then(module => {
// update i18n's locale instance
this.$i18n.locale = locale;
// set new messages from new locale file
this.$i18n.setLocaleMessage(locale, module.default);
// update url to point to new path, without reloading the page
window.history.replaceState('', '', this.switchLocalePath(locale));
});
}
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@lukaVarga this works great, thanks a lot for helping me out there!
@lukaVarga 's answer is great. This should be the default implementation of $i18n.setLocale(locale)
By manipulating the history state manually with window.history.replaceState() you are creating inconsistency in the internal VueRouter state which will still point to the previous URL. I don't know of any specific issues that this can cause but you should know that it's a hack and can cause issues.
My only suggestion would be to just accept the fact that page state will change on changing locale and design your page so that it's not an issue.
@rchl of course it's a hack, but not reloading the page should, in my opinion (and as I see I am not alone in this), be the default behavior of i18n when locale is changed. Reloading the page may be the easiest solution, but it may very well also have significant drawbacks, depending on the page itself. Like someone mentioned, it could be that the user fills out half the form and then changes the language and suddenly, all the changes are gone - that's a very common use case. In my use-case, users often land on a search page that compares many travel deals and reloading the page after changing the language on that specific page would trigger a resource expensive background job in BE to unnecessarily refetch all that data, and the user would have to wait another couple of seconds before seeing the new results.
The only sort-of issue that I've noticed in the year and a half since I've been using this in production (and considering there were no errors and none of the users complained, it's probably a non-issue) is that if you go to page A, then page B, change the locale (so the URL will change to B1) and then try to go back in history (via browser buttons), you will remain on the same page B1 and not be navigated to the page B and after clicking the button again, you'll be navigated to page A. I didn't really find it worth the time to try and resolve this, but I'm sure it's solvable. Even if it isn't, for me, 'suffering' this edge case that perhaps a tiny portion of users who've just changed the locale will encounter is worth the better UX that 100% of the users who change the locale can enjoy.
Well, I don't agree that it should work like that by default.
It sounds like an "optimization" and optimizations have that thing to them that makes them not work in some cases. And those wouldn't work if, for example, the asyncData needs to fetch different data depending on the chosen locale.
You've provided some use-cases where it is beneficial but to be fair I don't fully agree that it's something worth caring about. For example:
In my use-case, users often land on a search page that compares many travel deals and reloading the page after changing the language on that specific page would trigger a resource expensive background job in BE to unnecessarily refetch all that data
I don't see how triggering a page re-load is a problem. Especially since the user will do it once at most.
it could be that the user fills out half the form and then changes the language and suddenly
It doesn't sound very realistic that the user would change the language half-way through filling a form. I think that if the user is not fine with the language the page is using, he'll do it right away after the page has loaded. And even if he does it half-way through filling a form, oh, well, I suppose the form is not made out of 50 questions that would be a pain to re-answer. And if it is, maybe redesign the page as it's not a good UX.
And I think that the user expectation when he/she is about to change the language, is that the page will reload.
In my use case, users view the menu of a bar. Of course, guests will change the page language only once.
But bar owners will change the language frequently to test their menu in multiple languages, as they can supply their own translation.
In this use case, reloading means: losing all filters (okay, these can be encoded in the query string), losing scroll position, and reloading the whole page consuming bandwidth/cpu time on the client and putting unnecessary load on the server and database.
Of course, local and CDN caching, storing the scroll position in localStorage, etc. can solve these, but this is way more hacky than simply not reloading the page.
If someone needs language-specific data in asyncData, the code can be extended with a this.$nuxt.refresh() line, solving this problem (and still saving a lot on other resources).
The middle ground could be a second, optional function parameter, like $i18n.setLocale(locale, reload = true), so we could call
$i18n.setLocale(locale, false), you could still call $i18n.setLocale(locale), and everyone could be happy. It's backwards compatible but it must be well documented.
Most helpful comment
The
this.$router.pushsolution still reloads the page.Here's how I solved this issue: