useCookieLocale() does not work in server context (SSR)
Environment
- Operating System: Linux
- Node Version: v20.10.0
- Nuxt Version: 3.11.2
- CLI Version: 3.11.1
- Nitro Version: 2.9.6
- Package Manager: [email protected]
- Builder: -
- User Config: -
- Runtime Modules: -
- Build Modules: -
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:
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
Any updates on this?
My project sends requests to the backend (Django) to get localized product names, etc. Django determines the user's language from cookies. The problem is that if a user opens a localized link immediately (i.e. via SSR), when backend requests are sent, there will either be nothing in the cookies (if the user is visiting the site for the first time) or there will be the language that the user has previously selected, and not the one that should be used at the moment.
I would be very grateful to the development team if this issue could be fixed in the next update
I also believe that this issue should have a higher priority, as it causes a serious problem using i18n with data that is loaded from the backend
I agree, your rewrite looks better but unfortunately it will have the same functionality as the current implementation, setting the cookie using Nuxt's useCookie server side will only set the set-cookie header, so we probably need to add some logic to sync a Ref as well as the set-cookie header.
Related issue: https://github.com/nuxt/nuxt/issues/22631
This seems to be resolved in v10, let me know if you're still running into this issue after updating 🙏