next.js: Global 404 page is not available for internationalization
Verify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: win32
Arch: x64
Version: Windows 10 Pro
Binaries:
Node: 20.2.0
npm: N/A
Yarn: N/A
pnpm: N/A
Relevant packages:
next: 13.4.5-canary.3
eslint-config-next: N/A
react: 18.2.0
react-dom: 18.2.0
typescript: 4.9.4
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true), Internationalization (i18n), Routing (next/router, next/navigation, next/link)
Link to the code that reproduces this issue or a replay of the bug
https://github.com/Arctomachine/404-page-internationalization-root-layout
To Reproduce
- Create project as usually, start dev server
- Follow internationalization section guide and create
/app/[lang]
folder. Create layout file (starting from<html lang={lang}>
) that will act as root layout. - Create
/app/not-found.tsx
file according to not found section - Follow console instruction and make top level root layout (containing only `<>{children}</>) for this page to start working
- Stop dev server. Run build and then start scripts. Visit any not existing url that would trigger 404
Describe the Bug
There are multiple problems with it. One of them being actual bug, the rest just would make this the (currently) only solution bad - if it worked.
- 404 page contents blink for a second, then page goes completely white and empty. Numerous errors in browser console.
- This approach makes it impossible to fit error page into acting root layout under
/[lang]
- This approach makes it impossible to translate error page into other languages
Uploaded reproduction: https://404-page-internationalization-root-layout.vercel.app/en
Expected Behavior
Since there is not much to be expected from this solution, I will propose new expected workflow instead. A new way of making 404 page with internationalization in mind:
- treat the topmost available layout as root. Then not-found file inside of it will behave like global 404 page
- allow passing props into not-found file to change its contents based on language of currently visited page
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
any
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 34
- Comments: 24 (5 by maintainers)
The point is that a 404 page is about as “static” a page as you could possibly ever want to create. Localising a static 404 page should be dead easy in any web framework in 2024.
The sad truth is that NextJs has neglected and botched internationalisation for 8 years now – users should not expect anything new.
@huozhi In my project, the
not-found.tsx
file is located in theapp/[lng]
directory, and the 404 page does not take effect.@huozhi the solution you describe is not for issue in topic. It works for calling
notFound()
function, yes. But the issue here is global 404 page. If file is placed into/[lang]
folder, then default 404 page will be used instead of our file.@Arctomachine I encountered this issues as well today and here’s what I think is a working solution (until the logic works as listed in the expected behaviour above):
I got a middleware function that will always prepend a locale to the any URL requested (except for certain allow-listed assets):
This ensures that any URL will hit the
/[lang]
route.My
/app
folder is organized like this:As you can see, in the
/[lang]
dynamic segment, I only have static routes, which allows me to use the/[...notFound]
handler with the following page:This will ensure that the closest
not-found.tsx
file gets hit (ie. the one in/[lang]/not-found.tsx
), which has access to the lang from its layout.Obviously, this will only work if you don’t have another dynamic segment nested at the root of
/[lang]
as it would clash with/[lang]/[...notFound]
.It also relies on any request always getting routed with a
lang
prefix.Hope this helps!
But then it automatically turns whole site into dynamic rendering. For dynamic site this method might be just strange, but for static sites it is simply impossible solution.
Using
headers
in your not-found file will make it dynamic and uncachable. When the not found is dynamic, everything in that folder will turn dynamic. So with this method, you are eliminating all caching of your site.So should we just open new issue since this one does not look like it is ever going to be reopened and bug is not fixed?
Regarding to the reproduction, the approach using root layout that only rendering children and a root not-found that doesn’t contain
html
/body
will break the client rendering if you directly hit a non-existen route. The root not found page is composed by root layout and root not-found, so the output html of not-found page is missinghtml
andbody
that will lead to hydration errors later.You can remove the root layout file which renders only children, and place the root not-found to
app/[lang]/not-found.js
And not-found.js doesn’t work on layout group.