Skip to content

Commit 9fdc916

Browse files
committed
fix: edge-middleware i18n matching
1 parent b6ccbb5 commit 9fdc916

File tree

4 files changed

+50
-7
lines changed

4 files changed

+50
-7
lines changed

edge-runtime/lib/next-request.ts

+28
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Context } from '@netlify/edge-functions'
22

33
import {
44
addBasePath,
5+
addLocale,
56
addTrailingSlash,
67
normalizeDataUrl,
78
normalizeLocalePath,
@@ -73,6 +74,33 @@ const normalizeRequestURL = (
7374
}
7475
}
7576

77+
export const localizeRequest = (
78+
url: URL,
79+
nextConfig?: {
80+
basePath?: string
81+
i18n?: I18NConfig | null
82+
},
83+
): { localizedUrl: URL; locale?: string } => {
84+
const localizedUrl = new URL(url)
85+
localizedUrl.pathname = removeBasePath(localizedUrl.pathname, nextConfig?.basePath)
86+
87+
// Detect the locale from the URL
88+
const { detectedLocale } = normalizeLocalePath(localizedUrl.pathname, nextConfig?.i18n?.locales)
89+
90+
// Add the locale to the URL if not already present
91+
localizedUrl.pathname = addLocale(
92+
localizedUrl.pathname,
93+
detectedLocale ?? nextConfig?.i18n?.defaultLocale,
94+
)
95+
96+
localizedUrl.pathname = addBasePath(localizedUrl.pathname, nextConfig?.basePath)
97+
98+
return {
99+
localizedUrl: url,
100+
locale: detectedLocale,
101+
}
102+
}
103+
76104
export const buildNextRequest = (
77105
request: Request,
78106
context: Context,

edge-runtime/lib/util.ts

+14
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ export const addBasePath = (path: string, basePath?: string) => {
2929
return path
3030
}
3131

32+
// add locale prefix if not present, allowing for locale fallbacks
33+
export const addLocale = (path: string, locale?: string) => {
34+
if (
35+
locale &&
36+
path.toLowerCase() !== `/${locale.toLowerCase()}` &&
37+
!path.toLowerCase().startsWith(`/${locale.toLowerCase()}/`) &&
38+
!path.startsWith(`/api/`) &&
39+
!path.startsWith(`/_next/static/`)
40+
) {
41+
return `/${locale}${path}`
42+
}
43+
return path
44+
}
45+
3246
// https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/i18n/normalize-locale-path.ts
3347

3448
export interface PathLocale {

edge-runtime/middleware.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import nextConfig from './next.config.json' with { type: 'json' }
55

66
import { InternalHeaders } from './lib/headers.ts'
77
import { logger, LogLevel } from './lib/logging.ts'
8-
import { buildNextRequest, RequestData } from './lib/next-request.ts'
8+
import { buildNextRequest, localizeRequest, RequestData } from './lib/next-request.ts'
99
import { buildResponse, FetchEventResult } from './lib/response.ts'
1010
import {
1111
getMiddlewareRouteMatcher,
@@ -31,25 +31,29 @@ export async function handleMiddleware(
3131
context: Context,
3232
nextHandler: NextHandler,
3333
) {
34-
const nextRequest = buildNextRequest(request, context, nextConfig)
3534
const url = new URL(request.url)
35+
3636
const reqLogger = logger
3737
.withLogLevel(
3838
request.headers.has(InternalHeaders.NFDebugLogging) ? LogLevel.Debug : LogLevel.Log,
3939
)
4040
.withFields({ url_path: url.pathname })
4141
.withRequestID(request.headers.get(InternalHeaders.NFRequestID))
4242

43+
const { localizedUrl } = localizeRequest(url, nextConfig)
4344
// While we have already checked the path when mapping to the edge function,
4445
// Next.js supports extra rules that we need to check here too, because we
4546
// might be running an edge function for a path we should not. If we find
4647
// that's the case, short-circuit the execution.
47-
if (!matchesMiddleware(url.pathname, request, searchParamsToUrlQuery(url.searchParams))) {
48+
if (
49+
!matchesMiddleware(localizedUrl.pathname, request, searchParamsToUrlQuery(url.searchParams))
50+
) {
4851
reqLogger.debug('Aborting middleware due to runtime rules')
4952

5053
return
5154
}
5255

56+
const nextRequest = buildNextRequest(request, context, nextConfig)
5357
try {
5458
const result = await nextHandler({ request: nextRequest })
5559
const response = await buildResponse({

src/build/functions/edge.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,7 @@ const writeHandlerFile = async (ctx: PluginContext, { matchers, name }: NextDefi
6565

6666
// Writing a file with the matchers that should trigger this function. We'll
6767
// read this file from the function at runtime.
68-
await writeFile(
69-
join(handlerRuntimeDirectory, 'matchers.json'),
70-
JSON.stringify(augmentMatchers(matchers, ctx)),
71-
)
68+
await writeFile(join(handlerRuntimeDirectory, 'matchers.json'), JSON.stringify(matchers))
7269

7370
// The config is needed by the edge function to match and normalize URLs. To
7471
// avoid shipping and parsing a large file at runtime, let's strip it down to

0 commit comments

Comments
 (0)