1
0
forked from Mirrors/RGSX
- reorganization of all pause menu
- add xbox elite controller support, correct bug for xbox 360 controller showing "Select" for History rather than "Y"
- cleanup languages files
- improve API key handling for 1fichier and AllDebrid and logging
- update and simplify config variables and delete unused functions
- virtual keyboard for filter games now showing evreytime you have controller plugged, even on computer, steamdeck, handheld.
This commit is contained in:
skymike03
2025-09-12 00:46:45 +02:00
parent 9e128574be
commit 7fc5204135
15 changed files with 830 additions and 1061 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ ports/RGSX/logs/
ports/RGSX/images/
ports/RGSX/games/
ports/RGSX/__pycache__/
ports/RGSX/scripts/
ports/RGSX/sources.json
ports/gamelist.xml
windows/gamelist.xml

View File

@@ -183,6 +183,7 @@ try:
count = pygame.joystick.get_count()
except Exception:
count = 0
joystick_names = []
for i in range(count):
try:
@@ -197,7 +198,14 @@ if not joystick_names:
logger.debug("Aucun joystick détecté, utilisation du clavier par défaut.")
config.joystick = False
config.keyboard = True
# Si aucune marque spécifique détectée mais un joystick est présent, marquer comme générique
if not any([config.xbox_controller, config.playstation_controller, config.nintendo_controller,
config.eightbitdo_controller, config.steam_controller, config.trimui_controller,
config.logitech_controller]):
config.generic_controller = True
logger.debug("Aucun contrôleur spécifique détecté, utilisation du profil générique")
else:
# Des joysticks sont présents, activer le mode joystick et tenter la détection spécifique
config.joystick = True
config.keyboard = False
print(f"Joysticks détectés: {joystick_names}")
@@ -243,29 +251,18 @@ else:
# Note: virtual keyboard display now depends on controller presence (config.joystick)
logger.debug(f"Flags contrôleur: xbox={config.xbox_controller}, ps={config.playstation_controller}, nintendo={config.nintendo_controller}, eightbitdo={config.eightbitdo_controller}, steam={config.steam_controller}, trimui={config.trimui_controller}, logitech={config.logitech_controller}, generic={config.generic_controller}")
# Si aucune marque spécifique détectée mais un joystick est présent, marquer comme générique
if not any([config.xbox_controller, config.playstation_controller, config.nintendo_controller,
config.eightbitdo_controller, config.steam_controller, config.trimui_controller,
config.logitech_controller]):
config.generic_controller = True
logger.debug("Aucun contrôleur spécifique détecté, utilisation du profil générique")
# Initialisation des variables de grille
config.current_page = 0
config.selected_platform = 0
config.selected_key = (0, 0)
config.transition_state = "none"
# Initialisation des variables de répétition
config.repeat_action = None
config.repeat_key = None
config.repeat_start_time = 0
config.repeat_last_action = 0
# Charger la configuration de la musique AVANT d'initialiser l'audio
load_music_config()
# Charger la configuration musique AVANT d'initialiser le mixer pour respecter le paramètre music_enabled
try:
load_music_config()
logger.debug(f"Configuration musique chargée: music_enabled={getattr(config, 'music_enabled', True)}")
except Exception as e:
logger.warning(f"Impossible de charger la configuration musique avant init mixer: {e}")
# Initialisation du mixer Pygame (déférée/évitable si musique désactivée)
if getattr(config, 'music_enabled', True):
@@ -447,6 +444,8 @@ async def main():
):
if config.menu_state not in ["pause_menu", "controls_help", "controls_mapping", "history", "confirm_clear_history"]:
config.previous_menu_state = config.menu_state
# Capturer l'état d'origine pour une sortie fiable du menu pause
config.pause_origin_state = config.menu_state
config.menu_state = "pause_menu"
config.selected_option = 0
config.needs_redraw = True
@@ -454,13 +453,25 @@ async def main():
continue
if config.menu_state == "pause_menu":
action = handle_controls(event, sources, joystick, screen)
config.needs_redraw = True
#logger.debug(f"Événement transmis à handle_controls dans pause_menu: {event.type}")
continue
# Rien de spécifique ici, capturé par SIMPLE_HANDLE_STATES ci-dessous
pass
# Gestion des événements pour le menu de filtrage des plateformes
if config.menu_state == "filter_platforms":
# États simples factorisés (déclenchent juste handle_controls + redraw)
SIMPLE_HANDLE_STATES = {
"pause_menu",
"pause_controls_menu",
"pause_display_menu",
"pause_games_menu",
"pause_settings_menu",
"pause_api_keys_status",
"filter_platforms",
"display_menu",
"language_select",
"controls_help",
"confirm_cancel_download",
"reload_games_data",
}
if config.menu_state in SIMPLE_HANDLE_STATES:
action = handle_controls(event, sources, joystick, screen)
config.needs_redraw = True
continue
@@ -470,24 +481,6 @@ async def main():
if handle_accessibility_events(event):
config.needs_redraw = True
continue
if config.menu_state == "display_menu":
# Les événements sont gérés dans controls.handle_controls
action = handle_controls(event, sources, joystick, screen)
config.needs_redraw = True
continue
if config.menu_state == "language_select":
# Gérer les événements du sélecteur de langue via le système unifié
action = handle_controls(event, sources, joystick, screen)
config.needs_redraw = True
continue
if config.menu_state == "controls_help":
action = handle_controls(event, sources, joystick, screen)
config.needs_redraw = True
#logger.debug(f"Événement transmis à handle_controls dans controls_help: {event.type}")
continue
if config.menu_state == "confirm_clear_history":
action = handle_controls(event, sources, joystick, screen)
if action == "confirm":
@@ -509,7 +502,6 @@ async def main():
if config.menu_state == "reload_games_data":
action = handle_controls(event, sources, joystick, screen)
config.needs_redraw = True
#logger.debug(f"Événement transmis à handle_controls dans reload_games_data: {event.type}")
continue
if config.menu_state == "extension_warning":
@@ -800,7 +792,21 @@ async def main():
draw_extension_warning(screen)
elif config.menu_state == "pause_menu":
draw_pause_menu(screen, config.selected_option)
#logger.debug("Rendu de draw_pause_menu")
elif config.menu_state == "pause_controls_menu":
from display import draw_pause_controls_menu
draw_pause_controls_menu(screen, getattr(config, 'pause_controls_selection', 0))
elif config.menu_state == "pause_display_menu":
from display import draw_pause_display_menu
draw_pause_display_menu(screen, getattr(config, 'pause_display_selection', 0))
elif config.menu_state == "pause_games_menu":
from display import draw_pause_games_menu
draw_pause_games_menu(screen, getattr(config, 'pause_games_selection', 0))
elif config.menu_state == "pause_settings_menu":
from display import draw_pause_settings_menu
draw_pause_settings_menu(screen, getattr(config, 'pause_settings_selection', 0))
elif config.menu_state == "pause_api_keys_status":
from display import draw_pause_api_keys_status
draw_pause_api_keys_status(screen)
elif config.menu_state == "filter_platforms":
from display import draw_filter_platforms_menu
draw_filter_platforms_menu(screen)

View File

@@ -66,7 +66,7 @@
"history": {
"type": "button",
"button": 3,
"display": "Select"
"display": "Y"
},
"clear_history": {
"type": "button",

View File

@@ -13,74 +13,34 @@ except Exception:
pygame = None # type: ignore
# Version actuelle de l'application
app_version = "2.2.0.8"
def get_operating_system():
"""Renvoie le nom du système d'exploitation."""
return platform.system()
#log dans la console le système d'exploitation (désactivé en headless)
if not HEADLESS:
print(f"Système d'exploitation : {get_operating_system()}")
app_version = "2.2.1.0"
def get_application_root():
"""Détermine le dossier de l'application de manière portable."""
"""Détermine le dossier de l'application (PORTS)"""
try:
# Obtenir le chemin absolu du fichier config.py
current_file = os.path.abspath(__file__)
# Remonter au dossier parent de config.py (par exemple, dossier de l'application)
app_root = os.path.dirname(os.path.dirname(current_file))
if not HEADLESS:
print(f"Dossier de l'application : {app_root}")
return app_root
except NameError:
# Si __file__ n'est pas défini (par exemple, exécution dans un REPL)
return os.path.abspath(os.getcwd())
def get_system_root():
OPERATING_SYSTEM = get_operating_system()
"""Détermine le dossier racine du système de fichiers (par exemple, /userdata ou C:\\)."""
try:
if OPERATING_SYSTEM == "Windows":
# Sur Windows, extraire la lettre de disque
current_path = os.path.abspath(__file__)
drive, _ = os.path.splitdrive(current_path)
system_root = drive + os.sep
if not HEADLESS:
print(f"Dossier racine du système : {system_root}")
return system_root
elif OPERATING_SYSTEM == "Linux":
# tester si c'est batocera :
if os.path.exists("/usr/share/batocera"):
OPERATING_SYSTEM = "Batocera"
#remonter jusqu'à atteindre /userdata
current_path = os.path.abspath(__file__)
current_dir = current_path
while current_dir != os.path.dirname(current_dir): # Tant qu'on peut remonter
parent_dir = os.path.dirname(current_dir)
if os.path.basename(parent_dir) == "userdata": # Vérifier si le parent est userdata
system_root = parent_dir
if not HEADLESS:
print(f"Dossier racine du système : {system_root}")
return system_root
current_dir = parent_dir
# Si userdata n'est pas trouvé, retourner /
return "/"
else:
return "/"
except NameError:
return "/" if not OPERATING_SYSTEM == "Windows" else os.path.splitdrive(os.getcwd())[0] + os.sep
def detect_operating_system():
"""Renvoie le nom du système d'exploitation."""
OPERATING_SYSTEM = platform.system()
return OPERATING_SYSTEM
# Chemins de base
SYSTEM_FOLDER = get_system_root()
APP_FOLDER = os.path.join(get_application_root(), "RGSX")
ROMS_FOLDER = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(APP_FOLDER))), "roms")
SAVE_FOLDER = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(APP_FOLDER))), "saves", "ports", "rgsx")
RETROBAT_DATA_FOLDER = os.path.dirname(os.path.dirname(os.path.dirname(APP_FOLDER)))
USERDATA_FOLDER = os.path.dirname(os.path.dirname(os.path.dirname(APP_FOLDER)))
ROMS_FOLDER = os.path.join(USERDATA_FOLDER, "roms")
SAVE_FOLDER = os.path.join(USERDATA_FOLDER, "saves", "ports", "rgsx")
GAMELISTXML = os.path.join(ROMS_FOLDER, "ports","gamelist.xml")
GAMELISTXML_WINDOWS = os.path.join(ROMS_FOLDER, "windows","gamelist.xml")
# Configuration du logging
@@ -88,15 +48,12 @@ logger = logging.getLogger(__name__)
log_dir = os.path.join(APP_FOLDER, "logs")
log_file = os.path.join(log_dir, "RGSX.log")
# Chemins de base
GAMELISTXML = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(APP_FOLDER))), "roms", "ports", "gamelist.xml")
GAMELISTXML_WINDOWS = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(APP_FOLDER))), "roms", "windows", "gamelist.xml")
#Dossier /roms/ports/rgsx
#Dossier de l'APP : /roms/ports/rgsx
UPDATE_FOLDER = os.path.join(APP_FOLDER, "update")
LANGUAGES_FOLDER = os.path.join(APP_FOLDER, "languages")
MUSIC_FOLDER = os.path.join(APP_FOLDER, "assets", "music")
#Dossier /saves/ports/rgsx
#Dossier de sauvegarde : /saves/ports/rgsx
IMAGES_FOLDER = os.path.join(SAVE_FOLDER, "images")
GAMES_FOLDER = os.path.join(SAVE_FOLDER, "games")
SOURCES_FILE = os.path.join(SAVE_FOLDER, "systems_list.json")
@@ -104,7 +61,12 @@ JSON_EXTENSIONS = os.path.join(SAVE_FOLDER, "rom_extensions.json")
PRECONF_CONTROLS_PATH = os.path.join(APP_FOLDER, "assets", "controls")
CONTROLS_CONFIG_PATH = os.path.join(SAVE_FOLDER, "controls.json")
HISTORY_PATH = os.path.join(SAVE_FOLDER, "history.json")
API_KEY_1FICHIER = os.path.join(SAVE_FOLDER, "1FichierAPI.txt")
# Séparation chemin / valeur pour éviter les confusions lors du chargement
API_KEY_1FICHIER_PATH = os.path.join(SAVE_FOLDER, "1FichierAPI.txt")
API_KEY_ALLDEBRID_PATH = os.path.join(SAVE_FOLDER, "AllDebridAPI.txt")
# Valeurs chargées (remplies dynamiquement par utils.load_api_key_*).
API_KEY_1FICHIER = ""
API_KEY_ALLDEBRID = ""
RGSX_SETTINGS_PATH = os.path.join(SAVE_FOLDER, "rgsx_settings.json")
# URL
@@ -117,14 +79,12 @@ OTA_data_ZIP = os.path.join(OTA_SERVER_URL, "games.zip")
UNRAR_EXE = os.path.join(APP_FOLDER,"assets", "unrar.exe")
XDVDFS_EXE = os.path.join(APP_FOLDER,"assets", "xdvdfs.exe")
XDVDFS_LINUX = os.path.join(APP_FOLDER,"assets", "xdvdfs")
unrar_download_exe = os.path.join(OTA_SERVER_URL, "unrar.exe")
xdvdfs_download_exe = os.path.join(OTA_SERVER_URL, "xdvdfs.exe")
xdvdfs_download_linux = os.path.join(OTA_SERVER_URL, "xdvdfs")
if not HEADLESS:
# Print des chemins pour debug
print(f"OPERATING_SYSTEM: {detect_operating_system()}")
print(f"APP_FOLDER: {APP_FOLDER}")
print(f"USERDATA_FOLDER: {USERDATA_FOLDER}")
print(f"ROMS_FOLDER: {ROMS_FOLDER}")
print(f"SAVE_FOLDER: {SAVE_FOLDER}")
print(f"RGSX LOGS_FOLDER: {log_dir}")
@@ -133,7 +93,6 @@ if not HEADLESS:
print(f"IMAGES_FOLDER: {IMAGES_FOLDER}")
print(f"GAMES_FOLDER: {GAMES_FOLDER}")
print(f"SOURCES_FILE: {SOURCES_FILE}")
print(f"OPERATING_SYSTEM: {get_operating_system()}")
# Constantes pour la répétition automatique dans pause_menu

View File

