rembrembdocs

Via path

curl http://localhost:8787/ar/home

Via query parameter

curl http://localhost:8787/?lang=ar

Via cookie

curl -H 'Cookie: language=ja' http://localhost:8787/

Via header

curl -H 'Accept-Language: ar,en;q=0.9' http://localhost:8787/


## Default Configuration [​](#default-configuration)

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, }


## Key Behaviors [​](#key-behaviors)

### Detection Workflow [​](#detection-workflow)

1.  **Order**: Checks sources in this sequence by default:
    
    *   Query parameter (?lang=ar)
    *   Cookie (language=ar)
    *   Accept-Language header
2.  **Caching**: Stores detected language in a cookie (1 year by default)
    
3.  **Fallback**: Uses `fallbackLanguage` if no valid detection (must be in `supportedLanguages`)
    

## Advanced Configuration [​](#advanced-configuration)

### Custom Detection Order [​](#custom-detection-order)

Prioritize URL path detection (e.g., /en/about):

ts

app.use( languageDetector({ order: ['path', 'cookie', 'querystring', 'header'], lookupFromPathIndex: 0, // /en/profile → index 0 = 'en' supportedLanguages: ['en', 'ar'], fallbackLanguage: 'en', }) )


### Progressive Locale Matching [​](#progressive-locale-matching)

When a detected locale code like `ja-JP` is not in `supportedLanguages`, the middleware progressively truncates subtags to find a match. For example, `zh-Hant-CN` will try `zh-Hant`, then `zh`. An exact match is always preferred.

ts

app.use( languageDetector({ supportedLanguages: ['en', 'ja', 'zh-Hant'], fallbackLanguage: 'en', }) )

// Accept-Language: ja-JP → matches 'ja' // Accept-Language: zh-Hant-CN → matches 'zh-Hant'


### Language Code Transformation [​](#language-code-transformation)

Normalize complex codes (e.g., en-US → en):

ts

app.use( languageDetector({ convertDetectedLanguage: (lang) => lang.split('-')[0], supportedLanguages: ['en', 'ja'], fallbackLanguage: 'en', }) )


### Cookie Configuration [​](#cookie-configuration)

ts

app.use( languageDetector({ lookupCookie: 'app_lang', caches: ['cookie'], cookieOptions: { path: '/', // Cookie path sameSite: 'Lax', // Cookie same-site policy secure: true, // Only send over HTTPS maxAge: 86400 * 365, // 1 year expiration httpOnly: true, // Not accessible via JavaScript domain: '.example.com', // Optional: specific domain }, }) )


To disable cookie caching:

ts

languageDetector({ caches: false, })


### Debugging [​](#debugging)

Log detection steps:

ts

languageDetector({ debug: true, // Shows: "Detected from querystring: ar" })


## Options Reference [​](#options-reference)

### Basic Options [​](#basic-options)

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

### Detection Options [​](#detection-options)

Option

Type

Default

Description

`lookupQueryString`

`string`

`'lang'`

Query parameter name

`lookupCookie`

`string`

`'language'`

Cookie name

`lookupFromHeaderKey`

`string`

`'accept-language'`

Header name

`lookupFromPathIndex`

`number`

`0`

Path segment index

### Cookie Options [​](#cookie-options)

Option

Type

Default

Description

`caches`

`CacheType[] | false`

`['cookie']`

Cache settings

`cookieOptions.path`

`string`

`'/'`

Cookie path

`cookieOptions.sameSite`

`'Strict' | 'Lax' | 'None'`

`'Strict'`

SameSite policy

`cookieOptions.secure`

`boolean`

`true`

HTTPS only

`cookieOptions.maxAge`

`number`

`31536000`

Expiration (seconds)

`cookieOptions.httpOnly`

`boolean`

`true`

JS accessibility

`cookieOptions.domain`

`string`

`undefined`

Cookie domain

### Advanced Options [​](#advanced-options)

Option

Type

Default

Description

`ignoreCase`

`boolean`

`true`

Case-insensitive matching

`convertDetectedLanguage`

`(lang: string) => string`

`undefined`

Language code transformer

## Validation & Error Handling [​](#validation-error-handling)

*   `fallbackLanguage` must be in `supportedLanguages` (throws error during setup)
*   `lookupFromPathIndex` must be ≥ 0
*   Invalid configurations throw errors during middleware initialization
*   Failed detections silently use `fallbackLanguage`

## Common Recipes [​](#common-recipes)

### Path-Based Routing [​](#path-based-routing)

ts

app.get('/:lang/home', (c) => { const lang = c.get('language') // 'en', 'ar', etc. return c.json({ message: getLocalizedContent(lang) }) })


### Multiple Supported Languages [​](#multiple-supported-languages)

ts

languageDetector({ supportedLanguages: ['en', 'en-GB', 'ar', 'ar-EG'], convertDetectedLanguage: (lang) => lang.replace('_', '-'), // Normalize })