-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathmiddleware.ts
101 lines (89 loc) · 3.21 KB
/
middleware.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
89
90
91
92
93
94
95
96
97
98
99
100
101
import { NextRequest, NextResponse } from "next/server";
import langParser from "accept-language-parser";
import { defaultLocale, locales, getLocalePartsFrom } from "./i18n";
const findBestMatchingLocale = (acceptLangHeader: string) => {
// parse the locales acceptable in the header, and sort them by priority (q)
const parsedLangs = langParser.parse(acceptLangHeader);
// find the first locale that matches a locale in our list
for (let i = 0; i < parsedLangs.length; i++) {
const parsedLang = parsedLangs[i];
// attempt to match both the language and the country
const matchedLocale = locales.find((locale) => {
const localeParts = getLocalePartsFrom({ locale });
return (
parsedLang.code === localeParts.lang &&
parsedLang.region === localeParts.country
);
});
if (matchedLocale) {
return matchedLocale;
}
// if we didn't find a match for both language and country, try just the language
else {
const matchedLanguage = locales.find((locale) => {
const localeParts = getLocalePartsFrom({ locale });
return parsedLang.code === localeParts.lang;
});
if (matchedLanguage) {
return matchedLanguage;
}
}
}
// if we didn't find a match, return the default locale
return defaultLocale;
};
export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const defaultLocaleParts = getLocalePartsFrom({ locale: defaultLocale });
const currentPathnameParts = getLocalePartsFrom({ pathname });
// Check if the default locale is in the pathname
if (
currentPathnameParts.lang === defaultLocaleParts.lang &&
currentPathnameParts.country === defaultLocaleParts.country
) {
// we want to REMOVE the default locale from the pathname,
// and later use a rewrite so that Next will still match
// the correct code file as if there was a locale in the pathname
return NextResponse.redirect(
new URL(
pathname.replace(
`/${defaultLocaleParts.lang}/${defaultLocaleParts.country}`,
pathname.startsWith("/") ? "/" : ""
),
request.url
)
);
}
const pathnameIsMissingValidLocale = locales.every((locale) => {
const localeParts = getLocalePartsFrom({ locale });
return !pathname.startsWith(`/${localeParts.lang}/${localeParts.country}`);
});
if (pathnameIsMissingValidLocale) {
// rewrite it so next.js will render `/` as if it was `/en/us`
const matchedLocale = findBestMatchingLocale(
request.headers.get("Accept-Language") || defaultLocale
);
if (matchedLocale !== defaultLocale) {
const matchedLocaleParts = getLocalePartsFrom({ locale: matchedLocale });
return NextResponse.redirect(
new URL(
`/${matchedLocaleParts.lang}/${matchedLocaleParts.country}${pathname}`,
request.url
)
);
} else {
return NextResponse.rewrite(
new URL(
`/${defaultLocaleParts.lang}/${defaultLocaleParts.country}${pathname}`,
request.url
)
);
}
}
}
export const config = {
matcher: [
// Skip all internal paths (_next)
"/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js).*)",
],
};