- Home
- HTTP Headers
- Accept-Language Header
Header
Accept-Language Header
Learn how the Accept-Language header tells servers which languages your client prefers for localized content. Understand language tags and quality values.
TL;DR: Tells servers what languages your client prefers (en-US, es, fr, etc.). Used for content localization and serving appropriate language versions.
What is Accept-Language?
The Accept-Language header tells the server what human languages your client prefers. It’s like walking into a restaurant and saying “I speak English and a little Spanish” so they can give you the right menu.
Servers use this for content negotiation to serve localized versions of pages, error messages, and data.
How Accept-Language Works
Client specifies language preferences:
GET /welcome HTTP/1.1
Host: example.com
Accept-Language: en-US, en;q=0.9, es;q=0.8, fr;q=0.7
```text
**Server responds with appropriate language:**
```http
HTTP/1.1 200 OK
Content-Type: text/html
Content-Language: en-US
<h1>Welcome to our site!</h1>
Language Tag Format
Basic Language Codes
Accept-Language: en # English (any variant)
Accept-Language: es # Spanish (any variant)
Accept-Language: fr # French (any variant)
Accept-Language: de # German (any variant)
```http
### Language with Region
```http
Accept-Language: en-US # US English
Accept-Language: en-GB # British English
Accept-Language: es-ES # Spain Spanish
Accept-Language: es-MX # Mexican Spanish
Accept-Language: fr-CA # Canadian French
Quality Values (Preferences)
Accept-Language: en-US;q=1.0, en;q=0.9, es;q=0.8, fr;q=0.5
```text
This means:
- US English is most preferred (q=1.0)
- General English is second choice (q=0.9)
- Spanish is third choice (q=0.8)
- French is acceptable (q=0.5)
## Real-World Examples
### US Browser
```http
Accept-Language: en-US,en;q=0.9
European Browser
Accept-Language: de-DE,de;q=0.9,en;q=0.8
```text
### Multilingual User
```http
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7
Mobile App
Accept-Language: es-MX,es;q=0.9,en;q=0.8
```text
## Common Language Codes
### Major Languages
| Code | Language | Region |
| ------- | ---------- | -------------- |
| `en-US` | English | United States |
| `en-GB` | English | United Kingdom |
| `es-ES` | Spanish | Spain |
| `es-MX` | Spanish | Mexico |
| `fr-FR` | French | France |
| `fr-CA` | French | Canada |
| `de-DE` | German | Germany |
| `it-IT` | Italian | Italy |
| `pt-BR` | Portuguese | Brazil |
| `pt-PT` | Portuguese | Portugal |
### Asian Languages
| Code | Language | Region |
| ------- | -------- | -------------------- |
| `zh-CN` | Chinese | China (Simplified) |
| `zh-TW` | Chinese | Taiwan (Traditional) |
| `ja-JP` | Japanese | Japan |
| `ko-KR` | Korean | South Korea |
| `hi-IN` | Hindi | India |
| `ar-SA` | Arabic | Saudi Arabia |
## Server Response Strategies
### Exact Match
```http
# Client requests
Accept-Language: fr-CA
# Server has French Canadian content
Content-Language: fr-CA
Fallback to General Language
# Client requests
Accept-Language: es-AR
# Server only has general Spanish
Content-Language: es
```text
### Default Language
```http
# Client requests
Accept-Language: zh-CN
# Server only has English
Content-Language: en
Multiple Language Support
# Client requests
Accept-Language: de-DE,en;q=0.8
# Server responds in German
Content-Language: de-DE
```text
## Best Practices
### For Clients
**1. Include fallback languages**
```http
Accept-Language: fr-CA,fr;q=0.9,en;q=0.8
2. Be specific about regions when it matters
# Different Spanish variants
Accept-Language: es-MX,es;q=0.9,en;q=0.8
```text
**3. Use quality values for preferences**
```http
Accept-Language: de-DE;q=1.0,en;q=0.8,fr;q=0.6
For Servers
1. Implement graceful fallbacks
function selectLanguage(acceptLanguage, availableLanguages) {
const requested = parseAcceptLanguage(acceptLanguage)
// Try exact match first
for (const lang of requested) {
if (availableLanguages.includes(lang.code)) {
return lang.code
}
}
// Try language without region
for (const lang of requested) {
const baseLanguage = lang.code.split('-')[0]
const match = availableLanguages.find((l) => l.startsWith(baseLanguage))
if (match) return match
}
// Default to English or primary language
return 'en'
}
```javascript
**2. Set Content-Language in responses**
```javascript
app.get('/content', (req, res) => {
const language = selectLanguage(req.headers['accept-language'], ['en', 'es', 'fr'])
const content = getLocalizedContent(language)
res.set('Content-Language', language)
res.json(content)
})
3. Handle missing translations gracefully
function getLocalizedMessage(key, language) {
const messages = {
en: { welcome: 'Welcome!' },
es: { welcome: '¡Bienvenido!' },
fr: { welcome: 'Bienvenue!' }
}
// Try requested language
if (messages[language] && messages[language][key]) {
return messages[language][key]
}
// Fallback to English
return messages['en'][key] || key
}
```text
## Browser Behavior
### Automatic Headers
Browsers automatically send Accept-Language based on:
- User's OS language settings
- Browser language preferences
- Manually configured language preferences
### Typical Browser Headers
```http
# Chrome on Windows (US)
Accept-Language: en-US,en;q=0.9
# Firefox on macOS (Germany)
Accept-Language: de-DE,de;q=0.8,en-US;q=0.5,en;q=0.3
# Safari on iOS (Spain)
Accept-Language: es-ES,es;q=0.9,en;q=0.8
API Localization
Error Messages
app.use((err, req, res, next) => {
const language = selectLanguage(req.headers['accept-language'], ['en', 'es', 'fr'])
const errorMessages = {
en: 'An error occurred',
es: 'Ocurrió un error',
fr: "Une erreur s'est produite"
}
res.status(500).json({
error: errorMessages[language] || errorMessages['en']
})
})
```javascript
### Data Localization
```javascript
app.get('/products', (req, res) => {
const language = selectLanguage(req.headers['accept-language'], ['en', 'es', 'fr'])
const products = getProducts().map((product) => ({
id: product.id,
name: product.names[language] || product.names['en'],
description: product.descriptions[language] || product.descriptions['en'],
price: formatPrice(product.price, language)
}))
res.set('Content-Language', language)
res.json(products)
})
Testing Language Negotiation
Using curl
# Test English
curl -H "Accept-Language: en-US" https://example.com/api/messages
# Test Spanish
curl -H "Accept-Language: es-ES" https://example.com/api/messages
# Test with fallbacks
curl -H "Accept-Language: de-DE,en;q=0.8" https://example.com/api/messages
```text
### Using JavaScript
```javascript
fetch('/api/content', {
headers: {
'Accept-Language': 'fr-FR,fr;q=0.9,en;q=0.8'
}
})
Common Patterns
Progressive Language Support
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
```text
Prefer Chinese (China), fall back to general Chinese, then English.
### Regional Preferences
```http
Accept-Language: en-AU,en-GB;q=0.9,en;q=0.8
Prefer Australian English, then British English, then general English.
Multilingual User
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8,de;q=0.7
Russian speaker who also knows English and German.
Related Headers
- Content-Language - Server’s language choice
- Vary - Cache variation by language
- Accept - Content type preferences
- User-Agent - Client identification
Frequently Asked Questions
What is Accept-Language?
Accept-Language tells the server which languages the client prefers. Servers use this for content negotiation to return localized content. Example: Accept-Language: en-US, en;q=0.9, fr;q=0.8.
How does language preference work?
Languages are listed with optional quality values (q). Higher q means higher preference. en-US,en;q=0.9 prefers US English, then any English. Default q is 1.0.
Should I use Accept-Language for localization?
Use it as a default, but let users override. Store user preference in cookies or profiles. Accept-Language reflects browser settings, not necessarily user preference.
What is the difference between en and en-US?
en is generic English. en-US is US English specifically. en-GB is British English. Servers may match en-US to en if no specific variant exists.