Internationalization 404 bug
Unanswered
Dutch posted this in #help-forum
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
thanks in advance.
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!