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 import csv
from io import StringIO from io import StringIO
from typing import Dict, List from typing import Dict, List
from starlette.middleware.base import BaseHTTPMiddleware
app = FastAPI() from starlette.types import ASGIApp
templates = Jinja2Templates(directory="templates")
app.mount("/static", StaticFiles(directory="static"), name="static")
# Initialize GeoIP2 reader # Initialize GeoIP2 reader
try: try:
@ -42,6 +40,58 @@ def get_location_from_ip(ip):
print(f"Error getting location for IP {ip}: {e}") print(f"Error getting location for IP {ip}: {e}")
return None 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(): def load_all_scales():
scales = {} scales = {}
@ -78,7 +128,8 @@ async def index(request: Request):
return templates.TemplateResponse("index.html", { return templates.TemplateResponse("index.html", {
"request": request, "request": request,
"tags": tags, "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) @app.get("/tag/{tag}", response_class=HTMLResponse)

View File

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