Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Multi-channel, multi-locale support #1772

Closed
mvanpijkeren opened this issue Mar 10, 2025 · 2 comments
Closed

Multi-channel, multi-locale support #1772

mvanpijkeren opened this issue Mar 10, 2025 · 2 comments
Labels
enhancement New feature or request unconfirmed Needs triage.

Comments

@mvanpijkeren
Copy link

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

I am looking for a way in Next.js to handle a multi-channel, multi-locale website. Awesome work on this package for multi-locale websites!

We're going to build a e-commerce website for over 10+ countries with each of them having one or more languages. One country can also have multiple channels for specific products. So for example: the Belgium website in french is different than the french website. They have the same language but can have different settings, menus, products etc.

So we need a multi-channel, multi-locale website and I would like to implement that with next-intl. For now I found a workaround abusing the locales to achieve this. Would love to hear you thoughts on this!

And the feature request is to have some solution for this native in next-intl without abusing the locale if that's not recommended🙃

Describe the solution you'd like

Solution

I found the solution in extending the routing.ts locales. I extend the locale with a string structure like this:
[channel]-[lang]-[region]
Then with using localePrefix: 'as-needed' and some rewriting with the prefixes i can achieve a clean url.

Routing.ts

export const routing = defineRouting({
  // LOCALES
  // The format is: [channel]-[lang]-[region]
  locales: ["shop.netherlands.nl-nl-NL", "shop.belgium.be-nl-BE", "shop.belgium.be-fr-BE", "shop.germany.one.de-de-DE", "shop.germany.two.de-de-DE"],

  // DOMAINS
  domains: [
    {
      domain: "shop.netherlands.nl",
      defaultLocale: "shop.netherlands.nl-nl-NL",
      locales: ["shop.netherlands.nl-nl-NL"],
    },
    {
      domain: "shop.belgium.be",
      defaultLocale: "shop.belgium.be-nl-BE",
      locales: ["shop.belgium.be-nl-BE", "shop.belgium.be-fr-BE"],
    },
    {
      domain: "shop.germany.one.de",
      defaultLocale: "shop.germany.one.de-de-DE",
      locales: ["shop.germany.one.de-de-DE"],
    },
    {
      domain: "shop.germany.two.de-DE",
      defaultLocale: "shop.germany.two.de-de-DE",
      locales: ["shop.germany.two.de-de-DE"],
    },
  ],

  localePrefix: {
    mode: "as-needed",
    prefixes: {
      "shop.belgium.be-fr-BE": "/fr",
    },
  },

  defaultLocale: "shop.netherlands.nl-nl-NL",

  localeCookie: false,
});

Locale transformer

To transform the locale in useful parts i have this transformer to get the channel, lang and region.

// Splits a locale string into channel, lang, region
// shop.netherlands.nl-nl-NL => { channel: "shop.netherlands.nl", lang: "nl", region: "NL" }
// shop.belgium.be-nl-BE => { channel: "shop.belgium.be", lang: "nl", region: "BE" }
export function transformLocale(locale: string) {
  const [channel, lang, region] = locale.split("-");
  return { channel, lang, region };
}

Page.tsx

Then in my pages i can use this function to get the desired consts and use them for messages, api calls, etc.

export default async function HomePage({ params }: HomePageProps) {
  const { locale } = await params;
  const { channel, lang, region } = transformLocale(locale);
...etc

Conclusion

This works quite nice for now and it is pretty simple to implement. I didn't need to do any modifications to the middleware.
Is this a recommended way to handle multi-channel, multi-locale websites in Next.js with next-intl?

Describe alternatives you've considered

An alternative I considered was adding another dynamic path like locale but then for channel. The project structure would look like this:

/app
    /[channel]
        /[locale]
            /page.tsx

But for this to work i had to rewrite the complete middleware. That's something i want to avoid because the current middleware works really well!

@mvanpijkeren mvanpijkeren added enhancement New feature or request unconfirmed Needs triage. labels Mar 10, 2025
@amannn
Copy link
Owner

amannn commented Mar 11, 2025

Hey, thanks for the thoughtful question!

"shop.belgium.be-fr-BE"

So locales are really required to be valid IETF language tags. In v3 some features work even for invalid locales but others will break. In v4 (will be released soon), there will be an upfront warning when you're using invalid locales.

That being said, you can encode quite a bit into locales, including private, arbitrary information—so that should hopefully let you provide e.g. a differentiator for different German stores.

In combination with custom prefixes and a locale prefix config, I think this should get you pretty far! You can then extract your channel from the locale and use it as necessary in code.

Hope this helps, sounds like a really exciting project! 🙌

@amannn
Copy link
Owner

amannn commented Mar 11, 2025

I'll move this to a discussion since it seems to be more of a usage question …

Repository owner locked and limited conversation to collaborators Mar 11, 2025
@amannn amannn converted this issue into discussion #1776 Mar 11, 2025

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
enhancement New feature or request unconfirmed Needs triage.
Projects
None yet
Development

No branches or pull requests

2 participants