Files
AccountForger-neuerUpload/localization/language_manager.py
Claude Project Manager 04585e95b6 Initial commit
2025-08-01 23:50:28 +02:00

272 Zeilen
10 KiB
Python

# Path: localization/language_manager.py
"""
Sprachmanager für die Übersetzung der Benutzeroberfläche.
"""
import os
import json
import logging
import time
from typing import Dict, Any, Optional
from PyQt5.QtCore import QObject, pyqtSignal, QSettings
logger = logging.getLogger("language_manager")
class LanguageManager(QObject):
"""Verwaltet die Sprachen und Übersetzungen der Anwendung."""
# Signal, das ausgelöst wird, wenn sich die Sprache ändert
language_changed = pyqtSignal(str)
# Signal, das den Status des Sprachwechsels anzeigt (True = läuft, False = abgeschlossen)
language_change_status = pyqtSignal(bool)
def __init__(self, app=None):
"""
Initialisiert den Sprachmanager.
Args:
app: Die QApplication-Instanz
"""
super().__init__()
self.app = app
self.current_language = "de" # Standard ist Deutsch
self.translations = {}
self.available_languages = {}
self.last_change_time = 0 # Zeitpunkt des letzten Sprachwechsels
self.change_cooldown = 0.5 # Cooldown in Sekunden zwischen Sprachwechseln
self.is_changing_language = False # Status-Variable für laufenden Sprachwechsel
# Basisverzeichnis für Sprachdateien ermitteln
self.base_dir = os.path.dirname(os.path.abspath(__file__))
self.languages_dir = os.path.join(self.base_dir, "languages")
# Verfügbare Sprachen ermitteln und laden
self._discover_languages()
# Lade die gespeicherte Sprache, falls vorhanden
self.settings = QSettings("Chimaira", "SocialMediaAccountGenerator")
saved_language = self.settings.value("language", "de")
if saved_language in self.available_languages:
self.current_language = saved_language
self._load_language(self.current_language)
logger.info(f"Sprachmanager initialisiert mit Sprache: {self.current_language}")
def _discover_languages(self):
"""Ermittelt die verfügbaren Sprachen aus den Sprachdateien."""
self.available_languages = {}
try:
# Alle JSON-Dateien im Sprachverzeichnis suchen
language_files = []
for filename in os.listdir(self.languages_dir):
if filename.endswith(".json"):
language_code = filename.split(".")[0]
language_path = os.path.join(self.languages_dir, filename)
language_files.append((language_code, language_path))
# Definierte Reihenfolge der Sprachen
ordered_codes = ["de", "en", "fr", "es", "ja"]
# Sortierte Liste erstellen
for code in ordered_codes:
for language_code, language_path in language_files:
if language_code == code:
# Sprachinformationen aus der Datei lesen
try:
with open(language_path, 'r', encoding='utf-8') as file:
language_data = json.load(file)
language_name = language_data.get("language_name", language_code)
self.available_languages[language_code] = {
"name": language_name,
"path": language_path
}
except Exception as e:
logger.error(f"Fehler beim Laden der Sprachinformationen für {language_code}: {e}")
# Eventuelle restliche Sprachen hinzufügen
for language_code, language_path in language_files:
if language_code not in self.available_languages:
try:
with open(language_path, 'r', encoding='utf-8') as file:
language_data = json.load(file)
language_name = language_data.get("language_name", language_code)
self.available_languages[language_code] = {
"name": language_name,
"path": language_path
}
except Exception as e:
logger.error(f"Fehler beim Laden der Sprachinformationen für {language_code}: {e}")
logger.info(f"Verfügbare Sprachen: {', '.join(self.available_languages.keys())}")
except Exception as e:
logger.error(f"Fehler beim Ermitteln der verfügbaren Sprachen: {e}")
def _load_language(self, language_code: str) -> bool:
"""
Lädt die Übersetzungen für eine Sprache.
Args:
language_code: Der Sprachcode (z.B. "de", "en")
Returns:
bool: True bei Erfolg, False bei Fehler
"""
if language_code not in self.available_languages:
logger.error(f"Sprache {language_code} nicht verfügbar")
return False
try:
language_path = self.available_languages[language_code]["path"]
with open(language_path, 'r', encoding='utf-8') as file:
self.translations = json.load(file)
self.current_language = language_code
logger.info(f"Sprache {language_code} geladen")
# Signal auslösen, dass sich die Sprache geändert hat
self.language_changed.emit(language_code)
return True
except Exception as e:
logger.error(f"Fehler beim Laden der Sprache {language_code}: {e}")
return False
def get_text(self, key: str, default: str = None) -> str:
"""
Gibt den übersetzten Text für einen Schlüssel zurück.
Args:
key: Der Schlüssel für den Text (z.B. "main.title")
default: Der Standardtext, falls der Schlüssel nicht gefunden wurde
Returns:
str: Der übersetzte Text oder der Standardtext
"""
# Wenn kein Standardtext angegeben wurde, verwende den Schlüssel
if default is None:
default = key
# Versuche, den Text aus den Übersetzungen zu holen
try:
# Unterstütze verschachtelte Schlüssel mit Punktnotation
parts = key.split('.')
result = self.translations
for part in parts:
if part in result:
result = result[part]
else:
return default
# Wenn das Ergebnis ein unterstützter Datentyp ist, gib es zurück
if isinstance(result, (str, list, dict)):
return result
else:
logger.warning(
f"Schlüssel {key} hat unerwarteten Typ: {type(result)} - {result}"
)
return default
except Exception as e:
logger.warning(f"Fehler beim Abrufen des Textes für Schlüssel {key}: {e}")
return default
def change_language(self, language_code: str) -> bool:
"""
Ändert die aktive Sprache.
Args:
language_code: Der Sprachcode (z.B. "de", "en")
Returns:
bool: True bei Erfolg, False bei Fehler
"""
# Wenn bereits ein Sprachwechsel läuft, blockiere weitere Wechsel
if self.is_changing_language:
logger.debug(f"Ein Sprachwechsel läuft bereits, ignoriere Wechsel zu {language_code}")
return False
# Cooldown prüfen
current_time = time.time()
if current_time - self.last_change_time < self.change_cooldown:
logger.debug("Sprachwechsel zu schnell hintereinander")
return False
# Wenn es die gleiche Sprache ist, nichts tun
if language_code == self.current_language:
return True
# Status auf "Sprachwechsel läuft" setzen
self.is_changing_language = True
self.language_change_status.emit(True)
# Versuche die Sprache zu wechseln
success = self._load_language(language_code)
if success:
# Sprache in Einstellungen speichern
self.settings.setValue("language", language_code)
self.settings.sync()
# Aktualisiere den Zeitpunkt des letzten Sprachwechsels
self.last_change_time = time.time()
# Nach einer kurzen Verzögerung den Status zurücksetzen
# um sicherzustellen, dass die UI-Aktualisierung abgeschlossen ist
from PyQt5.QtCore import QTimer
QTimer.singleShot(500, self._reset_change_status)
return success
def _reset_change_status(self):
"""Setzt den Status des Sprachwechsels zurück."""
self.is_changing_language = False
self.language_change_status.emit(False)
logger.debug("Sprachwechsel-Status zurückgesetzt")
def get_current_language(self) -> str:
"""Gibt den Code der aktuellen Sprache zurück."""
return self.current_language
def get_language_name(self, language_code: str = None) -> str:
"""
Gibt den Namen einer Sprache zurück.
Args:
language_code: Der Sprachcode oder None für die aktuelle Sprache
Returns:
str: Der Name der Sprache
"""
if language_code is None:
language_code = self.current_language
if language_code in self.available_languages:
return self.available_languages[language_code].get("name", language_code)
else:
return language_code
def get_available_languages(self) -> Dict[str, str]:
"""
Gibt eine Liste der verfügbaren Sprachen zurück.
Returns:
Dict[str, str]: Ein Dictionary mit Sprachcodes als Schlüssel und Sprachnamen als Werten
"""
return {code: info.get("name", code) for code, info in self.available_languages.items()}
def is_language_change_in_progress(self) -> bool:
"""
Gibt zurück, ob gerade ein Sprachwechsel im Gange ist.
Returns:
bool: True wenn ein Sprachwechsel läuft, False sonst
"""
return self.is_changing_language