语言中间件
语言检测器中间件自动从各种来源确定用户的首选语言(locale),并通过 c.get('language')
使其可用。检测策略包括查询参数、Cookie、标头和 URL 路径段。非常适合国际化 (i18n) 和特定于语言环境的内容。
导入
ts
import { Hono } from 'hono'
import { languageDetector } from 'hono/language'
基本用法
从查询字符串、Cookie 和标头(默认顺序)检测语言,并回退到英语:
ts
const app = new Hono()
app.use(
languageDetector({
supportedLanguages: ['en', 'ar', 'ja'], // 必须包含回退语言
fallbackLanguage: 'en', // 必需
})
)
app.get('/', (c) => {
const lang = c.get('language')
return c.text(`你好!你的语言是 ${lang}`)
})
客户端示例
sh
# 通过路径
curl http://localhost:8787/ar/home
# 通过查询参数
curl http://localhost:8787/?lang=ar
# 通过 Cookie
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,
}
主要行为
检测工作流程
顺序 (Order):默认情况下按以下顺序检查来源:
- 查询参数 (?lang=ar)
- Cookie (language=ar)
- Accept-Language 标头
缓存 (Caching):将检测到的语言存储在 Cookie 中(默认 1 年)
回退 (Fallback):如果没有有效的检测,则使用
fallbackLanguage
(必须在supportedLanguages
中)
高级配置
自定义检测顺序
优先考虑 URL 路径检测(例如,/en/about):
ts
app.use(
languageDetector({
order: ['path', 'cookie', 'querystring', 'header'],
lookupFromPathIndex: 0, // /en/profile → 索引 0 = 'en'
supportedLanguages: ['en', 'ar'],
fallbackLanguage: 'en',
})
)
语言代码转换
规范化复杂的代码(例如,en-US → en):
ts
app.use(
languageDetector({
convertDetectedLanguage: (lang) => lang.split('-')[0],
supportedLanguages: ['en', 'ja'],
fallbackLanguage: 'en',
})
)
Cookie 配置
ts
app.use(
languageDetector({
lookupCookie: 'app_lang',
caches: ['cookie'],
cookieOptions: {
path: '/', // Cookie 路径
sameSite: 'Lax', // Cookie SameSite 策略
secure: true, // 仅通过 HTTPS 发送
maxAge: 86400 * 365, // 1 年过期时间
httpOnly: true, // 无法通过 JavaScript 访问
domain: '.example.com', // 可选:特定域名
},
})
)
要禁用 Cookie 缓存:
ts
languageDetector({
caches: false,
})
调试
记录检测步骤:
ts
languageDetector({
debug: true, // 显示: "Detected from querystring: ar"
})
选项参考
基本选项
选项 (Option) | 类型 (Type) | 默认值 (Default) | 必需 (Required) | 描述 (Description) |
---|---|---|---|---|
supportedLanguages | string[] | ['en'] | Yes | 允许的语言代码 (Allowed language codes) |
fallbackLanguage | string | 'en' | Yes | 默认语言 (Default language) |
order | DetectorType[] | ['querystring', 'cookie', 'header'] | No | 检测顺序 (Detection sequence) |
debug | boolean | false | No | 启用日志记录 (Enable logging) |
检测选项
选项 (Option) | 类型 (Type) | 默认值 (Default) | 描述 (Description) |
---|---|---|---|
lookupQueryString | string | 'lang' | 查询参数名 (Query parameter name) |
lookupCookie | string | 'language' | Cookie 名称 (Cookie name) |
lookupFromHeaderKey | string | 'accept-language' | 标头名称 (Header name) |
lookupFromPathIndex | number | 0 | 路径段索引 (Path segment index) |
Cookie 选项
选项 (Option) | 类型 (Type) | 默认值 (Default) | 描述 (Description) |
---|---|---|---|
caches | CacheType[] | false | ['cookie'] | 缓存设置 (Cache settings) |
cookieOptions.path | string | '/' | Cookie 路径 (Cookie path) |
cookieOptions.sameSite | 'Strict' | 'Lax' | 'None' | 'Strict' | SameSite 策略 (SameSite policy) |
cookieOptions.secure | boolean | true | 仅 HTTPS (HTTPS only) |
cookieOptions.maxAge | number | 31536000 | 过期时间(秒)(Expiration (seconds)) |
cookieOptions.httpOnly | boolean | true | JS 可访问性 (JS accessibility) |
cookieOptions.domain | string | undefined | Cookie 域名 (Cookie domain) |
高级选项
选项 (Option) | 类型 (Type) | 默认值 (Default) | 描述 (Description) |
---|---|---|---|
ignoreCase | boolean | true | 忽略大小写匹配 (Case-insensitive matching) |
convertDetectedLanguage | (lang: string) => string | undefined | 语言代码转换器 (Language code transformer) |
验证和错误处理
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('_', '-'), // 规范化
})