# smokesignal Deployment Guide - I18n Configuration ## Overview This guide covers the deployment-specific aspects of smokesignal's internationalization system, including environment configuration, translation file deployment, cache optimization, and production monitoring. ## Environment Variables ### I18n-Specific Configuration #### Required Variables ```bash # Default language for the application DEFAULT_LOCALE=en-us # Supported locales (comma-separated) SUPPORTED_LOCALES=en-us,fr-ca # Translation files directory (relative to binary) I18N_DIR=./i18n # Enable/disable translation caching I18N_CACHE_ENABLED=true # Translation cache TTL in seconds (default: 3600) I18N_CACHE_TTL=3600 ``` #### Optional Variables ```bash # Fallback locale when translation is missing FALLBACK_LOCALE=en-us # Enable translation debugging I18N_DEBUG=false # Gender context support GENDER_CONTEXT_ENABLED=true # Translation validation on startup I18N_VALIDATE_ON_STARTUP=true # Maximum translation key length I18N_MAX_KEY_LENGTH=255 ``` ### Cache Configuration for Multi-locale #### Redis/Valkey Settings ```bash # Cache prefix for locale-specific entries CACHE_LOCALE_PREFIX=locale # Separate cache database for i18n (Redis DB number) I18N_CACHE_DB=2 # Cache key format for translations # {locale}:{key}:{hash} I18N_CACHE_KEY_FORMAT="{locale}:tr:{key}:{hash}" # Cache key format for facets # {locale}:{facet_type}:{criteria_hash} FACET_CACHE_KEY_FORMAT="{locale}:facet:{type}:{hash}" # Cache key format for filter results # {locale}:{filter_criteria_hash} FILTER_CACHE_KEY_FORMAT="{locale}:filter:{hash}" ``` #### Cache Optimization ```bash # Enable cache compression for translation data CACHE_COMPRESSION_ENABLED=true # Cache memory allocation per locale (MB) CACHE_MEMORY_PER_LOCALE=64 # Cache eviction policy for i18n data I18N_CACHE_EVICTION_POLICY=lru # Preload translations into cache on startup I18N_PRELOAD_CACHE=true ``` ## Translation File Deployment ### Directory Structure Ensure your deployment includes the complete i18n directory structure: ``` deployment/ ├── smokesignal (binary) ├── i18n/ │ ├── en-us/ │ │ ├── filters.ftl │ │ ├── ui.ftl │ │ ├── events.ftl │ │ └── errors.ftl │ └── fr-ca/ │ ├── filters.ftl │ ├── ui.ftl │ ├── events.ftl │ └── errors.ftl ├── templates/ └── static/ ``` ### Container Deployment (Docker) #### Dockerfile Example ```dockerfile FROM rust:1.86-slim as builder # Build application WORKDIR /app COPY . . RUN cargo build --release FROM debian:bookworm-slim # Install runtime dependencies RUN apt-get update && apt-get install -y \ ca-certificates \ && rm -rf /var/lib/apt/lists/* # Copy binary and assets COPY --from=builder /app/target/release/smokesignal /usr/local/bin/ COPY --from=builder /app/i18n/ /app/i18n/ COPY --from=builder /app/templates/ /app/templates/ COPY --from=builder /app/static/ /app/static/ # Set working directory WORKDIR /app # Set environment variables ENV I18N_DIR=/app/i18n ENV DEFAULT_LOCALE=en-us ENV SUPPORTED_LOCALES=en-us,fr-ca EXPOSE 3000 CMD ["smokesignal"] ``` #### Docker Compose Example ```yaml version: '3.8' services: smokesignal: build: . ports: - "3000:3000" environment: # Database DATABASE_URL: postgresql://user:pass@postgres:5432/smokesignal # Cache REDIS_URL: redis://redis:6379 # I18n Configuration DEFAULT_LOCALE: en-us SUPPORTED_LOCALES: en-us,fr-ca I18N_DIR: /app/i18n I18N_CACHE_ENABLED: true I18N_CACHE_TTL: 3600 # Performance CACHE_LOCALE_PREFIX: locale I18N_CACHE_DB: 2 I18N_PRELOAD_CACHE: true volumes: - ./i18n:/app/i18n:ro depends_on: - postgres - redis postgres: image: postgres:16 environment: POSTGRES_DB: smokesignal POSTGRES_USER: user POSTGRES_PASSWORD: pass volumes: - postgres_data:/var/lib/postgresql/data redis: image: valkey/valkey:7 volumes: - redis_data:/data volumes: postgres_data: redis_data: ``` ### Kubernetes Deployment #### ConfigMap for Translations ```yaml apiVersion: v1 kind: ConfigMap metadata: name: smokesignal-i18n data: # Mount translation files as config filters-en-us.ftl: | # English filter translations filter-title = Filter Events # ... rest of translations filters-fr-ca.ftl: | # French filter translations filter-title = Filtrer les événements # ... rest of translations ``` #### Deployment Configuration ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: smokesignal spec: replicas: 3 selector: matchLabels: app: smokesignal template: metadata: labels: app: smokesignal spec: containers: - name: smokesignal image: smokesignal:latest ports: - containerPort: 3000 env: - name: DEFAULT_LOCALE value: "en-us" - name: SUPPORTED_LOCALES value: "en-us,fr-ca" - name: I18N_DIR value: "/app/i18n" - name: I18N_CACHE_ENABLED value: "true" - name: REDIS_URL valueFrom: secretKeyRef: name: smokesignal-secrets key: redis-url volumeMounts: - name: i18n-volume mountPath: /app/i18n readOnly: true volumes: - name: i18n-volume configMap: name: smokesignal-i18n ``` ## Performance Monitoring for I18n Features ### Metrics to Monitor #### Response Time Metrics ```bash # Average response time by locale smokesignal_http_request_duration_seconds{locale="en-us"} smokesignal_http_request_duration_seconds{locale="fr-ca"} # Cache hit rates for translations smokesignal_cache_hits_total{type="translation", locale="en-us"} smokesignal_cache_hits_total{type="translation", locale="fr-ca"} # Cache miss rates smokesignal_cache_misses_total{type="translation", locale="en-us"} smokesignal_cache_misses_total{type="translation", locale="fr-ca"} ``` #### Memory Usage Metrics ```bash # Memory usage per locale smokesignal_memory_usage_bytes{component="i18n", locale="en-us"} smokesignal_memory_usage_bytes{component="i18n", locale="fr-ca"} # Translation cache size smokesignal_cache_size_bytes{type="translation"} # Active translations loaded smokesignal_translations_loaded_total{locale="en-us"} smokesignal_translations_loaded_total{locale="fr-ca"} ``` ### Prometheus Configuration Add to your `prometheus.yml`: ```yaml global: scrape_interval: 15s scrape_configs: - job_name: 'smokesignal' static_configs: - targets: ['smokesignal:3000'] metrics_path: /metrics scrape_interval: 30s ``` ### Grafana Dashboard #### Translation Performance Panel ```json { "dashboard": { "title": "smokesignal I18n Performance", "panels": [ { "title": "Response Time by Locale", "type": "graph", "targets": [ { "expr": "avg(smokesignal_http_request_duration_seconds) by (locale)", "legendFormat": "{{locale}}" } ] }, { "title": "Cache Hit Rate", "type": "stat", "targets": [ { "expr": "rate(smokesignal_cache_hits_total[5m]) / (rate(smokesignal_cache_hits_total[5m]) + rate(smokesignal_cache_misses_total[5m]))" } ] }, { "title": "Memory Usage by Locale", "type": "graph", "targets": [ { "expr": "smokesignal_memory_usage_bytes{component=\"i18n\"}", "legendFormat": "{{locale}}" } ] } ] } } ``` ### Health Checks #### Translation Availability Check ```bash #!/bin/bash # check_translations.sh curl -f -H "Accept-Language: en-US" http://localhost:3000/health/translations curl -f -H "Accept-Language: fr-CA" http://localhost:3000/health/translations if [ $? -eq 0 ]; then echo "All translations available" exit 0 else echo "Translation health check failed" exit 1 fi ``` #### Cache Connectivity Check ```bash #!/bin/bash # check_i18n_cache.sh redis-cli -h redis ping redis-cli -h redis --scan --pattern "locale:*" | head -5 if [ $? -eq 0 ]; then echo "I18n cache healthy" exit 0 else echo "I18n cache check failed" exit 1 fi ``` ## Load Balancer Configuration ### Nginx with Locale-Aware Routing ```nginx upstream smokesignal_backend { server smokesignal-1:3000; server smokesignal-2:3000; server smokesignal-3:3000; } map $http_accept_language $locale { default en-us; ~*fr-ca fr-ca; ~*fr fr-ca; } server { listen 80; server_name smokesignal.example.com; # Add locale header for backend location / { proxy_pass http://smokesignal_backend; proxy_set_header Accept-Language $http_accept_language; proxy_set_header X-Detected-Locale $locale; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Cache static assets by locale location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ { proxy_pass http://smokesignal_backend; expires 1y; add_header Cache-Control "public, immutable"; add_header Vary "Accept-Language"; } } } ``` ### CDN Configuration #### CloudFlare Settings ```javascript // CloudFlare Worker for locale detection addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const url = new URL(request.url) const acceptLanguage = request.headers.get('Accept-Language') || '' // Detect locale from Accept-Language header let locale = 'en-us' if (acceptLanguage.includes('fr-ca') || acceptLanguage.includes('fr-CA')) { locale = 'fr-ca' } // Add locale to cache key const cacheKey = new Request(url.toString(), { headers: { ...request.headers, 'X-Locale': locale } }) // Check cache first const cache = caches.default let response = await cache.match(cacheKey) if (!response) { // Forward to origin with locale header const modifiedRequest = new Request(request, { headers: { ...request.headers, 'X-Detected-Locale': locale } }) response = await fetch(modifiedRequest) // Cache response with locale in key if (response.ok) { response = new Response(response.body, { status: response.status, statusText: response.statusText, headers: { ...response.headers, 'Cache-Control': 'public, max-age=3600', 'Vary': 'Accept-Language' } }) event.waitUntil(cache.put(cacheKey, response.clone())) } } return response } ``` ## Backup and Recovery ### Translation Files Backup ```bash #!/bin/bash # backup_translations.sh BACKUP_DIR="/backups/i18n/$(date +%Y-%m-%d)" mkdir -p "$BACKUP_DIR" # Backup translation files tar -czf "$BACKUP_DIR/translations.tar.gz" /app/i18n/ # Backup translation cache (if applicable) redis-cli --rdb "$BACKUP_DIR/translation_cache.rdb" echo "I18n backup completed: $BACKUP_DIR" ``` ### Disaster Recovery ```bash #!/bin/bash # restore_translations.sh BACKUP_DIR="$1" if [ -z "$BACKUP_DIR" ]; then echo "Usage: $0 " exit 1 fi # Restore translation files tar -xzf "$BACKUP_DIR/translations.tar.gz" -C / # Restore cache redis-cli FLUSHDB redis-cli --pipe < "$BACKUP_DIR/translation_cache.rdb" # Restart application systemctl restart smokesignal echo "I18n restoration completed" ``` ## Security Considerations ### Translation File Security 1. **File Permissions**: Ensure translation files are read-only for the application user 2. **Input Validation**: Validate locale parameters to prevent directory traversal 3. **Content Security**: Sanitize any user-generated content in translations ### Cache Security 1. **Redis Security**: Use authentication and encryption for Redis connections 2. **Cache Isolation**: Use separate cache databases for different environments 3. **Key Validation**: Validate cache keys to prevent injection attacks ## Troubleshooting ### Common Deployment Issues #### Translations Not Loading ```bash # Check file permissions ls -la /app/i18n/ find /app/i18n/ -name "*.ftl" -type f # Check environment variables env | grep I18N # Check application logs journalctl -u smokesignal -f | grep i18n ``` #### Cache Issues ```bash # Check Redis connectivity redis-cli ping # Check cache keys redis-cli --scan --pattern "locale:*" # Clear translation cache redis-cli FLUSHDB 2 ``` #### Performance Issues ```bash # Monitor response times by locale curl -w "%{time_total}" -H "Accept-Language: en-US" http://localhost:3000/events curl -w "%{time_total}" -H "Accept-Language: fr-CA" http://localhost:3000/events # Check memory usage ps aux | grep smokesignal free -h ``` This deployment guide ensures that smokesignal's i18n features work reliably in production environments with proper monitoring, caching, and security measures.