diff --git a/middleware.ts b/middleware.ts index c58b39a73cd20..ba0bd01835fce 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,9 +1,51 @@ import { NextResponse } from 'next/server'; -import createMiddleware from './next.middleware'; -import detectLanguage from './middlewares/detectLanguage'; +import { availableLocales } from './next.locales.mjs'; +import type { NextRequest } from 'next/server'; -const nextMiddleware = createMiddleware(NextResponse); +// This Middleware is responsible for handling automatic language detection from a user's Browser +// This middleware should only run on "/" requests coming to the Website +export const middleware = async (request: NextRequest) => { + const { pathname, search } = request.nextUrl; -const { middleware, matcher } = nextMiddleware([detectLanguage]); + // This function allows us to redirect with a Locale Code + const redirectWithLocale = (_locale: string) => { + const redirectUrl = `/${_locale}${pathname}${search}`; -export { middleware, matcher }; + return NextResponse.redirect(new URL(redirectUrl, request.url)); + }; + + const localeCookie = request.cookies.get('NEXT_LOCALE'); + + // If we already have a NEXT_LOCALE Cookie, then Redirect to the stored Locale Code + if (localeCookie?.value && localeCookie.value !== 'default') { + return redirectWithLocale(localeCookie.value); + } + + // If not, we try to check if the Browser is sending `Accept-Language` Header + const acceptedLanguagesRaw = request.headers.get('Accept-Language') || 'en'; + + // If present, we try to split the format into ['code', 'q=order', ...] + // Where q= is the precedence of the Accepted Language + // We then filter those out as we don't want them + const acceptedLanguages = acceptedLanguagesRaw + .split(';') + .map(collection => collection.split(',')) + .flat() + .filter(locale => !locale.startsWith('q=')); + + // We check if we have any matching Language in the order of preference given + // And if yes, we return that Locale Code + const matchedLocaleCode = acceptedLanguages.find(acceptedLocale => + availableLocales.some(locale => locale.code === acceptedLocale) + ); + + // We create a new Response Object containing the Locale Match or the default Language + const responseWithCookie = redirectWithLocale(matchedLocaleCode || 'en'); + + // Then we set a Cookie to avoid this calculation from happening on every / hit + responseWithCookie.cookies.set('NEXT_LOCALE', matchedLocaleCode || 'en'); + + return responseWithCookie; +}; + +export const config = { matcher: '/' }; diff --git a/middlewares/detectLanguage.ts b/middlewares/detectLanguage.ts deleted file mode 100644 index 6f47cd7c42e66..0000000000000 --- a/middlewares/detectLanguage.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { CustomMiddleware } from '@/types'; - -const detectLanguage: CustomMiddleware = { - handler: async (request, response, { availableLocales }) => { - const { pathname, search } = request.nextUrl; - - // This function allows us to redirect with a Locale Code - const redirectWithLocale = (_locale: string) => { - const redirectUrl = `/${_locale}${pathname}${search}`; - - return response.redirect(new URL(redirectUrl, request.url)); - }; - - const localeCookie = request.cookies.get('NEXT_LOCALE'); - - // If we already have a NEXT_LOCALE Cookie, then Redirect to the stored Locale Code - if (localeCookie?.value && localeCookie.value !== 'default') { - return redirectWithLocale(localeCookie.value); - } - - // If not, we try to check if the Browser is sending `Accept-Language` Header - const acceptedLanguagesRaw = request.headers.get('Accept-Language') || 'en'; - - // If present, we try to split the format into ['code', 'q=order', ...] - // Where q= is the precedence of the Accepted Language - // We then filter those out as we don't want them - const acceptedLanguages = acceptedLanguagesRaw - .split(';') - .map(collection => collection.split(',')) - .flat() - .filter(locale => !locale.startsWith('q=')); - - // We check if we have any matching Language in the order of preference given - // And if yes, we return that Locale Code - const matchedLocaleCode = acceptedLanguages.find(acceptedLocale => - availableLocales.some(locale => locale === acceptedLocale) - ); - - // We create a new Response Object containing the Locale Match or the default Language - const responseWithCookie = redirectWithLocale(matchedLocaleCode || 'en'); - - // Then we set a Cookie to avoid this calculation from happening on every / hit - responseWithCookie.cookies.set('NEXT_LOCALE', matchedLocaleCode || 'en'); - - return responseWithCookie; - }, - matcher: request => request.nextUrl.pathname === '/', - routes: ['/'], -}; - -export default detectLanguage; diff --git a/next.middleware.ts b/next.middleware.ts deleted file mode 100644 index 162899221bd16..0000000000000 --- a/next.middleware.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { availableLocales, getCurrentLocale } from './next.locales.mjs'; -import type { NextRequest, NextResponse } from 'next/server'; -import type { CustomMiddleware, NextMiddlewareLocale } from './types'; - -const availableLocaleCodes = availableLocales.map(locale => locale.code); - -const createMiddleware = (response: typeof NextResponse) => { - const localeMiddleware = (request: NextRequest): NextMiddlewareLocale => { - const currentLocale = getCurrentLocale(request.nextUrl.pathname); - - return { - currentLocale: currentLocale.code, - availableLocales: availableLocaleCodes, - isLocalisedRoute: currentLocale.code !== 'en', - }; - }; - - return (middlewares: CustomMiddleware[]) => { - const middleware = async (request: NextRequest) => { - const locale = localeMiddleware(request); - - const matchedMiddleware = middlewares.find(middleware => - middleware.matcher(request, locale) - ); - - if (matchedMiddleware) { - return matchedMiddleware.handler(request, response, locale); - } - - return response.next(); - }; - - const matcher = middlewares.map(middleware => middleware.routes).flat(); - - return { middleware, matcher }; - }; -}; - -export default createMiddleware; diff --git a/turbo.json b/turbo.json index 359c33c703be0..24c8c032af686 100644 --- a/turbo.json +++ b/turbo.json @@ -1,5 +1,6 @@ { "$schema": "https://turbo.build/schema.json", + "globalEnv": ["NODE_ENV"], "pipeline": { "serve": { "cache": false, diff --git a/types/index.ts b/types/index.ts index adc14cec0b4b5..633e08674b506 100644 --- a/types/index.ts +++ b/types/index.ts @@ -9,5 +9,4 @@ export * from './layouts'; export * from './navigation'; export * from './prevNextLink'; export * from './releases'; -export * from './middlewares'; export * from './dynamic'; diff --git a/types/middlewares.ts b/types/middlewares.ts deleted file mode 100644 index fcf39dc97ac0f..0000000000000 --- a/types/middlewares.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { NextRequest, NextResponse } from 'next/server'; - -export type NextMiddlewareLocale = { - isLocalisedRoute: boolean; - currentLocale: string | null; - availableLocales: string[]; -}; - -export type CustomMiddleware = { - handler: ( - request: NextRequest, - response: typeof NextResponse, - locale: NextMiddlewareLocale - ) => Promise; - matcher: (request: NextRequest, locale: NextMiddlewareLocale) => boolean; - routes: (string | RegExp)[]; -}; - -export type RouteSegment = { - filename: string; - localised: boolean; - routeWithLocale: string; - pathname: string; -};