mirror of
https://github.com/rangermix/TwitchDropsMiner.git
synced 2026-05-26 07:08:04 +00:00
Add proper i18n support with language selection in web GUI
The application already had a complete i18n system with 18+ language translation files, but the web GUI only showed English as an option. Changes: - Add /api/languages endpoint to fetch available languages from translator - Update SettingsUpdate model to include language field - Add SettingsManager.get_languages() method to expose available languages - Update SettingsManager to handle language changes via translator.set_language() - Populate language dropdown dynamically from available translations on page load - Add auto-save for language changes in frontend - Language is persisted to settings.json and loaded on startup The translator is initialized with the saved language at application startup (already implemented in src/__main__.py lines 101-105). Available languages include: English, Français, Deutsch, Español, Italiano, Português, Polski, Русский, Українська, 简体中文, 繁體中文, 日本語, العربية, Türkçe, Română, Nederlandse, Dansk, Čeština, Indonesian 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,7 @@ class ChannelSelectRequest(BaseModel):
|
||||
class SettingsUpdate(BaseModel):
|
||||
games_to_watch: list[str] | None = None
|
||||
dark_mode: bool | None = None
|
||||
language: str | None = None
|
||||
proxy: str | None = None
|
||||
connection_quality: int | None = None
|
||||
minimum_refresh_interval_minutes: int | None = None
|
||||
@@ -173,6 +174,15 @@ async def get_settings():
|
||||
return gui_manager.settings.get_settings()
|
||||
|
||||
|
||||
@app.get("/api/languages")
|
||||
async def get_languages():
|
||||
"""Get available languages"""
|
||||
if not gui_manager:
|
||||
raise HTTPException(status_code=503, detail="GUI not initialized")
|
||||
|
||||
return gui_manager.settings.get_languages()
|
||||
|
||||
|
||||
@app.post("/api/settings")
|
||||
async def update_settings(settings: SettingsUpdate):
|
||||
"""Update application settings"""
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from src.i18n.translator import _
|
||||
from src.models.game import Game
|
||||
|
||||
|
||||
@@ -41,6 +42,17 @@ class SettingsManager:
|
||||
"minimum_refresh_interval_minutes": self._settings.minimum_refresh_interval_minutes,
|
||||
}
|
||||
|
||||
def get_languages(self) -> dict[str, Any]:
|
||||
"""Get available languages and current selection.
|
||||
|
||||
Returns:
|
||||
Dictionary with available languages and current language
|
||||
"""
|
||||
return {
|
||||
"available": list(_.languages),
|
||||
"current": _.current,
|
||||
}
|
||||
|
||||
def update_settings(self, settings_data: dict[str, Any]):
|
||||
"""Update settings from user input.
|
||||
|
||||
@@ -51,6 +63,14 @@ class SettingsManager:
|
||||
self._settings.games_to_watch = settings_data["games_to_watch"]
|
||||
if "dark_mode" in settings_data:
|
||||
self._settings.dark_mode = settings_data["dark_mode"]
|
||||
if "language" in settings_data:
|
||||
language = settings_data["language"]
|
||||
try:
|
||||
_.set_language(language)
|
||||
self._settings.language = language
|
||||
except ValueError as e:
|
||||
# Invalid language, skip update
|
||||
pass
|
||||
if "connection_quality" in settings_data:
|
||||
self._settings.connection_quality = settings_data["connection_quality"]
|
||||
if "proxy" in settings_data:
|
||||
|
||||
@@ -542,6 +542,14 @@ function updateSettingsUI(settings) {
|
||||
document.getElementById('connection-quality').value = settings.connection_quality || 1;
|
||||
document.getElementById('minimum-refresh-interval').value = settings.minimum_refresh_interval_minutes || 30;
|
||||
|
||||
// Update language dropdown if we have the current language
|
||||
if (settings.language) {
|
||||
const languageSelect = document.getElementById('language');
|
||||
if (languageSelect) {
|
||||
languageSelect.value = settings.language;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.dark_mode) {
|
||||
document.body.classList.add('dark-mode');
|
||||
} else {
|
||||
@@ -861,6 +869,7 @@ async function confirmOAuth() {
|
||||
async function saveSettings() {
|
||||
const settings = {
|
||||
dark_mode: document.getElementById('dark-mode').checked,
|
||||
language: document.getElementById('language').value,
|
||||
connection_quality: parseInt(document.getElementById('connection-quality').value),
|
||||
minimum_refresh_interval_minutes: parseInt(document.getElementById('minimum-refresh-interval').value),
|
||||
games_to_watch: state.settings.games_to_watch || []
|
||||
@@ -878,6 +887,34 @@ async function saveSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchAndPopulateLanguages() {
|
||||
try {
|
||||
const response = await fetch('/api/languages');
|
||||
const data = await response.json();
|
||||
|
||||
const languageSelect = document.getElementById('language');
|
||||
if (!languageSelect) return;
|
||||
|
||||
// Clear existing options
|
||||
languageSelect.innerHTML = '';
|
||||
|
||||
// Populate with available languages
|
||||
data.available.forEach(lang => {
|
||||
const option = document.createElement('option');
|
||||
option.value = lang;
|
||||
option.textContent = lang;
|
||||
languageSelect.appendChild(option);
|
||||
});
|
||||
|
||||
// Set current language
|
||||
if (data.current) {
|
||||
languageSelect.value = data.current;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch languages:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function reloadCampaigns() {
|
||||
try {
|
||||
await fetch('/api/reload', {method: 'POST'});
|
||||
@@ -929,6 +966,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// Then save settings
|
||||
saveSettings();
|
||||
});
|
||||
document.getElementById('language').addEventListener('change', saveSettings);
|
||||
document.getElementById('connection-quality').addEventListener('change', saveSettings);
|
||||
document.getElementById('minimum-refresh-interval').addEventListener('change', saveSettings);
|
||||
document.getElementById('reload-btn').addEventListener('click', reloadCampaigns);
|
||||
@@ -944,6 +982,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
exitManualBtn.addEventListener('click', exitManualMode);
|
||||
}
|
||||
|
||||
// Fetch and populate available languages
|
||||
fetchAndPopulateLanguages();
|
||||
|
||||
// Request notification permission
|
||||
if ('Notification' in window && Notification.permission === 'default') {
|
||||
Notification.requestPermission();
|
||||
|
||||
Reference in New Issue
Block a user