nuxt-modules / i18n

I18n module for Nuxt
https://i18n.nuxtjs.org
MIT License
1.65k stars 465 forks source link

useCookieLocale() does not work in server context (SSR) #2975

Open localusercamp opened 2 weeks ago

localusercamp commented 2 weeks ago

Environment

Reproduction

https://stackblitz.com/edit/bobbiegoede-nuxt-i18n-starter-hmdag5?file=middleware%2Fssr-context-cookie.ts

Describe the bug

useCookieLocale() always return ref with empty string in server context (SSR).

This is useCookieLocale() source code:

export function useCookieLocale(): Ref<string> {
  // Support for importing from `#imports` is generated by auto `imports` nuxt module, so `ref` is imported from `vue`
  const locale: Ref<string> = ref('')
  const detect = runtimeDetectBrowserLanguage()

  if (detect && detect.useCookie) {
    const cookieKey = detect.cookieKey!

    let code: string | null = null
    if (import.meta.client) {
      code = useNuxtCookie<string>(cookieKey).value
    } else if (import.meta.server) {
      const cookie = useRequestHeaders(['cookie'])
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      code = (cookie as any)[cookieKey]
    }

    if (code && localeCodes.includes(code)) {
      locale.value = code
    }
  }

  return locale
}

In server part there is a useRequestHeaders(['cookie']) call which always return type

{ cookie?: string | undefined }

Next we have this line:

code = (cookie as any)[cookieKey]

It is incorrect, because, cookie variable is object which only has one property which is cookie, but in this line we are trying to get cookieKey key from it.

For example in my app this code:

export default defineNuxtRouteMiddleware(() => {
  if (import.meta.server) {
    console.log(useCookieLocale(), useRequestHeaders(['cookie']));
  }
}

Prints this to console: image

Additional context

Since Nuxt useCookie() is SSR friendly, i think that useCookieLocale could be rewritten as such:

export function useCookieLocale(): Ref<string> {
  // Support for importing from `#imports` is generated by auto `imports` nuxt module, so `ref` is imported from `vue`
  const locale: Ref<string> = ref('')
  const detect = runtimeDetectBrowserLanguage()

  if (detect && detect.useCookie) {
    const cookieKey = detect.cookieKey!

    const code = useNuxtCookie<string>(cookieKey).value ?? null

    if (code && localeCodes.includes(code)) {
      locale.value = code
    }
  }

  return locale
}

Logs

No response