feat(lang): Automatische Spracherkennung implementieren

Implementiert die serverseitige Spracherkennung basierend auf dem
Accept-Language-Header des Browsers. Das Backend liefert nun die
index.html-Datei dynamisch mit dem korrekten lang-Attribut aus.

Das Frontend-JavaScript wurde aktualisiert, um das lang-Attribut des
HTML-Dokuments zu berücksichtigen und eine konsistente
Sprachbehandlung zu gewährleisten.

Zusätzlich behebt dieser Commit einen Fehler, bei dem die
Beispiel-Vorschläge nach dem Hinzufügen eines Artikels nicht
ausgeblendet wurden. Außerdem wird die Funktionalität des
"Hinzufügen"-Buttons und der Enter-Taste wiederhergestellt.
This commit is contained in:
2025-10-28 21:41:17 +01:00
parent 7b484d1c33
commit 58836f7af6
2 changed files with 30 additions and 4 deletions

25
main.py
View File

@@ -12,6 +12,7 @@ from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.staticfiles import StaticFiles
from translations import get_standard_items, get_all_translations
from fastapi import FastAPI, HTTPException, Depends, status, WebSocket, WebSocketDisconnect, Request
from fastapi.responses import HTMLResponse
app = FastAPI()
@@ -639,4 +640,26 @@ async def websocket_endpoint(websocket: WebSocket, token: str):
# Create data directory if it doesn't exist
os.makedirs(os.path.dirname(DB_FILE), exist_ok=True)
init_db()
app.mount("/", StaticFiles(directory="static", html=True), name="static")
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/{full_path:path}", response_class=HTMLResponse)
async def catch_all(request: Request, full_path: str):
lang = "de" # default
accept_language = request.headers.get("accept-language")
if accept_language:
langs = accept_language.split(",")[0]
if "de" in langs:
lang = "de"
elif "en" in langs:
lang = "en"
with open("static/index.html") as f:
html_content = f.read()
# Replace lang and favicon path
html_content = html_content.replace('lang="de"', f'lang="{lang}"')
html_content = html_content.replace(
'href="/favicon.png"', 'href="/static/favicon.png"')
return HTMLResponse(content=html_content)

View File

@@ -467,7 +467,7 @@
}
async function fetchTranslations() {
const lang = navigator.language.startsWith('de') ? 'de' : 'en';
const lang = document.documentElement.lang;
const response = await fetch(`/api/translations/${lang}?_=${new Date().getTime()}`);
translations = await response.json();
updateUIWithTranslations();
@@ -531,7 +531,7 @@
}
async function fetchStandardItems() {
const lang = navigator.language.startsWith('de') ? 'de' : 'en';
const lang = document.documentElement.lang;
const response = await fetch(`/api/standard-items/${lang}`);
standardItems = await response.json();
}
@@ -707,11 +707,12 @@
}
itemNameInput.value = newValue;
suggestionBox.innerHTML = '';
suggestionInfo.style.display = 'none';
itemNameInput.focus();
}
async function sendNotification() {
const lang = navigator.language.startsWith('de') ? 'de' : 'en';
const lang = document.documentElement.lang;
notifyBtn.disabled = true;
notifyBtn.textContent = translations.sending_notification || 'Sending...';
@@ -828,12 +829,14 @@
await addItemsFromInput(itemNameInput.value, true);
itemNameInput.value = '';
suggestionBox.innerHTML = '';
suggestionInfo.style.display = 'none';
});
addOneButton.addEventListener('click', async () => {
await addItemsFromInput(itemNameInput.value, false);
itemNameInput.value = '';
suggestionBox.innerHTML = '';
suggestionInfo.style.display = 'none';
});
itemNameInput.addEventListener('input', handleInputChange);