> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Language

> Language detection middleware for internationalization.

## Overview

The `language` middleware detects user language preference from Accept-Language header, cookies, or query parameters.

Use it when you need:

* Multi-language support
* Content localization
* Language-based routing

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/language"
```

## Quick Start

```go theme={null}
app := mizu.New()

app.Use(language.New(language.Options{
    Supported: []string{"en", "es", "fr", "de"},
    Default:   "en",
}))

app.Get("/", func(c *mizu.Ctx) error {
    lang := language.Get(c)
    return c.JSON(200, map[string]string{"language": lang})
})
```

## Configuration

### Options

| Option       | Type       | Default         | Description         |
| ------------ | ---------- | --------------- | ------------------- |
| `Supported`  | `[]string` | Required        | Supported languages |
| `Default`    | `string`   | First supported | Default language    |
| `QueryKey`   | `string`   | `"lang"`        | Query parameter     |
| `CookieName` | `string`   | `"lang"`        | Cookie name         |

## Examples

### Basic Detection

```go theme={null}
app.Use(language.New(language.Options{
    Supported: []string{"en", "es", "fr"},
    Default:   "en",
}))
```

### From Query Parameter

```go theme={null}
// GET /page?lang=es
app.Use(language.New(language.Options{
    Supported: []string{"en", "es"},
    QueryKey:  "language",
}))
```

### Persist in Cookie

```go theme={null}
app.Use(language.New(language.Options{
    Supported:  []string{"en", "es", "fr"},
    CookieName: "preferred_language",
}))
```

### Language-Based Routing

```go theme={null}
app.Get("/:lang/page", func(c *mizu.Ctx) error {
    lang := c.Param("lang")
    // Validate and use language
    return c.JSON(200, getContent(lang))
})
```

## Detection Order

1. Query parameter (?lang=es)
2. Cookie (lang=es)
3. Accept-Language header
4. Default language

## API Reference

### Functions

```go theme={null}
// New creates language middleware
func New(opts Options) mizu.Middleware

// Get returns detected language
func Get(c *mizu.Ctx) string

// Set sets language preference
func Set(c *mizu.Ctx, lang string)
```

## Technical Details

### Implementation Architecture

The language middleware uses a multi-source detection strategy with priority-based resolution:

1. **Context Storage**: Detected language is stored in the request context using a private `contextKey` type
2. **Case-Insensitive Matching**: All language comparisons are performed case-insensitively using lowercase normalization
3. **Regional Support**: Handles both base language codes (e.g., "en") and regional variants (e.g., "en-US", "en-GB")
4. **Quality-Based Parsing**: Accept-Language header parsing respects quality values (q-values) for prioritization

### Key Components

* **isSupported()**: Validates if a language code exists in the supported languages map
* **normalize()**: Converts detected language codes to the exact format defined in supported languages
* **parseAcceptLanguage()**: Parses Accept-Language header with quality values, sorts by quality descending
* **Path Prefix Handling**: When enabled, strips the language prefix from the URL path (e.g., `/fr/page` becomes `/page`)

### Configuration Defaults

```go theme={null}
// Default values when not specified
QueryParam:  "lang"          // Query parameter name
CookieName:  "lang"          // Cookie name
Header:      "Accept-Language" // HTTP header
PathPrefix:  false           // Path prefix detection disabled
Default:     supported[0]    // First supported language
```

## Best Practices

* Support common language codes
* Provide language switcher UI
* Persist user preference
* Use ISO 639-1 codes (en, es, fr)

## Testing

The middleware includes comprehensive test coverage for all detection mechanisms and edge cases:

| Test Case                              | Description                                           | Expected Behavior                                                 |
| -------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------- |
| TestNew                                | Basic middleware creation with Accept-Language header | Detects language from Accept-Language header ("es")               |
| TestWithOptions\_QueryParam            | Custom query parameter detection                      | Detects language from query parameter "language=de"               |
| TestWithOptions\_Cookie                | Custom cookie name detection                          | Detects language from cookie "user\_lang=ja"                      |
| TestWithOptions\_PathPrefix            | Path prefix language detection                        | Detects "fr" from "/fr/page" and strips prefix to "/page"         |
| TestWithOptions\_AcceptLanguageQuality | Quality value parsing in Accept-Language              | Selects "fr" with q=0.9 over "en" with q=0.5                      |
| TestWithOptions\_AcceptLanguageRegion  | Regional language variant detection                   | Detects exact match "en-GB" from regional variants                |
| TestWithOptions\_Fallback              | Default language fallback                             | Falls back to "en" when unsupported language "zh" requested       |
| TestWithOptions\_Priority              | Detection priority order                              | Query parameter ("es") takes priority over Accept-Language ("fr") |
| TestFromContext                        | Context retrieval alias function                      | Get() and FromContext() return identical values                   |
| TestWithOptions\_NoHeader              | No language hints provided                            | Falls back to default language "en"                               |
| TestWithOptions\_CaseInsensitive       | Case-insensitive language matching                    | Matches "es" query to "ES" in supported languages                 |

## Related Middlewares

* [timezone](/middlewares/timezone) - Timezone detection
* [vary](/middlewares/vary) - Vary headers
