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

feat: Allow optimal routing by bypassing middleware #1742

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

syrusakbary
Copy link

@syrusakbary syrusakbary commented Feb 24, 2025

This PR optimizes next-intl by using middeware only for non-default locales.

Currently, using next-intl with app-routing localization, requires using the middleware always.

Since middleware in Next.js 13+ can be costly to run, this PR allows:

  • Not having to prefix any of the routes with a [locale] directory
  • Using middleware only for non-default locales (since the middleware sets the language context, we can retrieve it using the current way when rendering using the app router, and thus is no longer needed to retrieve it via the page params)

Copy link

vercel bot commented Feb 24, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
next-intl-example-app-router ❌ Failed (Inspect) Feb 25, 2025 5:12pm
next-intl-example-app-router-without-i18n-routing ❌ Failed (Inspect) Feb 25, 2025 5:12pm

Copy link

vercel bot commented Feb 24, 2025

@syrusakbary is attempting to deploy a commit to the next-intl Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Owner

@amannn amannn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for sharing the link to vercel/next.js#38273, I haven't heard about this yet! Seems like the Next.js team is tracking this issue in their bug tracker.

As for this PR, I'm having a bit a hard time to understand what you're trying to achieve. The middleware is required for i18n routing for quite a few features:

  1. Locale-prefix-based rewrites
  2. Domain-based rewrites
  3. Localized pathnames
  4. Setting a cookie (e.g. when changing a locale)
  5. Handling redirects as necessary

I don't really understand what kind of shortcut you want to take here, but the middleware is relevant for the default locale just as much as for non-default locales.

Can you provide more details on what exactly the issue is that you're facing?

As a side note, rootParams is coming to Next.js and will make it easier than ever to provide your own middleware in case you have special requirements. I hope to have more to share on this soon!

@syrusakbary
Copy link
Author

syrusakbary commented Feb 25, 2025

Sure! Let me explain our use case at Wasmer.

We want to use localization in a similar fashion as apple (via path routing).

That means, that the urls that we have are:

And also localized routes:

Basically, the default locale is english (and as such, it should not have prefixed urls) and we also want the default one to not use middlewares if possible (as they can slow down requests).

We want to see if we could achieve this by preserving the same app structure as we had before i18n the urls (that means having the src/app/page.tsx instead of src/app/[locale]/page.tsx).

So in summary: Locale is mainly dictated by the path (not domain or a cookie).

By doing this simple change, we can use i18n, keep the structure we had before, but as well we can internationalize the localized urls without any big change in the codebase (regarding structure) and without forcing middleware everywhere.

Happy to provide more insight if useful via text or even a Zoom call!

Note: I was not aware of the rootParams... thanks for sharing! I checked the https://github.com/amannn/nextjs-rootparams-test repo, and I wonder if we could use it (we want to have all our pages automatically localized) that means that we don't have unlocalized and localized routes. Just one kind of localized path (with the url requirements similar to Apple as I posted before). Any more insight on this will be greatly appreciated!

Update: just read the upcoming blogpost: https://github.com/amannn/next-intl/blob/bb47cbb79751cdd174cdb7d985eeb05daa7b9af9/docs/src/pages/blog/nextjs-root-params.mdx

Introduced a new field to allow bypassing middleware when possible
@syrusakbary syrusakbary changed the title Allow optimal routing by bypassing middleware feat: Allow optimal routing by bypassing middleware Feb 25, 2025
@amannn
Copy link
Owner

amannn commented Feb 26, 2025

For the routing structure you're describing, the localePrefix: 'as-needed' strategy is what apps with next-intl typically use today.

We want to see if we could achieve this by preserving the same app structure as we had before i18n the urls (that means having the src/app/page.tsx instead of src/app/[locale]/page.tsx).

You probably still only want to define your pages once for all locales, right? For this to work, you need some kind of middleware.

For the time being, if avoiding a middleware is the most important aspect for you, I think a prefix for the default locale might be required.

However, if you're willing to declare your pages separately for the default and secondary locales, this could theoretically be done with such a setup:

src
  (en)
    app
      page.tsx
  [locale]
    app
      page.tsx
...

Your pages could still share components (as much as the whole page), but it's required to define the page.tsx separately. This approach will require rootParams however to read the locale in i18n/request.ts.

Separately from this, it seems like the Next.js team is tracking vercel/next.js#38273 to hopefully improve this. They're actively working on the middleware currently to enable Node.js support, maybe that could yield some improvements 🤞. Edit: Added a question here.

So as a conclusion, I don't see next-intl in the position to provide workarounds for this currently as good alternatives are in reach—hope this makes sense!

@syrusakbary
Copy link
Author

However, if you're willing to declare your pages separately for the default and secondary locales, this could theoretically be done with such a setup:

Unfortunately, the [locale] will collide with other routes if we follow this approach, eg:

src
  (en)
    app
      page.tsx
      [username]
        page.tsx
  [locale]
    app
      page.tsx
      [username]
        page.tsx

Next.js will rightfully error here, since it will not know what page you are trying to access when accessing /myusername (is it (en)/[username]/page.tsx or is it [locale]/page.tsx?). As this scenario is impossible, this only left us to the always use middleware approach (which we are trying to avoid for now for the slowness issue).

If this small setting change is too much hassle, perhaps other way would be to export all the functions that middleware uses so I can recreate the middleware.tsx logic locally. Thoughts @amannn?

@amannn
Copy link
Owner

amannn commented Feb 27, 2025

@syrusakbary Right, another top-level param like [username] is indeed a conflict and not easy to resolve if you want to leave the page structure like this. But it would also conflict without the (en) route group, no?

Anyway, based on the currently available information, I don't really see fit for this adjustment currently in the next-intl middleware. If you have special requirements, I'd recommend providing your own middleware and navigation APIs that you can customize fully to your needs. It shouldn't be too much if you have specific requirements and don't need advanced features from the next-intl middleware like localized pathnames.

Next.js 15.2 just shipped and includes unstable_rootParams—maybe worth a shot to initialize your locale in i18n/request.ts from there!

perhaps other way would be to export all the functions that middleware uses so I can recreate the middleware.tsx logic locally

Sorry, currently I don't really see a good time for this. Next.js is working on reshaping their middleware API (ref) and I don't want to expose more public API in this area currently that might break soon. I hope you can understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants