Skip to content

Commit 09812f6

Browse files
committed
feat(locale-server-middleware): add server middleware for locale detection
1 parent 388419e commit 09812f6

File tree

14 files changed

+1363
-33317
lines changed

14 files changed

+1363
-33317
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,4 @@ combined.cjs
6262
combined.md
6363
test/fixtures/*/server/assets/
6464
playground/server/assets/
65+
.cursorrules

docs/guide/server-side-translations.md

Lines changed: 211 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,32 @@
22
outline: deep
33
---
44

5-
# 🌍 Server-Side Translations in Nuxt I18n Micro
5+
# 🌍 Server-Side Translations and Locale Information in Nuxt I18n Micro
66

77
## 📖 Overview
88

9-
Nuxt I18n Micro supports server-side translations, allowing you to translate content on the server and return it as part of the response. This is particularly useful for APIs or server-rendered applications where localization is needed before reaching the client.
9+
Nuxt I18n Micro supports server-side translations and locale information, allowing you to translate content and access locale details on the server. This is particularly useful for APIs or server-rendered applications where localization is needed before reaching the client.
1010

11-
The translations use locale messages defined in the Nuxt I18n configuration and are dynamically resolved based on the detected locale.
11+
The translations use locale messages defined in the Nuxt I18n configuration and are dynamically resolved based on the detected locale.
1212

1313
To clarify, the translations used by Nuxt I18n Micro in server-side handling are only sourced from the root-level translation files. Any nested translation files or subdirectories are not utilized in this context. The system will only retrieve translations from the root folder, ensuring a consistent and manageable approach to server-side translation retrieval.
1414

15-
---
15+
## 🛠️ Setting Up Server-Side Middleware
1616

17-
## 🛠️ Setting Up Server-Side Translations
17+
To enable server-side translations and locale information, use the provided middleware functions:
1818

19-
To enable server-side translations, use the provided middleware to handle locale detection and return translations dynamically. The `useTranslationServerMiddleware` function is designed for this purpose.
19+
- `useTranslationServerMiddleware` - for translating content
20+
- `useLocaleServerMiddleware` - for accessing locale information
2021

21-
---
22+
Both middleware functions are automatically available in all server routes.
23+
24+
The locale detection logic is shared between both middleware functions through the `detectCurrentLocale` utility function to ensure consistency across the module.
2225

2326
## ✨ Using Translations in Server Handlers
2427

25-
You can seamlessly translate content in any `eventHandler` by using the middleware.
28+
You can seamlessly translate content in any `eventHandler` by using the translation middleware.
2629

27-
### Example: Basic Usage
30+
### Example: Basic Translation Usage
2831
```typescript
2932
import { defineEventHandler } from 'h3'
3033

@@ -40,11 +43,83 @@ In this example:
4043
- The user's locale is detected automatically from query parameters, cookies, or headers.
4144
- The `t` function retrieves the appropriate translation for the detected locale.
4245

43-
---
46+
## 🌍 Using Locale Information in Server Handlers
47+
48+
### Basic Locale Information Usage
49+
50+
```typescript
51+
import { defineEventHandler } from 'h3'
52+
53+
export default defineEventHandler((event) => {
54+
const localeInfo = useLocaleServerMiddleware(event)
55+
56+
return {
57+
success: true,
58+
data: localeInfo,
59+
timestamp: new Date().toISOString()
60+
}
61+
})
62+
```
63+
64+
### Providing Custom Locale Parameters
65+
66+
```typescript
67+
import { defineEventHandler } from 'h3'
68+
69+
export default defineEventHandler((event) => {
70+
// Force specific locale with custom default
71+
const localeInfo = useLocaleServerMiddleware(event, 'en', 'ru')
72+
73+
return {
74+
success: true,
75+
data: localeInfo,
76+
timestamp: new Date().toISOString()
77+
}
78+
})
79+
```
80+
81+
### Response Structure
82+
83+
The locale middleware returns a `LocaleInfo` object with the following properties:
84+
85+
```typescript
86+
interface LocaleInfo {
87+
current: string // Current detected locale code
88+
default: string // Default locale code
89+
fallback: string // Fallback locale code
90+
available: string[] // Array of all available locale codes
91+
locale: Locale | null // Full locale configuration object
92+
isDefault: boolean // Whether current locale is the default
93+
isFallback: boolean // Whether current locale is the fallback
94+
}
95+
```
96+
97+
### Example Response
98+
99+
```json
100+
{
101+
"success": true,
102+
"data": {
103+
"current": "ru",
104+
"default": "en",
105+
"fallback": "en",
106+
"available": ["en", "ru", "de"],
107+
"locale": {
108+
"code": "ru",
109+
"iso": "ru-RU",
110+
"dir": "ltr",
111+
"displayName": "Русский"
112+
},
113+
"isDefault": false,
114+
"isFallback": false
115+
},
116+
"timestamp": "2024-01-15T10:30:00.000Z"
117+
}
118+
```
44119

45120
## 🌐 Providing a Custom Locale
46121

47-
If you need to specify a locale manually (e.g., for testing or certain requests), you can pass it to the middleware:
122+
If you need to specify a locale manually (e.g., for testing or certain requests), you can pass it to the translation middleware:
48123

49124
### Example: Custom Locale
50125
```typescript
@@ -66,12 +141,130 @@ export default defineEventHandler(async (event) => {
66141
})
67142
```
68143

69-
---
144+
## 📋 Locale Detection Logic
145+
146+
Both middleware functions automatically determine the user's locale using the following priority order:
147+
148+
1. **URL Parameters**: `?locale=ru`
149+
2. **Route Parameters**: `/ru/api/endpoint`
150+
3. **Cookies**: `user-locale` cookie
151+
4. **HTTP Headers**: `Accept-Language` header
152+
5. **Fallback Locale**: As configured in module options
153+
6. **Default Locale**: As configured in module options
154+
7. **Hardcoded Fallback**: `'en'`
155+
156+
> **Note**: The locale detection logic is shared between `useLocaleServerMiddleware` and `useTranslationServerMiddleware` to ensure consistency across the module.
157+
158+
## 📋 Advanced Usage Examples
159+
160+
### Conditional Response Based on Locale
161+
162+
```typescript
163+
import { defineEventHandler } from 'h3'
164+
165+
export default defineEventHandler((event) => {
166+
const { current, isDefault, locale } = useLocaleServerMiddleware(event)
167+
168+
// Return different content based on locale
169+
if (current === 'ru') {
170+
return {
171+
message: 'Привет, мир!',
172+
locale: current,
173+
isDefault
174+
}
175+
}
176+
177+
if (current === 'de') {
178+
return {
179+
message: 'Hallo, Welt!',
180+
locale: current,
181+
isDefault
182+
}
183+
}
184+
185+
// Default English response
186+
return {
187+
message: 'Hello, World!',
188+
locale: current,
189+
isDefault
190+
}
191+
})
192+
```
193+
194+
### Custom Locale Detection
195+
196+
```typescript
197+
import { defineEventHandler } from 'h3'
198+
199+
export default defineEventHandler((event) => {
200+
// Force German locale with English as fallback
201+
const { current, isDefault, locale } = useLocaleServerMiddleware(event, 'en', 'de')
202+
203+
return {
204+
message: 'Hallo, Welt!',
205+
locale: current,
206+
isDefault: false // Will be false since we forced German
207+
}
208+
})
209+
```
210+
211+
### Locale-Aware API with Validation
212+
213+
```typescript
214+
import { defineEventHandler, createError } from 'h3'
215+
216+
export default defineEventHandler((event) => {
217+
const { current, available, locale } = useLocaleServerMiddleware(event)
218+
219+
// Validate if the detected locale is supported
220+
if (!available.includes(current)) {
221+
throw createError({
222+
statusCode: 400,
223+
statusMessage: `Unsupported locale: ${current}. Available locales: ${available.join(', ')}`
224+
})
225+
}
226+
227+
// Return locale-specific configuration
228+
return {
229+
locale: current,
230+
direction: locale?.dir || 'ltr',
231+
displayName: locale?.displayName || current,
232+
availableLocales: available
233+
}
234+
})
235+
```
236+
237+
### Integration with Translation Middleware
238+
239+
You can combine locale information with translation middleware for comprehensive internationalization:
240+
241+
```typescript
242+
import { defineEventHandler } from 'h3'
243+
244+
export default defineEventHandler(async (event) => {
245+
const localeInfo = useLocaleServerMiddleware(event)
246+
const t = await useTranslationServerMiddleware(event)
247+
248+
return {
249+
locale: localeInfo.current,
250+
message: t('welcome_message'),
251+
availableLocales: localeInfo.available,
252+
isDefault: localeInfo.isDefault
253+
}
254+
})
255+
```
256+
257+
## 📝 Best Practices
258+
259+
1. **Always validate locales**: Check if the detected locale is in your available locales list
260+
2. **Use fallback logic**: Provide sensible defaults when locale detection fails
261+
3. **Cache locale information**: For performance-critical applications, consider caching locale detection results
262+
4. **Handle edge cases**: Account for unsupported locales and provide appropriate error responses
263+
5. **Combine with translations**: Use locale information alongside translation middleware for complete i18n support
70264

71-
## 📋 Detecting Locale
265+
## 🚀 Performance Considerations
72266

73-
The middleware automatically determines the user's locale using a fallback chain:
74-
1. **Query Parameter**: `?locale=fr`
75-
2. **Cookie**: `user-locale`
76-
3. **HTTP Header**: `Accept-Language`
77-
4. **Default Locale**: As defined in useTranslationServerMiddleware param.
267+
- Both middleware functions are lightweight and designed for fast execution
268+
- Locale detection uses efficient fallback chains
269+
- No external API calls are made during locale detection
270+
- Results are computed synchronously for optimal performance

0 commit comments

Comments
 (0)