nuxt-modules / i18n

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

`detectBrowserLanguage` does not detect browser lang as expected #3126

Open slow-groovin opened 6 days ago

slow-groovin commented 6 days ago

Environment


Reproduction

nuxt-i18n-BUG-REPRODUCE.zip

Describe the bug

with setting:

i18n:{
    strategy: 'prefix',
    locales: ['zh', 'en'], 
    detectBrowserLanguage: // 
    {
        useCookie: false,  //set true or false, not influenced the result
        cookieKey: 'i18n_redirected',
        redirectOn: 'root' // recommended
    }
  }

When Browser request header has accept-language: zh-CN,zh;q=0.9 Expect: redirect to /zh/hello But has: location: /en/hello

same with issues/1632

Additional context

No response

Logs

No response

BobbieGoede commented 6 days ago

Could you provide your reproduction as a reppository or a stackblitz project?

slow-groovin commented 5 days ago

Could you provide your reproduction as a reppository or a stackblitz project?

https://stackblitz.com/edit/nuxt-starter-824aop

I found its preview page has not Accept-Language in request headers, maybe you should run it locally

florianmrz commented 5 days ago

I was facing the exact same issue with server-side locale detection. The feature works in development mode, but running the app in production always redirects the user to the default locale's path.

The request header Accept-Language is missing because the event.node.req.headers property on the incoming request is always an empty object. This results in the default locale being used as a fallback.

To me this seems like a nuxt or h3 issue and not one with this module, but I might be wrong on this. I hope this information acts as a starting point for getting this issue resolved.

Here's a workaround that manually assigns this header based on the headersDistinct prop, allowing to use this feature:

// middleware/fix-locale-detection.global.ts

export default defineNuxtRouteMiddleware(() => {
  const event = useRequestEvent();
  const acceptLanguageHeader = event?.node.req.headersDistinct['accept-language']?.[0];
  if (acceptLanguageHeader) {
    event.node.req.headers['accept-language'] = acceptLanguageHeader;
  }
});
BobbieGoede commented 5 days ago

Perhaps related to https://github.com/nuxt-modules/i18n/issues/2975 which does point to it being an upstream issue (Nuxt/h3)

florianmrz commented 5 days ago

I think I spoke too soon, the above workaround doesn't actually fix the issue, only the symptoms of it. During testing, I saw that the feature only now works when I append some URL parameter to the URL (e.g. requesting /?1 instead of /) as the request would otherwise keep redirecting to the same locale even when switching the Accept-Language header in subsequent requests.

The real fix in my case seems to be disabling the caching of the root route (/) in the Nuxt routeRules prop.

My Nuxt config had the following route rules before:

// config.routeRules

{
  '/**': { swr: 600 }
}

I've adjusted this to be:

// config.routeRules

{
  '/de_de/**': { swr: 600 },
  '/de_de/': { swr: 600 },
  '/en_com/**': { swr: 600 },
  '/en_com/': { swr: 600 },
  // ... they are dynamically generated
}

This resolves the issue and the feature works as expected, without the bandaid fix in the comment above.

@BobbieGoede could this be the reason for the described behavior?

liaow-ww commented 19 hours ago

I faced the same problem, when I used detectBrowserLanguage: false , it didn't work, it still adds the cookie i18n_redirected.