/
locales.ts
88 lines (77 loc) · 2.83 KB
/
locales.ts
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
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
type LegacyMiddlewareCookies = { [key: string]: string }
type StableMiddlewareCookies = Map<string, string>
function getCookie(
cookies: LegacyMiddlewareCookies | StableMiddlewareCookies,
key: string
) {
if (typeof cookies.get === 'function') {
return cookies.get(key)
}
return (cookies as LegacyMiddlewareCookies)[key]
}
export function locales(request: NextRequest) {
const { nextUrl } = request
const shouldHandleLocale =
!/^\/(api|_next)\//.test(nextUrl.pathname) &&
!/\.(jpe?g|svg|png|webmanifest)$/.test(nextUrl.pathname) &&
nextUrl.locale !== ''
if (!shouldHandleLocale) return
// The locale code prefixed in the current URL, which can be empty.
const fullUrl = nextUrl.toString()
let localeInPath = fullUrl
// remove host and first slash from url
.slice(fullUrl.indexOf('//' + nextUrl.host) + nextUrl.host.length + 2)
// remove pathname, search, and extra slashes from url
localeInPath = localeInPath
.replace((nextUrl.pathname + nextUrl.search), '')
.replace('/', '')
let finalLocale
if (localeInPath) {
// If a locale is explicitly set, we don't do any modifications.
finalLocale = localeInPath
} else {
// If there is a locale cookie, we try to use it. If it doesn't exist or
// it's invalid, `nextUrl.locale` will be automatically figured out by Next
// via the `accept-languages` header.
const clientLocale = getCookie(request.cookies, 'NEXT_LOCALE')
if (clientLocale) {
try {
nextUrl.locale = clientLocale
} catch (err) {
// The locale from the cookie isn't valid.
// https://github.com/vercel/next.js/blob/e5dee17f776dcc79ebb269f7b7341fa6e2b6c3f1/packages/next/server/web/next-url.ts#L122-L129
}
}
finalLocale = nextUrl.locale
// Now we want to display the locale. If it's not the default one, we have
// to prefix the URL with that locale since it's missing. Only the default
// locale can be missing from there for consistency.
if (finalLocale !== nextUrl.defaultLocale) {
return NextResponse.redirect(
new URL(
'/' + finalLocale + nextUrl.pathname + nextUrl.search,
request.url
)
)
}
}
let pathname = nextUrl.pathname || '/'
if (pathname === '/') pathname += 'index'
else if (pathname.endsWith('/')) pathname = pathname.slice(0, -1)
// If we are not showing the correct localed page, rewrite the current request.
if (!pathname.endsWith('.' + finalLocale)) {
return NextResponse.rewrite(
new URL(
'/' + finalLocale + pathname + '.' + finalLocale + nextUrl.search,
request.url
)
)
}
}
export function withLocales(middleware: any) {
return (...args: any[]) => {
return locales(args[0]) || middleware(...args)
}
}