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

How to create a multilingual not-found page using route groups and nested layouts #53243

Closed
fabio-nettis opened this issue Jul 27, 2023 · 2 comments
Labels
bug Issue was opened via the bug report template. locked

Comments

@fabio-nettis
Copy link

fabio-nettis commented Jul 27, 2023

Describe the Bug

I'm struggling to get the localized not-found page to work with NextJS 13 (app-dir). I'm following the official guide on internationalization, as well as this solution from GitHub.

To Reproduce

[locale]
  -- [...not-found]
       - page.tsx <- empty page, just calls notFound() (catch-all segment)
  -- (browse)
       - someFolder1 <- may multiple pages and maybe nested layouts
       - layout.tsx
  -- (public)
       - someFolder2
       - layout.tsx
  -- (private)
       - someFolder3
       - layout.tsx
  -- layout.tsx
  -- not-found.tsx <- should be served for all notFound() errors (including catch-all segment)
The issue with this solution

When I call the notFound method from any of the route groups or visit an unmatched route; I receive an error stating: Unsupported Server Component type: Null. What seems pretty strange since both files definitely have a react component as default export.

import { notFound } from "next/navigation";

export default function CatchAllUnmatched(): JSX.Element {
  notFound();
  return <></>;
}

The other solution I have tried

I also tried to append a header to each response via a custom X-Language-Preference property I am adding inside my middleware file. In doing so I have moved the root layout as direct descendant of the app folder and retrieved the locale as follows:

export const getLocale = cache((): Language => {
  const preference = headers().get("X-Language-Preference");
  return (preference ?? fallbackLanguage) as Language;
});
The issue with this solution

The problem in this approach is that the lang property on the main html tag does not reset on client side navigation from /de to /fr for example. Also the 404 page is only displayed when an unmatched route is visited, calling the notFound method still results in the same error. So this solution is not viable as well.

What kind of answer would help me?

  • Any resources that display a real world example of a working internationalization example including a multilingual not found page, preferably also using route groups with nested layouts.

  • Possible reasons why I am encountering the error Unsupported Server Component type: Null when both files definitely have a react component as default export.

  • Any resources that may hint me in the right direction, be it a GitHub discussions, open issues, open pull requests or even Stack Overflow posts (but my own lol) that are relevant to the issue I am facing.

@fabio-nettis fabio-nettis added the bug Issue was opened via the bug report template. label Jul 27, 2023
@fabio-nettis
Copy link
Author

If anyone has this problem for a similarly advanced use-case I now finally have the solution. Using the 2nd approach is the correct way to address this issue.

  1. Move the root layout out of the [locale] folder and define a global not-found.tsx file containing all of your UI. Inside your layout you can then call the following function to retrieve the locale:
export const getLocale = cache((): Language => {
  const preference = headers().get("X-Language-Preference");
  return (preference ?? fallbackLanguage) as Language;
});
  1. Add a X-Language-Preference header (or however you want to call it) to each response passing via middleware, here you can define your own resolution strategy to retrieve the locale that shall be saved.
const headerName = "X-Language-Preference";

function getRequestLocale(request: NextRequest) {
  // ...
}

export default async function middleware(request: NextRequest) {
  const locale = getRequestLocale(request);
  const response = NextResponse.next();

  response.headers.set(headerName, locale);
  return response;
}

Why does this approach suddenly work?

After updating to version v13.4.12 containing this PR the 2nd solution suddenly started working, may been related to a bug or unwanted behavior.

@github-actions
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. locked
Projects
None yet
Development

No branches or pull requests

1 participant