-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmiddleware.ts
More file actions
98 lines (85 loc) · 3.05 KB
/
Copy pathmiddleware.ts
File metadata and controls
98 lines (85 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { NextResponse, type NextRequest } from 'next/server'
import redirectsMap from './redirects.json'
const LOCALES = ['en', 'ru']
const DEFAULT_LOCALE = 'en'
const COOKIE_NAME = 'NEXT_LOCALE'
const HAS_LOCALE_RE = new RegExp(`^\\/(${LOCALES.join('|')})(\\/|$)`)
const REDIRECTS = redirectsMap as Record<string, string>
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
// Skip static files
if (pathname.startsWith('/_next') || pathname.startsWith('/api') || pathname.includes('.')) {
return NextResponse.next()
}
// Marketing pages — no locale routing
const MARKETING_PATHS = [
'/pricing',
'/integrations',
'/contact',
'/links',
'/analytics',
'/partners',
'/for-partners',
'/enterprise',
'/api',
'/solutions',
'/customers',
'/blog',
'/changelog',
'/compare',
'/tools',
'/glossary',
'/anti-fraud',
]
if (pathname === '/' || MARKETING_PATHS.some(p => pathname === p || pathname.startsWith(`${p}/`))) {
return NextResponse.next()
}
// Legal section is RU-only. Normalize /legal/* and /en/legal/* to /ru/legal/*.
if (pathname === '/legal' || pathname.startsWith('/legal/') ||
pathname === '/en/legal' || pathname.startsWith('/en/legal/')) {
const url = request.nextUrl.clone()
url.pathname = '/ru/legal' + pathname.replace(/^(?:\/en)?\/legal/, '')
return NextResponse.redirect(url, 301)
}
// Handle old /help/article/{slug} redirects (strip locale prefix first if present)
const pathWithoutLocale = HAS_LOCALE_RE.test(pathname)
? '/' + pathname.split('/').slice(2).join('/')
: pathname
if (REDIRECTS[pathWithoutLocale]) {
const locale = HAS_LOCALE_RE.test(pathname) ? pathname.split('/')[1] : DEFAULT_LOCALE
const url = request.nextUrl.clone()
url.pathname = locale === DEFAULT_LOCALE
? REDIRECTS[pathWithoutLocale]
: `/${locale}${REDIRECTS[pathWithoutLocale]}`
return NextResponse.redirect(url, 301)
}
// If URL has a locale prefix (e.g. /ru/help)
if (HAS_LOCALE_RE.test(pathname)) {
const [, locale] = pathname.split('/')
const cookieLocale = request.cookies.get(COOKIE_NAME)?.value
if (locale !== cookieLocale) {
const response = NextResponse.next()
response.cookies.set(COOKIE_NAME, locale)
return response
}
return NextResponse.next()
}
// No locale prefix — determine locale
const cookieLocale = request.cookies.get(COOKIE_NAME)?.value
const acceptLang = request.headers.get('accept-language') || ''
const browserLocale = acceptLang.includes('ru') ? 'ru' : DEFAULT_LOCALE
const locale = cookieLocale || browserLocale
if (locale === DEFAULT_LOCALE) {
const url = request.nextUrl.clone()
url.pathname = `/${DEFAULT_LOCALE}${pathname}`
return NextResponse.rewrite(url)
}
const url = request.nextUrl.clone()
url.pathname = `/${locale}${pathname}`
return NextResponse.redirect(url)
}
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico|icon.svg|apple-icon.png|manifest|_pagefind).*)',
],
}