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

@ -2,7 +2,13 @@ Changelog for LXTools installer
## [Unreleased] ## [Unreleased]
- - replace pack with grid
### Added
18-06-2025
- Added language support for German
### Added ### Added
14-06-2025 14-06-2025

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
lx-icons/32/Lunix_Tools.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
lx-icons/48/Lunix_Tools.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
lx-icons/64/Lunix_Tools.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

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

View File

@ -1,7 +1,6 @@
import locale import locale
import gettext import gettext
import tkinter as tk import tkinter as tk
from pathlib import Path
from tkinter import ttk from tkinter import ttk
import os import os
import subprocess import subprocess
@ -10,10 +9,10 @@ from network import GiteaUpdate
class LXToolsAppConfig: class LXToolsAppConfig:
VERSION = "1.1.4" VERSION = "1.1.5"
APP_NAME = "Lunix Tools Installer" APP_NAME = "lxtoolsinstaller"
WINDOW_WIDTH = 450 WINDOW_WIDTH = 450
WINDOW_HEIGHT = 580 WINDOW_HEIGHT = 740
# Working directory # Working directory
WORK_DIR = os.getcwd() WORK_DIR = os.getcwd()
@ -21,7 +20,7 @@ class LXToolsAppConfig:
THEMES_DIR = os.path.join(WORK_DIR, "TK-Themes") THEMES_DIR = os.path.join(WORK_DIR, "TK-Themes")
# Locale settings # Locale settings
LOCALE_DIR = Path("/usr/share/locale/") LOCALE_DIR = "./locale/"
# Download URLs # Download URLs
WIREPY_URL = "https://git.ilunix.de/punix/Wire-Py/archive/main.zip" WIREPY_URL = "https://git.ilunix.de/punix/Wire-Py/archive/main.zip"
@ -94,7 +93,7 @@ class LXToolsAppConfig:
} }
@staticmethod @staticmethod
def setup_translations(): def setup_translations() -> gettext.gettext:
"""Initialize translations and set the translation function""" """Initialize translations and set the translation function"""
try: try:
locale.bindtextdomain( locale.bindtextdomain(
@ -113,6 +112,117 @@ class LXToolsAppConfig:
_ = LXToolsAppConfig.setup_translations() _ = LXToolsAppConfig.setup_translations()
class LocaleStrings:
MSGI = {
"refresh_and_check": _("Refreshing status and checking versions..."),
"start_install": _("Starting installation of "),
"install": _("Installing "),
"install_success": _(" installation successfully!"),
"install_failed": _("Installation failed: "),
"install_create": _("Created install script: "),
"install_script_failed": _("Installation script failed: "),
"install_timeout": _("Installation timed out"),
"installed": _("Installed "),
}
MSGU = {
"uninstall": _("Uninstalling "),
"uninstall_success": _(" uninstalled successfully!"),
"uninstall_failed": _("Uninstallation failed: "),
"uninstall_create": _("Created uninstall script: "),
"uninstall_script_failed": _("Uninstallation script failed: "),
"uninstall_timeout": _("Uninstallation timed out"),
}
# MSGO = Other messages
MSGO = {
"unknown_project": _("Unknown project: "),
"not_install": _(" is not installed."),
"download_from": _("Downloading from "),
"extract_files": _("Extracting files..."),
"download_failed": _("Download failed: "),
"head_string2": _("System: "),
"head_string3": _("Linux App Installer"),
"ready": _("Ready for installation"),
"no_internet": _("No internet connection"),
"repo_unavailable": _("Repository unavailable"),
"system_check": _("System checking..."),
"applications": _("Applications"),
"progress": _("Progress"),
"refresh2": _("Status refresh completed"),
}
# MSGC = Strings on Cards
MSGC = {
"checking": _("Checking..."),
"version_check": _("Version: Checking..."),
"latest": _("Latest: "),
"update_available": _("Update available "),
"up_to_date": _("Up to date"),
"latest_unknown": _("Latest unknown"),
"could_not_check": _("Could not check latest version"),
"check_last_failed": _("Latest: Check failed"),
"version_check_failed": _("Version check failed"),
"not_installed": _("Not installed"),
"available": _("Available "),
"available_unknown": _("Available unknown"),
"available_ckeck_failed": _("Available: Check failed"),
}
# MSGL = Strings on Logmessages
MSGL = {
"selected_app": _("Selected project: "),
"log_name": _("Installation Log"),
"work_dir": _("Working directory: "),
"icons_dir": _("Icons directory: "),
"detected_os": _("Detected OS: "),
"log_cleared": _("Log cleared"),
"working_dir": _("Working directory: "),
"user_interuppt": _("\nApplication interrupted by user."),
"fatal_error": _("Fatal error: "),
"fatal_app_error": _("Fatal Error Application failed to start: "),
}
# MSGB = Strings on Buttons
MSGB = {
"clear_log": _("Clear Log"),
"install": _("Install/Update"),
"uninstall": _("Uninstall"),
"refresh": _("Refresh Status"),
}
# MSGM = String on MessagDialogs
MSGM = {
"please_select": _("Please select a project to install."),
"network_error": _(
"No internet connection available.\nPlease check your network connection.",
),
"repo_error": _(
"Cannot access repository.\nPlease try again later.",
),
"has_success_update": _("has been successfully installed/updated."),
"please_select_uninstall": _("Please select a project to uninstall."),
}
# MSGP = Others print strings
MSGP = {
"tk_install": _("Installing tkinter for )"),
"command_string": _("Command: "),
"tk_success": _("TKinter installation completed successfully!"),
"tk_failed": _("TKinter installation failed: "),
"tk_timeout": _("TKinter installation timed out"),
"tk_install_error": _("Error installing tkinter: "),
"tk_command_error": _("No tkinter installation command defined for "),
"fail_load_image": _("Failed to load image from "),
"logviewer_check": _("LogViewer installation check:"),
"symlink_exist": _(" Symlink exists: "),
"executable_exist": _(" Executable exists: "),
"is_executable": _(" Is executable: "),
"final_result": _(" Final result: "),
"get_version_error": _("Error getting version for "),
}
class OSDetector: class OSDetector:
@staticmethod @staticmethod
def detect_os(): def detect_os():
@ -148,8 +258,8 @@ class OSDetector:
if detected_os in LXToolsAppConfig.TKINTER_INSTALL_COMMANDS: if detected_os in LXToolsAppConfig.TKINTER_INSTALL_COMMANDS:
commands = LXToolsAppConfig.TKINTER_INSTALL_COMMANDS[detected_os] commands = LXToolsAppConfig.TKINTER_INSTALL_COMMANDS[detected_os]
print(f"Installing tkinter for {detected_os}...") print(f"{LocaleStrings.MSGP["tk_install"]}{detected_os}...")
print(_(f"Command: {' '.join(commands)}")) print(f"{LocaleStrings.MSGP["command_string"]}{' '.join(commands)}")
try: try:
# Use pkexec for privilege escalation # Use pkexec for privilege escalation
@ -159,20 +269,20 @@ class OSDetector:
) )
if result.returncode == 0: if result.returncode == 0:
print(_("TKinter installation completed successfully!")) print(f"{LocaleStrings.MSGP["tk_succcess"]}")
return True return True
else: else:
print(_(f"TKinter installation failed: {result.stderr}")) print(f"{LocaleStrings.MSGP["tk_failed"]}{result.stderr}")
return False return False
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
print(_("TKinter installation timed out")) print(LocaleStrings.MSGP["tk_timeout"])
return False return False
except Exception as e: except Exception as e:
print(_(f"Error installing tkinter: {e}")) print(f"{LocaleStrings.MSGP['tk_install_error']}{str(e)}")
return False return False
else: else:
print(_(f"No tkinter installation command defined for {detected_os}")) print(f"{LocaleStrings.MSGP["tk_command_error"]}{detected_os}")
return False return False
@ -307,7 +417,7 @@ class Image:
self.images[image_key] = photo self.images[image_key] = photo
return photo return photo
except tk.TclError as e: except tk.TclError as e:
print(_(f"Failed to load image from {path}: {e}")) print(f"{LocaleStrings.MSGP["fail_load_image"]}{path}: {e}")
continue continue
# Return None if no image found # Return None if no image found
@ -356,11 +466,11 @@ class AppManager:
) )
# Debug logging # Debug logging
print(_("LogViewer installation check:")) print(LocaleStrings.MSGP["logviewer_check"])
print(_(f" Symlink exists: {symlink_exists}")) print(f"{LocaleStrings.MSGP["symlink_exist"]}{symlink_exists}")
print(_(f" Executable exists: {executable_exists}")) print(f"{LocaleStrings.MSGP["executable_exist"]}{executable_exists}")
print(_(f" Is executable: {executable_is_executable}")) print(f"{LocaleStrings.MSGP["is_executable"]}{executable_is_executable}")
print(_(f" Final result: {is_installed}")) print(f"{LocaleStrings.MSGP["final_result"]}{is_installed}")
return is_installed return is_installed
@ -385,7 +495,7 @@ class AppManager:
return version return version
return "Unknown" return "Unknown"
except Exception as e: except Exception as e:
print(_(f"Error getting version for {project_key}: {e}")) print(f"{LocaleStrings.MSGP["get_version_error"]}{project_key}: {e}")
return "Unknown" return "Unknown"
def get_latest_version(self, project_key): def get_latest_version(self, project_key):