Merge pull request #1 from rangermix/claude/add-i18n-support-011CUPwJtzv2esxMp4smVkDt

This commit is contained in:
Fengqing Liu
2025-10-23 21:42:04 +11:00
committed by GitHub
4 changed files with 81 additions and 0 deletions

1
.gitignore vendored
View File

@@ -26,3 +26,4 @@ data/
.idea/
*.iml
*.log
*.egg-info/

View File

@@ -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"""

View File

@@ -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,15 @@ 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, log warning
import logging
logging.warning(f"Invalid language '{language}': {e}")
if "connection_quality" in settings_data:
self._settings.connection_quality = settings_data["connection_quality"]
if "proxy" in settings_data:

View File

@@ -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,42 @@ 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) {
console.warn('Language select element not found');
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);
const languageSelect = document.getElementById('language');
if (languageSelect) {
languageSelect.innerHTML = '<option value="">Failed to load languages</option>';
}
addConsoleLine('Error: Unable to fetch available languages. Please check your connection or try again later.');
}
}
async function reloadCampaigns() {
try {
await fetch('/api/reload', {method: 'POST'});
@@ -929,6 +974,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 +990,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();