feat: add language detection middleware for request handling

- Implemented LanguageMiddleware to determine the user's language based on query parameters, Accept-Language header, or IP address.
- Updated the FastAPI app to include the middleware and pass the detected language to templates.
- Modified base.html to dynamically set the HTML language attribute based on the detected language.
This commit is contained in:
Miu Li 2025-06-17 07:48:38 +08:00
parent eb4d670ee0
commit 8f202262ee
2 changed files with 57 additions and 6 deletions

61
app.py
View File

@ -15,10 +15,8 @@ from datetime import datetime, UTC
import csv
from io import StringIO
from typing import Dict, List
app = FastAPI()
templates = Jinja2Templates(directory="templates")
app.mount("/static", StaticFiles(directory="static"), name="static")
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
# Initialize GeoIP2 reader
try:
@ -42,6 +40,58 @@ def get_location_from_ip(ip):
print(f"Error getting location for IP {ip}: {e}")
return None
class LanguageMiddleware(BaseHTTPMiddleware):
def __init__(self, app: ASGIApp):
super().__init__(app)
self.default_language = "en" # Default language
self.supported_languages = ["zh", "en"] # Supported languages
async def dispatch(self, request: Request, call_next):
# Get language from query parameter
lang = request.query_params.get("lang")
# If no language in query params, try to get from Accept-Language header
if not lang:
accept_language = request.headers.get("accept-language", "")
if accept_language:
# Parse Accept-Language header and get the first language
lang = accept_language.split(",")[0].split(";")[0].strip()[:2]
# If still no language, try to detect from IP
if not lang and geoip_reader:
try:
ip = request.headers.get("X-Forwarded-For", "").split(",")[0].strip() or \
request.headers.get("X-Real-IP", "") or \
request.client.host
response = geoip_reader.city(ip)
country_to_lang = { # Map country to language
"China": "zh",
"Hong Kong": "zh",
"Taiwan": "zh",
"Macau": "zh",
"United States": "en",
"United Kingdom": "en",
}
lang = country_to_lang.get(response.country.name, self.default_language)
except:
lang = self.default_language
# Ensure language is supported
if lang not in self.supported_languages:
lang = self.default_language
# Add language to request state
request.state.language = lang
# Continue processing the request
response = await call_next(request)
return response
app = FastAPI()
app.add_middleware(LanguageMiddleware)
templates = Jinja2Templates(directory="templates")
app.mount("/static", StaticFiles(directory="static"), name="static")
# 加载所有问卷数据
def load_all_scales():
scales = {}
@ -78,7 +128,8 @@ async def index(request: Request):
return templates.TemplateResponse("index.html", {
"request": request,
"tags": tags,
"readme_content": readme_content # 新增模板变量
"readme_content": readme_content,
"language": request.state.language # Pass language to template
})
@app.get("/tag/{tag}", response_class=HTMLResponse)

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<!-- <html lang="zh"> -->
<html lang="{{ language }}">
<head>
<meta charset="UTF-8">