Source code for mindroot.coreplugins.l8n.middleware
fromfastapiimportRequesttry:from.language_detectionimport(_parse_accept_language_header,get_fallback_language,set_language_for_request)exceptImportError:# For standalone testingfromlanguage_detectionimport(_parse_accept_language_header,get_fallback_language,set_language_for_request)importos# Global variable to store the current request language# This will be set by the middleware for each request_current_request_language=None
[docs]defget_request_language()->str:""" Get the language that was detected for the current request. This function is called by the monkey patch system to get the language for template translation. Returns: Language code for the current request """global_current_request_languageprint(f"L8n: Current request language is '{_current_request_language}'")# If we have a request-specific language, use itif_current_request_language:return_current_request_language# Fallback to environment variable or defaultprint("L8n: No request language set, falling back to environment variable or default")returnos.environ.get('MINDROOT_LANGUAGE','en')
[docs]defdetect_language_from_request(request:Request)->str:""" Detect the preferred language from a FastAPI request. Checks multiple sources in order of priority: 1. URL parameter (?lang=es) 2. Cookie value (mindroot_language) 3. Accept-Language header 4. Environment variable 5. Default to 'en' Args: request: FastAPI Request object Returns: Detected language code """# 1. Check URL parameter first (highest priority)print(f"L8n: Checking URL parameters for language: {request.query_params}")url_lang=request.query_params.get('lang')ifurl_lang:returnget_fallback_language(url_lang.lower())# 2. Check cookie valueprint(f"L8n: Checking cookies for language: {request.cookies}")cookie_lang=request.cookies.get('mindroot_language')ifcookie_lang:print(f"L8n: Found language in cookie: {cookie_lang}")returnget_fallback_language(cookie_lang.lower())# 3. Check Accept-Language headerprint(f"L8n: Accept-Language header: {request.headers.get('accept-language')}")accept_language=request.headers.get('accept-language')ifaccept_language:print(f"L8n: Parsing Accept-Language header: {accept_language}")parsed_lang=_parse_accept_language_header(accept_language)ifparsed_lang:print(f"L8n: Parsed language from header: {parsed_lang}")returnget_fallback_language(parsed_lang)# 4. Check environment variableenv_lang=os.environ.get('MINDROOT_LANGUAGE')ifenv_lang:returnget_fallback_language(env_lang.lower())# 5. Default to Englishreturn'en'
[docs]asyncdefmiddleware(request:Request,call_next):""" L8n middleware for language detection and setting. This middleware runs early in the request pipeline to: 1. Detect the preferred language for the request 2. Store it globally for use by the template system 3. Set it in the request state for other components Args: request: FastAPI Request object call_next: Next middleware/handler in the chain Returns: Response from the next handler """global_current_request_languagetry:print("L8n middleware: Starting language detection")# Detect the language for this requestdetected_language=detect_language_from_request(request)print(f"L8n: Detected language '{detected_language}' for {request.url.path}")# Store it globally for the template system_current_request_language=detected_language# Also store it in request state for other componentsrequest.state.language=detected_language# Set it using the language detection systemset_language_for_request(detected_language)# Debug logging (can be removed in production)print(f"L8n: Detected language '{detected_language}' for {request.url.path}")# Process the requestresponse=awaitcall_next(request)# Optionally set a cookie to remember the language preference# Only set if it was explicitly requested via URL parameterifrequest.query_params.get('lang'):response.set_cookie(key="mindroot_language",value=detected_language,max_age=30*24*60*60,# 30 dayshttponly=True,samesite="lax")returnresponseexceptExceptionase:print(f"L8n middleware error: {e}")# If there's an error, continue with default language_current_request_language='en'request.state.language='en'returnawaitcall_next(request)finally:# Clean up the global variable after the request_current_request_language=None