@@ -1,20 +1,17 @@
import shutil
import pygame # type: ignore
import config
# Constantes pour la répétition automatique - importées de config.py
from config import REPEAT_DELAY, REPEAT_INTERVAL, REPEAT_ACTION_DEBOUNCE
from config import CONTROLS_CONFIG_PATH
import shutil
import asyncio
import json
import os
import sys
import config
from config import REPEAT_DELAY, REPEAT_INTERVAL, REPEAT_ACTION_DEBOUNCE
from config import CONTROLS_CONFIG_PATH
from display import draw_validation_transition
from network import download_rom, download_from_1fichier, is_1fichier_url
from network import download_rom, download_from_1fichier, is_1fichier_url, request_cancel
from utils import (
load_games, check_extension_before_download, is_extension_supported,
load_extensions_json, play_random_music, sanitize_filename,
load_api_key_1fichier, load_api_key_alldebrid, save_music_config
save_music_config, load_api_keys
)
from history import load_history, clear_history, add_to_history, save_history
import logging
@@ -34,16 +31,19 @@ VALID_STATES = [
"platform", "game", "confirm_exit",
"extension_warning", "pause_menu", "controls_help", "history", "controls_mapping",
"reload_games_data", "restart_popup", "error", "loading", "confirm_clear_history",
"language_select", "filter_platforms", "display_menu"
"language_select", "filter_platforms", "display_menu",
# Nouveaux sous-menus hiérarchiques (refonte pause menu)
"pause_controls_menu", # sous-menu Controls (aide, remap)
"pause_display_menu", # sous-menu Display (layout, font size, unsupported, unknown ext, filter)
"pause_games_menu", # sous-menu Games (source mode, update/redownload cache)
"pause_settings_menu", # sous-menu Settings (music on/off, symlink toggle, api keys status)
"pause_api_keys_status" # sous-menu API Keys (affichage statut des clés)
]
def validate_menu_state(state):
if state not in VALID_STATES:
logger.debug(f"État invalide {state}, retour à platform")
return "platform"
if state == "history": # Éviter de revenir à history
logger.debug(f"État history non autorisé comme previous_menu_state, retour à platform")
return "platform"
return state
@@ -133,6 +133,7 @@ def load_controls_config(path=CONTROLS_CONFIG_PATH):
# 3) Fallback clavier par défaut
logging.getLogger(__name__).info("Aucun fichier utilisateur ou préréglage trouvé, utilisation des contrôles par défaut")
return default_config.copy()
except Exception as e:
logging.getLogger(__name__).error(f"Erreur load_controls_config: {e}")
return default_config.copy()
@@ -318,6 +319,8 @@ def handle_controls(event, sources, joystick, screen):
config.repeat_last_action = current_time
config.needs_redraw = True
elif is_input_matched(event, "history"):
# Capturer l'origine si on vient directement des plateformes
config.history_origin = "platform"
config.menu_state = "history"
config.needs_redraw = True
logger.debug("Ouverture history depuis platform")
@@ -334,6 +337,8 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
#logger.debug(f"Plateforme sélectionnée: {config.platforms[config.current_platform]}, {len(config.games)} jeux chargés")
elif is_input_matched(event, "cancel"):
# Capturer l'origine (plateformes) pour un retour correct si l'utilisateur choisit "Non"
config.confirm_exit_origin = "platform"
config.menu_state = "confirm_exit"
config.confirm_selection = 0
config.needs_redraw = True
@@ -584,14 +589,8 @@ def handle_controls(event, sources, joystick, screen):
config.current_history_item = len(config.history) -1
task_id = str(pygame.time.get_ticks())
if is_1fichier_url(url):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
# Fallback AllDebrid
try:
config.API_KEY_ALLDEBRID = load_api_key_alldebrid()
except Exception:
config.API_KEY_ALLDEBRID = getattr(config, "API_KEY_ALLDEBRID", "")
if not config.API_KEY_1FICHIER and not getattr(config, "API_KEY_ALLDEBRID", ""):
keys = load_api_keys()
if not keys.get('1fichier') and not keys.get('alldebrid'):
config.history[-1]["status"] = "Erreur"
config.history[-1]["message"] = "API NOT FOUND"
save_history(config.history)
@@ -626,14 +625,8 @@ def handle_controls(event, sources, joystick, screen):
config.current_history_item = len(config.history) - 1
# Vérifier d'abord si c'est un lien 1fichier
if is_1fichier_url(url):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
# Fallback AllDebrid
try:
config.API_KEY_ALLDEBRID = load_api_key_alldebrid()
except Exception:
config.API_KEY_ALLDEBRID = getattr(config, "API_KEY_ALLDEBRID", "")
if not config.API_KEY_1FICHIER and not getattr(config, "API_KEY_ALLDEBRID", ""):
keys = load_api_keys()
if not keys.get('1fichier') and not keys.get('alldebrid'):
config.previous_menu_state = config.menu_state
config.menu_state = "error"
try:
@@ -748,13 +741,8 @@ def handle_controls(event, sources, joystick, screen):
))
config.current_history_item = len(config.history) - 1
if is_1fichier_url(url):
if not config.API_KEY_1FICHIER:
# Fallback AllDebrid
try:
config.API_KEY_ALLDEBRID = load_api_key_alldebrid()
except Exception:
config.API_KEY_ALLDEBRID = getattr(config, "API_KEY_ALLDEBRID", "")
if not config.API_KEY_1FICHIER and not getattr(config, "API_KEY_ALLDEBRID", ""):
keys = load_api_keys()
if not keys.get('1fichier') and not keys.get('alldebrid'):
config.previous_menu_state = config.menu_state
config.menu_state = "error"
try:
@@ -821,14 +809,8 @@ def handle_controls(event, sources, joystick, screen):
config.current_history_item = len(config.history) -1
task_id = str(pygame.time.get_ticks())
if is_1fichier_url(url):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
# Fallback AllDebrid
try:
config.API_KEY_ALLDEBRID = load_api_key_alldebrid()
except Exception:
config.API_KEY_ALLDEBRID = getattr(config, "API_KEY_ALLDEBRID", "")
if not config.API_KEY_1FICHIER and not getattr(config, "API_KEY_ALLDEBRID", ""):
keys = load_api_keys()
if not keys.get('1fichier') and not keys.get('alldebrid'):
config.history[-1]["status"] = "Erreur"
config.history[-1]["message"] = "API NOT FOUND"
save_history(config.history)
@@ -892,14 +874,8 @@ def handle_controls(event, sources, joystick, screen):
config.current_history_item = len(config.history) -1
task_id = str(pygame.time.get_ticks())
if is_1fichier_url(url):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
# Fallback AllDebrid
try:
config.API_KEY_ALLDEBRID = load_api_key_alldebrid()
except Exception:
config.API_KEY_ALLDEBRID = getattr(config, "API_KEY_ALLDEBRID", "")
if not config.API_KEY_1FICHIER and not getattr(config, "API_KEY_ALLDEBRID", ""):
keys = load_api_keys()
if not keys.get('1fichier') and not keys.get('alldebrid'):
config.history[-1]["status"] = "Erreur"
config.history[-1]["message"] = "API NOT FOUND"
save_history(config.history)
@@ -969,75 +945,6 @@ def handle_controls(event, sources, joystick, screen):
config.confirm_clear_selection = 0 # 0 pour "Non", 1 pour "Oui"
config.needs_redraw = True
logger.debug("Passage à confirm_clear_history depuis history")
elif is_input_matched(event, "confirm"):
if history:
entry = history[config.current_history_item]
platform = entry["platform"]
game_name = entry["game_name"]
for game in config.games:
if game[0] == game_name and config.platforms[config.current_platform] == platform:
config.pending_download = check_extension_before_download(game[1], platform, game_name)
if config.pending_download:
url, platform, game_name, is_zip_non_supported = config.pending_download
# Recalculer le support exact et décider via le flag is_zip_non_supported
is_supported = is_extension_supported(
sanitize_filename(game_name),
platform,
load_extensions_json()
)
if not is_supported and not is_zip_non_supported:
config.previous_menu_state = config.menu_state
config.menu_state = "extension_warning"
config.extension_confirm_selection = 0
config.needs_redraw = True
logger.debug(f"Extension non supportée pour retéléchargement, passage à extension_warning pour {game_name}")
else:
task_id = str(pygame.time.get_ticks())
if is_1fichier_url(url):
if not config.API_KEY_1FICHIER:
# Fallback AllDebrid
try:
config.API_KEY_ALLDEBRID = load_api_key_alldebrid()
except Exception:
config.API_KEY_ALLDEBRID = getattr(config, "API_KEY_ALLDEBRID", "")
if not config.API_KEY_1FICHIER and not getattr(config, "API_KEY_ALLDEBRID", ""):
config.previous_menu_state = config.menu_state
config.menu_state = "error"
logger.warning("clé api absente pour 1fichier et AllDebrid")
try:
both_paths = f"{os.path.join(config.SAVE_FOLDER,'1FichierAPI.txt')} or {os.path.join(config.SAVE_FOLDER,'AllDebridAPI.txt')}"
config.error_message = _("error_api_key").format(both_paths)
except Exception:
config.error_message = "Please enter API key (1fichier or AllDebrid)"
config.history[-1]["status"] = "Erreur"
config.history[-1]["progress"] = 0
config.history[-1]["message"] = "API NOT FOUND"
save_history(config.history)
config.needs_redraw = True
logger.error("Clé API 1fichier et AllDebrid absentes, retéléchargement impossible.")
config.pending_download = None
return action
task = asyncio.create_task(download_from_1fichier(url, platform, game_name, is_zip_non_supported, task_id))
else:
task = asyncio.create_task(download_rom(url, platform, game_name, is_zip_non_supported, task_id))
config.download_tasks[task_id] = (task, url, game_name, platform)
config.previous_menu_state = config.menu_state
config.menu_state = "history"
config.needs_redraw = True
logger.debug(f"Retéléchargement: {game_name} pour {platform} depuis {url}, task_id={task_id}")
config.pending_download = None
action = "redownload"
else:
config.menu_state = "error"
try:
config.error_message = _("error_invalid_download_data")
except Exception:
config.error_message = "Invalid download data"
config.pending_download = None
config.needs_redraw = True
logger.error(f"config.pending_download est None pour {game_name}")
break
elif is_input_matched(event, "cancel") or is_input_matched(event, "history"):
if config.history and config.current_history_item < len(config.history):
entry = config.history[config.current_history_item]
@@ -1047,7 +954,14 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
logger.debug("Demande d'annulation de téléchargement")
return action
config.menu_state = validate_menu_state(config.previous_menu_state)
# Retour à l'origine capturée si disponible sinon previous_menu_state
target = getattr(config, 'history_origin', getattr(config, 'previous_menu_state', 'platform'))
config.menu_state = validate_menu_state(target)
if hasattr(config, 'history_origin'):
try:
delattr(config, 'history_origin')
except Exception:
pass
config.current_history_item = 0
config.history_scroll_offset = 0
config.needs_redraw = True
@@ -1088,7 +1002,7 @@ def handle_controls(event, sources, joystick, screen):
# Confirmation vider l'historique
elif config.menu_state == "confirm_clear_history":
logger.debug(f"État confirm_clear_history, confirm_clear_selection={config.confirm_clear_selection}, événement={event.type}, valeur={getattr(event, 'value', None)}")
if is_input_matched(event, "confirm"):
# 0 = Non, 1 = Oui
if config.confirm_clear_selection == 1: # Oui
@@ -1098,7 +1012,6 @@ def handle_controls(event, sources, joystick, screen):
config.history_scroll_offset = 0
config.menu_state = "history"
config.needs_redraw = True
logger.info("Historique vidé après confirmation")
else: # Non
config.menu_state = "history"
config.needs_redraw = True
@@ -1110,8 +1023,6 @@ def handle_controls(event, sources, joystick, screen):
config.needs_redraw = True
logger.debug("Annulation du vidage de l'historique, retour à history")
# État download_result supprimé
# Confirmation quitter
elif config.menu_state == "confirm_exit":
if is_input_matched(event, "confirm"):
@@ -1128,9 +1039,16 @@ def handle_controls(event, sources, joystick, screen):
pass
return "quit"
else:
config.menu_state = validate_menu_state(config.previous_menu_state)
# Retour à l'état capturé (confirm_exit_origin) sinon previous_menu_state sinon platform
target = getattr(config, 'confirm_exit_origin', getattr(config, 'previous_menu_state', 'platform'))
config.menu_state = validate_menu_state(target)
if hasattr(config, 'confirm_exit_origin'):
try:
delattr(config, 'confirm_exit_origin')
except Exception:
pass
config.needs_redraw = True
logger.debug(f"Retour à {config.menu_state} depuis confirm_exit")
logger.debug(f"Retour à {config.menu_state} depuis confirm_exit (annulation)")
elif is_input_matched(event, "left") or is_input_matched(event, "right"):
config.confirm_selection = 1 - config.confirm_selection
config.needs_redraw = True
@@ -1141,58 +1059,213 @@ def handle_controls(event, sources, joystick, screen):
#logger.debug(f"État pause_menu, selected_option={config.selected_option}, événement={event.type}, valeur={getattr(event, 'value', None)}")
# Start toggles back to previous state when already in pause
if is_input_matched(event, "start"):
config.menu_state = validate_menu_state(config.previous_menu_state)
target = getattr(config, 'pause_origin_state', getattr(config, 'previous_menu_state', 'platform'))
config.menu_state = validate_menu_state(target)
config.needs_redraw = True
logger.debug(f"Start: retour à {config.menu_state} depuis pause_menu")
elif is_input_matched(event, "up"):
config.selected_option = max(0, config.selected_option - 1)
config.needs_redraw = True
elif is_input_matched(event, "down"):
# Nombre d'options dynamique (inclut éventuellement l'option source des jeux)
total = getattr(config, 'pause_menu_total_options', 11) # fallback 11 (Restart added)
# Menu racine hiérarchique: nombre dynamique (langue + catégories)
total = getattr(config, 'pause_menu_total_options', 7)
config.selected_option = min(total - 1, config.selected_option + 1)
config.needs_redraw = True
elif is_input_matched(event, "confirm"):
if config.selected_option == 0: # Controls
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
config.menu_state = "controls_help"
if config.selected_option == 0: # Language selector direct
config.menu_state = "language_select"
config.previous_menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
#logger.debug(f"Passage à controls_help depuis pause_menu")
elif config.selected_option == 1: # Remap controls
elif config.selected_option == 1: # Controls submenu
config.menu_state = "pause_controls_menu"
if not hasattr(config, 'pause_controls_selection'):
config.pause_controls_selection = 0
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif config.selected_option == 2: # Display submenu
config.menu_state = "pause_display_menu"
if not hasattr(config, 'pause_display_selection'):
config.pause_display_selection = 0
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif config.selected_option == 3: # Games submenu
config.menu_state = "pause_games_menu"
if not hasattr(config, 'pause_games_selection'):
config.pause_games_selection = 0
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif config.selected_option == 4: # Settings submenu
config.menu_state = "pause_settings_menu"
if not hasattr(config, 'pause_settings_selection'):
config.pause_settings_selection = 0
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif config.selected_option == 5: # Restart
from utils import restart_application
restart_application(2000)
elif config.selected_option == 6: # Quit
# Capturer l'origine pause_menu pour retour si annulation
config.confirm_exit_origin = "pause_menu"
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
#logger.debug(f"Previous menu state avant controls_mapping: {config.previous_menu_state}")
#Supprimer le fichier de configuration des contrôles s'il existe
config.menu_state = "confirm_exit"
config.confirm_selection = 0
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif is_input_matched(event, "cancel"):
target = getattr(config, 'pause_origin_state', getattr(config, 'previous_menu_state', 'platform'))
config.menu_state = validate_menu_state(target)
config.needs_redraw = True
logger.debug(f"Retour à {config.menu_state} depuis pause_menu")
# Sous-menu Controls
elif config.menu_state == "pause_controls_menu":
sel = getattr(config, 'pause_controls_selection', 0)
if is_input_matched(event, "up"):
config.pause_controls_selection = (sel - 1) % 3
config.needs_redraw = True
elif is_input_matched(event, "down"):
config.pause_controls_selection = (sel + 1) % 3
config.needs_redraw = True
elif is_input_matched(event, "confirm"):
if sel == 0: # Aide
config.previous_menu_state = "pause_controls_menu"
config.menu_state = "controls_help"
elif sel == 1: # Remap
if os.path.exists(config.CONTROLS_CONFIG_PATH):
try:
os.remove(config.CONTROLS_CONFIG_PATH)
logger.debug(f"Fichier de configuration des contrôles supprimé: {config.CONTROLS_CONFIG_PATH}")
except Exception as e:
logger.error(f"Erreur lors de la suppression du fichier de configuration des contrôles: {e}")
logger.error(f"Erreur suppression controls_config: {e}")
config.previous_menu_state = "pause_controls_menu"
config.menu_state = "controls_mapping"
else: # Back
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif is_input_matched(event, "cancel") or is_input_matched(event, "start"):
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
# Sous-menu Display
elif config.menu_state == "pause_display_menu":
sel = getattr(config, 'pause_display_selection', 0)
total = 6 # layout, font, unsupported, unknown, filter, back
if is_input_matched(event, "up"):
config.pause_display_selection = (sel - 1) % total
config.needs_redraw = True
elif is_input_matched(event, "down"):
config.pause_display_selection = (sel + 1) % total
config.needs_redraw = True
elif is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm"):
sel = getattr(config, 'pause_display_selection', 0)
# 0 layout cycle
if sel == 0 and (is_input_matched(event, "left") or is_input_matched(event, "right")):
layouts = [(3,3),(3,4),(4,3),(4,4)]
try:
idx = layouts.index((config.GRID_COLS, config.GRID_ROWS))
except ValueError:
idx = 0
idx = (idx + 1) % len(layouts) if is_input_matched(event, "right") else (idx - 1) % len(layouts)
new_cols, new_rows = layouts[idx]
try:
from rgsx_settings import set_display_grid
set_display_grid(new_cols, new_rows)
except Exception as e:
logger.error(f"Erreur set_display_grid: {e}")
config.GRID_COLS = new_cols
config.GRID_ROWS = new_rows
# Redémarrage automatique
try:
from utils import restart_application
config.menu_state = "restart_popup"
config.popup_message = _("popup_restarting") if _ else "Restarting..."
config.popup_timer = 2000
restart_application(2000)
except Exception as e:
logger.error(f"Erreur restart après layout: {e}")
config.needs_redraw = True
logger.debug(f"Passage à controls_mapping depuis pause_menu")
elif config.selected_option == 2: # History
# 1 font size
elif sel == 1 and (is_input_matched(event, "left") or is_input_matched(event, "right")):
from accessibility import save_accessibility_settings
opts = getattr(config, 'font_scale_options', [0.75,1.0,1.25,1.5,1.75])
idx = getattr(config, 'current_font_scale_index', 1)
idx = max(0, idx-1) if is_input_matched(event, "left") else min(len(opts)-1, idx+1)
if idx != getattr(config, 'current_font_scale_index', 1):
config.current_font_scale_index = idx
scale = opts[idx]
config.accessibility_settings["font_scale"] = scale
try:
save_accessibility_settings(config.accessibility_settings)
except Exception as e:
logger.error(f"Erreur sauvegarde accessibilité: {e}")
try:
config.init_font()
except Exception as e:
logger.error(f"Erreur init polices: {e}")
config.needs_redraw = True
# 2 unsupported toggle
elif sel == 2 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
try:
from rgsx_settings import get_show_unsupported_platforms, set_show_unsupported_platforms
current = get_show_unsupported_platforms()
new_val = set_show_unsupported_platforms(not current)
from utils import load_sources
load_sources()
config.popup_message = _("menu_show_unsupported_enabled") if new_val else _("menu_show_unsupported_disabled")
config.popup_timer = 3000
config.needs_redraw = True
except Exception as e:
logger.error(f"Erreur toggle unsupported: {e}")
# 3 allow unknown extensions
elif sel == 3 and (is_input_matched(event, "left") or is_input_matched(event, "right") or is_input_matched(event, "confirm")):
try:
from rgsx_settings import get_allow_unknown_extensions, set_allow_unknown_extensions
current = get_allow_unknown_extensions()
new_val = set_allow_unknown_extensions(not current)
config.popup_message = _("menu_allow_unknown_ext_enabled") if new_val else _("menu_allow_unknown_ext_disabled")
config.popup_timer = 3000
config.needs_redraw = True
except Exception as e:
logger.error(f"Erreur toggle allow_unknown_extensions: {e}")
# 4 filter platforms
elif sel == 4 and (is_input_matched(event, "confirm") or is_input_matched(event, "right")):
config.filter_return_to = "pause_display_menu"
config.menu_state = "filter_platforms"
config.selected_filter_index = 0
config.filter_platforms_scroll_offset = 0
config.needs_redraw = True
# 5 back
elif sel == 5 and (is_input_matched(event, "confirm")):
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif is_input_matched(event, "cancel") or is_input_matched(event, "start"):
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
# Sous-menu Games
elif config.menu_state == "pause_games_menu":
sel = getattr(config, 'pause_games_selection', 0)
total = 4 # history, source, redownload, back
if is_input_matched(event, "up"):
config.pause_games_selection = (sel - 1) % total
config.needs_redraw = True
elif is_input_matched(event, "down"):
config.pause_games_selection = (sel + 1) % total
config.needs_redraw = True
elif is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right"):
sel = getattr(config, 'pause_games_selection', 0)
if sel == 0 and is_input_matched(event, "confirm"): # history
config.history = load_history()
config.current_history_item = 0
config.history_scroll_offset = 0
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
config.previous_menu_state = "pause_games_menu"
config.menu_state = "history"
config.needs_redraw = True
logger.debug(f"Passage à history depuis pause_menu")
elif config.selected_option == 3: # Language
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
config.menu_state = "language_select"
config.selected_language_index = 0
config.needs_redraw = True
logger.debug(f"Passage à language_select depuis pause_menu")
elif config.selected_option == 4: # Display
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
config.menu_state = "display_menu"
if not hasattr(config, 'display_menu_selection'):
config.display_menu_selection = 0
config.needs_redraw = True
logger.debug("Passage au menu affichage")
elif config.selected_option == 5: # Source toggle (index shifted by removal of filter)
elif sel == 1 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")):
try:
from rgsx_settings import get_sources_mode, set_sources_mode
current_mode = get_sources_mode()
@@ -1208,13 +1281,33 @@ def handle_controls(event, sources, joystick, screen):
logger.info(f"Changement du mode des sources vers {new_mode}")
except Exception as e:
logger.error(f"Erreur changement mode sources: {e}")
elif config.selected_option == 6: # Redownload game cache
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
elif sel == 2 and is_input_matched(event, "confirm"): # redownload cache
config.previous_menu_state = "pause_games_menu"
config.menu_state = "reload_games_data"
config.redownload_confirm_selection = 0
config.needs_redraw = True
logger.debug(f"Passage à reload_games_data depuis pause_menu")
elif config.selected_option == 7: # Music toggle
elif sel == 3 and is_input_matched(event, "confirm"): # back
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif is_input_matched(event, "cancel") or is_input_matched(event, "start"):
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
# Sous-menu Settings
elif config.menu_state == "pause_settings_menu":
sel = getattr(config, 'pause_settings_selection', 0)
total = 4 # music, symlink, api keys, back
if is_input_matched(event, "up"):
config.pause_settings_selection = (sel - 1) % total
config.needs_redraw = True
elif is_input_matched(event, "down"):
config.pause_settings_selection = (sel + 1) % total
config.needs_redraw = True
elif is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right"):
sel = getattr(config, 'pause_settings_selection', 0)
if sel == 0 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")):
config.music_enabled = not config.music_enabled
save_music_config()
if config.music_enabled:
@@ -1225,28 +1318,32 @@ def handle_controls(event, sources, joystick, screen):
else:
pygame.mixer.music.stop()
config.needs_redraw = True
logger.info(f"Musique {'activée' if config.music_enabled else 'désactivée'} via menu pause")
elif config.selected_option == 8: # Symlink option
logger.info(f"Musique {'activée' if config.music_enabled else 'désactivée'} via settings")
elif sel == 1 and (is_input_matched(event, "confirm") or is_input_matched(event, "left") or is_input_matched(event, "right")):
from rgsx_settings import set_symlink_option, get_symlink_option
current_status = get_symlink_option()
success, message = set_symlink_option(not current_status)
config.popup_message = message
config.popup_timer = 3000 if success else 5000
config.needs_redraw = True
logger.info(f"Symlink option {'activée' if not current_status else 'désactivée'} via menu pause")
elif config.selected_option == 9: # Restart
from utils import restart_application
restart_application(2000)
elif config.selected_option == 10: # Quit
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
config.menu_state = "confirm_exit"
config.confirm_selection = 0
logger.info(f"Symlink option {'activée' if not current_status else 'désactivée'} via settings")
elif sel == 2 and is_input_matched(event, "confirm"):
config.menu_state = "pause_api_keys_status"
config.needs_redraw = True
logger.debug(f"Passage à confirm_exit depuis pause_menu")
elif is_input_matched(event, "cancel"):
config.menu_state = validate_menu_state(config.previous_menu_state)
elif sel == 3 and is_input_matched(event, "confirm"):
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif is_input_matched(event, "cancel") or is_input_matched(event, "start"):
config.menu_state = "pause_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
elif config.menu_state == "pause_api_keys_status":
if is_input_matched(event, "cancel") or is_input_matched(event, "confirm") or is_input_matched(event, "start"):
config.menu_state = "pause_settings_menu"
config.last_state_change_time = pygame.time.get_ticks()
config.needs_redraw = True
logger.debug(f"Retour à {config.menu_state} depuis pause_menu")
# Aide contrôles
elif config.menu_state == "controls_help":
@@ -1535,9 +1632,10 @@ def handle_controls(event, sources, joystick, screen):
# Return either to display menu or pause menu depending on origin
target = getattr(config, 'filter_return_to', 'pause_menu')
config.menu_state = target
if target == 'display_menu':
# reset display selection to the Filter item for convenience
if target == 'display_menu': # ancien cas (fallback)
config.display_menu_selection = 3
elif target == 'pause_display_menu': # nouveau sous-menu hiérarchique
config.pause_display_selection = 4 # positionner sur Filter
else:
config.selected_option = 5 # keep pointer on Filter in pause menu
config.filter_return_to = None
@@ -1546,6 +1644,8 @@ def handle_controls(event, sources, joystick, screen):
config.menu_state = target
if target == 'display_menu':
config.display_menu_selection = 3
elif target == 'pause_display_menu':
config.pause_display_selection = 4
else:
config.selected_option = 5
config.filter_return_to = None
@@ -1555,6 +1655,8 @@ def handle_controls(event, sources, joystick, screen):
config.menu_state = target
if target == 'display_menu':
config.display_menu_selection = 3
elif target == 'pause_display_menu':
config.pause_display_selection = 4
else:
config.selected_option = 5
config.filter_return_to = None

