i18n: Translated strings don't wait for page transition

Version

@nuxtjs/i18n: 7.0.1 nuxt: 2.15.7

Nuxt configuration

Please change to [x] if relevant for this issue:

  • Applies to a site deployed to a static server (site generated with nuxt generate)
  • Applies to a site deployed to a server with a Node backend

@nuxtjs/i18n configuration

i18n: {
    locales: [
      { code: "en", iso: "en-US", name: "English", file: "en-US" },
      { code: "pt", iso: "pt-PT", name: "Português", file: "pt-PT" }
    ],
    defaultLocale: "en",
    detectBrowserLanguage: {
      redirectOn: "root"
    },
    strategy: "prefix",
    lazy: true,
    langDir: "i18n/",
    parsePages: false,
    vueI18n: {
      fallbackLocale: "en"
    },
    skipSettingLocaleOnNavigate: true
  }

Reproduction Link

I created a Code Sandbox: https://codesandbox.io/s/cocky-galileo-z8qhk?file=/pages/index.vue

Steps to reproduce

Access the code sandbox and click either one of the language selection links.

What is Expected?

The translated string should only change after the page transition completed.

What is actually happening?

The translated string changes before transition is completed and is then re-rendered.

About this issue

Most upvoted comments

This is an issue for me as well; the documented solution (skipSettingLocaleOnNavigate: true in i18n object in nuxt.config.ts) does not work when doing e.g. navigateTo(switchLocalePath(locale)).

I’ve confirmed the documented solution partially “works” with navigating via <nuxt-link :to="navigateTo(switchLocalePath(locale)"... but it would be great to provide full support for other methods of changing route in Nuxt.

In my case I am using a <select @change="navigateTo(switchLocalePath(locale))">... element so that users on mobile devices can switch language in an intuitive way and we don’t have to build a custom dropdown element that works on all screensizes etc.

I am saying “partly works” is because setting skipSettingLocaleOnNavigate: true in nuxt.config.ts does prevent locale changing when using <nuxt-link>. However the documented solution for switching locale before the enter transition via the defaultTransition.beforeEnter navigation guard does not work (e.g. Cannot read properties of undefined (reading 'defaultTransition').

I’ve tried multiple ways of setting this via nuxt.config.ts app.pageTransition. beforeEnter and also via router.options.ts (where according to Nuxt documentation you should do these type of things), but in both cases there is no nuxtApp context available. The only thing that seems to “work” is the above.

For the people who can rely on using <nuxt-link> for this you can find a working solution below:

  • skipSettingLocaleOnNavigate: true in nuxt.config.ts -> i18n object
  • create a client side only plugin with the code below:
export default defineNuxtPlugin(nuxtApp => {
    const router = useRouter()
    router.afterEach(() => {
        setTimeout(() => {
            nuxtApp.$i18n.finalizePendingLocaleChange()
        }, 300) // whatever the duration of your page transition is
    })
})

Would be good if a good solution could be provided by the package itself though, switching language looks quite bugged out now by default and it should not be needed to write all this code for such a basic thing.

Will have a look at it on monday and let you know! Thanks for looking at it 😃

Never mind! It doesn’t work when I’m on a detail page such as /en/startup, when I use switchLocale it calls my api with {locale: nl, slug: startup}, it should be {locale: nl, slug: opstarten}. Sorry for the false hope.

Your proposed solution is working though, so thank you.

@gerbenvandijk I just did a fresh install and the default setup from the docs: https://i18n.nuxtjs.org/docs/guide/lang-switcher#wait-for-page-transition seems to work, can you confirm it’s fixed? I’m using

"nuxt": "^3.10.1",
"@nuxtjs/i18n": "^8.1.0",

This is my i18n config

    i18n: {
        skipSettingLocaleOnNavigate: true,
        strategy: 'prefix_except_default',
        defaultLocale: 'nl',
        langDir: 'lang',
        locales: [
            {code: 'nl', file: 'nl.json', iso: 'nl', name: 'NL'},
            {code: 'en', file: 'en.json', iso: 'en', name: 'EN'},
        ],
        detectBrowserLanguage: false,
        customRoutes: "page",
    },

That logic doesn’t work when explicitly using $i18n.setLocale which you are doing from LangSwitcher.vue. It only works on navigating to a route with a different locale.

You’d want to change the lang switcher to something like:

    <nuxt-link
      v-for="locale of $i18n.locales"
      :key="locale.code"
      :to="switchLocalePath(locale.code)"
    >
      {{ locale.name }}
    </nuxt-link>