add requests for arch linux

This commit is contained in:
2025-06-23 14:44:33 +02:00
parent 01bd6ab263
commit ed269af1d2
3 changed files with 431 additions and 428 deletions

View File

@ -2,6 +2,7 @@ import locale
import gettext
import tkinter as tk
from tkinter import ttk
from pathlib import Path
import os
import sys
import shutil
@ -10,261 +11,9 @@ import stat
from network import GiteaUpdate
class LXToolsAppConfig:
VERSION = "1.1.5"
APP_NAME = "lxtoolsinstaller"
WINDOW_WIDTH = 450
WINDOW_HEIGHT = 580
# Working directory
WORK_DIR = os.getcwd()
ICONS_DIR = os.path.join(WORK_DIR, "lx-icons")
THEMES_DIR = os.path.join(WORK_DIR, "TK-Themes")
# Locale settings
LOCALE_DIR = "./locale/"
# Download URLs
WIREPY_URL = "https://git.ilunix.de/punix/Wire-Py/archive/main.zip"
SHARED_LIBS_URL = "https://git.ilunix.de/punix/shared_libs/archive/main.zip"
# API URLs for version checking
WIREPY_API_URL = "https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases"
SHARED_LIBS_API_URL = (
"https://git.ilunix.de/api/v1/repos/punix/shared_libs/releases"
)
# Project configurations
PROJECTS = {
"wirepy": {
"name": "Wire-Py",
"description": "WireGuard VPN Manager with GUI",
"download_url": WIREPY_URL,
"api_url": WIREPY_API_URL,
"icon_key": "icon_vpn",
"main_executable": "wirepy.py",
"symlink_name": "wirepy",
"config_file": "wp_app_config.py",
"desktop_file": "Wire-Py.desktop",
"policy_file": "org.sslcrypt.policy",
"requires_ssl": True,
},
"logviewer": {
"name": "LogViewer",
"description": "System Log Viewer with GUI",
"download_url": SHARED_LIBS_URL,
"api_url": SHARED_LIBS_API_URL,
"icon_key": "icon_log",
"main_executable": "logviewer.py",
"symlink_name": "logviewer",
"config_file": "logview_app_config.py",
"desktop_file": "LogViewer.desktop",
"policy_file": None,
"requires_ssl": False,
},
}
# OS Detection List (order matters - specific first, generic last)
OS_DETECTION = [
("mint", "Linux Mint"),
("pop", "Pop!_OS"),
("manjaro", "Manjaro"),
("garuda", "Garuda Linux"),
("endeavouros", "EndeavourOS"),
("fedora", "Fedora"),
("tumbleweed", "SUSE Tumbleweed"),
("leap", "SUSE Leap"),
("arch", "Arch Linux"),
("ubuntu", "Ubuntu"),
("debian", "Debian"),
]
# Package manager commands for TKinter installation
TKINTER_INSTALL_COMMANDS = {
"Ubuntu": ["apt", "update", "&&", "apt", "install", "-y", "python3-tk"],
"Debian": ["apt", "update", "&&", "apt", "install", "-y", "python3-tk"],
"Linux Mint": ["apt", "update", "&&", "apt", "install", "-y", "python3-tk"],
"Pop!_OS": ["apt", "update", "&&", "apt", "install", "-y", "python3-tk"],
"Fedora": ["dnf", "install", "-y", "tkinter"],
"Arch Linux": ["pacman", "-S", "--noconfirm", "tk"],
"Manjaro": ["pacman", "-S", "--noconfirm", "tk"],
"Garuda Linux": ["pacman", "-S", "--noconfirm", "tk"],
"EndeavourOS": ["pacman", "-S", "--noconfirm", "tk"],
"SUSE Tumbleweed": ["zypper", "install", "-y", "python314-tk"],
"SUSE Leap": ["zypper", "install", "-y", "python312-tk"],
}
class Detector:
@staticmethod
def extract_data_files():
if getattr(sys, "_MEIPASS", None) is not None:
# Liste der Quellordner (entspricht dem "datas"-Eintrag in lxtools_installer.spec)
source_dirs = [
os.path.join(sys._MEIPASS, "locale"), # für locale/...
os.path.join(sys._MEIPASS, "TK-Themes"), # für TK-Themes/...
os.path.join(sys._MEIPASS, "lx-icons"), # für lx-icons/...
]
target_dir = os.path.abspath(
os.getcwd()
) # Zielverzeichnis: aktueller Ordner
for source_dir in source_dirs:
group_name = os.path.basename(
source_dir
) # Erhält den Gruppen-Name (z.B. 'locale', 'TK-Themes')
for root, dirs, files in os.walk(source_dir):
for file in files:
src_path = os.path.join(root, file)
# Relativer Pfad innerhalb des Quellordners
rel_path_from_source_root = os.path.relpath(
src_path, source_dir
)
# Ziel-Pfad unter dem Gruppen-Ordner im aktuellen Verzeichnis
dst_path = os.path.join(
target_dir, group_name, rel_path_from_source_root
)
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
shutil.copy2(src_path, dst_path)
@staticmethod
def setup_translations() -> gettext.gettext:
"""Initialize translations and set the translation function"""
try:
locale.bindtextdomain(
LXToolsAppConfig.APP_NAME, LXToolsAppConfig.LOCALE_DIR
)
gettext.bindtextdomain(
LXToolsAppConfig.APP_NAME, LXToolsAppConfig.LOCALE_DIR
)
gettext.textdomain(LXToolsAppConfig.APP_NAME)
except:
pass
return gettext.gettext
LXToolsAppConfig.extract_data_files()
# Initialize 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:
@staticmethod
def detect_os():
def get_os() -> str:
"""Detect operating system using ordered list"""
try:
with open("/etc/os-release", "r") as f:
@ -280,54 +29,77 @@ class OSDetector:
return "File not found"
@staticmethod
def check_tkinter_available():
"""Check if tkinter is available"""
def get_host_python_version() -> str:
try:
import tkinter
result = subprocess.run(
["python3", "--version"], capture_output=True, text=True, check=True
)
version_str = result.stdout.strip().replace("Python ", "")
return version_str[:4] # example "3.13"
except Exception:
print("Python not found")
return None
@staticmethod
def get_user_gt_1() -> bool:
"""This method may be required for the future if the number of users"""
path = Path("/home")
user_directories = [
entry
for entry in path.iterdir()
if entry.is_dir() and entry.name != "root" and entry.name != "lost+found"
]
# Count the number of user directories
numbers = len(user_directories)
if not numbers > 1:
return True
except ImportError:
else:
return False
@staticmethod
def install_tkinter():
"""Install tkinter based on detected OS"""
detected_os = OSDetector.detect_os()
def get_wget() -> bool:
"""Check if wget is installed"""
if detected_os in LXToolsAppConfig.TKINTER_INSTALL_COMMANDS:
commands = LXToolsAppConfig.TKINTER_INSTALL_COMMANDS[detected_os]
print(f"{LocaleStrings.MSGP["tk_install"]}{detected_os}...")
print(f"{LocaleStrings.MSGP["command_string"]}{' '.join(commands)}")
try:
# Use pkexec for privilege escalation
full_command = ["pkexec", "bash", "-c", " ".join(commands)]
result = subprocess.run(
full_command, capture_output=True, text=True, timeout=300
)
if result.returncode == 0:
print(f"{LocaleStrings.MSGP["tk_succcess"]}")
return True
else:
print(f"{LocaleStrings.MSGP["tk_failed"]}{result.stderr}")
return False
except subprocess.TimeoutExpired:
print(LocaleStrings.MSGP["tk_timeout"])
return False
except Exception as e:
print(f"{LocaleStrings.MSGP['tk_install_error']}{str(e)}")
return False
result = subprocess.run(
["which", "wget"], capture_output=True, text=True, check=False
)
if result.returncode == 0:
return True
else:
return False
@staticmethod
def get_unzip() -> bool:
"""Check if wget is installed"""
result = subprocess.run(
["which", "unzip"], capture_output=True, text=True, check=False
)
if result.returncode == 0:
return True
else:
return False
@staticmethod
def get_requests() -> bool:
"""Check if requests is installed"""
result = subprocess.run(
["pacman", "-Qs", "python-requests"],
capture_output=True,
text=True,
check=False,
)
if result.returncode == 0:
return True
else:
print(f"{LocaleStrings.MSGP["tk_command_error"]}{detected_os}")
return False
class Theme:
@staticmethod
def apply_light_theme(root):
def apply_light_theme(root) -> bool:
"""Apply light theme"""
try:
theme_dir = LXToolsAppConfig.THEMES_DIR
@ -358,41 +130,41 @@ class Theme:
class System:
@staticmethod
def create_directories(directories):
def create_directories(directories) -> None:
"""Create system directories using pkexec"""
for directory in directories:
subprocess.run(["pkexec", "mkdir", "-p", directory], check=True)
@staticmethod
def copy_file(src, dest, make_executable=False):
def copy_file(src, dest, make_executable=False) -> None:
"""Copy file using pkexec"""
subprocess.run(["pkexec", "cp", src, dest], check=True)
if make_executable:
subprocess.run(["pkexec", "chmod", "755", dest], check=True)
@staticmethod
def copy_directory(src, dest):
def copy_directory(src, dest) -> None:
"""Copy directory using pkexec"""
subprocess.run(["pkexec", "cp", "-r", src, dest], check=True)
@staticmethod
def remove_file(path):
def remove_file(path) -> None:
"""Remove file using pkexec"""
subprocess.run(["pkexec", "rm", "-f", path], check=False)
@staticmethod
def remove_directory(path):
def remove_directory(path) -> None:
"""Remove directory using pkexec"""
subprocess.run(["pkexec", "rm", "-rf", path], check=False)
@staticmethod
def create_symlink(target, link_name):
def create_symlink(target, link_name) -> None:
"""Create symbolic link using pkexec"""
subprocess.run(["pkexec", "rm", "-f", link_name], check=False)
subprocess.run(["pkexec", "ln", "-sf", target, link_name], check=True)
@staticmethod
def create_ssl_key(pem_file):
def create_ssl_key(pem_file) -> bool:
"""Create SSL key using pkexec"""
try:
subprocess.run(
@ -408,7 +180,7 @@ class Image:
def __init__(self):
self.images = {}
def load_image(self, image_key, fallback_paths=None):
def load_image(self, image_key, fallback_paths=None) -> None | tk.PhotoImage:
"""Load PNG image using tk.PhotoImage with fallback options"""
if image_key in self.images:
return self.images[image_key]
@ -467,15 +239,16 @@ class AppManager:
def __init__(self):
self.projects = LXToolsAppConfig.PROJECTS
def get_project_info(self, project_key):
def get_project_info(self, project_key) -> dict | None:
"""Get project information by key"""
return self.projects.get(project_key)
def get_all_projects(self):
def get_all_projects(self) -> dict:
"""Get all project configurations"""
return self.projects
def is_installed(self, project_key):
def is_installed(self, project_key) -> bool:
detected_os = Detector.get_os()
"""Check if project is installed with better detection"""
if project_key == "wirepy":
# Check for wirepy symlink
@ -487,14 +260,16 @@ class AppManager:
# Check for logviewer symlink AND executable file
symlink_exists = os.path.exists("/usr/local/bin/logviewer")
executable_exists = os.path.exists(
"/usr/local/share/shared_libs/logviewer.py"
f"{LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]}/logviewer.py"
)
executable_is_executable = False
if executable_exists:
try:
# Check if file is executable
file_stat = os.stat("/usr/local/share/shared_libs/logviewer.py")
file_stat = os.stat(
f"{LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]}/logviewer.py"
)
executable_is_executable = bool(file_stat.st_mode & stat.S_IEXEC)
except:
executable_is_executable = False
@ -515,13 +290,14 @@ class AppManager:
return False
def get_installed_version(self, project_key):
def get_installed_version(self, project_key) -> str:
detected_os = Detector.get_os()
"""Get installed version from config file"""
try:
if project_key == "wirepy":
config_file = "/usr/local/share/shared_libs/wp_app_config.py"
config_file = f"{LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]}/wp_app_config.py"
elif project_key == "logviewer":
config_file = "/usr/local/share/shared_libs/logview_app_config.py"
config_file = f"{LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]}/logview_app_config.py"
else:
return "Unknown"
@ -537,7 +313,7 @@ class AppManager:
print(f"{LocaleStrings.MSGP["get_version_error"]}{project_key}: {e}")
return "Unknown"
def get_latest_version(self, project_key):
def get_latest_version(self, project_key) -> str:
"""Get latest version from API"""
project_info = self.get_project_info(project_key)
if not project_info:
@ -545,7 +321,7 @@ class AppManager:
return GiteaUpdate.api_down(project_info["api_url"])
def check_other_apps_installed(self, exclude_key):
def check_other_apps_installed(self, exclude_key) -> bool:
"""Check if other apps are still installed"""
return any(
self.is_installed(key) for key in self.projects.keys() if key != exclude_key
@ -554,7 +330,7 @@ class AppManager:
class LxTools:
@staticmethod
def center_window_cross_platform(window, width, height):
def center_window_cross_platform(window, width, height) -> None:
"""
Centers a window on the primary monitor in a way that works on both X11 and Wayland
@ -640,3 +416,276 @@ class LxTools:
x = (screen_width - width) // 2
y = (screen_height - height) // 2
window.geometry(f"{width}x{height}+{x}+{y}")
class LXToolsAppConfig:
@staticmethod
def extract_data_files() -> None:
if getattr(sys, "_MEIPASS", None) is not None:
# Liste der Quellordner (entspricht dem "datas"-Eintrag in lxtools_installer.spec)
source_dirs = [
os.path.join(sys._MEIPASS, "locale"), # für locale/...
os.path.join(sys._MEIPASS, "TK-Themes"), # für TK-Themes/...
os.path.join(sys._MEIPASS, "lx-icons"), # für lx-icons/...
]
target_dir = os.path.abspath(
os.getcwd()
) # Zielverzeichnis: aktueller Ordner
for source_dir in source_dirs:
group_name = os.path.basename(
source_dir
) # Erhält den Gruppen-Name (z.B. 'locale', 'TK-Themes')
for root, dirs, files in os.walk(source_dir):
for file in files:
src_path = os.path.join(root, file)
# Relativer Pfad innerhalb des Quellordners
rel_path_from_source_root = os.path.relpath(
src_path, source_dir
)
# Ziel-Pfad unter dem Gruppen-Ordner im aktuellen Verzeichnis
dst_path = os.path.join(
target_dir, group_name, rel_path_from_source_root
)
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
shutil.copy2(src_path, dst_path)
# Set the SSL certificate file path by start as appimage
os.environ["SSL_CERT_FILE"] = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "certs", "cacert.pem"
)
@staticmethod
def setup_translations() -> gettext.gettext:
"""Initialize translations and set the translation function"""
try:
locale.bindtextdomain(
LXToolsAppConfig.APP_NAME, LXToolsAppConfig.LOCALE_DIR
)
gettext.bindtextdomain(
LXToolsAppConfig.APP_NAME, LXToolsAppConfig.LOCALE_DIR
)
gettext.textdomain(LXToolsAppConfig.APP_NAME)
except:
pass
return gettext.gettext
VERSION = "1.1.5"
APP_NAME = "lxtoolsinstaller"
WINDOW_WIDTH = 450
WINDOW_HEIGHT = 580
# Working directory
WORK_DIR = os.getcwd()
ICONS_DIR = os.path.join(WORK_DIR, "lx-icons")
THEMES_DIR = os.path.join(WORK_DIR, "TK-Themes")
# Locale settings
LOCALE_DIR = "./locale/"
# Download URLs
WIREPY_URL = "https://git.ilunix.de/punix/Wire-Py/archive/main.zip"
SHARED_LIBS_URL = "https://git.ilunix.de/punix/shared_libs/archive/main.zip"
# API URLs for version checking
WIREPY_API_URL = "https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases"
SHARED_LIBS_API_URL = (
"https://git.ilunix.de/api/v1/repos/punix/shared_libs/releases"
)
# Project configurations
PROJECTS = {
"wirepy": {
"name": "Wire-Py",
"description": "WireGuard VPN Manager with GUI",
"download_url": WIREPY_URL,
"api_url": WIREPY_API_URL,
"icon_key": "icon_vpn",
"main_executable": "wirepy.py",
"symlink_name": "wirepy",
"config_file": "wp_app_config.py",
"desktop_file": "Wire-Py.desktop",
"policy_file": "org.sslcrypt.policy",
"requires_ssl": True,
},
"logviewer": {
"name": "LogViewer",
"description": "System Log Viewer with GUI",
"download_url": SHARED_LIBS_URL,
"api_url": SHARED_LIBS_API_URL,
"icon_key": "icon_log",
"main_executable": "logviewer.py",
"symlink_name": "logviewer",
"config_file": "logview_app_config.py",
"desktop_file": "LogViewer.desktop",
"policy_file": None,
"requires_ssl": False,
},
}
# OS Detection List (order matters - specific first, generic last)
OS_DETECTION = [
("mint", "Linux Mint"),
("pop", "Pop!_OS"),
("manjaro", "Manjaro"),
("garuda", "Garuda Linux"),
("endeavouros", "EndeavourOS"),
("fedora", "Fedora"),
("tumbleweed", "SUSE Tumbleweed"),
("leap", "SUSE Leap"),
("arch", "Arch Linux"),
("ubuntu", "Ubuntu"),
("debian", "Debian"),
]
# Package manager commands for TKinter installation
TKINTER_INSTALL_COMMANDS = {
"Ubuntu": "apt install -y python3-tk",
"Debian": "apt install -y python3-tk",
"Linux Mint": "apt install -y python3-tk",
"Pop!_OS": "apt install -y python3-tk",
"Fedora": "dnf install -y python3-tkinter",
"Arch Linux": "pacman -S --noconfirm tk",
"Manjaro": "pacman -S --noconfirm tk",
"Garuda Linux": "pacman -S --noconfirm tk",
"EndeavourOS": "pacman -S --noconfirm tk",
"SUSE Tumbleweed": "zypper install -y python3-tk",
"SUSE Leap": "zypper install -y python3-tk",
}
SHARED_LIBS_DESTINATION = {
"Ubuntu": "/usr/lib/python3/dist-packages/shared_libs",
"Debian": "/usr/lib/python3/dist-packages/shared_libs",
"Linux Mint": "/usr/lib/python3/dist-packages/shared_libs",
"Pop!_OS": "/usr/lib/python3/dist-packages/shared_libs",
"Fedora": f"/usr/lib64/python{Detector.get_host_python_version()}/site-packages/shared_libs",
"Arch Linux": f"/usr/lib64/python{Detector.get_host_python_version()}/site-packages/shared_libs",
"Manjaro": f"/usr/lib64/python{Detector.get_host_python_version()}/site-packages/shared_libs",
"Garuda Linux": f"/usr/lib64/python{Detector.get_host_python_version()}/site-packages/shared_libs",
"EndeavourOS": f"/usr/lib64/python{Detector.get_host_python_version()}/site-packages/shared_libs",
"SUSE Tumbleweed": f"/usr/lib64/python{Detector.get_host_python_version()}/site-packages/shared_libs",
"SUSE Leap": f"/usr/lib64/python{Detector.get_host_python_version()}/site-packages/shared_libs",
}
LXToolsAppConfig.extract_data_files()
# Initialize 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"),
"python_check": _("Python not installed"),
}
# 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 "),
}