Next.js Discord

Discord Forum

Internationalization 404 bug

Unanswered
Dutch posted this in #help-forum
Open in Discord
DutchOP
So I'm trying to add Internationalization to my app and I successfully made it work on pages, but It doesn't allow the not-found.tsx file to work whenever i try to access an invalid route.

root/middleware.ts:
import Negotiator from 'negotiator'
import { type NextRequest, NextResponse } from 'next/server'

const locales = ['en-US', 'pt-PT'] as const

type Locale = (typeof locales)[number]

function getLocale(request: NextRequest): Locale {
  const headers = {
    'accept-language': request.headers.get('accept-language') || ''
  }
  const languages = new Negotiator({ headers }).languages()
  const defaultLocale: Locale = 'pt-PT'

  const matchedLocale = languages.find((lang) =>
    locales.includes(lang as Locale)
  )

  return (matchedLocale as Locale) || defaultLocale
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl

  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  )

  if (pathnameHasLocale) {
    return
  }

  const locale = getLocale(request)
  const newPathname = `/${locale}${pathname}`
  const url = new URL(newPathname, request.url)

  return NextResponse.redirect(url)
}

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

root/app/[lang]/not-found.tsx:
import { getDictionary } from '@/app/[lang]/dictionaries'

export default async function NotFound({
  params
}: {
  params: { lang: 'en-US' | 'pt-PT' }
}) {
  const { lang } = params
  const dict = await getDictionary(lang)

  return (
    <div className="flex flex-1 items-center justify-center">
      <span className="text-3xl">{dict.errors[404].message}</span>
    </div>
  )
}


thanks in advance.

4 Replies

@Dutch So I'm trying to add Internationalization to my app and I successfully made it work on pages, but It doesn't allow the `not-found.tsx` file to work whenever i try to access an invalid route. `root/middleware.ts`: ts import Negotiator from 'negotiator' import { type NextRequest, NextResponse } from 'next/server' const locales = ['en-US', 'pt-PT'] as const type Locale = (typeof locales)[number] function getLocale(request: NextRequest): Locale { const headers = { 'accept-language': request.headers.get('accept-language') || '' } const languages = new Negotiator({ headers }).languages() const defaultLocale: Locale = 'pt-PT' const matchedLocale = languages.find((lang) => locales.includes(lang as Locale) ) return (matchedLocale as Locale) || defaultLocale } export function middleware(request: NextRequest) { const { pathname } = request.nextUrl const pathnameHasLocale = locales.some( (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}` ) if (pathnameHasLocale) { return } const locale = getLocale(request) const newPathname = `/${locale}${pathname}` const url = new URL(newPathname, request.url) return NextResponse.redirect(url) } export const config = { matcher: ['/((?!_next|api).*)'] } `root/app/[lang]/not-found.tsx`: tsx import { getDictionary } from '@/app/[lang]/dictionaries' export default async function NotFound({ params }: { params: { lang: 'en-US' | 'pt-PT' } }) { const { lang } = params const dict = await getDictionary(lang) return ( <div className="flex flex-1 items-center justify-center"> <span className="text-3xl">{dict.errors[404].message}</span> </div> ) } thanks in advance.
Only app/not-found.tsx is recognised as a 404 page. So you need to use app/not-found.tsx. You probably need to use a client component there to have access to the locale via usePathname, but I think it shouldn’t be too difficult if your i18n lib supports client components
but i also realized it was not working with other pages too
so something within my configuration was incorrect, i’ll read docs and see if i can find the issue. thanks again!