Humainoid-robotics / backend /src /api /translation_middleware.py
Awais
Restore original HF deployment with RAG search fallback fix
04dc214
Raw
History Blame Contribute Delete
5.27 kB
"""
Translation middleware for FastAPI
Handles language detection and response translation
"""
from fastapi import Request
from typing import Optional
import re
class TranslationMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
if scope["type"] == "http":
request = Request(scope, receive)
# Detect language from various sources
lang = self.detect_language(request)
# Add language to request state
if "state" not in scope:
scope["state"] = {}
scope["state"]["lang"] = lang
await self.app(scope, receive, send)
def detect_language(self, request: Request) -> str:
"""
Detect language from request
Priority: 1. User preference (via API) 2. Query param 3. Header 4. Cookie 5. Default
"""
# 1. Check for user preference in path (e.g., /api/i18n/translate?lang=ur)
lang = request.query_params.get("lang")
if lang:
validated_lang = self.validate_language(lang)
if validated_lang != "en": # Only return if it's a valid non-default language
return validated_lang
# 2. Check for language in request path patterns that might indicate preferred language
# This could come from frontend routing or user preferences stored in session
# 3. Check Accept-Language header
accept_language = request.headers.get("Accept-Language")
if accept_language:
# Parse Accept-Language header (e.g., "en-US,en;q=0.9,ur;q=0.8")
languages = self.parse_accept_language(accept_language)
if languages:
for lang_code in languages:
validated_lang = self.validate_language(lang_code)
if validated_lang != "en": # Prioritize non-English languages if user specified them
return validated_lang
# 4. Check cookie (could be set by frontend based on user selection)
lang = request.cookies.get("NEXT_LOCALE") or request.cookies.get("locale")
if lang:
validated_lang = self.validate_language(lang)
if validated_lang != "en":
return validated_lang
# 5. Default to English
return "en"
def parse_accept_language(self, header: str) -> list:
"""Parse Accept-Language header and return sorted list of languages by priority"""
languages = []
# Split by comma and sort by quality value (q=x.x)
items = []
for item in header.split(","):
parts = item.strip().split(";")
lang = parts[0].strip()
quality = 1.0 # Default quality
# Extract quality value if present (e.g., "ur;q=0.8")
for part in parts[1:]:
if part.strip().startswith("q="):
try:
quality = float(part.strip()[2:])
except ValueError:
pass
items.append((lang, quality))
# Sort by quality (highest first)
items.sort(key=lambda x: x[1], reverse=True)
for lang, _ in items:
# Extract language code (e.g., "en-US" -> "en")
lang_code = lang.split("-")[0]
if lang_code not in languages: # Avoid duplicates
languages.append(lang_code)
return languages
def validate_language(self, lang: str) -> str:
"""Validate and normalize language code"""
# List of supported languages
supported = ['en', 'ur', 'ur-PK', 'ar', 'es', 'fr', 'de', 'zh', 'hi', 'pt', 'ru', 'ja']
if lang in supported:
return lang
# Handle common variations and aliases
lang_aliases = {
'urdu': 'ur',
'roman-urdu': 'ur-PK',
'roman_urdu': 'ur-PK',
'ur-pk': 'ur-PK',
'uk': 'ur',
'pakistani': 'ur-PK',
'english': 'en',
'spanish': 'es',
'french': 'fr',
'german': 'de',
'chinese': 'zh',
'japanese': 'ja',
'hindi': 'hi',
'portuguese': 'pt',
'russian': 'ru',
'arabic': 'ar',
}
lang_lower = lang.lower().replace('_', '-').strip()
if lang_lower in supported:
return lang_lower
if lang_lower in lang_aliases:
return lang_aliases[lang_lower]
# Handle locale variants (e.g., ur_PK -> ur-PK)
if '_' in lang_lower:
locale_variant = lang_lower.replace('_', '-')
if locale_variant in supported:
return locale_variant
# Try to find partial match
for supported_lang in supported:
if lang_lower == supported_lang.lower():
return supported_lang
# Default to English
return "en"
def get_request_language(request: Request) -> str:
"""Helper function to get language from request state"""
if hasattr(request.state, 'lang'):
return getattr(request.state, "lang", "en")
# Fallback for cases where middleware didn't set the language
return "en"