Added language support for German

This commit is contained in:
2025-06-18 00:04:09 +02:00
parent 5b7cc4de97
commit 5740b22583
14 changed files with 275 additions and 133 deletions

View File

@ -10,6 +10,7 @@ import zipfile
from manager import (
OSDetector,
Theme,
LocaleStrings,
LXToolsAppConfig,
System,
Image,
@ -19,9 +20,6 @@ from manager import (
from network import NetworkChecker
from message import MessageDialog
# Initialize translations
_ = LXToolsAppConfig.setup_translations()
class InstallationManager:
def __init__(
@ -38,10 +36,12 @@ class InstallationManager:
"""Install or update project"""
project_info = self.app_manager.get_project_info(project_key)
if not project_info:
raise Exception(_(f"Unknown project: {project_key}"))
raise Exception(f"{LocaleStrings.MSG["unknow_project"]}{project_key}")
self.update_progress(_(f"Starting installation of {project_info['name']}..."))
self.log(_(f"=== Installing {project_info['name']} ==="))
self.update_progress(
f"{LocaleStrings.MSGI["start_install"]}{project_info['name']}..."
)
self.log(f"=== {LocaleStrings.MSGI["install"]}{project_info['name']} ===")
try:
# Create installation script
@ -51,17 +51,19 @@ class InstallationManager:
self._execute_install_script(script_content)
self.update_progress(
_(f"{project_info['name']} installation completed successfully!")
f"{project_info["name"]}{LocaleStrings.MSGI["install_success"]}"
)
self.log(
f"=== {project_info["name"]}{LocaleStrings.MSGI["install_success"]} ==="
)
self.log(_(f"=== {project_info['name']} installed successfully ==="))
# Set success icon
self.update_icon("success")
except Exception as e:
self.log(_(f"ERROR: Installation failed: {e}"))
self.log(f"ERROR: {LocaleStrings.MSGI["install_failed"]}{e}")
self.update_icon("error")
raise Exception(_(f"Installation failed: {e}"))
raise Exception(f"{LocaleStrings.MSGI["install_failed"]}{e}")
def _create_install_script(self, project_key):
"""Create installation script based on project"""
@ -70,7 +72,7 @@ class InstallationManager:
elif project_key == "logviewer":
return self._create_logviewer_install_script()
else:
raise Exception(_(f"Unknown project: {project_key}"))
raise Exception(f"{LocaleStrings.MSGI["unknow_project"]}{project_key}")
def _create_wirepy_install_script(self):
"""Create Wire-Py installation script"""
@ -299,7 +301,7 @@ echo "LogViewer installation completed!"
# Make script executable
os.chmod(script_file.name, 0o755)
self.log(_(f"Created install script: {script_file.name}"))
self.log(f"{LocaleStrings.MSGI["install_create"]}{script_file.name}")
# Execute with pkexec
result = subprocess.run(
@ -319,12 +321,14 @@ echo "LogViewer installation completed!"
os.unlink(script_file.name)
if result.returncode != 0:
raise Exception(_(f"Installation script failed: {result.stderr}"))
raise Exception(
f"{LocaleStrings.MSGI["install_script_failed"]}{result.stderr}"
)
except subprocess.TimeoutExpired:
raise Exception(_("Installation timed out"))
raise Exception(LocaleStrings.MSGI["install_timeout"])
except subprocess.CalledProcessError as e:
raise Exception(_(f"Installation script failed: {e}"))
raise Exception(f"{LocaleStrings.MSGI["install_script_failed"]}{e}")
def update_progress(self, message):
if self.progress_callback:
@ -349,13 +353,17 @@ class UninstallationManager:
"""Uninstall project"""
project_info = self.app_manager.get_project_info(project_key)
if not project_info:
raise Exception(f"Unknown project: {project_key}")
raise Exception(f"{LocaleStrings.MSGO["unknow_project"]}{project_key}")
if not self.app_manager.is_installed(project_key):
raise Exception(_(f"{project_info['name']} is not installed."))
raise Exception(
f"{project_info["name"]}{LocaleStrings.MSGO["not_installed"]}"
)
self.update_progress(_(f"Uninstalling {project_info['name']}..."))
self.log(_(f"=== Uninstalling {project_info['name']} ==="))
self.update_progress(
f"{LocaleStrings.MSGU["uninstall"]}{project_info['name']}..."
)
self.log(f"=== {LocaleStrings.MSGU["uninstall"]}{project_info['name']} ===")
try:
# Create uninstallation script
@ -364,12 +372,16 @@ class UninstallationManager:
# Execute uninstallation
self._execute_uninstall_script(script_content)
self.update_progress(_(f"{project_info['name']} uninstalled successfully!"))
self.log(_(f"=== {project_info['name']} uninstalled successfully ==="))
self.update_progress(
f"{project_info['name']}{LocaleStrings.MSGU["uninstall_success"]}"
)
self.log(
f"=== {project_info['name']}{LocaleStrings.MSGU["uninstall_success"]} ==="
)
except Exception as e:
self.log(_(f"ERROR: Uninstallation failed: {e}"))
raise Exception(_(f"Uninstallation failed: {e}"))
self.log(f"ERROR: {LocaleStrings.MSGU['uninstall_failed']}{e}")
raise Exception(f"{LocaleStrings.MSGU["uninstall_failed"]}{e}")
def _create_uninstall_script(self, project_key):
"""Create uninstallation script based on project"""
@ -378,7 +390,7 @@ class UninstallationManager:
elif project_key == "logviewer":
return self._create_logviewer_uninstall_script()
else:
raise Exception(_(f"Unknown project: {project_key}"))
raise Exception(f"{LocaleStrings.MSGO["unknow_project"]}{project_key}")
def _create_wirepy_uninstall_script(self):
"""Create Wire-Py uninstallation script"""
@ -513,7 +525,7 @@ echo "LogViewer uninstallation completed!"
# Make script executable
os.chmod(script_file.name, 0o755)
self.log(_(f"Created uninstall script: {script_file.name}"))
self.log(f"{LocaleStrings.MSGU["uninstall_create"]}{script_file.name}")
# Execute with pkexec
result = subprocess.run(
@ -533,12 +545,14 @@ echo "LogViewer uninstallation completed!"
os.unlink(script_file.name)
if result.returncode != 0:
raise Exception(_(f"Uninstallation script failed: {result.stderr}"))
raise Exception(
f"{LocaleStrings.MSGU["uninstall_script_failed"]}{result.stderr}"
)
except subprocess.TimeoutExpired:
raise Exception(_("Uninstallation timed out"))
raise Exception(LocaleStrings.MSGU["uninstall_timeout"])
except subprocess.CalledProcessError as e:
raise Exception(_(f"Uninstallation script failed: {e}"))
raise Exception(f"{LocaleStrings.MSGU["uninstall_script_failed"]}{e}")
def update_progress(self, message):
if self.progress_callback:
@ -555,13 +569,13 @@ class DownloadManager:
"""Download and extract ZIP file"""
try:
if progress_callback:
progress_callback(_(f"Downloading from {url}..."))
progress_callback(f"{LocaleStrings.MSGO["download_from"]}{url}...")
with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as tmp_file:
urllib.request.urlretrieve(url, tmp_file.name)
if progress_callback:
progress_callback(_("Extracting files..."))
progress_callback(LocaleStrings.MSGO["extract_files"])
with zipfile.ZipFile(tmp_file.name, "r") as zip_ref:
zip_ref.extractall(extract_to)
@ -571,7 +585,7 @@ class DownloadManager:
except Exception as e:
if progress_callback:
progress_callback(_(f"Download failed: {str(e)}"))
progress_callback(f"{LocaleStrings.MSGO["download_failed"]}{e}")
return False
@ -694,7 +708,7 @@ class LXToolsGUI:
tk.Label(
text_frame,
text=f"v {LXToolsAppConfig.VERSION}Linux App Installer",
text=f"v {LXToolsAppConfig.VERSION}{LocaleStrings.MSGO["head_string3"]}",
font=("Helvetica", 9),
fg="#bdc3c7",
bg="#2c3e50",
@ -706,7 +720,7 @@ class LXToolsGUI:
tk.Label(
right_side,
text=f"System: {self.detected_os}",
text=f"{LocaleStrings.MSGO["head_string2"]}{self.detected_os}",
font=("Helvetica", 11),
fg="#ecf0f1",
bg="#2c3e50",
@ -729,23 +743,29 @@ class LXToolsGUI:
def check_ready_status(self):
"""Check if system is ready for installation"""
# Prüfungen:
# Checks:
internet_ok = NetworkChecker.check_internet_connection()
repo_ok = NetworkChecker.check_repository_access()
if internet_ok and repo_ok:
self.update_header_status(_("Ready for installation"), "#1abc9c") # Green
self.update_header_status(LocaleStrings.MSGO["ready"], "#1abc9c") # Green
elif not internet_ok:
self.update_header_status(_("No internet connection"), "#e74c3c") # Red
self.update_header_status(
LocaleStrings.MSGO["no_internet"], "#e74c3c"
) # Red
elif not repo_ok:
self.update_header_status(_("Repository unavailable"), "#f39c12") # Orange
self.update_header_status(
LocaleStrings.MSGO["repo_unavailable"], "#f39c12"
) # Orange
else:
self.update_header_status(_("System checking..."), "#3498db") # Blue
self.update_header_status(
LocaleStrings.MSGO["system_check"], "#3498db"
) # Blue
def _create_projects_tab(self):
"""Create projects tab with project cards"""
projects_frame = ttk.Frame(self.notebook)
self.notebook.add(projects_frame, text=_("Applications"))
self.notebook.add(projects_frame, text=LocaleStrings.MSGO["applications"])
# Scrollable frame
canvas = tk.Canvas(projects_frame, bg=self.colors["bg"])
@ -842,7 +862,7 @@ class LXToolsGUI:
# Status label
status_label = tk.Label(
status_frame,
text="Checking...",
text=f"{LocaleStrings.MSGC["checking"]}",
font=("Helvetica", 10),
bg=self.colors["card_bg"],
fg="#95a5a6",
@ -853,7 +873,7 @@ class LXToolsGUI:
# Version label
version_label = tk.Label(
status_frame,
text="Version: Checking...",
text=LocaleStrings.MSGC["version_check"],
font=("Helvetica", 9),
bg=self.colors["card_bg"],
fg="#95a5a6",
@ -936,12 +956,12 @@ class LXToolsGUI:
self._update_frame_children_bg(new_content, self.colors["selected_bg"])
project_info = self.app_manager.get_project_info(project_key)
self.log_message(f"Selected project: {project_info['name']}")
self.log_message(f"{LocaleStrings.MSGL["selected_app"]}{project_info["name"]}")
def _create_log_tab(self):
"""Create log tab"""
log_frame = ttk.Frame(self.notebook)
self.notebook.add(log_frame, text=_("Installation Log"))
self.notebook.add(log_frame, text=LocaleStrings.MSGL["log_name"])
# Log text with scrollbar
log_container = tk.Frame(log_frame)
@ -971,7 +991,7 @@ class LXToolsGUI:
# Clear log button
clear_log_btn = ttk.Button(
log_controls, text=_("Clear Log"), command=self.clear_log
log_controls, text=LocaleStrings.MSGB["clear_log"], command=self.clear_log
)
clear_log_btn.pack(side="right")
@ -979,14 +999,18 @@ class LXToolsGUI:
self.log_message(
f"=== {LXToolsAppConfig.APP_NAME} v {LXToolsAppConfig.VERSION} ==="
)
self.log_message(_(f"Working directory: {LXToolsAppConfig.WORK_DIR}"))
self.log_message(_(f"Icons directory: {LXToolsAppConfig.ICONS_DIR}"))
self.log_message(_(f"Detected OS: {self.detected_os}"))
self.log_message(_("Ready for installation..."))
self.log_message(f"{LocaleStrings.MSGL["work_dir"]}{LXToolsAppConfig.WORK_DIR}")
self.log_message(
f"{LocaleStrings.MSGL["icons_dir"]}{LXToolsAppConfig.ICONS_DIR}"
)
self.log_message(f"{LocaleStrings.MSGL["detected_os"]}{self.detected_os}")
self.log_message(f"{LocaleStrings.MSGO["ready"]}...")
def _create_progress_section(self):
"""Create progress section with download icon"""
progress_frame = ttk.LabelFrame(self.root, text=_("Progress"), padding=10)
progress_frame = ttk.LabelFrame(
self.root, text=LocaleStrings.MSGO["progress"], padding=10
)
progress_frame.pack(fill="x", padx=15, pady=10)
# Container for Icon and Progress
@ -1000,7 +1024,7 @@ class LXToolsGUI:
# Progress Text (right, expandable)
self.progress_label = tk.Label(
progress_container,
text=_("Ready for installation..."),
text=f"{LocaleStrings.MSGO["ready"]}...",
font=("Helvetica", 10),
fg="blue",
anchor="w",
@ -1044,7 +1068,7 @@ class LXToolsGUI:
# Create buttons
install_btn = ttk.Button(
button_frame,
text=_("Install/Update"),
text=LocaleStrings.MSGB["install"],
command=self.install_selected,
style="Install.TButton",
padding=8,
@ -1053,7 +1077,7 @@ class LXToolsGUI:
uninstall_btn = ttk.Button(
button_frame,
text=_("Uninstall"),
text=LocaleStrings.MSGB["uninstall"],
command=self.uninstall_selected,
style="Uninstall.TButton",
padding=8,
@ -1062,7 +1086,7 @@ class LXToolsGUI:
refresh_btn = ttk.Button(
button_frame,
text=_("Refresh Status"),
text=LocaleStrings.MSGB["refresh"],
command=self.refresh_status,
style="Refresh.TButton",
padding=8,
@ -1111,23 +1135,24 @@ class LXToolsGUI:
def refresh_status(self):
"""Refresh application status and version information"""
self.update_progress(_("Refreshing status and checking versions..."))
self.update_progress(LocaleStrings.MSGI["refresh_and_check"])
self._reset_download_icon()
self.log_message(_("=== Refreshing Status ==="))
self.log_message(f"=== {LocaleStrings.MSGB["refresh"]} ===")
self.root.focus_set()
for project_key, project_info in self.app_manager.get_all_projects().items():
status_label = self.status_labels[project_key]
version_label = self.version_labels[project_key]
self.log_message(_(f"Checking {project_info['name']}..."))
self.log_message(f"{LocaleStrings.MSGC["checking"]} {project_info['name']}")
if self.app_manager.is_installed(project_key):
installed_version = self.app_manager.get_installed_version(project_key)
status_label.config(
text=_(f"✅ Installed ({installed_version})"), fg="green"
text=f"{LocaleStrings.MSGI["installed"]}({installed_version})",
fg="green",
)
self.log_message(
_(f"{project_info['name']}: Installed {installed_version}")
f"{project_info['name']}: {LocaleStrings.MSGI["installed"]}({installed_version})"
)
# Get latest version from API
@ -1136,87 +1161,88 @@ class LXToolsGUI:
if latest_version != "Unknown":
if installed_version != f"v. {latest_version}":
version_label.config(
text=_(
f"Latest: v. {latest_version} (Update available)"
),
text=f"{LocaleStrings.MSGC["latest"]}(v. {latest_version}) {LocaleStrings.MSGC["update_available"]}",
fg="orange",
)
self.log_message(
_(
f"{project_info['name']}: Update available v. {latest_version}"
)
f"{project_info['name']}: {LocaleStrings.MSGC["update_available"]}(v. {latest_version})"
)
else:
version_label.config(
text=f"Latest: v. {latest_version} (Up to date)",
text=f"{LocaleStrings.MSGC["latest"]}: (v. {latest_version}) {LocaleStrings.MSGC["up_to_date"]}",
fg="green",
)
self.log_message(f"{project_info['name']}: Up to date")
self.log_message(
f"{project_info['name']}: {LocaleStrings.MSGC["up_to_date"]}",
)
else:
version_label.config(text="Latest: Unknown", fg="gray")
version_label.config(
text=LocaleStrings.MSGC["latest_unknown"], fg="gray"
)
self.log_message(
f"{project_info['name']}: Could not check latest version"
f"{project_info['name']}: {LocaleStrings.MSGC["could_not_check"]}"
)
except Exception as e:
version_label.config(text="Latest: Check failed", fg="gray")
version_label.config(
text=LocaleStrings.MSGC["check_last_failed"], fg="gray"
)
self.log_message(
f"{project_info['name']}: Version check failed: {e}"
f"{project_info['name']}: {LocaleStrings.MSGC["version_check_failed"]}: {e}"
)
else:
status_label.config(text="❌ Not installed", fg="red")
self.log_message(_(f"{project_info['name']}: Not installed"))
status_label.config(
text=f"{LocaleStrings.MSGC["not_installed"]}", fg="red"
)
self.log_message(
f"{project_info['name']}: {LocaleStrings.MSGC["not_installed"]}"
)
# Still show latest available version
try:
latest_version = self.app_manager.get_latest_version(project_key)
if latest_version != "Unknown":
version_label.config(
text=_(f"Available: v {latest_version}"), fg="blue"
text=f"{project_info['name']} {LocaleStrings.MSGC["available"]}: v {latest_version}",
fg="blue",
)
self.log_message(
_(f"{project_info['name']}: Available v {latest_version}")
f"{project_info['name']} {LocaleStrings.MSGC["available"]}: v {latest_version}"
)
else:
version_label.config(text=_("Available: Unknown"), fg="gray")
version_label.config(
text=LocaleStrings.MSGC["available_unknown"], fg="gray"
)
except Exception as e:
version_label.config(text=_("Available: Check failed"), fg="gray")
version_label.config(
text=LocaleStrings.MSGC["available_check_unknown"], fg="gray"
)
self.log_message(
_(f"{project_info['name']}: Version check failed: {e}")
f" {project_info['name']}: {LocaleStrings.MSGC["version_check_failed"]}: {e}"
)
self.update_progress(_("Status refresh completed."))
self.log_message(_("=== Status refresh completed ==="))
self.update_progress(LocaleStrings.MSGO["refresh2"])
self.log_message(f"=== {LocaleStrings.MSGO["refresh2"]} ===")
self.check_ready_status()
def install_selected(self):
"""Handle install button click"""
if not self.selected_project:
MessageDialog("error", _("Please select a project to install."))
MessageDialog("error", LocaleStrings.MSGM["please_select"])
self.root.focus_set()
return
# Check internet connection
if not NetworkChecker.check_internet_connection():
self.update_download_icon("error")
MessageDialog(
"error",
_(
"Network Error",
"No internet connection available.\nPlease check your network connection.",
),
)
MessageDialog("error", LocaleStrings.MSGM["network_error"])
self.root.focus_set()
return
if not NetworkChecker.check_repository_access():
self.update_download_icon("error")
MessageDialog(
"error",
_(
"Repository Error",
"Cannot access repository.\nPlease try again later.",
),
)
MessageDialog("error", LocaleStrings.MSGM["repo_error"])
self.root.focus_set()
return
@ -1230,12 +1256,13 @@ class LXToolsGUI:
self.update_download_icon("success")
MessageDialog(
"info",
_(f"{project_info['name']} has been successfully installed/updated."),
f"{project_info["name"]} {LocaleStrings.MSGM["has_success_update"]}",
)
self.refresh_status()
except Exception as e:
self.update_download_icon("error")
MessageDialog("error", _(f"{e}"))
MessageDialog("error", f"{e}")
self.root.focus_set()
@ -1243,14 +1270,16 @@ class LXToolsGUI:
"""Handle uninstall button click"""
if not self.selected_project:
MessageDialog("error", _("Please select a project to uninstall."))
MessageDialog("error", LocaleStrings.MSGM["please_select_uninstall"])
self.root.focus_set()
return
project_info = self.app_manager.get_project_info(self.selected_project)
if not self.app_manager.is_installed(self.selected_project):
MessageDialog("error", _(f"{project_info['name']} is not installed."))
MessageDialog(
"error", f"{project_info["name"]} {LocaleStrings.MSGO["not_installed"]}"
)
self.root.focus_set()
return
@ -1258,14 +1287,13 @@ class LXToolsGUI:
self.uninstallation_manager.uninstall_project(self.selected_project)
MessageDialog(
"info",
_(
f"{project_info['name']} has been successfully uninstalled.",
),
f"{project_info["name"]} {LocaleStrings.MSGU["uninstall_success"]}",
)
self.refresh_status()
self.root.focus_set()
except Exception as e:
MessageDialog("error", _(f"Uninstallation failed: {e}"))
MessageDialog("error", f"{LocaleStrings.MSGU["uninstall_failed"]}: {e}")
self.root.focus_set()
def update_progress(self, message):
@ -1273,7 +1301,7 @@ class LXToolsGUI:
if self.progress_label:
self.progress_label.config(text=message)
self.progress_label.update()
print(_(f"Progress: {message}"))
print(f"{LocaleStrings.MSGO["progress"]}: {message}")
def log_message(self, message):
"""Add message to log"""
@ -1283,13 +1311,13 @@ class LXToolsGUI:
self.log_text.insert(tk.END, log_entry)
self.log_text.see(tk.END)
self.log_text.update()
print(_(f"Log: {message}"))
print(f"Log: {message}")
def clear_log(self):
"""Clear the log"""
if self.log_text:
self.log_text.delete(1.0, tk.END)
self.log_message(_("Log cleared"))
self.log_message(MSGL["log_cleared"])
def run(self):
"""Start the GUI application"""
@ -1300,21 +1328,19 @@ class LXToolsGUI:
def main():
"""Main function to start the application"""
print(f"=== {LXToolsAppConfig.APP_NAME} v {LXToolsAppConfig.VERSION} ===")
print(_(f"Working directory: {os.getcwd()}"))
print(f"{LocaleStrings.MSGL["working_dir"]}{os.getcwd()}")
try:
# Create and run the GUI
app = LXToolsGUI()
app.run()
except KeyboardInterrupt:
print(_("\nApplication interrupted by user."))
print(LocaleStrings.MSGL["user_interrupt"])
except Exception as e:
print(_(f"Fatal error: {e}"))
print(f"{LocaleStrings.MSGL["fatal_error"]}: {e}")
try:
MessageDialog(
"error", _("Fatal Error", f"Application failed to start: {e}")
)
MessageDialog("error", f"{LocaleStrings.MSGL['fatal_app_error']}: {e}")
except:
pass