언어 감지 미들웨어
언어 감지 미들웨어는 사용자의 선호 언어(로케일)를 다양한 소스에서 자동으로 식별하고 c.get('language')를 통해 제공한다. 쿼리 파라미터, 쿠키, 헤더, URL 경로 세그먼트 등 다양한 전략을 사용해 언어를 감지한다. 국제화(i18n)와 로케일별 콘텐츠 제공에 적합하다.
Import
ts
import { Hono } from 'hono'
import { languageDetector } from 'hono/language'기본 사용법
쿼리 문자열, 쿠키, 헤더(기본 순서)에서 언어를 감지하고, 실패 시 영어로 대체하는 예제:
ts
const app = new Hono()
app.use(
languageDetector({
supportedLanguages: ['en', 'ar', 'ja'], // fallback 언어를 반드시 포함
fallbackLanguage: 'en', // 필수
})
)
app.get('/', (c) => {
const lang = c.get('language')
return c.text(`Hello! Your language is ${lang}`)
})클라이언트 예제
sh
# 경로를 통한 방식
curl http://localhost:8787/ar/home
# 쿼리 파라미터를 통한 방식
curl http://localhost:8787/?lang=ar
# 쿠키를 통한 방식
curl -H 'Cookie: language=ja' http://localhost:8787/
# 헤더를 통한 방식
curl -H 'Accept-Language: ar,en;q=0.9' http://localhost:8787/기본 설정
ts
export const DEFAULT_OPTIONS: DetectorOptions = {
order: ['querystring', 'cookie', 'header'],
lookupQueryString: 'lang',
lookupCookie: 'language',
lookupFromHeaderKey: 'accept-language',
lookupFromPathIndex: 0,
caches: ['cookie'],
ignoreCase: true,
fallbackLanguage: 'en',
supportedLanguages: ['en'],
cookieOptions: {
sameSite: 'Strict',
secure: true,
maxAge: 365 * 24 * 60 * 60,
httpOnly: true,
},
debug: false,
}주요 동작
언어 감지 워크플로
순서: 기본적으로 다음 순서로 소스를 확인한다:
- 쿼리 파라미터 (?lang=ar)
- 쿠키 (language=ar)
- Accept-Language 헤더
캐싱: 감지된 언어를 쿠키에 저장한다 (기본값 1년)
대체 언어: 유효한 감지 결과가 없으면
fallbackLanguage를 사용한다 (supportedLanguages목록에 포함되어 있어야 함)
고급 설정
커스텀 감지 순서
URL 경로 감지를 우선시하는 예시 (/en/about):
ts
app.use(
languageDetector({
order: ['path', 'cookie', 'querystring', 'header'],
lookupFromPathIndex: 0, // /en/profile → index 0 = 'en'
supportedLanguages: ['en', 'ar'],
fallbackLanguage: 'en',
})
)언어 코드 변환
복잡한 코드를 정규화한다 (예: en-US → en):
ts
app.use(
languageDetector({
convertDetectedLanguage: (lang) => lang.split('-')[0],
supportedLanguages: ['en', 'ja'],
fallbackLanguage: 'en',
})
)쿠키 설정
ts
app.use(
languageDetector({
lookupCookie: 'app_lang',
caches: ['cookie'],
cookieOptions: {
path: '/', // 쿠키 경로
sameSite: 'Lax', // 쿠키 same-site 정책
secure: true, // HTTPS에서만 전송
maxAge: 86400 * 365, // 1년 만료 기간
httpOnly: true, // 자바스크립트로 접근 불가
domain: '.example.com', // 선택 사항: 특정 도메인
},
})
)쿠키 캐싱을 비활성화하려면:
ts
languageDetector({
caches: false,
})디버깅
로그 감지 단계:
ts
languageDetector({
debug: true, // "쿼리 문자열에서 감지됨: ar"을 표시
})옵션 참조
기본 옵션
| 옵션 | 타입 | 기본값 | 필수 여부 | 설명 |
|---|---|---|---|---|
supportedLanguages | string[] | ['en'] | 예 | 허용된 언어 코드 |
fallbackLanguage | string | 'en' | 예 | 기본 언어 |
order | DetectorType[] | ['querystring', 'cookie', 'header'] | 아니오 | 감지 순서 |
debug | boolean | false | 아니오 | 로깅 활성화 |
탐지 옵션
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
lookupQueryString | string | 'lang' | 쿼리 파라미터 이름 |
lookupCookie | string | 'language' | 쿠키 이름 |
lookupFromHeaderKey | string | 'accept-language' | 헤더 이름 |
lookupFromPathIndex | number | 0 | 경로 세그먼트 인덱스 |
쿠키 옵션
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
caches | CacheType[] | false | ['cookie'] | 캐시 설정 |
cookieOptions.path | string | '/' | 쿠키 경로 |
cookieOptions.sameSite | 'Strict' | 'Lax' | 'None' | 'Strict' | SameSite 정책 |
cookieOptions.secure | boolean | true | HTTPS 전용 |
cookieOptions.maxAge | number | 31536000 | 만료 시간 (초) |
cookieOptions.httpOnly | boolean | true | JS 접근 가능성 |
cookieOptions.domain | string | undefined | 쿠키 도메인 |
고급 설정
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
ignoreCase | boolean | true | 대소문자 구분 없이 매칭 |
convertDetectedLanguage | (lang: string) => string | undefined | 언어 코드 변환 함수 |
유효성 검사 및 에러 처리
fallbackLanguage는supportedLanguages목록에 포함되어야 한다 (설정 중 에러 발생)lookupFromPathIndex값은 0 이상이어야 한다- 잘못된 설정은 미들웨어 초기화 과정에서 에러를 발생시킨다
- 언어 감지 실패 시 자동으로
fallbackLanguage를 사용한다
일반적인 활용 예제
경로 기반 라우팅
ts
app.get('/:lang/home', (c) => {
const lang = c.get('language') // 'en', 'ar' 등
return c.json({ message: getLocalizedContent(lang) })
})다국어 지원
ts
languageDetector({
supportedLanguages: ['en', 'en-GB', 'ar', 'ar-EG'],
convertDetectedLanguage: (lang) => lang.replace('_', '-'), // 언어 코드 정규화
})