View File

@@ -1403,54 +1403,178 @@ def draw_display_menu(screen):
screen.blit(instruction_surface, instruction_rect)
def draw_pause_menu(screen, selected_option):
"""Dessine le menu pause avec un style moderne."""
"""Dessine le menu pause racine (catégories)."""
screen.blit(OVERLAY, (0, 0))
from rgsx_settings import get_symlink_option, get_sources_mode, get_show_unsupported_platforms
mode = get_sources_mode()
source_label = _("games_source_rgsx") if mode == "rgsx" else _("games_source_custom")
if config.music_enabled:
music_name = config.current_music_name or ""
music_option = _("menu_music_enabled").format(music_name)
else:
music_option = _("menu_music_disabled")
symlink_option = _("symlink_option_enabled") if get_symlink_option() else _("symlink_option_disabled")
# Nouvel ordre: Language / Controls / Display / Games / Settings / Restart / Quit
options = [
_("menu_controls"), # 0
_("menu_remap_controls"), # 1
_("menu_history"), # 2
_("menu_language"), # 3
_("menu_display"), # 4 new merged display menu
f"{_('menu_games_source_prefix')}: {source_label}", # 5 (shifted left)
_("menu_redownload_cache"), # 6
music_option, # 7
symlink_option, # 8
_("menu_restart"), # 9 (new)
_("menu_quit") # 10
_("menu_language") if _ else "Language", # 0 -> sélecteur de langue direct
_("menu_controls"), # 1 -> sous-menu controls
_("menu_display"), # 2 -> sous-menu display
_("menu_games") if _ else "Games", # 3 -> sous-menu games (history + sources + update)
_("menu_settings_category") if _ else "Settings", # 4 -> sous-menu settings
_("menu_restart"), # 5 -> reboot
_("menu_quit") # 6 -> quit
]
menu_width = int(config.screen_width * 0.8)
line_height = config.font.get_height() + 10
button_height = int(config.screen_height * 0.0463)
margin_top_bottom = 20
menu_height = len(options) * (button_height + 10) + 2 * margin_top_bottom
menu_width = int(config.screen_width * 0.6)
button_height = int(config.screen_height * 0.048)
margin_top_bottom = 24
menu_height = len(options) * (button_height + 12) + 2 * margin_top_bottom
menu_x = (config.screen_width - menu_width) // 2
menu_y = (config.screen_height - menu_height) // 2
pygame.draw.rect(screen, THEME_COLORS["button_idle"], (menu_x, menu_y, menu_width, menu_height), border_radius=12)
pygame.draw.rect(screen, THEME_COLORS["border"], (menu_x, menu_y, menu_width, menu_height), 2, border_radius=12)
for i, option in enumerate(options):
draw_stylized_button(
screen,
option,
menu_x + 20,
menu_y + margin_top_bottom + i * (button_height + 10),
menu_y + margin_top_bottom + i * (button_height + 12),
menu_width - 40,
button_height,
selected=i == selected_option
)
# Stocker le nombre total d'options pour la navigation dynamique
config.pause_menu_total_options = len(options)
def _draw_submenu_generic(screen, title, options, selected_index):
"""Helper générique pour dessiner un sous-menu hiérarchique."""
screen.blit(OVERLAY, (0, 0))
menu_width = int(config.screen_width * 0.72)
button_height = int(config.screen_height * 0.045)
margin_top_bottom = 26
menu_height = (len(options)+1) * (button_height + 10) + 2 * margin_top_bottom # +1 pour le titre
menu_x = (config.screen_width - menu_width) // 2
menu_y = (config.screen_height - menu_height) // 2
pygame.draw.rect(screen, THEME_COLORS["button_idle"], (menu_x, menu_y, menu_width, menu_height), border_radius=14)
pygame.draw.rect(screen, THEME_COLORS["border"], (menu_x, menu_y, menu_width, menu_height), 2, border_radius=14)
# Title
title_surface = config.font.render(title, True, THEME_COLORS["text"])
title_rect = title_surface.get_rect(center=(config.screen_width//2, menu_y + margin_top_bottom//2 + title_surface.get_height()//2))
screen.blit(title_surface, title_rect)
# Options
start_y = title_rect.bottom + 10
for i, opt in enumerate(options):
draw_stylized_button(
screen,
opt,
menu_x + 20,
start_y + i * (button_height + 10),
menu_width - 40,
button_height,
selected=(i == selected_index)
)
def draw_pause_controls_menu(screen, selected_index):
options = [
_("menu_controls"), # aide contrôles (réutilisée)
_("menu_remap_controls"), # remap
_("menu_back") if _ else "Back"
]
_draw_submenu_generic(screen, _("menu_controls") if _ else "Controls", options, selected_index)
def draw_pause_display_menu(screen, selected_index):
from rgsx_settings import get_show_unsupported_platforms, get_allow_unknown_extensions
# Layout label
layouts = [(3,3),(3,4),(4,3),(4,4)]
try:
idx = layouts.index((config.GRID_COLS, config.GRID_ROWS))
except ValueError:
idx = 0
layout_value = f"{layouts[idx][0]}x{layouts[idx][1]}"
layout_txt = f"{_('submenu_display_layout') if _ else 'Layout'}: < {layout_value} >"
# Font size
opts = getattr(config, 'font_scale_options', [0.75, 1.0, 1.25, 1.5, 1.75])
cur_idx = getattr(config, 'current_font_scale_index', 1)
font_value = f"{opts[cur_idx]}x"
font_txt = f"{_('submenu_display_font_size') if _ else 'Font Size'}: < {font_value} >"
unsupported = get_show_unsupported_platforms()
status_unsupported = _('status_on') if unsupported else _('status_off')
# Construire label sans statut pour insérer les chevrons proprement
raw_unsupported_label = _('submenu_display_show_unsupported') if _ else 'Show unsupported systems: {status}'
# Retirer éventuel placeholder et ponctuation finale
if '{status}' in raw_unsupported_label:
raw_unsupported_label = raw_unsupported_label.split('{status}')[0].rstrip(' :')
unsupported_txt = f"{raw_unsupported_label}: < {status_unsupported} >"
allow_unknown = get_allow_unknown_extensions()
status_unknown = _('status_on') if allow_unknown else _('status_off')
raw_unknown_label = _('submenu_display_allow_unknown_ext') if _ else 'Hide unknown ext warn: {status}'
if '{status}' in raw_unknown_label:
raw_unknown_label = raw_unknown_label.split('{status}')[0].rstrip(' :')
unknown_txt = f"{raw_unknown_label}: < {status_unknown} >"
filter_txt = _("submenu_display_filter_platforms") if _ else "Filter Platforms"
back_txt = _("menu_back") if _ else "Back"
options = [layout_txt, font_txt, unsupported_txt, unknown_txt, filter_txt, back_txt]
_draw_submenu_generic(screen, _("menu_display"), options, selected_index)
def draw_pause_games_menu(screen, selected_index):
from rgsx_settings import get_sources_mode
mode = get_sources_mode()
source_label = _("games_source_rgsx") if mode == "rgsx" else _("games_source_custom")
source_txt = f"{_('menu_games_source_prefix')}: < {source_label} >"
update_txt = _("menu_redownload_cache")
# Première entrée: Historique des téléchargements (utiliser la clé menu_history)
history_txt = _("menu_history") if _ else "History"
back_txt = _("menu_back") if _ else "Back"
options = [history_txt, source_txt, update_txt, back_txt]
_draw_submenu_generic(screen, _("menu_games") if _ else "Games", options, selected_index)
def draw_pause_settings_menu(screen, selected_index):
from rgsx_settings import get_symlink_option
# Music
if config.music_enabled:
music_name = config.current_music_name or ""
music_option = _("menu_music_enabled").format(music_name)
else:
music_option = _("menu_music_disabled")
# Uniformiser en < value > pour les réglages basculables
if ' : ' in music_option:
base, val = music_option.split(' : ',1)
music_option = f"{base} : < {val.strip()} >"
symlink_option = _("symlink_option_enabled") if get_symlink_option() else _("symlink_option_disabled")
if ' ' in symlink_option:
parts = symlink_option.split(' ',1)
# On garde phrase intacte si elle n'a pas de forme label: valeur ; sinon transformer
if ' : ' in symlink_option:
base, val = symlink_option.split(' : ',1)
symlink_option = f"{base} : < {val.strip()} >"
api_keys_txt = _("menu_api_keys_status") if _ else "API Keys"
back_txt = _("menu_back") if _ else "Back"
options = [music_option, symlink_option, api_keys_txt, back_txt]
_draw_submenu_generic(screen, _("menu_settings_category") if _ else "Settings", options, selected_index)
def draw_pause_api_keys_status(screen):
screen.blit(OVERLAY, (0,0))
from utils import load_api_keys
keys = load_api_keys()
# Layout simple
lines = [
_("api_keys_status_title") if _ else "API Keys Status",
("1fichier", keys.get('1fichier')),
("AllDebrid", keys.get('alldebrid'))
]
menu_width = int(config.screen_width * 0.55)
menu_height = int(config.screen_height * 0.35)
menu_x = (config.screen_width - menu_width)//2
menu_y = (config.screen_height - menu_height)//2
pygame.draw.rect(screen, THEME_COLORS["button_idle"], (menu_x, menu_y, menu_width, menu_height), border_radius=16)
pygame.draw.rect(screen, THEME_COLORS["border"], (menu_x, menu_y, menu_width, menu_height), 2, border_radius=16)
title_surface = config.font.render(lines[0], True, THEME_COLORS["text"])
title_rect = title_surface.get_rect(center=(config.screen_width//2, menu_y + 40))
screen.blit(title_surface, title_rect)
status_on = _("status_present") if _ else "Present"
status_off = _("status_missing") if _ else "Missing"
y = title_rect.bottom + 20
for provider, present in lines[1:]:
status_txt = status_on if present else status_off
text = f"{provider}: {status_txt}"
surf = config.small_font.render(text, True, THEME_COLORS["text"])
rect = surf.get_rect(center=(config.screen_width//2, y))
screen.blit(surf, rect)
y += surf.get_height() + 12
back_txt = _("menu_back") if _ else "Back"
back_surf = config.small_font.render(back_txt, True, THEME_COLORS["fond_lignes"]) # Indication
back_rect = back_surf.get_rect(center=(config.screen_width//2, menu_y + menu_height - 30))
screen.blit(back_surf, back_rect)
def draw_filter_platforms_menu(screen):
"""Affiche le menu de filtrage des plateformes (afficher/masquer)."""
from rgsx_settings import load_rgsx_settings
@@ -1591,8 +1715,11 @@ def draw_controls_help(screen, previous_state):
# États autorisés (même logique qu'avant)
allowed_states = {
# États classiques où l'aide était accessible
"error", "platform", "game", "confirm_exit",
"extension_warning", "history", "clear_history"
"extension_warning", "history", "clear_history",
# Nouveaux états hiérarchiques pause
"pause_controls_menu", "pause_menu"
}
if previous_state not in allowed_states:
return

View File

@@ -51,7 +51,6 @@ def save_history(history):
os.makedirs(os.path.dirname(history_path), exist_ok=True)
with open(history_path, "w", encoding='utf-8') as f:
json.dump(history, f, indent=2, ensure_ascii=False)
logger.debug(f"Historique sauvegardé dans {history_path}")
except Exception as e:
logger.error(f"Erreur lors de l'écriture de {history_path} : {e}")

View File

@@ -1,15 +1,10 @@
{
"controls_mapping_title": "Steuerung konfigurieren",
"controls_mapping_instruction": "3 Sekunden halten zum Konfigurieren:",
"controls_mapping_waiting": "Warte auf eine Taste oder einen Button...",
"controls_mapping_press": "Drücke eine Taste oder einen Button",
"welcome_message": "Willkommen bei RGSX",
"disclaimer_line1": "Es ist gefährlich, allein zu gehen, nimm alles, was du brauchst!",
"disclaimer_line2": "Aber lade nur Spiele herunter,",
"disclaimer_line3": "von denen du die Originale besitzt!",
"disclaimer_line4": "RGSX ist nicht verantwortlich für heruntergeladene Inhalte,",
"disclaimer_line5": "und hostet keine ROMs.",
"loading_test_connection": "Verbindung wird getestet...",
"loading_download_data": "Spiele und Bilder werden heruntergeladen...",
"loading_progress": "Fortschritt: {0}%",
@@ -19,27 +14,18 @@
"loading_extracting_data": "Der initiale Datenordner wird entpackt...",
"loading_load_systems": "Systeme werden geladen...",
"error_extract_data_failed": "Herunterladen oder Entpacken des initialen Datenordners fehlgeschlagen.",
"error_sources_load_failed": "Quellen konnten nicht geladen werden. Öffne das Menü und wähle dann Spiele-Cache erneut herunterladen",
"error_no_internet": "Keine Internetverbindung. Überprüfe dein Netzwerk.",
"error_controls_mapping": "Fehler beim Zuordnen der Steuerung",
"error_api_key": "Achtung, du musst deinen API-Schlüssel (nur Premium) in der Datei {0} eingeben",
"error_api_key_extended": "Achtung, du musst deinen API-Schlüssel (nur Premium) in der Datei /userdata/saves/ports/rgsx/1FichierAPI.txt einfügen. Öffne die Datei in einem Texteditor und füge den API-Schlüssel ein",
"error_invalid_download_data": "Ungültige Downloaddaten",
"error_delete_sources": "Fehler beim Löschen der Datei systems_list.json oder Ordner",
"error_extension": "Nicht unterstützte Erweiterung oder Downloadfehler",
"error_no_download": "Keine Downloads ausstehend.",
"platform_no_platform": "Keine Plattform",
"platform_page": "Seite {0}/{1}",
"game_no_games": "Keine Spiele verfügbar",
"game_count": "{0} ({1} Spiele)",
"game_filter": "Aktiver Filter: {0}",
"game_search": "Filtern: {0}",
"game_header_name": "Name",
"game_header_size": "Größe",
"history_title": "Downloads ({0})",
"history_empty": "Keine Downloads im Verlauf",
"history_column_system": "System",
@@ -51,28 +37,21 @@
"history_status_completed": "Abgeschlossen",
"history_status_error": "Fehler: {0}",
"history_status_canceled": "Abgebrochen",
"download_status": "{0}: {1}",
"download_progress": "{0}% {1} MB / {2} MB",
"download_canceled": "Download vom Benutzer abgebrochen.",
"extension_warning_zip": "Die Datei '{0}' ist ein Archiv und Batocera unterstützt keine Archive für dieses System. Die automatische Extraktion der Datei erfolgt nach dem Download, fortfahren?",
"extension_warning_unsupported": "Die Dateierweiterung für '{0}' wird laut der Konfiguration es_systems.cfg von Batocera nicht unterstützt. Möchtest du fortfahren?",
"extension_warning_enable_unknown_hint": "\nUm diese Meldung auszublenden: \"Warnung bei unbekannter Erweiterung ausblenden\" in Pausenmenü > Anzeige aktivieren",
"confirm_exit": "Anwendung beenden?",
"confirm_exit_with_downloads": "Achtung: {0} Download(s) laufen. Trotzdem beenden?",
"confirm_clear_history": "Verlauf löschen?",
"confirm_redownload_cache": "Spieleliste aktualisieren?",
"popup_redownload_success": "Cache gelöscht, bitte die Anwendung neu starten",
"popup_no_cache": "Kein Cache gefunden.\nBitte starte die Anwendung neu, um die Spiele zu laden.",
"popup_countdown": "Diese Nachricht schließt in {0} Sekunde{1}",
"language_select_title": "Sprachauswahl",
"language_select_instruction": "Verwende die Pfeiltasten zum Navigieren und Enter zum Auswählen",
"language_changed": "Sprache geändert zu {0}",
"menu_controls": "Steuerung",
"menu_remap_controls": "Steuerung neu zuordnen",
"menu_history": "Verlauf",
@@ -81,21 +60,13 @@
"menu_display": "Anzeige",
"display_layout": "Anzeigelayout",
"menu_redownload_cache": "Spieleliste aktualisieren",
"menu_music_toggle": "Musik ein/aus",
"menu_music_enabled": "Musik aktiviert: {0}",
"menu_music_disabled": "Musik deaktiviert",
"menu_restart": "Neustart",
"menu_filter_platforms": "Systeme filtern",
"filter_platforms_title": "Systemsichtbarkeit",
"filter_all": "Alle anzeigen",
"filter_none": "Alle ausblenden",
"filter_apply": "Anwenden",
"filter_back": "Zurück",
"filter_platforms_info": "Sichtbar: {0} | Versteckt: {1} / Gesamt: {2}",
"filter_unsaved_warning": "Ungespeicherte Änderungen",
"menu_show_unsupported_on": "Nicht unterstützte Systeme anzeigen: Ja",
"menu_show_unsupported_off": "Nicht unterstützte Systeme anzeigen: Nein",
"menu_show_unsupported_text": "systeme versteckt",
"menu_show_unsupported_enabled": "Sichtbarkeit nicht unterstützter Systeme aktiviert",
"menu_show_unsupported_disabled": "Sichtbarkeit nicht unterstützter Systeme deaktiviert",
"menu_allow_unknown_ext_on": "Warnung bei unbekannter Erweiterung ausblenden: Ja",
@@ -103,64 +74,15 @@
"menu_allow_unknown_ext_enabled": "Ausblenden der Warnung bei unbekannter Erweiterung aktiviert",
"menu_allow_unknown_ext_disabled": "Ausblenden der Warnung bei unbekannter Erweiterung deaktiviert",
"menu_quit": "Beenden",
"button_yes": "Ja",
"button_no": "Nein",
"button_OK": "OK",
"popup_restarting": "Neustart...",
"controls_hold_message": "3 Sekunden halten für: '{0}'",
"controls_skip_message": "Drücke Esc, um zu überspringen (nur PC)",
"controls_waiting": "Warten...",
"controls_hold": "3 Sekunden halten",
"controls_action_confirm": "Bestätigen",
"controls_action_cancel": "Abbrechen",
"controls_action_up": "Hoch",
"controls_action_down": "Runter",
"controls_action_left": "Links",
"controls_action_right": "Rechts",
"controls_action_page_up": "Vorherige Seite",
"controls_action_page_down": "Nächste Seite",
"controls_action_clear_history": "Mehrfachauswahl / Verlauf leeren",
"controls_action_history": "Verlauf",
"controls_action_filter": "Filtern",
"controls_action_delete": "Löschen",
"controls_action_space": "Leerzeichen",
"controls_action_start": "Hilfe / Einstellungen",
"controls_desc_confirm": "Bestätigen (z.B.: A, Enter)",
"controls_desc_cancel": "Abbrechen/Zurück (z.B.: B, Rücktaste)",
"controls_desc_up": "Nach oben navigieren",
"controls_desc_down": "Nach unten navigieren",
"controls_desc_left": "Nach links navigieren",
"controls_desc_right": "Nach rechts navigieren",
"controls_desc_page_up": "Vorherige Seite/Schnelles Scrollen nach oben (z.B.: BildAuf, LB)",
"controls_desc_page_down": "Nächste Seite/Schnelles Scrollen nach unten (z.B.: BildAb, RB)",
"controls_desc_clear_history": "Mehrfachauswahl (Spieleliste) / Verlauf löschen (Verlaufsmenü) (z.B.: X)",
"controls_desc_history": "Verlauf öffnen (z.B.: H, Y)",
"controls_desc_filter": "Filter öffnen (z.B.: F, Select)",
"controls_desc_delete": "Zeichen löschen (z.B.: LT, Entf)",
"controls_desc_space": "Leerzeichen hinzufügen (z.B.: RT, Leertaste)",
"controls_desc_start": "Pausenmenü öffnen (z.B.: Start, AltGr)",
"action_retry": "Wiederholen",
"action_quit": "Beenden",
"action_select": "Auswählen",
"action_history": "Verlauf",
"action_download": "Herunterladen",
"action_filter": "Filtern",
"action_cancel": "Abbrechen",
"action_back": "Zurück",
"action_navigate": "Navigieren",
"action_page": "Seite",
"action_cancel_download": "Download abbrechen",
"action_background": "Hintergrund",
"action_confirm": "Bestätigen",
"action_redownload": "Erneut herunterladen",
"action_clear_history": "Verlauf löschen",
"network_checking_updates": "Updates werden geprüft...",
"network_update_available": "Update verfügbar: {0}",
"network_extracting_update": "Update wird extrahiert...",
@@ -175,7 +97,6 @@
"network_extraction_partial": "Extraktion erfolgreich, aber einige Dateien wurden aufgrund von Fehlern übersprungen: {0}",
"network_extraction_success": "Extraktion erfolgreich",
"network_zip_extraction_error": "Fehler beim Extrahieren des ZIP {0}: {1}",
"network_permission_error": "Keine Schreibberechtigung für {0}",
"network_file_not_found": "Die Datei {0} existiert nicht",
"network_cannot_get_filename": "Dateiname konnte nicht abgerufen werden",
"network_cannot_get_download_url": "Download-URL konnte nicht abgerufen werden",
@@ -191,36 +112,40 @@
"controls_pages": "Seiten",
"controls_confirm_select": "Bestätigen/Auswählen",
"controls_cancel_back": "Abbrechen/Zurück",
"controls_history": "Verlauf",
"controls_clear_history": "Mehrfachauswahl / Verlauf",
"controls_filter_search": "Filtern/Suchen",
"network_download_failed": "Download nach {0} Versuchen fehlgeschlagen",
"network_api_error": "Fehler bei der API-Anfrage, der Schlüssel könnte falsch sein: {0}",
"network_download_error": "Downloadfehler {0}: {1}",
"network_download_ok": "Download erfolgreich: {0}",
"utils_extracted": "Extrahiert: {0}",
"utils_corrupt_zip": "Beschädigtes ZIP-Archiv: {0}",
"utils_permission_denied": "Berechtigung während der Extraktion verweigert: {0}",
"utils_extraction_failed": "Extraktion fehlgeschlagen: {0}",
"utils_unrar_unavailable": "Befehl unrar nicht verfügbar",
"utils_rar_list_failed": "Fehler beim Auflisten der RAR-Dateien: {0}",
"utils_xdvdfs_unavailable": "xdvdfs-Tool nicht verfügbar (fehlend oder keine Berechtigung)",
"menu_symlink_option": "Symlink-Option",
"symlink_option_enabled": "Symlink-Option aktiviert",
"symlink_option_disabled": "Symlink-Option deaktiviert",
"symlink_settings_saved_successfully": "Symlink-Einstellungen erfolgreich gespeichert",
"symlink_settings_save_error": "Fehler beim Speichern der Symlink-Einstellungen"
,
"menu_games_source_prefix": "Spielquelle",
"games_source_rgsx": "RGSX",
"sources_mode_rgsx_select_info": "RGSX: Spieleliste aktualisieren",
"games_source_custom": "Benutzerdefiniert"
,
"games_source_custom": "Benutzerdefiniert",
"sources_mode_custom_select_info": "Benutzerdefiniert: URL in {0} setzen und Spieleliste aktualisieren",
"sources_mode_custom_missing_url": "Keine benutzerdefinierte URL gesetzt (bearbeite {0})",
"sources_mode_custom_download_error": "Download der benutzerdefinierten Quelle fehlgeschlagen",
"menu_show_unsupported_and_hidden": "{0} nicht unterstützte und ausgeblendete Systeme anzeigen",
"menu_show_unsupported_all_displayed": "Alle Systeme angezeigt"
"menu_show_unsupported_all_displayed": "Alle Systeme angezeigt",
"menu_settings_category": "Einstellungen",
"menu_back": "Zurück",
"submenu_display_layout": "Layout",
"submenu_display_font_size": "Schriftgröße",
"submenu_display_show_unsupported": "Nicht unterstützte Systeme: {status}",
"submenu_display_allow_unknown_ext": "Warnung unbek. Ext verbergen: {status}",
"submenu_display_filter_platforms": "Systeme filtern",
"status_on": "An",
"status_off": "Aus",
"status_present": "Vorhanden",
"status_missing": "Fehlt",
"menu_api_keys_status": "API-Schlüssel",
"api_keys_status_title": "Status der API-Schlüssel",
"menu_games": "Spiele"
}

View File

@@ -1,15 +1,10 @@
{
"controls_mapping_title": "Controls configuration",
"controls_mapping_instruction": "Hold for 3s to configure:",
"controls_mapping_waiting": "Waiting for a key or button...",
"controls_mapping_press": "Press a key or button",
"welcome_message": "Welcome to RGSX",
"disclaimer_line1": "It's dangerous to go alone, take all you need!",
"disclaimer_line2": "But only download games",
"disclaimer_line3": "that you already own!",
"disclaimer_line4": "RGSX is not responsible for downloaded content,",
"disclaimer_line5": "and does not host ROMs.",
"loading_test_connection": "Testing connection...",
"loading_download_data": "Downloading initial Data folder...",
"loading_progress": "Progress: {0}%",
@@ -19,27 +14,18 @@
"loading_extracting_data": "Extracting initial Data folder...",
"loading_load_systems": "Loading systems...",
"error_extract_data_failed": "Failed to download or extract the initial Data folder.",
"error_sources_load_failed": "Failed to load sources. Open the menu then select Redownload Games cache",
"error_no_internet": "No Internet connection. Check your network.",
"error_controls_mapping": "Failed to map controls",
"error_api_key": "Please enter your API key (premium only) in the file {0}",
"error_api_key_extended": "Please enter your API key (premium only) in the file /userdata/saves/ports/rgsx/1FichierAPI.txt by opening it in a text editor and pasting your API key",
"error_invalid_download_data": "Invalid download data",
"error_delete_sources": "Error deleting systems_list.json file or folders",
"error_extension": "Unsupported extension or download error",
"error_no_download": "No pending download.",
"platform_no_platform": "No platform",
"platform_page": "Page {0}/{1}",
"game_no_games": "No games available",
"game_count": "{0} ({1} games)",
"game_filter": "Active filter: {0}",
"game_search": "Filter: {0}",
"game_header_name": "Name",
"game_header_size": "Size",
"history_title": "Downloads ({0})",
"history_empty": "No downloads in history",
"history_column_system": "System",
@@ -51,28 +37,21 @@
"history_status_completed": "Completed",
"history_status_error": "Error: {0}",
"history_status_canceled": "Canceled",
"download_status": "{0}: {1}",
"download_progress": "{0}% {1} MB / {2} MB",
"download_canceled": "Download canceled by user.",
"extension_warning_zip": "The file '{0}' is an archive and Batocera does not support archives for this system. Automatic extraction will occur after download, continue?",
"extension_warning_unsupported": "The file extension for '{0}' is not supported by Batocera according to the es_systems.cfg configuration. Do you want to continue?",
"extension_warning_enable_unknown_hint": "\nTo hide this message: enable \"Hide unknown extension warning\" in Pause Menu > Display",
"confirm_exit": "Exit application?",
"confirm_exit_with_downloads": "Attention: {0} download(s) in progress. Quit anyway?",
"confirm_clear_history": "Clear history?",
"confirm_redownload_cache": "Update games list?",
"popup_redownload_success": "Cache cleared, please restart the application",
"popup_no_cache": "No cache found.\nPlease restart the application to load games.",
"popup_countdown": "This message will close in {0} second{1}",
"language_select_title": "Language Selection",
"language_select_instruction": "Use arrow keys to navigate and Enter to select",
"language_changed": "Language changed to {0}",
"menu_controls": "Controls",
"menu_remap_controls": "Remap controls",
"menu_history": "History",
@@ -81,21 +60,13 @@
"menu_display": "Display",
"display_layout": "Display layout",
"menu_redownload_cache": "Update games list",
"menu_music_toggle": "Toggle music",
"menu_music_enabled": "Music enabled: {0}",
"menu_music_disabled": "Music disabled",
"menu_restart": "Restart",
"menu_filter_platforms": "Filter systems",
"filter_platforms_title": "Systems visibility",
"filter_all": "Show all",
"filter_none": "Hide all",
"filter_apply": "Apply",
"filter_back": "Back",
"filter_platforms_info": "Visible: {0} | Hidden: {1} / Total: {2}",
"filter_unsaved_warning": "Unsaved changes",
"menu_show_unsupported_on": "Show unsupported systems: Yes",
"menu_show_unsupported_off": "Show unsupported systems: No",
"menu_show_unsupported_text": "hidden systems",
"menu_show_unsupported_enabled": "Unsupported systems visibility enabled",
"menu_show_unsupported_disabled": "Unsupported systems visibility disabled",
"menu_allow_unknown_ext_on": "Hide unknown extension warning: Yes",
@@ -103,64 +74,15 @@
"menu_allow_unknown_ext_enabled": "Hide unknown extension warning enabled",
"menu_allow_unknown_ext_disabled": "Hide unknown extension warning disabled",
"menu_quit": "Quit",
"button_yes": "Yes",
"button_no": "No",
"button_OK": "OK",
"popup_restarting": "Restarting...",
"controls_hold_message": "Hold for 3s for: '{0}'",
"controls_skip_message": "Press Esc to skip (PC only)",
"controls_waiting": "Waiting...",
"controls_hold": "Hold 3s",
"controls_action_confirm": "Confirm",
"controls_action_cancel": "Cancel",
"controls_action_up": "Up",
"controls_action_down": "Down",
"controls_action_left": "Left",
"controls_action_right": "Right",
"controls_action_page_up": "Previous Page",
"controls_action_page_down": "Next Page",
"controls_action_clear_history": "Multi-select / Clear History",
"controls_action_history": "History",
"controls_action_filter": "Filter",
"controls_action_delete": "Delete",
"controls_action_space": "Space",
"controls_action_start": "Help / Settings",
"controls_desc_confirm": "Validate (e.g. A, Enter)",
"controls_desc_cancel": "Cancel/Back (e.g. B, Backspace)",
"controls_desc_up": "Navigate up",
"controls_desc_down": "Navigate down",
"controls_desc_left": "Navigate left",
"controls_desc_right": "Navigate right",
"controls_desc_page_up": "Previous page/Fast scroll up (e.g. PageUp, LB)",
"controls_desc_page_down": "Next page/Fast scroll down (e.g. PageDown, RB)",
"controls_desc_clear_history": "Multi-select (game list) / Clear history (history menu) (e.g. X)",
"controls_desc_history": "Open history (e.g. H, Y)",
"controls_desc_filter": "Open filter (e.g. F, Select)",
"controls_desc_delete": "Delete character (e.g. LT, Delete)",
"controls_desc_space": "Add space (e.g. RT, Space)",
"controls_desc_start": "Open pause menu (e.g. Start, AltGr)",
"action_retry": "Retry",
"action_quit": "Quit",
"action_select": "Select",
"action_history": "History",
"action_download": "Download",
"action_filter": "Filter",
"action_cancel": "Cancel",
"action_back": "Back",
"action_navigate": "Navigate",
"action_page": "Page",
"action_cancel_download": "Cancel download",
"action_background": "Background",
"action_confirm": "Confirm",
"action_redownload": "Redownload",
"action_clear_history": "Clear history",
"network_checking_updates": "Checking for updates...",
"network_update_available": "Update available: {0}",
"network_extracting_update": "Extracting update...",
@@ -175,7 +97,6 @@
"network_extraction_success": "Extraction successful",
"network_download_extract_ok": "Download and extraction successful of {0}",
"network_zip_extraction_error": "Error extracting ZIP {0}: {1}",
"network_permission_error": "No write permission in {0}",
"network_file_not_found": "File {0} does not exist",
"network_cannot_get_filename": "Cannot retrieve filename",
"network_cannot_get_download_url": "Cannot retrieve download URL",
@@ -183,14 +104,12 @@
"network_api_error": "API request error, the key may be incorrect: {0}",
"network_download_error": "Download error {0}: {1}",
"network_download_ok": "Download OK: {0}",
"utils_extracted": "Extracted: {0}",
"utils_corrupt_zip": "Corrupted ZIP archive: {0}",
"utils_permission_denied": "Permission denied during extraction: {0}",
"utils_extraction_failed": "Extraction failed: {0}",
"utils_unrar_unavailable": "Unrar command not available",
"utils_rar_list_failed": "Failed to list RAR files: {0}",
"utils_xdvdfs_unavailable": "xdvdfs tool unavailable (missing or permission denied)",
"download_initializing": "Initializing...",
"accessibility_font_size": "Font size: {0}",
"confirm_cancel_download": "Cancel current download?",
@@ -203,24 +122,30 @@
"controls_pages": "Pages",
"controls_confirm_select": "Confirm/Select",
"controls_cancel_back": "Cancel/Back",
"controls_history": "History",
"controls_clear_history": "Multi-select / History",
"controls_filter_search": "Filter/Search",
"menu_symlink_option": "Symlink Option",
"symlink_option_enabled": "Symlink option enabled",
"symlink_option_disabled": "Symlink option disabled",
"symlink_settings_saved_successfully": "Symlink settings saved successfully",
"symlink_settings_save_error": "Error saving symlink settings",
"menu_games_source_prefix": "Game source",
"games_source_rgsx": "RGSX",
"sources_mode_rgsx_select_info": "RGSX: update the games list",
"games_source_custom": "Custom",
"sources_mode_custom_select_info": "Custom mode: set URL in {0} then update games list",
"sources_mode_custom_missing_url": "No custom URL set (edit {0})",
"sources_mode_custom_download_error": "Custom source download failed",
"menu_show_unsupported_and_hidden": "Show unsupported and hidden {0} systems",
"menu_show_unsupported_all_displayed": "Hide all unsupported systems"
"menu_show_unsupported_all_displayed": "Hide all unsupported systems",
"menu_settings_category": "Settings",
"menu_back": "Back",
"submenu_display_layout": "Layout",
"submenu_display_font_size": "Font Size",
"submenu_display_show_unsupported": "Show unsupported systems: {status}",
"submenu_display_allow_unknown_ext": "Hide unknown ext warn: {status}",
"submenu_display_filter_platforms": "Filter systems",
"status_on": "On",
"status_off": "Off",
"status_present": "Present",
"status_missing": "Missing",
"menu_api_keys_status": "API Keys",
"api_keys_status_title": "API Keys Status",
"menu_games": "Games"
}

View File

@@ -1,15 +1,10 @@
{
"controls_mapping_title": "Configuración de controles",
"controls_mapping_instruction": "Mantén pulsado 3s para configurar:",
"controls_mapping_waiting": "Esperando una tecla o botón...",
"controls_mapping_press": "Pulsa una tecla o botón",
"welcome_message": "Bienvenido a RGSX",
"disclaimer_line1": "¡Es peligroso ir solo, toma todo lo que necesites!",
"disclaimer_line2": "Pero solo descarga juegos",
"disclaimer_line3": "de los que poseas los originales.",
"disclaimer_line4": "RGSX no es responsable del contenido descargado,",
"disclaimer_line5": "y no aloja ROMs.",
"loading_test_connection": "Probando conexión...",
"loading_download_data": "Descargando juegos e imágenes...",
"loading_progress": "Progreso: {0}%",
@@ -19,28 +14,18 @@
"loading_extracting_data": "Extrayendo la carpeta de datos inicial...",
"loading_load_systems": "Cargando sistemas...",
"error_extract_data_failed": "Error al descargar o extraer la carpeta de datos inicial.",
"error_sources_load_failed": "Error al cargar las fuentes. Abre el menú y selecciona Volver a descargar la caché de juegos",
"error_no_internet": "Sin conexión a Internet. Verifica tu red.",
"error_controls_mapping": "Error al mapear los controles",
"error_api_key": "Atención, debes ingresar tu clave API (solo premium) en el archivo {0}",
"error_api_key_extended": "Atención, debes ingresar tu clave API (solo premium) en el archivo /userdata/saves/ports/rgsx/1FichierAPI.txt, abrirlo en un editor de texto y pegar la clave API",
"error_invalid_download_data": "Datos de descarga no válidos",
"error_delete_sources": "Error al eliminar el archivo systems_list.json o carpetas",
"error_extension": "Extensión no soportada o error de descarga",
"error_no_download": "No hay descargas pendientes.",
"platform_no_platform": "Ninguna plataforma",
"platform_page": "Página {0}/{1}",
"game_no_games": "No hay juegos disponibles",
"game_count": "{0} ({1} juegos)",
"game_filter": "Filtro activo: {0}",
"game_search": "Filtrar: {0}",
"game_header_name": "Nombre",
"game_header_size": "Tamaño",
"history_title": "Descargas ({0})",
"history_empty": "No hay descargas en el historial",
"history_column_system": "Sistema",
@@ -52,28 +37,21 @@
"history_status_completed": "Completado",
"history_status_error": "Error: {0}",
"history_status_canceled": "Cancelado",
"download_status": "{0}: {1}",
"download_progress": "{0}% {1} MB / {2} MB",
"download_canceled": "Descarga cancelada por el usuario.",
"extension_warning_zip": "El archivo '{0}' es un archivo comprimido y Batocera no soporta archivos comprimidos para este sistema. La extracción automática del archivo se realizará después de la descarga, ¿continuar?",
"extension_warning_unsupported": "La extensión del archivo '{0}' no está soportada por Batocera según la configuración es_systems.cfg. ¿Deseas continuar?",
"extension_warning_enable_unknown_hint": "\nPara no mostrar este mensaje: activa \"Ocultar aviso de extensión desconocida\" en Menú de pausa > Pantalla",
"confirm_exit": "¿Salir de la aplicación?",
"confirm_exit_with_downloads": "Atención: {0} descarga(s) en curso. ¿Salir de todas formas?",
"confirm_clear_history": "¿Vaciar el historial?",
"confirm_redownload_cache": "¿Actualizar la lista de juegos?",
"popup_redownload_success": "Caché borrada, por favor reinicia la aplicación",
"popup_no_cache": "No se encontró caché.\nPor favor, reinicia la aplicación para cargar los juegos.",
"popup_countdown": "Este mensaje se cerrará en {0} segundo{1}",
"language_select_title": "Selección de idioma",
"language_select_instruction": "Usa las flechas para navegar y Enter para seleccionar",
"language_changed": "Idioma cambiado a {0}",
"menu_controls": "Controles",
"menu_remap_controls": "Remapear controles",
"menu_history": "Historial",
@@ -82,21 +60,13 @@
"menu_display": "Pantalla",
"display_layout": "Distribución",
"menu_redownload_cache": "Actualizar lista de juegos",
"menu_music_toggle": "Activar/Desactivar música",
"menu_music_enabled": "Música activada: {0}",
"menu_music_disabled": "Música desactivada",
"menu_restart": "Reiniciar",
"menu_filter_platforms": "Filtrar sistemas",
"filter_platforms_title": "Visibilidad de sistemas",
"filter_all": "Mostrar todo",
"filter_none": "Ocultar todo",
"filter_apply": "Aplicar",
"filter_back": "Volver",
"filter_platforms_info": "Visibles: {0} | Ocultos: {1} / Total: {2}",
"filter_unsaved_warning": "Cambios no guardados",
"menu_show_unsupported_on": "Mostrar sistemas no soportados: Sí",
"menu_show_unsupported_off": "Mostrar sistemas no soportados: No",
"menu_show_unsupported_text": "sistemas ocultos",
"menu_show_unsupported_enabled": "Visibilidad de sistemas no soportados activada",
"menu_show_unsupported_disabled": "Visibilidad de sistemas no soportados desactivada",
"menu_allow_unknown_ext_on": "Ocultar aviso de extensión desconocida: Sí",
@@ -104,64 +74,15 @@
"menu_allow_unknown_ext_enabled": "Aviso de extensión desconocida oculto (activado)",
"menu_allow_unknown_ext_disabled": "Aviso de extensión desconocida visible (desactivado)",
"menu_quit": "Salir",
"button_yes": "Sí",
"button_no": "No",
"button_OK": "OK",
"popup_restarting": "Reiniciando...",
"controls_hold_message": "Mantén presionado durante 3s para: '{0}'",
"controls_skip_message": "Presiona Esc para omitir (solo PC)",
"controls_waiting": "Esperando...",
"controls_hold": "Mantener 3s",
"controls_action_confirm": "Confirmar",
"controls_action_cancel": "Cancelar",
"controls_action_up": "Arriba",
"controls_action_down": "Abajo",
"controls_action_left": "Izquierda",
"controls_action_right": "Derecha",
"controls_action_page_up": "Página anterior",
"controls_action_page_down": "Página siguiente",
"controls_action_clear_history": "Multi-selección / Vaciar historial",
"controls_action_history": "Historial",
"controls_action_filter": "Filtrar",
"controls_action_delete": "Eliminar",
"controls_action_space": "Espacio",
"controls_action_start": "Ayuda / Configuración",
"controls_desc_confirm": "Validar (ej: A, Enter)",
"controls_desc_cancel": "Cancelar/Volver (ej: B, Retroceso)",
"controls_desc_up": "Navegar hacia arriba",
"controls_desc_down": "Navegar hacia abajo",
"controls_desc_left": "Navegar a izquierda",
"controls_desc_right": "Navegar a derecha",
"controls_desc_page_up": "Página anterior/Desplazamiento rápido arriba (ej: RePág, LB)",
"controls_desc_page_down": "Página siguiente/Desplazamiento rápido abajo (ej: AvPág, RB)",
"controls_desc_clear_history": "Multi-selección (lista juegos) / Vaciar historial (menú historial) (ej: X)",
"controls_desc_history": "Abrir historial (ej: H, Y)",
"controls_desc_filter": "Abrir filtro (ej: F, Select)",
"controls_desc_delete": "Eliminar carácter (ej: LT, Supr)",
"controls_desc_space": "Añadir espacio (ej: RT, Espacio)",
"controls_desc_start": "Abrir el menú de pausa (ej: Start, AltGr)",
"action_retry": "Reintentar",
"action_quit": "Salir",
"action_select": "Seleccionar",
"action_history": "Historial",
"action_download": "Descargar",
"action_filter": "Filtrar",
"action_cancel": "Cancelar",
"action_back": "Volver",
"action_navigate": "Navegar",
"action_page": "Página",
"action_cancel_download": "Cancelar la descarga",
"action_background": "Fondo",
"action_confirm": "Confirmar",
"action_redownload": "Volver a descargar",
"action_clear_history": "Vaciar el historial",
"network_checking_updates": "Verificando actualizaciones...",
"network_update_available": "Actualización disponible: {0}",
"network_extracting_update": "Extrayendo la actualización...",
@@ -176,7 +97,6 @@
"network_extraction_partial": "Extracción exitosa, pero algunos archivos fueron omitidos debido a errores: {0}",
"network_extraction_success": "Extracción exitosa",
"network_zip_extraction_error": "Error al extraer el ZIP {0}: {1}",
"network_permission_error": "Sin permiso de escritura en {0}",
"network_file_not_found": "El archivo {0} no existe",
"network_cannot_get_filename": "No se pudo obtener el nombre del archivo",
"network_cannot_get_download_url": "No se pudo obtener la URL de descarga",
@@ -192,28 +112,19 @@
"controls_pages": "Páginas",
"controls_confirm_select": "Confirmar/Seleccionar",
"controls_cancel_back": "Cancelar/Volver",
"controls_history": "Historial",
"controls_clear_history": "Multi-selección / Historial",
"controls_filter_search": "Filtrar/Buscar",
"network_download_failed": "Error en la descarga tras {0} intentos",
"network_api_error": "Error en la solicitud de API, la clave puede ser incorrecta: {0}",
"network_download_error": "Error en la descarga {0}: {1}",
"network_download_ok": "Descarga exitosa: {0}",
"utils_extracted": "Extraído: {0}",
"utils_corrupt_zip": "Archivo ZIP corrupto: {0}",
"utils_permission_denied": "Permiso denegado durante la extracción: {0}",
"utils_extraction_failed": "Error en la extracción: {0}",
"utils_unrar_unavailable": "Comando unrar no disponible",
"utils_rar_list_failed": "Error al listar los archivos RAR: {0}",
"utils_xdvdfs_unavailable": "Herramienta xdvdfs no disponible (faltante o sin permisos)",
"menu_symlink_option": "Opción Symlink",
"symlink_option_enabled": "Opción symlink habilitada",
"symlink_option_disabled": "Opción symlink deshabilitada",
"symlink_settings_saved_successfully": "Configuración symlink guardada con éxito",
"symlink_settings_save_error": "Error al guardar la configuración symlink",
"menu_games_source_prefix": "Origen de juegos",
"games_source_rgsx": "RGSX",
"sources_mode_rgsx_select_info": "RGSX: actualizar la lista de juegos",
@@ -222,5 +133,19 @@
"sources_mode_custom_missing_url": "No se ha establecido URL personalizada (editar {0})",
"sources_mode_custom_download_error": "Fallo en la descarga de la fuente personalizada",
"menu_show_unsupported_and_hidden": "Mostrar {0} sistemas no soportados y ocultos",
"menu_show_unsupported_all_displayed": "Todos los sistemas mostrados"
"menu_show_unsupported_all_displayed": "Todos los sistemas mostrados",
"menu_settings_category": "Ajustes",
"menu_back": "Volver",
"submenu_display_layout": "Disposición",
"submenu_display_font_size": "Tamaño Fuente",
"submenu_display_show_unsupported": "Mostrar sistemas no soportados: {status}",
"submenu_display_allow_unknown_ext": "Ocultar aviso ext. desconocida: {status}",
"submenu_display_filter_platforms": "Filtrar sistemas",
"status_on": "Sí",
"status_off": "No",
"status_present": "Presente",
"status_missing": "Ausente",
"menu_api_keys_status": "Claves API",
"api_keys_status_title": "Estado de las claves API",
"menu_games": "Juegos"
}

View File

@@ -5,7 +5,6 @@
"disclaimer_line3": "dont vous possédez les originaux !",
"disclaimer_line4": "RGSX n'est pas responsable des contenus téléchargés,",
"disclaimer_line5": "et n'heberge pas de ROMs.",
"loading_test_connection": "Test de la connexion...",
"loading_download_data": "Téléchargement des jeux et images...",
"loading_progress": "Progression : {0}%",
@@ -15,28 +14,18 @@
"loading_extracting_data": "Extraction du dossier de données initial...",
"loading_load_systems": "Chargement des systèmes...",
"error_extract_data_failed": "Échec du téléchargement ou de l'extraction du dossier de données initial.",
"error_sources_load_failed": "Échec de chargement des sources, ouvrir le menu puis sélectionner Retélécharger le cache des jeux",
"error_no_internet": "Pas de connexion Internet. Vérifiez votre réseau.",
"error_controls_mapping": "Échec du mappage des contrôles",
"error_api_key": "Attention il faut renseigner sa clé API (premium only) dans le fichier {0}",
"error_api_key_extended": "Attention il faut renseigner sa clé API (premium only) dans le fichier /userdata/saves/ports/rgsx/1FichierAPI.txt à ouvrir dans un éditeur de texte et coller la clé API",
"error_invalid_download_data": "Données de téléchargement invalides",
"error_delete_sources": "Erreur lors de la suppression du fichier systems_list.json ou dossiers",
"error_extension": "Extension non supportée ou erreur de téléchargement",
"error_no_download": "Aucun téléchargement en attente.",
"platform_no_platform": "Aucune plateforme",
"platform_page": "Page {0}/{1}",
"game_no_games": "Aucun jeu disponible",
"game_count": "{0} ({1} jeux)",
"game_filter": "Filtre actif : {0}",
"game_search": "Filtrer : {0}",
"game_header_name": "Nom",
"game_header_size": "Taille",
"history_title": "Téléchargements ({0})",
"history_empty": "Aucun téléchargement dans l'historique",
"history_column_system": "Système",
@@ -48,28 +37,21 @@
"history_status_completed": "Terminé",
"history_status_error": "Erreur : {0}",
"history_status_canceled": "Annulé",
"download_status": "{0} : {1}",
"download_progress": "{0}% {1} Mo / {2} Mo",
"download_canceled": "Téléchargement annulé par l'utilisateur.",
"extension_warning_zip": "Le fichier '{0}' est une archive et Batocera ne prend pas en charge les archives pour ce système. L'extraction automatique du fichier aura lieu après le téléchargement, continuer ?",
"extension_warning_unsupported": "L'extension du fichier '{0}' n'est pas supportée par Batocera d'après la configuration es_systems.cfg. Voulez-vous continuer ?",
"extension_warning_enable_unknown_hint": "\nPour ne plus afficher ce messager : Activer l'option \"Masquer avertissement\" dans le Menu Pause>Display",
"confirm_exit": "Quitter l'application ?",
"confirm_exit_with_downloads": "Attention : {0} téléchargement(s) en cours. Quitter quand même ?",
"confirm_clear_history": "Vider l'historique ?",
"confirm_redownload_cache": "Mettre à jour la liste des jeux ?",
"popup_redownload_success": "Le cache a été effacé, merci de relancer l'application",
"popup_no_cache": "Aucun cache trouvé.\nVeuillez redémarrer l'application pour charger les jeux.",
"popup_countdown": "Ce message se fermera dans {0} seconde{1}",
"language_select_title": "Sélection de la langue",
"language_select_instruction": "Utilisez les flèches pour naviguer et Entrée pour sélectionner",
"language_changed": "Langue changée pour {0}",
"menu_controls": "Contrôles",
"menu_remap_controls": "Remapper les contrôles",
"menu_history": "Historique",
@@ -79,85 +61,28 @@
"display_layout": "Disposition",
"menu_redownload_cache": "Mettre à jour la liste des jeux",
"menu_quit": "Quitter",
"menu_music_toggle": "Activer/Désactiver la musique",
"menu_music_enabled": "Musique activée : {0}",
"menu_music_disabled": "Musique désactivée",
"menu_music_disabled": "Musique désactivée",
"menu_restart": "Redémarrer",
"menu_filter_platforms": "Filtrer les systèmes",
"filter_platforms_title": "Affichage des systèmes",
"filter_all": "Tout afficher",
"filter_none": "Tout masquer",
"filter_apply": "Appliquer",
"filter_back": "Retour",
"filter_platforms_info": "Visibles: {0} | Masqués: {1} / Total: {2}",
"filter_unsaved_warning": "Modifications non sauvegardées",
"menu_show_unsupported_on": "Afficher systèmes non supportés : Oui",
"menu_show_unsupported_off": "Afficher systèmes non supportés : Non",
"menu_show_unsupported_text": "systèmes cachés",
"menu_show_unsupported_enabled": "Affichage systèmes non supportés activé",
"menu_show_unsupported_disabled": "Affichage systèmes non supportés désactivé",
"menu_allow_unknown_ext_on": "Masquer avertissement extension inconnue : Oui",
"menu_allow_unknown_ext_off": "Masquer avertissement extension inconnue : Non",
"menu_allow_unknown_ext_enabled": "Masquer avertissement extension inconnue activé",
"menu_allow_unknown_ext_disabled": "Masquer avertissement extension inconnue désactivé",
"button_yes": "Oui",
"button_no": "Non",
"button_OK": "OK",
"popup_restarting": "Redémarrage...",
"controls_hold_message": "Maintenez pendant 3s pour : '{0}'",
"controls_skip_message": "Appuyez sur Échap pour passer(Pc only)",
"controls_waiting": "Attente...",
"controls_hold": "Maintenez 3s",
"controls_action_confirm": "Confirmer",
"controls_action_cancel": "Annuler",
"controls_action_up": "Haut",
"controls_action_down": "Bas",
"controls_action_left": "Gauche",
"controls_action_right": "Droite",
"controls_action_page_up": "Page Précédente",
"controls_action_page_down": "Page Suivante",
"controls_action_clear_history": "Multi-sélection / Vider Historique",
"controls_action_history": "Historique",
"controls_action_filter": "Filtrer",
"controls_action_delete": "Supprimer",
"controls_action_space": "Espace",
"controls_action_start": "Aide / Réglages",
"controls_desc_confirm": "Valider (ex: A, Entrée)",
"controls_desc_cancel": "Annuler/Retour (ex: B, Echap)",
"controls_desc_up": "Naviguer vers le haut",
"controls_desc_down": "Naviguer vers le bas",
"controls_desc_left": "Naviguer à gauche",
"controls_desc_right": "Naviguer à droite",
"controls_desc_page_up": "Défilement Rapide - (ex: PageUp, LB)",
"controls_desc_page_down": "Défilement Rapide + (ex: PageDown, RB)",
"controls_desc_history": "Ouvrir l'historique (ex: H, Y)",
"controls_desc_clear_history": "Multi-sélection (liste jeux) / Vider historique (menu historique) (ex: X)",
"controls_desc_filter": "Mode Filtre : Ouvrir/Valider (ex: F, Select)",
"controls_desc_delete": "Mode Filtre : Supprimer caractère (ex: LT, Suppr)",
"controls_desc_space": "Mode Filtre : Ajouter espace (ex: RT, Espace)",
"controls_desc_start": "Ouvrir le menu pause (ex: Start, AltGr)",
"action_retry": "Retenter",
"action_quit": "Quitter",
"action_select": "Sélectionner",
"action_history": "Historique",
"action_download": "Télécharger",
"action_filter": "Filtrer",
"action_cancel": "Annuler",
"action_back": "Retour",
"action_navigate": "Naviguer",
"action_page": "Page",
"action_cancel_download": "Annuler le téléchargement",
"action_background": "Arrière plan",
"action_confirm": "Confirmer",
"action_redownload": "Retélécharger",
"action_clear_history": "Vider l'historique",
"network_checking_updates": "Vérification des mises à jour...",
"network_update_available": "Mise à jour disponible : {0}",
"network_extracting_update": "Extraction de la mise à jour...",
@@ -172,10 +97,9 @@
"network_extraction_partial": "Extraction réussie, mais certains fichiers ont été ignorés en raison d'erreurs : {0}",
"network_extraction_success": "Extraction réussie",
"network_zip_extraction_error": "Erreur lors de l'extraction du ZIP {0}: {1}",
"network_permission_error": "Pas de permission d'écriture dans {0}",
"network_file_not_found": "Le fichier {0} n'existe pas",
"network_cannot_get_filename": "Impossible de récupérer le nom du fichier",
"network_cannot_get_download_url": "Impossible de récupérer l'URL de téléchargement",
"network_cannot_get_download_url": "Impossible de récupérer l'URL de téléchargement",
"download_initializing": "Initialisation en cours...",
"accessibility_font_size": "Taille de police : {0}",
"confirm_cancel_download": "Annuler le téléchargement en cours ?",
@@ -188,32 +112,19 @@
"controls_pages": "Pages",
"controls_confirm_select": "Confirmer/Sélectionner",
"controls_cancel_back": "Annuler/Retour",
"controls_history": "Historique",
"controls_clear_history": "Multi-sélection / Historique",
"controls_filter_search": "Filtrer/Rechercher",
"network_download_failed": "Échec du téléchargement après {0} tentatives",
"network_api_error": "Erreur lors de la requête API, la clé est peut-être incorrecte: {0}",
"network_download_error": "Erreur téléchargement {0}: {1}",
"network_download_ok": "Téléchargement ok : {0}",
"utils_extracted": "Extracted: {0}",
"utils_corrupt_zip": "Archive ZIP corrompue: {0}",
"utils_permission_denied": "Permission refusée lors de l'extraction: {0}",
"utils_extraction_failed": "Échec de l'extraction: {0}",
"utils_unrar_unavailable": "Commande unrar non disponible",
"utils_rar_list_failed": "Échec de la liste des fichiers RAR: {0}",
"utils_xdvdfs_unavailable": "Outil xdvdfs indisponible (manquant ou permission refusée)",
"controls_mapping_title": "Configuration des contrôles",
"controls_mapping_instruction": "Maintenir 3s pour configurer :",
"controls_mapping_waiting": "En attente d'une touche ou d'un bouton...",
"controls_mapping_press": "Appuyez sur une touche ou un bouton",
"menu_symlink_option": "Option Symlink",
"symlink_option_enabled": "Option symlink activée",
"symlink_option_disabled": "Option symlink désactivée",
"symlink_settings_saved_successfully": "Paramètres symlink sauvegardés avec succès",
"symlink_settings_save_error": "Erreur lors de la sauvegarde des paramètres symlink",
"menu_games_source_prefix": "Source des jeux",
"games_source_rgsx": "RGSX",
"sources_mode_rgsx_select_info": "RGSX : mettre à jour la liste des jeux",
@@ -222,5 +133,19 @@
"sources_mode_custom_missing_url": "Aucune URL personnalisée définie (modifier {0})",
"sources_mode_custom_download_error": "Échec du téléchargement de la source personnalisée",
"menu_show_unsupported_and_hidden": "Afficher les systèmes non supportés et masqués : {0}",
"menu_show_unsupported_all_displayed": "Tous les systèmes sont affichés"
"menu_show_unsupported_all_displayed": "Tous les systèmes sont affichés",
"menu_settings_category": "Réglages",
"menu_back": "Retour",
"submenu_display_layout": "Disposition",
"submenu_display_font_size": "Taille Police",
"submenu_display_show_unsupported": "Afficher systèmes non supportés : {status}",
"submenu_display_allow_unknown_ext": "Masquer avert. ext inconnue : {status}",
"submenu_display_filter_platforms": "Filtrer systèmes",
"status_on": "Oui",
"status_off": "Non",
"status_present": "Présente",
"status_missing": "Absente",
"menu_api_keys_status": "Clés API",
"api_keys_status_title": "Statut des clés API",
"menu_games": "Jeux"
}

View File

@@ -1,224 +1,151 @@
{
"controls_mapping_title": "Configurazione dei controlli",
"controls_mapping_instruction": "Tieni premuto per 3s per configurare:",
"controls_mapping_waiting": "In attesa di un tasto o pulsante...",
"controls_mapping_press": "Premi un tasto o un pulsante",
"welcome_message": "Benvenuto in RGSX",
"disclaimer_line1": "È pericoloso andare da soli, prendi tutto ciò che ti serve!",
"disclaimer_line2": "Ma scarica solo giochi",
"disclaimer_line3": "che possiedi già!",
"disclaimer_line4": "RGSX non è responsabile dei contenuti scaricati,",
"disclaimer_line5": "e non ospita ROM.",
"loading_test_connection": "Verifica connessione...",
"loading_download_data": "Download cartella Dati iniziale...",
"loading_progress": "Progresso: {0}%",
"loading_check_updates": "Verifica aggiornamenti... Attendere...",
"error_check_updates_failed": "Impossibile verificare gli aggiornamenti.",
"loading_downloading_games_images": "Download giochi e immagini...",
"loading_extracting_data": "Estrazione cartella Dati iniziale...",
"loading_load_systems": "Caricamento sistemi...",
"error_extract_data_failed": "Errore nel download o nell'estrazione della cartella Dati iniziale.",
"error_sources_load_failed": "Errore nel caricamento delle sorgenti. Apri il menu e seleziona Aggiorna cache giochi",
"error_no_internet": "Nessuna connessione Internet. Controlla la rete.",
"error_controls_mapping": "Impossibile mappare i controlli",
"error_api_key": "Inserisci la tua API key (solo premium) nel file {0}",
"error_api_key_extended": "Inserisci la tua API key (solo premium) nel file /userdata/saves/ports/rgsx/1FichierAPI.txt aprendolo in un editor e incollando la chiave",
"error_invalid_download_data": "Dati di download non validi",
"error_delete_sources": "Errore nell'eliminazione del file systems_list.json o delle cartelle",
"error_extension": "Estensione non supportata o errore di download",
"error_no_download": "Nessun download in sospeso.",
"platform_no_platform": "Nessuna piattaforma",
"platform_page": "Pagina {0}/{1}",
"game_no_games": "Nessun gioco disponibile",
"game_count": "{0} ({1} giochi)",
"game_filter": "Filtro attivo: {0}",
"game_search": "Filtro: {0}",
"game_header_name": "Nome",
"game_header_size": "Dimensione",
"history_title": "Download ({0})",
"history_empty": "Nessun download nella cronologia",
"history_column_system": "Sistema",
"history_column_game": "Nome del gioco",
"history_column_size": "Dimensione",
"history_column_status": "Stato",
"history_status_downloading": "Download: {0}%",
"history_status_extracting": "Estrazione: {0}%",
"history_status_completed": "Completato",
"history_status_error": "Errore: {0}",
"history_status_canceled": "Annullato",
"download_status": "{0}: {1}",
"download_progress": "{0}% {1} MB / {2} MB",
"download_canceled": "Download annullato dall'utente.",
"extension_warning_zip": "Il file '{0}' è un archivio e Batocera non supporta archivi per questo sistema. L'estrazione automatica avverrà dopo il download, continuare?",
"extension_warning_unsupported": "L'estensione del file '{0}' non è supportata da Batocera secondo la configurazione di es_systems.cfg. Vuoi continuare?",
"extension_warning_enable_unknown_hint": "\nPer non visualizzare questo messaggio: abilita \"Nascondi avviso estensione sconosciuta\" in Menu Pausa > Schermo",
"confirm_exit": "Uscire dall'applicazione?",
"confirm_exit_with_downloads": "Attenzione: {0} download in corso. Uscire comunque?",
"confirm_clear_history": "Cancellare la cronologia?",
"confirm_redownload_cache": "Aggiornare l'elenco dei giochi?",
"popup_redownload_success": "Cache pulita, riavvia l'applicazione",
"popup_no_cache": "Nessuna cache trovata.\nRiavvia l'applicazione per caricare i giochi.",
"popup_countdown": "Questo messaggio si chiuderà tra {0} secondo{1}",
"language_select_title": "Selezione lingua",
"language_select_instruction": "Usa le frecce per navigare e Invio per selezionare",
"language_changed": "Lingua cambiata in {0}",
"menu_controls": "Controlli",
"menu_remap_controls": "Rimappa controlli",
"menu_history": "Cronologia",
"menu_language": "Lingua",
"menu_accessibility": "Accessibilità",
"menu_display": "Schermo",
"display_layout": "Layout schermo",
"menu_redownload_cache": "Aggiorna elenco giochi",
"menu_music_toggle": "Attiva/Disattiva musica",
"menu_music_enabled": "Musica attivata: {0}",
"menu_music_disabled": "Musica disattivata",
"menu_restart": "Riavvia",
"menu_filter_platforms": "Filtra sistemi",
"filter_platforms_title": "Visibilità sistemi",
"filter_all": "Mostra tutto",
"filter_none": "Nascondi tutto",
"filter_apply": "Applica",
"filter_back": "Indietro",
"filter_platforms_info": "Visibili: {0} | Nascosti: {1} / Totale: {2}",
"filter_unsaved_warning": "Modifiche non salvate",
"menu_show_unsupported_on": "Mostra sistemi non supportati: Sì",
"menu_show_unsupported_off": "Mostra sistemi non supportati: No",
"menu_show_unsupported_text": "sistemi nascosti",
"menu_show_unsupported_enabled": "Visibilità sistemi non supportati abilitata",
"menu_show_unsupported_disabled": "Visibilità sistemi non supportati disabilitata",
"menu_allow_unknown_ext_on": "Nascondi avviso estensione sconosciuta: Sì",
"menu_allow_unknown_ext_off": "Nascondi avviso estensione sconosciuta: No",
"menu_allow_unknown_ext_enabled": "Nascondi avviso estensione sconosciuta abilitato",
"menu_allow_unknown_ext_disabled": "Nascondi avviso estensione sconosciuta disabilitato",
"menu_quit": "Esci",
"button_yes": "Sì",
"button_no": "No",
"button_OK": "OK",
"popup_restarting": "Riavvio...",
"controls_hold_message": "Tieni premuto per 3s per: '{0}'",
"controls_skip_message": "Premi Esc per ignorare (solo PC)",
"controls_waiting": "In attesa...",
"controls_hold": "Tieni premuto 3s",
"controls_action_confirm": "Conferma",
"controls_action_cancel": "Annulla",
"controls_action_up": "Su",
"controls_action_down": "Giù",
"controls_action_left": "Sinistra",
"controls_action_right": "Destra",
"controls_action_page_up": "Pagina precedente",
"controls_action_page_down": "Pagina successiva",
"controls_action_clear_history": "Selezione multipla / Cancella cronologia",
"controls_action_history": "Cronologia",
"controls_action_filter": "Filtro",
"controls_action_delete": "Elimina",
"controls_action_space": "Spazio",
"controls_action_start": "Aiuto / Impostazioni",
"controls_desc_confirm": "Conferma (es. A, Invio)",
"controls_desc_cancel": "Annulla/Indietro (es. B, Backspace)",
"controls_desc_up": "Naviga in alto",
"controls_desc_down": "Naviga in basso",
"controls_desc_left": "Naviga a sinistra",
"controls_desc_right": "Naviga a destra",
"controls_desc_page_up": "Pagina precedente/Scorrimento veloce su (es. PagSu, LB)",
"controls_desc_page_down": "Pagina successiva/Scorrimento veloce giù (es. PagGiù, RB)",
"controls_desc_clear_history": "Selezione multipla (lista giochi) / Cancella cronologia (menu cronologia) (es. X)",
"controls_desc_history": "Apri cronologia (es. H, Y)",
"controls_desc_filter": "Apri filtro (es. F, Select)",
"controls_desc_delete": "Elimina carattere (es. LT, Canc)",
"controls_desc_space": "Aggiungi spazio (es. RT, Spazio)",
"controls_desc_start": "Apri menu pausa (es. Start, AltGr)",
"action_retry": "Riprova",
"action_quit": "Esci",
"action_select": "Seleziona",
"action_history": "Cronologia",
"action_download": "Scarica",
"action_filter": "Filtro",
"action_cancel": "Annulla",
"action_back": "Indietro",
"action_navigate": "Naviga",
"action_page": "Pagina",
"action_cancel_download": "Annulla download",
"action_background": "Sfondo",
"action_confirm": "Conferma",
"action_redownload": "Scarica di nuovo",
"action_clear_history": "Cancella cronologia",
"network_checking_updates": "Verifica aggiornamenti...",
"network_update_available": "Aggiornamento disponibile: {0}",
"network_extracting_update": "Estrazione aggiornamento...",
"network_update_completed": "Aggiornamento completato",
"network_update_success": "Aggiornamento a {0} completato con successo. Riavvia l'applicazione.",
"network_update_success_message": "Aggiornamento completato con successo",
"network_no_update_available": "Nessun aggiornamento disponibile",
"network_update_error": "Errore durante l'aggiornamento: {0}",
"network_check_update_error": "Errore durante il controllo degli aggiornamenti: {0}",
"network_extraction_failed": "Impossibile estrarre l'aggiornamento: {0}",
"network_extraction_partial": "Estrazione riuscita, ma alcuni file sono stati ignorati a causa di errori: {0}",
"network_extraction_success": "Estrazione riuscita",
"network_download_extract_ok": "Download ed estrazione riusciti di {0}",
"network_zip_extraction_error": "Errore durante l'estrazione dello ZIP {0}: {1}",
"network_permission_error": "Nessun permesso di scrittura in {0}",
"network_file_not_found": "Il file {0} non esiste",
"network_cannot_get_filename": "Impossibile ottenere il nome del file",
"network_cannot_get_download_url": "Impossibile ottenere l'URL di download",
"network_download_failed": "Download fallito dopo {0} tentativi",
"network_api_error": "Errore richiesta API, la chiave potrebbe essere errata: {0}",
"network_download_error": "Errore download {0}: {1}",
"network_download_ok": "Download OK: {0}",
"utils_extracted": "Estratto: {0}",
"utils_corrupt_zip": "Archivio ZIP corrotto: {0}",
"utils_permission_denied": "Permesso negato durante l'estrazione: {0}",
"utils_extraction_failed": "Estrazione fallita: {0}",
"utils_unrar_unavailable": "Comando unrar non disponibile",
"utils_rar_list_failed": "Impossibile elencare i file RAR: {0}",
"utils_xdvdfs_unavailable": "Strumento xdvdfs non disponibile (mancante o permesso negato)",
"download_initializing": "Inizializzazione...",
"accessibility_font_size": "Dimensione carattere: {0}",
"confirm_cancel_download": "Annullare il download corrente?",
"controls_help_title": "Guida ai controlli",
"controls_category_navigation": "Navigazione",
"controls_category_main_actions": "Azioni principali",
"controls_category_downloads": "Download",
"controls_category_search": "Ricerca",
"controls_navigation": "Navigazione",
"controls_pages": "Pagine",
"controls_confirm_select": "Conferma/Seleziona",
"controls_cancel_back": "Annulla/Indietro",
"controls_history": "Cronologia",
"controls_clear_history": "Selezione multipla / Cronologia",
"controls_filter_search": "Filtro/Ricerca",
"menu_symlink_option": "Opzione Symlink",
"symlink_option_enabled": "Opzione symlink abilitata",
"symlink_option_disabled": "Opzione symlink disabilitata",
"symlink_settings_saved_successfully": "Impostazioni symlink salvate con successo",
"symlink_settings_save_error": "Errore nel salvataggio delle impostazioni symlink",
"menu_games_source_prefix": "Sorgente giochi",
"games_source_rgsx": "RGSX",
"sources_mode_rgsx_select_info": "RGSX: aggiorna l'elenco dei giochi",
"games_source_custom": "Personalizzato",
"sources_mode_custom_select_info": "Modalità personalizzata: imposta l'URL in {0} poi aggiorna l'elenco giochi",
"sources_mode_custom_missing_url": "Nessun URL personalizzato impostato (modifica {0})",
"sources_mode_custom_download_error": "Download sorgente personalizzata fallito",
"menu_show_unsupported_and_hidden": "Mostra {0} sistemi non supportati e nascosti",
"menu_show_unsupported_all_displayed": "Tutti i sistemi visualizzati"
}
"welcome_message": "Benvenuto in RGSX",
"disclaimer_line1": "È pericoloso andare da soli, prendi tutto ciò che ti serve!",
"disclaimer_line2": "Ma scarica solo giochi",
"disclaimer_line3": "che possiedi già!",
"disclaimer_line4": "RGSX non è responsabile dei contenuti scaricati,",
"disclaimer_line5": "e non ospita ROM.",
"loading_test_connection": "Verifica connessione...",
"loading_download_data": "Download cartella Dati iniziale...",
"loading_progress": "Progresso: {0}%",
"loading_check_updates": "Verifica aggiornamenti... Attendere...",
"error_check_updates_failed": "Impossibile verificare gli aggiornamenti.",
"loading_downloading_games_images": "Download giochi e immagini...",
"loading_extracting_data": "Estrazione cartella Dati iniziale...",
"loading_load_systems": "Caricamento sistemi...",
"error_extract_data_failed": "Errore nel download o nell'estrazione della cartella Dati iniziale.",
"error_no_internet": "Nessuna connessione Internet. Controlla la rete.",
"error_api_key": "Inserisci la tua API key (solo premium) nel file {0}",
"error_invalid_download_data": "Dati di download non validi",
"error_delete_sources": "Errore nell'eliminazione del file systems_list.json o delle cartelle",
"platform_no_platform": "Nessuna piattaforma",
"platform_page": "Pagina {0}/{1}",
"game_no_games": "Nessun gioco disponibile",
"game_count": "{0} ({1} giochi)",
"game_filter": "Filtro attivo: {0}",
"game_search": "Filtro: {0}",
"game_header_name": "Nome",
"game_header_size": "Dimensione",
"history_title": "Download ({0})",
"history_empty": "Nessun download nella cronologia",
"history_column_system": "Sistema",
"history_column_game": "Nome del gioco",
"history_column_size": "Dimensione",
"history_column_status": "Stato",
"history_status_downloading": "Download: {0}%",
"history_status_extracting": "Estrazione: {0}%",
"history_status_completed": "Completato",
"history_status_error": "Errore: {0}",
"history_status_canceled": "Annullato",
"download_status": "{0}: {1}",
"download_canceled": "Download annullato dall'utente.",
"extension_warning_zip": "Il file '{0}' è un archivio e Batocera non supporta archivi per questo sistema. L'estrazione automatica avverrà dopo il download, continuare?",
"extension_warning_unsupported": "L'estensione del file '{0}' non è supportata da Batocera secondo la configurazione di es_systems.cfg. Vuoi continuare?",
"extension_warning_enable_unknown_hint": "\nPer non visualizzare questo messaggio: abilita \"Nascondi avviso estensione sconosciuta\" in Menu Pausa > Schermo",
"confirm_exit": "Uscire dall'applicazione?",
"confirm_exit_with_downloads": "Attenzione: {0} download in corso. Uscire comunque?",
"confirm_clear_history": "Cancellare la cronologia?",
"confirm_redownload_cache": "Aggiornare l'elenco dei giochi?",
"popup_redownload_success": "Cache pulita, riavvia l'applicazione",
"popup_no_cache": "Nessuna cache trovata.\nRiavvia l'applicazione per caricare i giochi.",
"popup_countdown": "Questo messaggio si chiuderà tra {0} secondo{1}",
"language_select_title": "Selezione lingua",
"language_select_instruction": "Usa le frecce per navigare e Invio per selezionare",
"language_changed": "Lingua cambiata in {0}",
"menu_controls": "Controlli",
"menu_remap_controls": "Rimappa controlli",
"menu_history": "Cronologia",
"menu_language": "Lingua",
"menu_accessibility": "Accessibilità",
"menu_display": "Schermo",
"display_layout": "Layout schermo",
"menu_redownload_cache": "Aggiorna elenco giochi",
"menu_music_enabled": "Musica attivata: {0}",
"menu_music_disabled": "Musica disattivata",
"menu_restart": "Riavvia",
"menu_filter_platforms": "Filtra sistemi",
"filter_platforms_title": "Visibilità sistemi",
"filter_platforms_info": "Visibili: {0} | Nascosti: {1} / Totale: {2}",
"filter_unsaved_warning": "Modifiche non salvate",
"menu_show_unsupported_enabled": "Visibilità sistemi non supportati abilitata",
"menu_show_unsupported_disabled": "Visibilità sistemi non supportati disabilitata",
"menu_allow_unknown_ext_on": "Nascondi avviso estensione sconosciuta: Sì",
"menu_allow_unknown_ext_off": "Nascondi avviso estensione sconosciuta: No",
"menu_allow_unknown_ext_enabled": "Nascondi avviso estensione sconosciuta abilitato",
"menu_allow_unknown_ext_disabled": "Nascondi avviso estensione sconosciuta disabilitato",
"menu_quit": "Esci",
"button_yes": "Sì",
"button_no": "No",
"button_OK": "OK",
"popup_restarting": "Riavvio...",
"controls_action_clear_history": "Selezione multipla / Cancella cronologia",
"controls_action_history": "Cronologia",
"controls_action_delete": "Elimina",
"controls_action_space": "Spazio",
"controls_action_start": "Aiuto / Impostazioni",
"network_checking_updates": "Verifica aggiornamenti...",
"network_update_available": "Aggiornamento disponibile: {0}",
"network_extracting_update": "Estrazione aggiornamento...",
"network_update_completed": "Aggiornamento completato",
"network_update_success": "Aggiornamento a {0} completato con successo. Riavvia l'applicazione.",
"network_update_success_message": "Aggiornamento completato con successo",
"network_no_update_available": "Nessun aggiornamento disponibile",
"network_update_error": "Errore durante l'aggiornamento: {0}",
"network_check_update_error": "Errore durante il controllo degli aggiornamenti: {0}",
"network_extraction_failed": "Impossibile estrarre l'aggiornamento: {0}",
"network_extraction_partial": "Estrazione riuscita, ma alcuni file sono stati ignorati a causa di errori: {0}",
"network_extraction_success": "Estrazione riuscita",
"network_download_extract_ok": "Download ed estrazione riusciti di {0}",
"network_zip_extraction_error": "Errore durante l'estrazione dello ZIP {0}: {1}",
"network_file_not_found": "Il file {0} non esiste",
"network_cannot_get_filename": "Impossibile ottenere il nome del file",
"network_cannot_get_download_url": "Impossibile ottenere l'URL di download",
"network_download_failed": "Download fallito dopo {0} tentativi",
"network_api_error": "Errore richiesta API, la chiave potrebbe essere errata: {0}",
"network_download_error": "Errore download {0}: {1}",
"network_download_ok": "Download OK: {0}",
"utils_extracted": "Estratto: {0}",
"utils_corrupt_zip": "Archivio ZIP corrotto: {0}",
"utils_permission_denied": "Permesso negato durante l'estrazione: {0}",
"utils_extraction_failed": "Estrazione fallita: {0}",
"utils_unrar_unavailable": "Comando unrar non disponibile",
"utils_rar_list_failed": "Impossibile elencare i file RAR: {0}",
"download_initializing": "Inizializzazione...",
"accessibility_font_size": "Dimensione carattere: {0}",
"confirm_cancel_download": "Annullare il download corrente?",
"controls_help_title": "Guida ai controlli",
"controls_category_navigation": "Navigazione",
"controls_category_main_actions": "Azioni principali",
"controls_category_downloads": "Download",
"controls_category_search": "Ricerca",
"controls_navigation": "Navigazione",
"controls_pages": "Pagine",
"controls_confirm_select": "Conferma/Seleziona",
"controls_cancel_back": "Annulla/Indietro",
"controls_filter_search": "Filtro/Ricerca",
"symlink_option_enabled": "Opzione symlink abilitata",
"symlink_option_disabled": "Opzione symlink disabilitata",
"menu_games_source_prefix": "Sorgente giochi",
"games_source_rgsx": "RGSX",
"sources_mode_rgsx_select_info": "RGSX: aggiorna l'elenco dei giochi",
"games_source_custom": "Personalizzato",
"sources_mode_custom_select_info": "Modalità personalizzata: imposta l'URL in {0} poi aggiorna l'elenco giochi",
"sources_mode_custom_missing_url": "Nessun URL personalizzato impostato (modifica {0})",
"sources_mode_custom_download_error": "Download sorgente personalizzata fallito",
"menu_show_unsupported_and_hidden": "Mostra {0} sistemi non supportati e nascosti",
"menu_show_unsupported_all_displayed": "Tutti i sistemi visualizzati",
"menu_settings_category": "Impostazioni",
"menu_back": "Indietro",
"submenu_display_layout": "Layout",
"submenu_display_font_size": "Dimensione Carattere",
"submenu_display_show_unsupported": "Mostra sistemi non supportati: {status}",
"submenu_display_allow_unknown_ext": "Nascondi avviso est. sconosciuta: {status}",
"submenu_display_filter_platforms": "Filtra sistemi",
"status_on": "Sì",
"status_off": "No",
"status_present": "Presente",
"status_missing": "Assente",
"menu_api_keys_status": "Chiavi API",
"api_keys_status_title": "Stato delle chiavi API",
"menu_games": "Giochi"
}

View File

@@ -1,15 +1,10 @@
{
"controls_mapping_title": "Configuração dos controles",
"controls_mapping_instruction": "Mantenha pressionado por 3s para configurar:",
"controls_mapping_waiting": "Aguardando uma tecla ou botão...",
"controls_mapping_press": "Pressione uma tecla ou botão",
"welcome_message": "Bem-vindo ao RGSX",
"disclaimer_line1": "É perigoso ir sozinho, leve tudo o que precisar!",
"disclaimer_line2": "Mas baixe apenas jogos",
"disclaimer_line3": "que você já possui!",
"disclaimer_line4": "O RGSX não é responsável pelo conteúdo baixado,",
"disclaimer_line5": "e não hospeda ROMs.",
"loading_test_connection": "Testando conexão...",
"loading_download_data": "Baixando pasta inicial Data...",
"loading_progress": "Progresso: {0}%",
@@ -19,27 +14,18 @@
"loading_extracting_data": "Extraindo pasta inicial Data...",
"loading_load_systems": "Carregando sistemas...",
"error_extract_data_failed": "Falha ao baixar ou extrair a pasta inicial Data.",
"error_sources_load_failed": "Falha ao carregar fontes. Abra o menu e selecione Redownload Games cache",
"error_no_internet": "Sem conexão com a Internet. Verifique sua rede.",
"error_controls_mapping": "Falha ao mapear controles",
"error_api_key": "Insira sua chave API (somente premium) no arquivo {0}",
"error_api_key_extended": "Insira sua chave API (somente premium) no arquivo /userdata/saves/ports/rgsx/1FichierAPI.txt abrindo-o em um editor de texto e colando sua chave",
"error_invalid_download_data": "Dados de download inválidos",
"error_delete_sources": "Erro ao deletar arquivo sources.json ou pastas",
"error_extension": "Extensão não suportada ou erro no download",
"error_no_download": "Nenhum download pendente.",
"platform_no_platform": "Sem plataforma",
"platform_page": "Página {0}/{1}",
"game_no_games": "Nenhum jogo disponível",
"game_count": "{0} ({1} jogos)",
"game_filter": "Filtro ativo: {0}",
"game_search": "Filtro: {0}",
"game_header_name": "Nome",
"game_header_size": "Tamanho",
"history_title": "Downloads ({0})",
"history_empty": "Nenhum download no histórico",
"history_column_system": "Sistema",
@@ -51,28 +37,21 @@
"history_status_completed": "Concluído",
"history_status_error": "Erro: {0}",
"history_status_canceled": "Cancelado",
"download_status": "{0}: {1}",
"download_progress": "{0}% {1} MB / {2} MB",
"download_canceled": "Download cancelado pelo usuário.",
"extension_warning_zip": "O arquivo '{0}' é um arquivo compactado e o Batocera não suporta arquivos compactados para este sistema. A extração automática ocorrerá após o download, continuar?",
"extension_warning_unsupported": "A extensão do arquivo '{0}' não é suportada pelo Batocera segundo a configuração es_systems.cfg. Deseja continuar?",
"extension_warning_enable_unknown_hint": "\nPara não ver esta mensagem: ative \"Ocultar aviso de extensão desconhecida\" em Menu de Pausa > Exibição",
"confirm_exit": "Sair da aplicação?",
"confirm_exit_with_downloads": "Atenção: {0} download(s) em andamento. Sair mesmo assim?",
"confirm_clear_history": "Limpar histórico?",
"confirm_redownload_cache": "Atualizar lista de jogos?",
"popup_redownload_success": "Cache limpo, reinicie a aplicação",
"popup_no_cache": "Nenhum cache encontrado.\nReinicie a aplicação para carregar os jogos.",
"popup_countdown": "Esta mensagem fechará em {0} segundo{1}",
"language_select_title": "Seleção de Idioma",
"language_select_instruction": "Use as setas para navegar e Enter para selecionar",
"language_changed": "Idioma alterado para {0}",
"menu_controls": "Controles",
"menu_remap_controls": "Remapear controles",
"menu_history": "Histórico",
@@ -81,21 +60,13 @@
"menu_display": "Exibição",
"display_layout": "Layout de exibição",
"menu_redownload_cache": "Atualizar lista de jogos",
"menu_music_toggle": "Ativar/Desativar música",
"menu_music_enabled": "Música ativada: {0}",
"menu_music_disabled": "Música desativada",
"menu_restart": "Reiniciar",
"menu_filter_platforms": "Filtrar sistemas",
"filter_platforms_title": "Visibilidade dos sistemas",
"filter_all": "Mostrar todos",
"filter_none": "Ocultar todos",
"filter_apply": "Aplicar",
"filter_back": "Voltar",
"filter_platforms_info": "Visíveis: {0} | Ocultos: {1} / Total: {2}",
"filter_unsaved_warning": "Alterações não salvas",
"menu_show_unsupported_on": "Mostrar sistemas não suportados: Sim",
"menu_show_unsupported_off": "Mostrar sistemas não suportados: Não",
"menu_show_unsupported_text": "sistemas ocultos",
"menu_show_unsupported_enabled": "Visibilidade de sistemas não suportados ativada",
"menu_show_unsupported_disabled": "Visibilidade de sistemas não suportados desativada",
"menu_allow_unknown_ext_on": "Ocultar aviso de extensão desconhecida: Sim",
@@ -103,63 +74,15 @@
"menu_allow_unknown_ext_enabled": "Aviso de extensão desconhecida oculto (ativado)",
"menu_allow_unknown_ext_disabled": "Aviso de extensão desconhecida visível (desativado)",
"menu_quit": "Sair",
"button_yes": "Sim",
"button_no": "Não",
"button_OK": "OK",
"popup_restarting": "Reiniciando...",
"controls_hold_message": "Mantenha pressionado por 3s para: '{0}'",
"controls_skip_message": "Pressione Esc para ignorar (somente PC)",
"controls_waiting": "Aguardando...",
"controls_hold": "Segure 3s",
"controls_action_confirm": "Confirmar",
"controls_action_cancel": "Cancelar",
"controls_action_up": "Cima",
"controls_action_down": "Baixo",
"controls_action_left": "Esquerda",
"controls_action_right": "Direita",
"controls_action_page_up": "Página anterior",
"controls_action_page_down": "Próxima página",
"controls_action_clear_history": "Seleção múltipla / Limpar histórico",
"controls_action_history": "Histórico",
"controls_action_filter": "Filtro",
"controls_action_delete": "Deletar",
"controls_action_space": "Espaço",
"controls_action_start": "Ajuda / Configurações",
"controls_desc_confirm": "Validar (ex: A, Enter)",
"controls_desc_cancel": "Cancelar/Voltar (ex: B, Backspace)",
"controls_desc_up": "Navegar para cima",
"controls_desc_down": "Navegar para baixo",
"controls_desc_left": "Navegar para a esquerda",
"controls_desc_right": "Navegar para a direita",
"controls_desc_page_up": "Página anterior/Rolagem rápida para cima (ex: PageUp, LB)",
"controls_desc_page_down": "Próxima página/Rolagem rápida para baixo (ex: PageDown, RB)",
"controls_desc_clear_history": "Seleção múltipla (lista) / Limpar histórico (histórico) (ex: X)",
"controls_desc_history": "Abrir histórico (ex: H, Y)",
"controls_desc_filter": "Abrir filtro (ex: F, Select)",
"controls_desc_delete": "Deletar caractere (ex: LT, Delete)",
"controls_desc_space": "Adicionar espaço (ex: RT, Space)",
"controls_desc_start": "Abrir menu de pausa (ex: Start, AltGr)",
"action_retry": "Repetir",
"action_quit": "Sair",
"action_select": "Selecionar",
"action_history": "Histórico",
"action_download": "Baixar",
"action_filter": "Filtrar",
"action_cancel": "Cancelar",
"action_back": "Voltar",
"action_navigate": "Navegar",
"action_page": "Página",
"action_cancel_download": "Cancelar download",
"action_background": "Segundo plano",
"action_confirm": "Confirmar",
"action_redownload": "Rebaixar",
"action_clear_history": "Limpar histórico",
"network_checking_updates": "Verificando atualizações...",
"network_update_available": "Atualização disponível: {0}",
"network_extracting_update": "Extraindo atualização...",
@@ -174,7 +97,6 @@
"network_extraction_success": "Extração concluída",
"network_download_extract_ok": "Download e extração concluídos de {0}",
"network_zip_extraction_error": "Erro ao extrair ZIP {0}: {1}",
"network_permission_error": "Sem permissão de escrita em {0}",
"network_file_not_found": "Arquivo {0} não existe",
"network_cannot_get_filename": "Não foi possível obter o nome do arquivo",
"network_cannot_get_download_url": "Não foi possível obter a URL de download",
@@ -182,14 +104,12 @@
"network_api_error": "Erro na requisição da API, a chave pode estar incorreta: {0}",
"network_download_error": "Erro de download {0}: {1}",
"network_download_ok": "Download OK: {0}",
"utils_extracted": "Extraído: {0}",
"utils_corrupt_zip": "Arquivo ZIP corrompido: {0}",
"utils_permission_denied": "Permissão negada durante extração: {0}",
"utils_extraction_failed": "Extração falhou: {0}",
"utils_unrar_unavailable": "Comando unrar não disponível",
"utils_rar_list_failed": "Falha ao listar arquivos RAR: {0}",
"utils_xdvdfs_unavailable": "Ferramenta xdvdfs indisponível (faltando ou sem permissão)",
"download_initializing": "Inicializando...",
"accessibility_font_size": "Tamanho da fonte: {0}",
"confirm_cancel_download": "Cancelar download atual?",
@@ -202,16 +122,9 @@
"controls_pages": "Páginas",
"controls_confirm_select": "Confirmar/Selecionar",
"controls_cancel_back": "Cancelar/Voltar",
"controls_history": "Histórico",
"controls_clear_history": "Seleção múltipla / Histórico",
"controls_filter_search": "Filtrar/Buscar",
"menu_symlink_option": "Opção de Symlink",
"symlink_option_enabled": "Opção de symlink ativada",
"symlink_option_disabled": "Opção de symlink desativada",
"symlink_settings_saved_successfully": "Configurações de symlink salvas com sucesso",
"symlink_settings_save_error": "Erro ao salvar configurações de symlink",
"menu_games_source_prefix": "Fonte de jogos",
"games_source_rgsx": "RGSX",
"sources_mode_rgsx_select_info": "RGSX: atualizar a lista de jogos",
@@ -220,5 +133,19 @@
"sources_mode_custom_missing_url": "Nenhuma URL personalizada definida (edite {0})",
"sources_mode_custom_download_error": "Falha no download da fonte personalizada",
"menu_show_unsupported_and_hidden": "Mostrar {0} sistemas não suportados e ocultos",
"menu_show_unsupported_all_displayed": "Todos os sistemas exibidos"
"menu_show_unsupported_all_displayed": "Todos os sistemas exibidos",
"menu_settings_category": "Configurações",
"menu_back": "Voltar",
"submenu_display_layout": "Layout",
"submenu_display_font_size": "Tamanho da Fonte",
"submenu_display_show_unsupported": "Mostrar sistemas não suportados: {status}",
"submenu_display_allow_unknown_ext": "Ocultar aviso ext. desconhecida: {status}",
"submenu_display_filter_platforms": "Filtrar sistemas",
"status_on": "Sim",
"status_off": "Não",
"status_present": "Presente",
"status_missing": "Ausente",
"menu_api_keys_status": "Chaves API",
"api_keys_status_title": "Status das chaves API",
"menu_games": "Jogos"
}

View File

@@ -15,7 +15,7 @@ try:
except Exception:
pygame = None # type: ignore
from config import OTA_VERSION_ENDPOINT,APP_FOLDER, UPDATE_FOLDER, OTA_UPDATE_ZIP
from utils import sanitize_filename, extract_zip, extract_rar, load_api_key_1fichier, load_api_key_alldebrid, normalize_platform_name
from utils import sanitize_filename, extract_zip, extract_rar, load_api_key_1fichier, load_api_key_alldebrid, normalize_platform_name, load_api_keys
from history import save_history
import logging
import datetime
@@ -318,8 +318,8 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
# Spécifique: si le système est "BIOS" on force le dossier BIOS
if platform_folder == "bios" or platform == "BIOS" or platform == "- BIOS by TMCTV -":
dest_dir = config.RETROBAT_DATA_FOLDER
logger.debug(f"Plateforme 'BIOS' détectée, destination forcée vers RETROBAT_DATA_FOLDER: {dest_dir}")
dest_dir = config.USERDATA_FOLDER
logger.debug(f"Plateforme 'BIOS' détectée, destination forcée vers USERDATA_FOLDER: {dest_dir}")
os.makedirs(dest_dir, exist_ok=True)
if not os.access(dest_dir, os.W_OK):
@@ -634,13 +634,16 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
return result[0], result[1]
async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=False, task_id=None):
config.API_KEY_1FICHIER = load_api_key_1fichier()
if not config.API_KEY_1FICHIER:
# Fallback: essayer AllDebrid
config.API_KEY_ALLDEBRID = load_api_key_alldebrid()
logger.debug(f"Clé API 1fichier absente, fallback AllDebrid: {'présente' if config.API_KEY_ALLDEBRID else 'absente'}")
# Charger/rafraîchir les clés API (mtime aware)
keys_info = load_api_keys()
config.API_KEY_1FICHIER = keys_info.get('1fichier', '')
config.API_KEY_ALLDEBRID = keys_info.get('alldebrid', '')
if not config.API_KEY_1FICHIER and config.API_KEY_ALLDEBRID:
logger.debug("Clé 1fichier absente, utilisation fallback AllDebrid")
elif not config.API_KEY_1FICHIER and not config.API_KEY_ALLDEBRID:
logger.debug("Aucune clé API disponible (1fichier ni AllDebrid)")
logger.debug(f"Début téléchargement 1fichier: {game_name} depuis {url}, is_zip_non_supported={is_zip_non_supported}, task_id={task_id}")
logger.debug(f"Clé API 1fichier: {'présente' if config.API_KEY_1FICHIER else 'absente'}")
logger.debug(f"Clé API 1fichier: {'présente' if config.API_KEY_1FICHIER else 'absente'} / AllDebrid: {'présente' if config.API_KEY_ALLDEBRID else 'absente'} (reloaded={keys_info.get('reloaded')})")
result = [None, None]
# Créer une queue spécifique pour cette tâche
@@ -673,8 +676,8 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
# Spécifique: si le système est "- BIOS by TMCTV -" on force le dossier BIOS
if platform_folder == "bios" or platform == "BIOS" or platform == "- BIOS by TMCTV -":
dest_dir = config.RETROBAT_DATA_FOLDER
logger.debug(f"Plateforme '- BIOS by TMCTV -' détectée, destination forcée vers RETROBAT_DATA_FOLDER: {dest_dir}")
dest_dir = config.USERDATA_FOLDER
logger.debug(f"Plateforme '- BIOS by TMCTV -' détectée, destination forcée vers USERDATA_FOLDER: {dest_dir}")
logger.debug(f"Vérification répertoire destination: {dest_dir}")
os.makedirs(dest_dir, exist_ok=True)
@@ -685,6 +688,7 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
# Choisir la stratégie d'accès: 1fichier direct via API, sinon AllDebrid pour débrider
if config.API_KEY_1FICHIER:
logger.debug("Mode téléchargement sélectionné: 1fichier (API directe)")
headers = {
"Authorization": f"Bearer {config.API_KEY_1FICHIER}",
"Content-Type": "application/json"
@@ -726,6 +730,7 @@ async def download_from_1fichier(url, platform, game_name, is_zip_non_supported=
logger.debug(f"URL de téléchargement obtenue via 1fichier: {final_url}")
else:
# AllDebrid: débrider l'URL 1fichier vers une URL directe
logger.debug("Mode téléchargement sélectionné: AllDebrid (fallback, débridage 1fichier)")
if not getattr(config, 'API_KEY_ALLDEBRID', ''):
logger.error("Aucune clé API (1fichier/AllDebrid) disponible")
result[0] = False

View File

@@ -122,14 +122,14 @@ def load_extensions_json():
def _detect_es_systems_cfg_paths():
"""Retourne une liste de chemins possibles pour es_systems.cfg selon l'OS.
- RetroBat (Windows): {config.RETROBAT_DATA_FOLDER}\\system\\templates\\emulationstation\\es_systems.cfg
- RetroBat (Windows): {config.USERDATA_FOLDER}\\system\\templates\\emulationstation\\es_systems.cfg
- Batocera (Linux): /usr/share/emulationstation/es_systems.cfg
Ajoute aussi les fichiers customs: /userdata/system/configs/emulationstation/es_systems_*.cfg
"""
candidates = []
try:
if platform.system() == 'Windows':
base = getattr(config, 'RETROBAT_DATA_FOLDER', None)
base = getattr(config, 'USERDATA_FOLDER', None)
if base:
candidates.append(os.path.join(base, 'system', 'templates', 'emulationstation', 'es_systems.cfg'))
else:
@@ -1250,66 +1250,82 @@ def set_music_popup(music_name):
config.music_popup_start_time = pygame.time.get_ticks() / 1000 # Temps actuel en secondes
config.needs_redraw = True # Forcer le redraw pour afficher le nom de la musique
def load_api_key_1fichier():
"""Charge la clé API 1fichier depuis le dossier de sauvegarde, crée le fichier si absent."""
API_KEY_1FICHIER = os.path.join(config.SAVE_FOLDER, "1FichierAPI.txt")
logger.debug(f"Chemin du fichier de clé API: {API_KEY_1FICHIER}")
logger.debug(f"Tentative de chargement de la clé API depuis: {API_KEY_1FICHIER}")
try:
# Vérifie si le fichier existe déjà
if not os.path.exists(API_KEY_1FICHIER):
logger.info(f"Fichier de clé API non trouvé")
# Crée le dossier parent si nécessaire
os.makedirs(config.SAVE_FOLDER, exist_ok=True)
# Crée le fichier vide si absent
with open(API_KEY_1FICHIER, "w") as f:
f.write("")
logger.info(f"Fichier de clé API créé : {API_KEY_1FICHIER}")
return ""
except OSError as e:
logger.error(f"Erreur lors de la création du fichier de clé API : {e}")
return ""
# Lit la clé API depuis le fichier
try:
with open(API_KEY_1FICHIER, "r", encoding="utf-8") as f:
api_key = f.read().strip()
logger.debug(f"Clé API 1fichier lue: '{api_key}' (longueur: {len(api_key)})")
if not api_key:
logger.warning("Clé API 1fichier vide, veuillez la renseigner dans le fichier pour pouvoir utiliser les fonctionnalités de téléchargement sur 1fichier.")
API_KEY_1FICHIER = api_key
config.API_KEY_1FICHIER = api_key
logger.debug(f"Clé API 1fichier chargée dans la configuration : '{config.API_KEY_1FICHIER}'")
return api_key
except OSError as e:
logger.error(f"Erreur lors de la lecture de la clé API : {e}")
return ""
def load_api_keys(force: bool = False):
"""Charge les clés API (1fichier, AllDebrid) en une seule passe.
def load_api_key_alldebrid():
"""Charge la clé API AllDebrid depuis le dossier de sauvegarde, crée le fichier si absent."""
- Crée les fichiers vides s'ils n'existent pas
- Met à jour config.API_KEY_1FICHIER et config.API_KEY_ALLDEBRID
- Utilise un cache basé sur le mtime pour éviter des relectures
- force=True ignore le cache et relit systématiquement
Retourne: { '1fichier': str, 'alldebrid': str, 'reloaded': bool }
"""
try:
api_file = os.path.join(config.SAVE_FOLDER, "AllDebridAPI.txt")
logger.debug(f"Chemin du fichier de clé API AllDebrid: {api_file}")
if not os.path.exists(api_file):
logger.info("Fichier de clé API AllDebrid non trouvé")
os.makedirs(config.SAVE_FOLDER, exist_ok=True)
with open(api_file, "w", encoding="utf-8") as f:
f.write("")
logger.info(f"Fichier de clé API AllDebrid créé : {api_file}")
return ""
with open(api_file, "r", encoding="utf-8") as f:
api_key = f.read().strip()
logger.debug(f"Clé API AllDebrid lue: '{api_key}' (longueur: {len(api_key)})")
if not api_key:
logger.warning("Clé API AllDebrid vide, renseignez-la dans AllDebridAPI.txt pour activer le débridage.")
# Stocke dans la config pour usage global
try:
config.API_KEY_ALLDEBRID = api_key
except Exception:
pass
return api_key
paths = {
'1fichier': getattr(config, 'API_KEY_1FICHIER_PATH', ''),
'alldebrid': getattr(config, 'API_KEY_ALLDEBRID_PATH', ''),
}
cache_attr = '_api_keys_cache'
if not hasattr(config, cache_attr):
setattr(config, cache_attr, {'1fichier_mtime': None, 'alldebrid_mtime': None})
cache_data = getattr(config, cache_attr)
reloaded = False
for key_name, path in paths.items():
if not path:
continue
# Création fichier vide si absent
try:
if not os.path.exists(path):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w', encoding='utf-8') as f:
f.write("")
except Exception as ce:
logger.error(f"Impossible de préparer le fichier clé {key_name}: {ce}")
continue
try:
mtime = os.path.getmtime(path)
except Exception:
mtime = None
cache_key = f"{key_name}_mtime"
if force or (mtime is not None and mtime != cache_data.get(cache_key)):
# Lecture
try:
with open(path, 'r', encoding='utf-8') as f:
value = f.read().strip()
except Exception as re:
logger.error(f"Erreur lecture clé {key_name}: {re}")
value = ""
# Assignation dans config
if key_name == '1fichier':
config.API_KEY_1FICHIER = value
else:
config.API_KEY_ALLDEBRID = value
cache_data[cache_key] = mtime
reloaded = True
return {
'1fichier': getattr(config, 'API_KEY_1FICHIER', ''),
'alldebrid': getattr(config, 'API_KEY_ALLDEBRID', ''),
'reloaded': reloaded
}
except Exception as e:
logger.error(f"Erreur lors du chargement de la clé API AllDebrid: {e}")
return ""
logger.error(f"Erreur load_api_keys: {e}")
return {
'1fichier': getattr(config, 'API_KEY_1FICHIER', ''),
'alldebrid': getattr(config, 'API_KEY_ALLDEBRID', ''),
'reloaded': False
}
# Wrappers rétro-compatibilité (dépréciés)
def load_api_key_1fichier(force: bool = False): # pragma: no cover
return load_api_keys(force).get('1fichier', '')
def load_api_key_alldebrid(force: bool = False): # pragma: no cover
return load_api_keys(force).get('alldebrid', '')
# Ancien nom conservé comme alias
def ensure_api_keys_loaded(force: bool = False): # pragma: no cover
return load_api_keys(force)
def load_music_config():
"""Charge la configuration musique depuis rgsx_settings.json."""