diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts
index 9d85556ab49c0..f7cbf822fff76 100644
--- a/packages/next/src/build/index.ts
+++ b/packages/next/src/build/index.ts
@@ -3301,6 +3301,16 @@ export default async function build(
                     orig,
                     path.join(distDir, 'server', updatedRelativeDest)
                   )
+
+                  // since the app router not found is prioritized over pages router,
+                  // we have to ensure the app router entries are available for all locales
+                  if (i18n) {
+                    for (const locale of i18n.locales) {
+                      const curPath = `/${locale}/404`
+                      pagesManifest[curPath] = updatedRelativeDest
+                    }
+                  }
+
                   pagesManifest['/404'] = updatedRelativeDest
                 }
               })
diff --git a/test/e2e/app-dir/not-found-with-pages-i18n/app/app-dir/[[...slug]]/page.tsx b/test/e2e/app-dir/not-found-with-pages-i18n/app/app-dir/[[...slug]]/page.tsx
new file mode 100644
index 0000000000000..84e51b866c775
--- /dev/null
+++ b/test/e2e/app-dir/not-found-with-pages-i18n/app/app-dir/[[...slug]]/page.tsx
@@ -0,0 +1,44 @@
+import { notFound } from 'next/navigation'
+
+export async function generateStaticParams() {
+  return []
+}
+
+async function validateSlug(slug: string[]) {
+  try {
+    const isValidPath =
+      slug.length === 1 && (slug[0] === 'about' || slug[0] === 'contact')
+
+    if (!isValidPath) {
+      return false
+    }
+
+    return true
+  } catch (error) {
+    throw error
+  }
+}
+
+export default async function CatchAll({
+  params,
+}: {
+  params: Promise<{ slug: string[] }>
+}) {
+  const { slug } = await params
+  const slugArray = Array.isArray(slug) ? slug : [slug]
+
+  // Validate the slug
+  const isValid = await validateSlug(slugArray)
+
+  // If not valid, show 404
+  if (!isValid) {
+    notFound()
+  }
+
+  return (
+    <div>
+      <h1>Catch All</h1>
+      <p>This is a catch all page added to the APP router</p>
+    </div>
+  )
+}
diff --git a/test/e2e/app-dir/not-found-with-pages-i18n/app/layout.tsx b/test/e2e/app-dir/not-found-with-pages-i18n/app/layout.tsx
new file mode 100644
index 0000000000000..a14e64fcd5e33
--- /dev/null
+++ b/test/e2e/app-dir/not-found-with-pages-i18n/app/layout.tsx
@@ -0,0 +1,16 @@
+export const metadata = {
+  title: 'Next.js',
+  description: 'Generated by Next.js',
+}
+
+export default function RootLayout({
+  children,
+}: {
+  children: React.ReactNode
+}) {
+  return (
+    <html lang="en">
+      <body>{children}</body>
+    </html>
+  )
+}
diff --git a/test/e2e/app-dir/not-found-with-pages-i18n/app/not-found.tsx b/test/e2e/app-dir/not-found-with-pages-i18n/app/not-found.tsx
new file mode 100644
index 0000000000000..9e2f20f4cca7c
--- /dev/null
+++ b/test/e2e/app-dir/not-found-with-pages-i18n/app/not-found.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+
+const NotFound = () => (
+  <div>
+    <h1>APP ROUTER - 404 PAGE</h1>
+    <p>This page is using the APP ROUTER</p>
+  </div>
+)
+
+export default NotFound
diff --git a/test/e2e/app-dir/not-found-with-pages-i18n/next.config.js b/test/e2e/app-dir/not-found-with-pages-i18n/next.config.js
new file mode 100644
index 0000000000000..ee7663cef2d2b
--- /dev/null
+++ b/test/e2e/app-dir/not-found-with-pages-i18n/next.config.js
@@ -0,0 +1,12 @@
+/**
+ * @type {import('next').NextConfig}
+ */
+const nextConfig = {
+  i18n: {
+    locales: ['en-GB', 'en'],
+    defaultLocale: 'en',
+    localeDetection: false,
+  },
+}
+
+module.exports = nextConfig
diff --git a/test/e2e/app-dir/not-found-with-pages-i18n/not-found-with-pages.test.ts b/test/e2e/app-dir/not-found-with-pages-i18n/not-found-with-pages.test.ts
new file mode 100644
index 0000000000000..5b6a635bd3d6b
--- /dev/null
+++ b/test/e2e/app-dir/not-found-with-pages-i18n/not-found-with-pages.test.ts
@@ -0,0 +1,31 @@
+import { nextTestSetup } from 'e2e-utils'
+
+describe('not-found-with-pages', () => {
+  const { next, isNextStart } = nextTestSetup({
+    files: __dirname,
+  })
+
+  if (isNextStart) {
+    it('should write all locales to the pages manifest', async () => {
+      const pagesManifest = JSON.parse(
+        await next.readFile('.next/server/pages-manifest.json')
+      )
+
+      expect(pagesManifest['/404']).toBe('pages/404.html')
+      expect(pagesManifest['/en/404']).toBe('pages/404.html')
+      expect(pagesManifest['/en-GB/404']).toBe('pages/404.html')
+    })
+  }
+
+  it('should prefer the app router 404 over the pages router 404 when both are present', async () => {
+    const browser = await next.browser('/app-dir/foo')
+    expect(await browser.elementByCss('h1').text()).toBe(
+      'APP ROUTER - 404 PAGE'
+    )
+
+    await browser.loadPage(next.url)
+    expect(await browser.elementByCss('h1').text()).toBe(
+      'APP ROUTER - 404 PAGE'
+    )
+  })
+})
diff --git a/test/e2e/app-dir/not-found-with-pages-i18n/pages/404.tsx b/test/e2e/app-dir/not-found-with-pages-i18n/pages/404.tsx
new file mode 100644
index 0000000000000..be5a6a9368ef2
--- /dev/null
+++ b/test/e2e/app-dir/not-found-with-pages-i18n/pages/404.tsx
@@ -0,0 +1,24 @@
+import React from 'react'
+import { GetStaticProps } from 'next'
+
+interface NotFoundProps {
+  message: string
+}
+
+const NotFound = ({ message }: NotFoundProps) => (
+  <div>
+    <h1>PAGES ROUTER - 404 PAGE</h1>
+    <p>This page is using the PAGES ROUTER</p>
+    <p>{message}</p>
+  </div>
+)
+
+export const getStaticProps: GetStaticProps<NotFoundProps> = async () => {
+  return {
+    props: {
+      message: 'Custom message fetched at build time',
+    },
+  }
+}
+
+export default NotFound
diff --git a/test/e2e/app-dir/not-found-with-pages-i18n/pages/[[...slug]].tsx b/test/e2e/app-dir/not-found-with-pages-i18n/pages/[[...slug]].tsx
new file mode 100644
index 0000000000000..2da5fd5f318d5
--- /dev/null
+++ b/test/e2e/app-dir/not-found-with-pages-i18n/pages/[[...slug]].tsx
@@ -0,0 +1,39 @@
+import React from 'react'
+
+export const getStaticProps = ({ params }: { params: { slug: string[] } }) => {
+  try {
+    const slugArray = Array.isArray(params.slug) ? params.slug : [params.slug]
+
+    const isValidPath =
+      slugArray.length === 1 &&
+      (slugArray[0] === 'about' || slugArray[0] === 'contact')
+
+    if (!isValidPath) {
+      return {
+        notFound: true,
+      }
+    }
+
+    return {
+      props: {
+        slug: params.slug,
+      },
+    }
+  } catch (error) {
+    throw error
+  }
+}
+
+export const getStaticPaths = async () => ({
+  paths: [],
+  fallback: 'blocking',
+})
+
+const CatchAll = () => (
+  <div>
+    <h1>Catch All</h1>
+    <p>This is a catch all page added to the pages router</p>
+  </div>
+)
+
+export default CatchAll