i18nexus / next-i18n-router

Next.js App Router internationalized routing and locale detection.
MIT License
262 stars 18 forks source link

404 Not found page for static, api or _next items #55

Closed klonwar closed 9 months ago

klonwar commented 9 months ago

Hi, I'm trying to configure "404 not found" behavior properly and I noticed that strange things happen when I'm trying to request not existing items with static, api, or _next paths.

When requesting http://localhost:3000/123/123/123, the correct locale stored in cookies is passed to Root Layout and 404 page is rendered correctly image

But when I'm trying to request http://localhost:3000/api/123/123, it passes "api" as a locale image

My middleware.ts copied from documentation:

export const middleware = (request: NextRequest) => {
  return i18nRouter(request, NextI18nRouterConfig)
}

export const config = {
  matcher: ['/((?!api|static|.*\\..*|_next).*)'],
}

Not found page is accessed via dummy component image

export default function NotFoundDummy() {
  notFound()
}

Is there any option to pass locale stored in cookie in the root layout for such pages? Or just do not pass anything at all? I'm not sure what's the expected behavior here :)

i18nexus commented 9 months ago

The middleware is bypassed for paths that start with /api. You can see that in the config here: /((?!api|static|.*\\..*|_next).*)

Paths that start with /api conventionally are used in NextJS for Route Handlers.

If you're not using route handlers and you want paths that start with /api to go to a 404 page, then you just have to remove api from the middleware config:

/((?!static|.*\\..*|_next).*)

Hope this helps!

klonwar commented 9 months ago

Thank you!

Is there any option to enhance middleware somehow to make localized 404 page just work everywhere, no matter if it's missing static file, api route, system file from _next or just regular route? And not break existing logic when file or route actually exist?

Just want to return valid 404 page based on saved cookie without getting errors about "api" or "_next" locales in console. Of course I can determine locale by myself in the root layout if the provided value is not listed in supoorted languages list, but maybe there is better way to do this without changing component logic?

i18nexus commented 9 months ago

The middleware matcher defines what requests are run through middleware. Requests to "_next" and public static files are not run through the middleware and therefore not affected by this library. Can you give an example of the type of errors you're getting?

klonwar commented 9 months ago

Sure! Let's imagine user trying to open /missing.ico. In that case I'm getting "missing.ico" as a locale in RootLayout. For now I added a simple validator that throws an error in case of incorrect locale:

image

But the point is that without the correct locale, I can't set the html lang to the correct one in root layout: <html lang={locale} .... And of course I need locale to show localized 404 page text. For such urls as /missing.ico, /api/missing, /_next/missing it seems impossible in current configuration (I'm getting 'missing.ico', 'api', '_next' as a locale in root layout).

So, the error is that I cannot get correct locale in root layout.

i18nexus commented 9 months ago

Ah I see the issue. Thanks for the clarification. The solution here would be to have this in your RootLayout:

import {notFound} from 'next/navigation';
...
if (!i18nConfig.locales.includes(locale)) {
  notFound();
}

We should definitely add this to our examples. Does this solve your problem?

klonwar commented 9 months ago

Good suggestion, thank you! It really works if I create another not-found.tsx page outside the [locale] dir. One thing to notice is that there should be <html> tag because it will be rendered outside our [locale] layout (which is actually root layout for a localized app). For example:

export default () => {
  return (
    <html>
      <body>
        <h1>404 - Page Not Found</h1>
      </body>
    </html>
  )
}

Seems like an acceptable workaroud for me. In that file I'm able to retrieve language manually. It's a little sad that you have to make the layout from scratch inside this page, but the main thing is that it seems to work. Thank you for your help!