# Locale Parameters API Documentation ## Overview The Smokesignal event filtering system provides comprehensive internationalization (i18n) support through locale-aware API endpoints. This document describes how to use locale parameters in filtering endpoints and configure i18n middleware. ## Supported Languages - **en-us**: English (United States) - Default - **fr-ca**: French (Canada) with gender support ## API Endpoints with Locale Support ### Filter Events Endpoint **URL**: `GET /events` **Locale Detection Priority**: 1. User profile language settings (authenticated users) 2. `language` cookie value 3. `Accept-Language` HTTP header 4. Default fallback to `en-US` #### Query Parameters All standard filtering parameters are supported with locale-aware responses: ``` GET /events?mode=inperson&status=scheduled&date_range=today ``` #### Headers ##### Accept-Language Header The system parses standard Accept-Language headers with quality values: ```http Accept-Language: fr-CA,fr;q=0.9,en;q=0.8 Accept-Language: en-US,en;q=0.9 Accept-Language: es-ES,es;q=0.9,en;q=0.8 ``` **Examples**: - `fr-CA,fr;q=0.9,en;q=0.8` → Returns French Canadian interface - `en-US,en;q=0.9` → Returns English interface - `invalid-locale` → Falls back to English ##### HTMX Language Headers For HTMX requests, language context is preserved: ```http HX-Request: true HX-Current-Language: fr-CA Accept-Language: fr-CA,fr;q=0.9,en;q=0.8 ``` #### Response Format The API returns locale-aware responses with: - **Translated facet labels**: Categories, date ranges, status options - **Localized display names**: Event modes, status values - **Proper pluralization**: Event counts, result summaries - **Currency formatting**: Price displays (if applicable) - **Date formatting**: Locale-specific date representations #### Example Request/Response **Request**: ```http GET /events?mode=inperson&date_range=today Accept-Language: fr-CA,fr;q=0.9,en;q=0.8 ``` **Response** (French Canadian): ```json { "events": [...], "facets": { "modes": [ { "value": "inperson", "count": 15, "i18n_key": "mode-inperson", "display_name": "En personne" } ], "date_ranges": [ { "value": "today", "count": 8, "i18n_key": "date-range-today", "display_name": "Aujourd'hui" } ] }, "total_count": 15, "current_locale": "fr-CA" } ``` ### Facets-Only Endpoint **URL**: `GET /events/facets` Returns only facet data with translations: ```http GET /events/facets?mode=online Accept-Language: fr-CA ``` ### Event Suggestions Endpoint **URL**: `GET /events/suggestions` Autocomplete suggestions with locale-aware labels: ```http GET /events/suggestions?q=concert Accept-Language: fr-CA ``` ## Cache Behavior The system uses locale-aware caching to ensure optimal performance: ### Cache Key Format ``` filter:{criteria_hash}:{locale} ``` **Examples**: - `filter:abc123:en-us` - English cache entry - `filter:abc123:fr-ca` - French Canadian cache entry ### Cache Isolation Each locale maintains separate cache entries to prevent: - Translation leakage between languages - Incorrect facet display names - Inconsistent user experiences ## Error Handling ### Invalid Locale Fallback When an unsupported locale is requested: 1. **Log warning**: Invalid locale detected 2. **Fallback**: Automatically use `en-US` 3. **Continue processing**: No error returned to client ### Malformed Headers The system gracefully handles: - Empty Accept-Language headers - Malformed quality values - Invalid language tags - Excessively long header values ### Error Response Format Error messages respect the user's language preference: ```json { "error": "Invalid filter criteria", "error_code": "INVALID_CRITERIA", "locale": "fr-CA", "message": "Critères de filtre invalides" } ``` ## Performance Considerations ### Optimizations - **Static Translation Loading**: Translations compiled into binary - **Locale-Specific Caching**: Separate cache entries per locale - **Lazy Loading**: Translations loaded on demand - **Memory Efficiency**: Shared FluentBundle resources ### Benchmarks Typical performance impact of i18n features: - **Translation lookup**: < 1μs - **Facet calculation with locale**: +5-10ms - **Cache key generation**: < 100ns - **Accept-Language parsing**: < 10μs ## Integration Examples ### Frontend JavaScript ```javascript // Set user language preference fetch('/events?mode=online', { headers: { 'Accept-Language': navigator.language || 'en-US' } }); // HTMX with language context
``` ### cURL Examples ```bash # Request with French Canadian preference curl -H "Accept-Language: fr-CA,fr;q=0.9,en;q=0.8" \ "https://api.example.com/events?mode=inperson" # Request with quality values curl -H "Accept-Language: en-US,en;q=0.9,fr;q=0.8" \ "https://api.example.com/events/facets" # HTMX request with language context curl -H "HX-Request: true" \ -H "HX-Current-Language: fr-CA" \ -H "Accept-Language: fr-CA" \ "https://api.example.com/events" ``` ### Server Integration ```rust use smokesignal::http::middleware_i18n::Language; use smokesignal::filtering::FilteringService; // Handler with automatic locale extraction pub async fn handle_filter_events( ctx: UserRequestContext, Extension(filtering_service): Extension, // Language automatically extracted from headers/cookies/profile language: Language, query: Query, ) -> Result { let locale_str = language.to_string(); // Use locale-aware filtering let results = filtering_service .filter_events_with_locale(&criteria, &options, &locale_str) .await?; // Template rendering with i18n context let html = renderer.render("events", &context)?; Ok(html) } ``` ## Security Considerations ### Input Validation - **Locale strings**: Validated against supported languages - **Header parsing**: Protected against injection attacks - **Cache keys**: Sanitized to prevent cache poisoning ### Rate Limiting Locale-aware rate limiting considers: - Language-specific cache effectiveness - Regional usage patterns - Translation server load ## Migration Guide ### Adding New Languages 1. **Create translation files**: Add `.ftl` files in `i18n/{locale}/` 2. **Update supported languages**: Modify `SUPPORTED_LANGUAGES` constant 3. **Test translation coverage**: Run `cargo test i18n` 4. **Deploy**: Translation files are embedded in binary ### Upgrading Existing Code ```rust // Old: No locale support let results = filtering_service.filter_events(&criteria).await?; // New: With locale support let results = filtering_service .filter_events_with_locale(&criteria, &options, &locale) .await?; ``` ## Troubleshooting ### Common Issues **Issue**: Translations not appearing - **Check**: Translation files in correct directory structure - **Verify**: Locale string format (`en-US` not `en_US`) - **Test**: Use browser dev tools to inspect Accept-Language header **Issue**: Cache inconsistency between languages - **Solution**: Clear locale-specific cache entries - **Command**: `FLUSHDB` or restart Redis/Valkey **Issue**: Performance degradation - **Monitor**: Cache hit rates per locale - **Optimize**: Translation loading patterns - **Scale**: Consider translation CDN for high-traffic deployments ### Debug Information Enable debug logging for i18n operations: ```bash RUST_LOG=smokesignal::i18n=debug,smokesignal::filtering=debug cargo run ``` **Log Examples**: ``` DEBUG smokesignal::i18n: Language detected from header: fr-CA DEBUG smokesignal::filtering: Cache key generated: filter:abc123:fr-ca DEBUG smokesignal::i18n: Translation lookup: date-range-today -> Aujourd'hui ```