Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Locale detection could be more flexible #1369

Open
rongsen-kaligo opened this issue Sep 25, 2024 · 4 comments
Open

Locale detection could be more flexible #1369

rongsen-kaligo opened this issue Sep 25, 2024 · 4 comments
Labels
enhancement New feature or request has-workaround

Comments

@rongsen-kaligo
Copy link

rongsen-kaligo commented Sep 25, 2024

Is your feature request related to a problem? Please describe.

Background

Although next-intl offers built-in locale detection, it follows a specific internal detection order that isn’t easily customizable for unique requirements. Currently, the only option is to disable it and create custom locale detection logic. It would be beneficial if we could configure the detection priority and leverage the existing internal logic, avoiding the need to develop detection mechanisms from scratch.

Current state

import createMiddleware from 'next-intl/middleware';
import {routing} from './i18n/routing';
 
export default createMiddleware(routing, {
  localeDetection: false // turn off detection from accept-language header and cookie
});

By setting localeDetection to false will disable detection based on accept-language header and a potentially existing cookie value from a previous visit. This might not fit into use cases that wan to only disable either options and not both.

I have a use case where I need to detect the locale from the URL and cookie, using a default locale as a fallback. The default locale will vary based on the incoming requests. I will query the default locale from the database based on the incoming requests, which will allow me to determine the default locale set for a particular user if the request contains an authentication token.

Describe the solution you'd like

Proposal

It'd be great if users can override the locale detection priority while reusing the detection logics from next-intl without reinventing the wheel. Users are also allowed to add their own detection logics for really unique use cases.

import {
  detectFromUrl,
  detectFromAcceptLanguage,
  detectFromCookie,
  detectFromDefaultLocale,
} from 'next-intl/middleware';

export default createMiddleware(routing, {
  localeDetection: [
    detectFromUrl,
    // detectFromAcceptLanguage, // disable detection based on accept-language header
    detectFromCookie,
    detectFromDefaultLocale,
  ],
});

The proposed change will disable locale detection based on the accept-language header while keeping the other detection methods unchanged.

Describe alternatives you've considered

Disable localeDetection and write our own locale detection logics before executing the next-intl middleware.

@rongsen-kaligo rongsen-kaligo added enhancement New feature or request unconfirmed Needs triage. labels Sep 25, 2024
@amannn
Copy link
Owner

amannn commented Sep 27, 2024

Can you share more details about your use case why you'd want to keep cookie-based detection but not accept-language? How does the current behavior of the middleware get in the way of your use case?

@rongsen-kaligo
Copy link
Author

rongsen-kaligo commented Sep 27, 2024

Can you share more details about your use case why you'd want to keep cookie-based detection but not accept-language? How does the current behavior of the middleware get in the way of your use case?

@amannn Sure, let me elaborate more on that with more details.

Note

TLDR; accept-language header hinders us from using our own default locale in our multi-tenant web app because next-intl will always infer from accept-language first before using defaultLocale.

We are using next-intl in a multi-tenant environment and each tenant will have their own default locale.

For each tenant, we will first retrieve locale configuration via API call which includes the default locale and supported locales. Let me list down the 2 scenarios below:

First time user without locale prefix in their URL

A first time user might not always have locale prefix in their URL, e.g. they are redirected from another service or website so it's best to let our web app to determine the selected locale for each incoming request.

  1. Incoming request from a first time user via https://abc.multi-tenant.com
  2. Retrieve tenant configuration for abc tenant which supports [en-US, en-GB] and en-GB is the default locale
  3. Use next-intl's locale detection to detect the suitable locale for this first time user
  4. Given that there is no locale prefix in the URL, no locale cookie, the first time should be redirected to https://abc.multi-tenant.com/en-GB because we want all first time users to use the default locale. This is where a problem arises. Due to next-intl's locale detection, it will use accept-language as the final locale before it can use the defaultLocale, for a user with accept-language=en-US, next-intl will redirect them to https://abc.multi-tenant.com/en-US which is not what we wanted.
  5. Done.

Repeated user without locale prefix in their URL

A repeated user will most probably have NEXT_LOCALE=en-GB set in the cookie where next-intl can infer from.

  1. Incoming request from a repeated user via https://abc.multi-tenant.com
  2. Retrieve tenant configuration for abc tenant which supports [en-US, en-GB] and en-GB is the default locale
  3. Given that it is a repeated user, there is a high likelihood that the user already has NEXT_LOCALE cookie set in their browser where next-intl can infer the locale from. This is also a behavior we wanted.
  4. Done

Hope this helps clear your doubt. 🙇‍♂️

@amannn
Copy link
Owner

amannn commented Oct 1, 2024

Thanks for the details!

Given that there is no locale prefix in the URL, no locale cookie, the first time should be redirected to https://abc.multi-tenant.com/en-GB because we want all first time users to use the default locale.

Can you expand on why a user wouldn't want to land on /en-US in this case if that is their preference?

That being said, what you can do already is composing the middleware and assigning locales dynamically. With this, you could for example detect if a cookie is set, and if not, restrict the locales to [tenant.defaultLocale].

Sorry if this sounds like a workaround to you 😄. My situation is just that users sometimes ask for more flexibility and getting all use cases under one roof needs careful understanding of the use cases. Ideally, I want to support all legit use cases, but offering too many options can cause users to shoot themselves in the foot. Therefore, especially if a use case can already be achieved, I'm a bit hesitant with introducing more configuration.

I've made a note of this issue in any case in #1362, might need to have a look at this again in combination with other opened discussions.

@rongsen-kaligo
Copy link
Author

rongsen-kaligo commented Oct 2, 2024

Can you expand on why a user wouldn't want to land on /en-US in this case if that is their preference?

@amannn Sure, this is because a tenant is allowed to configure their default locale in our multi-tenant web apps and they want all users who visit the web app without any locale prefix to use the default locale instead of the one from their machine.

With this, you could for example detect if a cookie is set, and if not, restrict the locales to [tenant.defaultLocale].

Well, this is one workaround.

Sorry if this sounds like a workaround to you 😄. My situation is just that users sometimes ask for more flexibility and getting all use cases under one roof needs careful understanding of the use cases. Ideally, I want to support all legit use cases, but offering too many options can cause users to shoot themselves in the foot. Therefore, especially if a use case can already be achieved, I'm a bit hesitant with introducing more configuration.

I completely agree with your perspective. I often need to dive into next-intl’s source code to understand its internals. While I appreciate its i18n handling, especially locale detection, I wish it were more composable. The current single approach is great but limited. Composability would allow for better customization without rewriting components like locale detection from scratch.

I've made a note of this issue in any case in #1362, might need to have a look at this again in combination with other opened discussions.

Really appreciate that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request has-workaround
Projects
None yet
Development

No branches or pull requests

2 participants