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
|
/** middleware.ts */
export const runtime = 'nodejs';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import acceptLanguage from 'accept-language';
import { fallbackLng, languages, cookieName } from '@/i18n/settings';
acceptLanguage.languages(languages);
export function middleware(request: NextRequest) {
/**
* 1. 쿠키에서 언어 가져오기
*/
let lng = request.cookies.get(cookieName)?.value;
/**
* 2. 쿠키가 없다면 브라우저의 Accept-Language 헤더에서 언어를 추론
*/
if (!lng) {
const headerLang = request.headers.get('accept-language');
lng = acceptLanguage.get(headerLang) || fallbackLng;
}
const { pathname, searchParams, origin } = request.nextUrl;
/**
* 3. "/"" 경로로 들어온 경우 -> "/{lng}"로 리다이렉트
* (예) / -> /en, / -> /ko ...
*/
if (pathname === '/') {
const redirectUrl = new URL(`/${lng}`, origin);
// 쿼리 파라미터가 있을 경우도 붙여주기
redirectUrl.search = searchParams.toString();
return NextResponse.redirect(redirectUrl);
}
/**
* 4. 현재 pathname이 언어 경로를 포함하고 있는지 확인
* - /en
* - /en/... (다른 하위 경로들)
* - /ko
* - /ko/...
*/
const hasValidLngInPath = languages.some(
(language) => pathname === `/${language}` || pathname.startsWith(`/${language}/`),
);
/**
* 5. 언어 경로가 누락된 경우 -> "/{lng}" + 기존 pathname 으로 리다이렉트
* 예) /dashboard -> /en/dashboard
*/
if (!hasValidLngInPath) {
const redirectUrl = new URL(`/${lng}${pathname}`, origin);
redirectUrl.search = searchParams.toString();
return NextResponse.redirect(redirectUrl);
}
/**
* 6. 위 조건에 걸리지 않았다면 그대로 Next.js로 넘긴다.
*/
const response = NextResponse.next();
/**
* 7. 쿠키에 저장된 언어와 현재 lng가 다르면 업데이트
*/
const currentCookie = request.cookies.get(cookieName)?.value;
if (lng && lng !== currentCookie) {
response.cookies.set(cookieName, lng, { path: '/' });
}
return response;
}
/**
* 8. (선택) 매칭할 경로 설정
* - _next, 정적파일(.*), API 등의 경로는 제외시키는 예시
*/
export const config = {
matcher: [
'/((?!_next|.*\\..*|api).*)',
],
};
|