vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.68k stars 26.61k forks source link

i18n: Incremental migration to app results in 404 not found page #57704

Open iljamulders opened 10 months ago

iljamulders commented 10 months ago

Link to the code that reproduces this issue

https://github.com/iljamulders/nextjs-i18n-incremental-adopt

To Reproduce

  1. Start the application in development (next dev)
  2. Go to http://localhost:3000/en/about or http://localhost:3000/nl/about
  3. You will see the 404 page not found

Current vs. Expected behavior

The internationalization example will always return a 404 not found when i18n is turned on in next.config.js

// next.config.js

/** @type {import("next").NextConfig} */
module.exports = {
  reactStrictMode: true,
  i18n: {
    locales: ['en', 'nl'],
    defaultLocale: 'en'
  }
}
// app/[lang]/about/page.tsx

export default async function Page({ params: { lang } }: { params: { lang: string } }) {
    return <div>Current language: {lang}</div>
}

This makes it impossible to incrementally adopt to the app router.

Expected behavior

https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#migrating-from-pages-to-app

The app directory is intentionally designed to work simultaneously with the pages directory to allow for incremental page-by-page migration.

Verify canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.0.0: Fri Sep 15 14:41:43 PDT 2023; root:xnu-10002.1.13~1/RELEASE_ARM64_T6000
Binaries:
  Node: 20.9.0
  npm: 10.2.0
  Yarn: 1.22.19
  pnpm: N/A
Relevant Packages:
  next: 14.0.1-canary.2
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.1.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

App Router, Internationalization (i18n)

Additional context

No response

shinwonse commented 9 months ago

Anyone have solved it? I am also struggling with it.

moogblob commented 9 months ago

Think it's the same as #53724

bulhiCzar commented 8 months ago

next: 14.0.4 the problem is relevant with the logical next.config.ts.

/ - page is displayed
/nl - 404 
/en - 404
simonmares commented 7 months ago

Hi, another dev trying to use app router in existing internationalized next app with pages router.

I also confirm this is still a problem in 14.0.4 as I tested it using reproduction repo https://github.com/iljamulders/nextjs-i18n-incremental-adopt, thanks @iljamulders.

It seems that any locale you specify in next.config i18n.locales make subsequent path segments to be routed only to pages router and ignores any routes in app router.

Only workaround I see is to put app router routes under extra path e.g. /extra/nl/about which wouldn't match the i18n logic in pages router. That's not desirable as you can't move existing pages under app router without changing urls.

I've experienced this first in https://nextjs.org/blog/next-13-4 only on Vercel production (not locally) of our existing app, but couldn't reproduce locally and not even on Vercel deployment with a new Next.js project. Currently it behaves same during development and in production.

simonmares commented 7 months ago

@leerob Hi, there seems to be i18n incompatibility using app and pages router together since day one. There is very clear and simple reproduction repository. Could you have a look?

iljamulders commented 7 months ago

@simonmares & @leerob Unfortunately we still can't use the new app router after more than a year of it being stable :(

@leerob could you shed any light on when this issue will be addressed? PS love your youtube vids, keep them coming!

shinwonse commented 7 months ago

How about using monorepo with pages router and app router? If I use monorepo and create next configuration file for each project, I think it should be work.

cupofjoakim commented 7 months ago

This is blocking us too. All routes are internationalised, and migrating ~30 complex pages at the same time in a high traffic repo makes this a no-go for now.

I would expect the behaviour of trying to match any route in the app router first before looking at the config locales and matching them against the pages router. That seems to be what's going on here, but maybe i'm looking in the wrong place: https://github.com/vercel/next.js/blob/f45a15b621225a4ad3d401e4d3d114dd17647a90/packages/next/src/server/require.ts#L24

leerob commented 7 months ago

Hey folks, sorry for the slow reply here. You are correct there isn't a way to mix the Pages Router i18n configuration with the App Router. This does make incremental adoption more difficult in this case. One option is to move the Pages Router setup from the i18n configuration to a Middleware-based configuration. Since this is the approach recommended in the App Router, it would allow you to then incrementally move routes from Pages -> App as you're ready. Hope this helps.

iljamulders commented 7 months ago

@leerob

Thanks for your reply! I will give this a go.

Some notes for other devs trying to achieve this:

The lang attribute (in the pages router)

If you remove the i18n config, the lang attribute will be removed from <html>, so remember to add it as high as possible in your pages/_app.tsx

The 404 page

Next.js renders the closest not-found page when a route segment calls the notFound function. We can use this mechanism to provide a localized 404 page by adding a not-found file within the [locale] folder.

// app/[locale]/not-found.tsx

// not-found.js components do not accept any props.
// So we need to make it a client component and useParams() to get the locale 
'use client'

import { useParams } from 'next/navigation'

export default function NotFoundPage() {
    const params = useParams()

    return <h1>404 with locale: {params?.locale}</h1>
}

Note however that Next.js will only render this page when the notFound function is called from within a route, not for all unknown routes in general.

To catch unknown routes too, you can define a catch-all route that explicitly calls the notFound function.

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

import {notFound} from 'next/navigation';

export default function CatchAllPage() {
  notFound();
}
abriginets commented 7 months ago

@leerob could you please elaborate on this? If I understand it correctly, translation libraries, such as next-translate, were depending on built-in i18n property and the routing features it gives. Now, in app dir i18n is handled by the developers themselves, yet the presence of i18n key on next.config.js affecting routing for both pages and app dir. So I can't quite comprehend how the use of middleware would help us here? Shouldn't this be marked as a critical bug and prioritized then? It looks like partial migration from pages to app dir is currently not possible entirely and the only choice we have at this point is to start developing new application using only app dir and somehow connect pages and app applications through DNS and redirects which doubles the effort and hosting expenses.