mirror of
https://github.com/Faraphel/Atlas-Install.git
synced 2025-07-02 02:38:30 +02:00
remade all the translation in a easier, faster and more readable way
This commit is contained in:
parent
97477bba79
commit
423a02ce4c
39 changed files with 394 additions and 435 deletions
|
@ -7,8 +7,8 @@
|
|||
},
|
||||
"installation_completed": {
|
||||
"text": {
|
||||
"fr": "Merci d'avoir téléchargé {{ mod_config.name }} !\nSi vous avez un problème en démarrant le jeu avec Dolphin, essayer dans Configurer > Avancé > Modifier la taille de la mémoire émulée et mettre MEM2 à 128MB\n\nAmusez-vous !",
|
||||
"en": "Thanks for downloading {{ mod_config.name }} !\nIf You have an issue starting the game with Dolphin, try in Config > Advanced > Enable Emulated Memory Size Override and set MEM2 to 128MB\n\nHave fun !"
|
||||
"fr": "Merci d'avoir téléchargé {{ mod_config.name }} !\nSi vous avez un problème en démarrant le jeu avec Dolphin, essayer de mettre MEM2 dans Configurer > Avancé > Modifier la taille de la mémoire émulée à 128MB\n\nAmusez-vous !",
|
||||
"en": "Thanks for downloading {{ mod_config.name }} !\nIf You have an issue when starting the game with Dolphin, try to set MEM2 in Config > Advanced > Enable Emulated Memory Size Override to 128MB\n\nHave fun !"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,124 +1,112 @@
|
|||
{
|
||||
"name": "English",
|
||||
"translation": {
|
||||
"INSTALLER_TITLE": "MKWF-Install",
|
||||
"LANGUAGE_SELECTION": "Language",
|
||||
"TRACK_FILTER": "Track Filters",
|
||||
"ADVANCED_CONFIGURATION": "Advanced",
|
||||
"HELP": "Help",
|
||||
"INVALID_SOURCE_PATH": "Invalid path for source game",
|
||||
"DISCORD": "Discord",
|
||||
"GITHUB WIKI": "Github Wiki",
|
||||
"READTHEDOCS": "ReadTheDocs",
|
||||
"ORIGINAL_GAME_FILE": "Original Game File",
|
||||
"SELECT_SOURCE_GAME": "Select the source game",
|
||||
"WII GAMES": "Wii games",
|
||||
"ERROR": "Error",
|
||||
"ERROR_INVALID_SOURCE_GAME": "The source game path is invalid",
|
||||
"GAME_DIRECTORY_DESTINATION": "Game Directory Destination",
|
||||
"SELECT_DESTINATION_GAME": "Select the destination game",
|
||||
"WARNING": "Warning",
|
||||
"WARNING_DESTINATION_GAME_NOT_WRITABLE": "The destination game path is not writable",
|
||||
"INSTALL": "Install",
|
||||
"ERROR_INVALID_DESTINATION_GAME": "The destination game path is invalid",
|
||||
"WARNING_LOW_SPACE_CONTINUE": "The space left on the drive is low. Continue ?",
|
||||
"INSTALLATION_COMPLETED": "Installation Completed",
|
||||
"INSTALLATION_FINISHED_WITH_SUCCESS": "The installation ended successfully !",
|
||||
"OPEN_MYSTUFF_SETTINGS": "Open MyStuff settings",
|
||||
"THREADS_USAGE": "Threads usage",
|
||||
"USE": "Use",
|
||||
"THREADS": "threads",
|
||||
"MESSAGE_FROM_MOD_AUTHOR": "Message from the author",
|
||||
"GLOBAL_MOD_SETTINGS": "Global mod settings",
|
||||
"SPECIFIC_MOD_SETTINGS": "Specific mod settings",
|
||||
"CONFIGURE_MYSTUFF_PATCH": "Configure the MyStuff patchs",
|
||||
"DISABLED": "Disabled",
|
||||
"ENABLED": "Enabled",
|
||||
"NEW_PROFILE": "New Profile",
|
||||
"DELETE_PROFILE": "Delete Profile",
|
||||
"ADD_MYSTUFF": "Add MyStuff patch",
|
||||
"REMOVE_MYSTUFF": "Remove MyStuff patch",
|
||||
"MYSTUFF_PROFILE_ALREADY_EXIST": "This MyStuff profile already exist !",
|
||||
"MYSTUFF_PROFILE_FORBIDDEN_NAME": "This MyStuff profile name can't be used !",
|
||||
"SELECT_MYSTUFF": "Select MyStuff patch",
|
||||
"TYPE_PREVIEW_WINDOW": "Type of preview window",
|
||||
"NOT_FOUND": "not found",
|
||||
"TYPE_MOD_SETTINGS": "Type of mod settings",
|
||||
"BMG_LAYER_MODE": "bmg layer mode",
|
||||
"IS_NOT_IMPLEMENTED": "is not implemented",
|
||||
"IMAGE_LAYER_TYPE": "image layer type",
|
||||
"OPERATION": "Operation",
|
||||
"PATH": "Path",
|
||||
"MODE": "Mode",
|
||||
"SOURCE": "Source",
|
||||
"OUTSIDE_ALLOWED_RANGE": "outside of allowed range",
|
||||
"IN_PATCH": "in patch",
|
||||
"INSTALLING_PATCH": "Installing the patch",
|
||||
"PATCH_TITLE": "Patch",
|
||||
"PRE-PATCH_TITLE": "Pre-patch",
|
||||
"PATCHING": "Patching",
|
||||
"FORBIDDEN_TRACK_ATTRIBUTE": "Forbidden track attribute",
|
||||
"FORBIDDEN_ARENA_ATTRIBUTE": "Forbidden arena attribute",
|
||||
"EXTRACTING_AUTOADD_FILES": "Extracting autoadd files...",
|
||||
"EXTRACTING_ORIGINAL_TRACKS": "Extracting original tracks...",
|
||||
"INSTALLING_MYSTUFF": "Installing MyStuff",
|
||||
"INSTALLING_ALL_MYSTUFF_PATCHS": "Installing all the mystuff patchs",
|
||||
"PREPARING": "Preparing",
|
||||
"SPECIAL_FILE": "special file",
|
||||
"REPACKING": "Repacking",
|
||||
"ALL_ARCHIVES": "all archives",
|
||||
"INSTALLING_ALL": "Installing all",
|
||||
"CONVERTING_GAME_TO": "Converting game to",
|
||||
"DELETING_EXTRACTED_GAME": "Deleting the extracted game...",
|
||||
"NOT_MKW_GAME": "Not a Mario Kart Wii game",
|
||||
"GAME_ALREADY_MODDED": "This game is already modded",
|
||||
"COPYING_GAME": "Copying Game...",
|
||||
"EXTRACTING": "Extracting",
|
||||
"ESTIMATED_TIME_REMAINING": "estimated time remaining",
|
||||
"CHANGING_GAME_METADATA": "Changing game metadata...",
|
||||
"EXTRACTION": "Extraction",
|
||||
"MYSTUFF": "MyStuff",
|
||||
"PREPARING_FILES": "Preparing files",
|
||||
"PRE-PATCHING": "Pre-Patching",
|
||||
"CONVERTING_TO_GAME_FILE": "Converting to game file",
|
||||
"CANNOT_FIND_COLOR": "Can't find color",
|
||||
"NORMALIZING_TRACKS": "Normalizing tracks",
|
||||
"INVALID_MACRO": "Invalid macro",
|
||||
"INVALID_AST_TYPE": "Invalid ast type",
|
||||
"MAGIC_ATTRIBUTE_ARE_FORBIDDEN": "Magic attribute are forbidden",
|
||||
"CANNOT_SET_ATTRIBUTE": "Can't set value of attribute",
|
||||
"CANNOT_SET_ENVIRONMENT": "Can't set value of environment",
|
||||
"CANNOT_SET_ARGUMENT": "Can't set value of argument",
|
||||
"CALLING_FUNCTION_NOT_ALLOWED": "Calling this function is not allowed",
|
||||
"FORBIDDEN_SYNTAX": "Forbidden syntax",
|
||||
"MAGIC_METHOD_FORBIDDEN": "Magic method are not allowed",
|
||||
"CANNOT_GET_ERROR_MESSAGE": "Can't get the error message",
|
||||
"RAISED": "raised",
|
||||
"CANNOT_FIND_TOOL": "Can't find tool",
|
||||
"IN_TOOLS_DIRECTORY": "in the tools directory.",
|
||||
"CANNOT_EXTRACT_A_DIRECTORY": "Can't extract a directory",
|
||||
"CANNOT_FIND_SLOT": "Can't find slot",
|
||||
"FORBIDDEN_TRACKGROUP_ATTRIBUTE": "Forbidden TrackGroup attribute",
|
||||
"SAFE_EVAL_ERROR": "Safe eval error",
|
||||
"TEMPLATE_USED": "Template used",
|
||||
"MORE_IN_ERROR_LOG": "More information in the error.log file",
|
||||
"COPY_FUNCTION_FORBIDDEN": "Copying functions is forbidden",
|
||||
"GET_METHOD_FORBIDDEN": "Using getattr on a method is forbidden",
|
||||
"CAN_ONLY_CALL_METHOD_OF_CONSTANT": "You can only call methods on constant",
|
||||
"CAN_ONLY_CALL_FUNCTION_IN_ENV": "You can only call function from the environment",
|
||||
"ENABLE_DEVELOPER_MODE": "Enable the developer mode",
|
||||
"TESTING_MOD_SETTINGS": "Test mod settings",
|
||||
"SETTINGS_FILE": "Settings file",
|
||||
"EXPORT_SETTINGS": "Export settings",
|
||||
"IMPORT_SETTINGS": "Import settings",
|
||||
"PREPARING_RIIVOLUTION": "Preparing for Riivolution",
|
||||
"CONVERTING_TO_RIIVOLUTION": "Converting to Riivolution patch",
|
||||
"PATCHS": "patchs",
|
||||
"PRE-PATCHS": "pre-patchs",
|
||||
"CALCULATING_HASH_FOR": "Calculating hash for",
|
||||
"WARNING_NOT_ROOT": "The application require root permission. You should start the application with 'sudo'. Continue anyway ?",
|
||||
"WARNING_INSTALLER_PERMISSION": "The application need writing and execution permissions to its own files. You can use 'sudo chmod 777 -R <installer-path>' to fix that. Continue anyway ?",
|
||||
"WARNING_EMPTY_CACHE": "By emptying the cache, you will gain %.2fGB, but reinstalling a mod will be take way longer. Continue ?",
|
||||
"EMPTY_CACHE": "Empty the cache"
|
||||
}
|
||||
"name": "English",
|
||||
"translation": {
|
||||
"TITLE_INSTALL": "MKWF-Install",
|
||||
"TITLE_MOD_SETTINGS": "Mod Settings",
|
||||
"TITLE_MYSTUFF_SETTINGS": "MyStuff Settings",
|
||||
|
||||
"MENU_LANGUAGE_SELECTION": "Language",
|
||||
"MENU_ADVANCED": "Advanced",
|
||||
"MENU_ADVANCED_MYSTUFF": "MyStuff settings",
|
||||
"MENU_ADVANCED_THREADS": "Thread usage",
|
||||
"MENU_ADVANCED_THREADS_SELECTION": "Use %i threads",
|
||||
"MENU_ADVANCED_EMPTY_CACHE": "Empty the cache",
|
||||
"MENU_ADVANCED_DEVELOPER_MODE": "Enable developer settings",
|
||||
"MENU_HELP": "Help",
|
||||
|
||||
"PART_EXTRACTION": "Extraction",
|
||||
"PART_PRE_RIIVOLUTION": "Pre-Riivolution",
|
||||
"PART_MYSTUFF": "MyStuff",
|
||||
"PART_PREPARING_FILES": "Preparing files",
|
||||
"PART_PREPATCH": "Pre-Patch",
|
||||
"PART_LECODE": "LE-CODE",
|
||||
"PART_PATCH": "Patch",
|
||||
"PART_RIIVOLUTION": "Riivolution",
|
||||
"PART_CONVERSION": "Conversion",
|
||||
|
||||
"TEXT_SOURCE_GAME": "Source Game",
|
||||
"TEXT_GAME_DESTINATION": "Game Destination",
|
||||
"TEXT_INSTALL": "Install",
|
||||
"TEXT_SELECT_SOURCE_GAME": "Select a source game",
|
||||
"TEXT_SELECT_GAME_DESTINATION": "Select the game destination",
|
||||
"TEXT_WII_GAMES": "Wii games",
|
||||
"TEXT_INSTALLATION_COMPLETED": "Installation Completed",
|
||||
"TEXT_INSTALLATION_FINISHED_SUCCESSFULLY": "The installation finished successfully !",
|
||||
"TEXT_MESSAGE_FROM_AUTHOR": "Message from the author",
|
||||
"TEXT_MOD_GLOBAL_SETTINGS": "Global settings",
|
||||
"TEXT_MOD_SPECIFIC_SETTINGS": "Specific settings",
|
||||
"TEXT_MOD_TEST_SETTINGS": "Test settings",
|
||||
"TEXT_DISABLED": "Disabled",
|
||||
"TEXT_ENABLED": "Enabled",
|
||||
"TEXT_IMPORT_SETTINGS": "Import settings",
|
||||
"TEXT_EXPORT_SETTINGS": "Export settings",
|
||||
"TEXT_SETTINGS_FILE": "Settings file",
|
||||
"TEXT_NEW_PROFILE": "New profile",
|
||||
"TEXT_DELETE_PROFILE": "Delete profile",
|
||||
"TEXT_ADD_MYSTUFF": "Add MyStuff",
|
||||
"TEXT_REMOVE_MYSTUFF": "Remove MyStuff",
|
||||
"TEXT_SELECT_MYSTUFF": "Select MyStuff",
|
||||
"TEXT_COPYING_GAME": "Copying game",
|
||||
"TEXT_EXTRACTING_GAME": "Extracting game - %i%% (estimated time remaining : %s)",
|
||||
"TEXT_CHANGING_GAME_METADATA": "Changing game metadata",
|
||||
"TEXT_EXTRACTING_AUTOADD": "Extracting autoadd files",
|
||||
"TEXT_EXTRACTING_ORIGINAL_TRACKS": "Extracting original tracks \"%s\"",
|
||||
"TEXT_INSTALLING_MYSTUFF": "Installing MyStuff \"%s\"",
|
||||
"TEXT_PREPARING_SPECIAL_FILE": "Preparing special file \"%s\"",
|
||||
"TEXT_PREPARING_MAIN_DOL": "Preparing main.dol",
|
||||
"TEXT_REPACKING_ARCHIVE": "Repacking archive \"%s\"",
|
||||
"TEXT_PATCHING_LECODE": "Patching LECODE.bin",
|
||||
"TEXT_CONVERT_GAME_TO": "Converting game to %s",
|
||||
"TEXT_DELETING_EXTRACTED_GAME": "Deleting extracted game",
|
||||
"TEXT_CONVERTING_TO_RIIVOLUTION": "Converting to Riivolution",
|
||||
"TEXT_CALCULATING_HASH": "Calculating hash for \"%s\"",
|
||||
"TEXT_NORMALIZING_TRACKS": "Normalizing tracks :\n%s",
|
||||
"TEXT_PATCHING": "Patching \"%s\"",
|
||||
|
||||
"WARNING": "Warning",
|
||||
"WARNING_EMPTY_CACHE": "By emptying the cache, you will gain %.2fGB, but reinstalling a mod will be take way longer. Continue ?",
|
||||
"WARNING_DESTINATION_NOT_WRITABLE": "The game destination directory is not writable. Continue anyway ?",
|
||||
"WARNING_LOW_SPACE_CONTINUE": "Low space remaining on disk %s (%.2fGB). Continue anyway ?",
|
||||
"WARNING_NOT_ROOT": "Root permissions are required. You should start the application with 'sudo'. Continue anyway ?",
|
||||
"WARNING_INSTALLER_PERMISSION": "Writing and execution permissions are required. You can use 'sudo chmod 777 -R <installer-path>' to fix that. Continue anyway ?",
|
||||
|
||||
"ERROR": "Error",
|
||||
"ERROR_SEE_LOGS": "See error.log for more information",
|
||||
"ERROR_INVALID_SOURCE_GAME": "Invalid source game : \"%s\"",
|
||||
"ERROR_INVALID_GAME_DESTINATION": "Invalid game destination : \"%s\"",
|
||||
"ERROR_MYSTUFF_PROFILE_ALREADY_EXIST": "The MyStuff profile \"%s\" already exist !",
|
||||
"ERROR_MYSTUFF_PROFILE_FORBIDDEN_NAME": "The MyStuff profile name \"%s\" is forbidden !",
|
||||
"ERROR_NOT_MKW_GAME": "This game is not a Mario Kart Wii game : \"%s\"",
|
||||
"ERROR_GAME_ALREADY_MODDED": "This game is already modded : \"%s\"",
|
||||
"ERROR_PATH_OUTSIDE_RANGE": "Path \"%s\" is outside allowed range : \"%s\"",
|
||||
"ERROR_PREVIEW_WINDOW_NOT_FOUND": "Preview window type \"%s\" not found",
|
||||
"ERROR_CANNOT_FIND_COLOR": "Can't find color : \"%s\"",
|
||||
"ERROR_CANNOT_FIND_SLOT": "Can't find slot : \"%s\"",
|
||||
"ERROR_MOD_SETTINGS_NOT_FOUND": "Mod settings type \"%s\" not found",
|
||||
"ERROR_FORBIDDEN_TRACK_ATTRIBUTE": "Forbidden track attribute : \"%s\"",
|
||||
"ERROR_FORBIDDEN_ARENA_ATTRIBUTE": "Forbidden arena attribute : \"%s\"",
|
||||
"ERROR_FORBIDDEN_TRACKGROUP_ATTRIBUTE": "Forbidden track group attribute : \"%s\"",
|
||||
"ERROR_SAFEEVAL": "Safe eval error (template used : \"%s\")",
|
||||
"ERROR_INVALID_MACRO": "Invalid macro : \"%s\"",
|
||||
"ERROR_INVALID_AST_TYPE": "Invalid AST type : \"%s\"",
|
||||
"ERROR_FORBIDDEN_MAGIC_ATTRIBUTE": "Magic attribute are forbidden : \"%s\"",
|
||||
"ERROR_FORBIDDEN_MAGIC_METHOD": "Magic method are forbidden : \"%s\"",
|
||||
"ERROR_GETTING_METHOD_FORBIDDEN": "Getting method is forbidden : \"%s\"",
|
||||
"ERROR_CANNOT_SET_ATTRIBUTE": "Setting attribute is forbidden : \"%s\"",
|
||||
"ERROR_CANNOT_SET_ENVIRONMENT": "Setting environment variable is forbidden : \"%s\"",
|
||||
"ERROR_CANNOT_SET_ARGUMENT": "Setting argument variable is forbidden : \"%s\"",
|
||||
"ERROR_CAN_ONLY_CALL_CONSTANT_METHOD": "Only calling method of constant is allowed",
|
||||
"ERROR_CAN_ONLY_CALL_ENV_FUNCTION": "You only can call function from the environment",
|
||||
"ERROR_FORBIDDEN_SYNTAX": "Forbidden syntax : \"%s\"",
|
||||
"ERROR_FUNCTION_COPY_FORBIDDEN": "Copying a function is forbidden",
|
||||
"ERROR_CANNOT_GET_ERROR_MESSAGE": "Can't get the error message",
|
||||
"ERROR_WT": "%s raised %i :\n%s",
|
||||
"ERROR_CANNOT_FIND_TOOL": "Can't find tool \"%s\" in the tools directory",
|
||||
"ERROR_CANNOT_EXTRACT_DIRECTORY": "Directory can't be extracted",
|
||||
"ERROR_PATCH_MODE_NOT_IMPLEMENTED": "Patch mode \"%s\" is not implemented (in patch : \"%s\")",
|
||||
"ERROR_SOURCE_NOT_IMPLEMENTED": "Source \"%s\" is not implemented (in patch : \"%s\")",
|
||||
"ERROR_OPERATION_NOT_IMPLEMENTED": "Operation \"%s\" is not implemented",
|
||||
"ERROR_BMG_LAYER_MODE_NOT_IMPLEMENTED": "Bmg layer mode \"%s\" not implemented",
|
||||
"ERROR_IMAGE_LAYER_TYPE_NOT_IMPLEMENTED": "Image layer type \"%s\" not implemented"
|
||||
}
|
||||
}
|
|
@ -1,125 +1,112 @@
|
|||
{
|
||||
"name": "Français",
|
||||
"translation": {
|
||||
"INSTALLER_TITLE": "MKWF-Install",
|
||||
"LANGUAGE_SELECTION": "Langue",
|
||||
"TRACK_FILTER": "filtrer les courses",
|
||||
"ADVANCED_CONFIGURATION": "Avancée",
|
||||
"HELP": "Aide",
|
||||
"name": "Français",
|
||||
"translation": {
|
||||
"TITLE_INSTALL": "MKWF-Install",
|
||||
"TITLE_MOD_SETTINGS": "Paramètres du mod",
|
||||
"TITLE_MYSTUFF_SETTINGS": "Paramètres MyStuff",
|
||||
|
||||
"INVALID_SOURCE_PATH": "Chemin invalide pour le jeu source",
|
||||
"DISCORD": "Discord",
|
||||
"GITHUB WIKI": "Wiki Github",
|
||||
"READTHEDOCS": "ReadTheDocs",
|
||||
"ORIGINAL_GAME_FILE": "Fichier du jeu original",
|
||||
"SELECT_SOURCE_GAME": "Sélectionner le jeu source",
|
||||
"WII GAMES": "jeux Wii",
|
||||
"ERROR": "Erreur",
|
||||
"ERROR_INVALID_SOURCE_GAME": "Chemin invalide pour le jeu source",
|
||||
"GAME_DIRECTORY_DESTINATION": "Dossier de destination du jeu",
|
||||
"SELECT_DESTINATION_GAME": "Sélectionner le dossier de destination du jeu",
|
||||
"WARNING": "Attention",
|
||||
"WARNING_DESTINATION_GAME_NOT_WRITABLE": "Le chemin de destination n'est pas modifiable",
|
||||
"INSTALL": "Installer",
|
||||
"ERROR_INVALID_DESTINATION_GAME": "Chemin invalide pour la destination du jeu",
|
||||
"WARNING_LOW_SPACE_CONTINUE": "L'espace restant sur le disque dur est faible. Continuer ?",
|
||||
"INSTALLATION_COMPLETED": "Installation Complété",
|
||||
"INSTALLATION_FINISHED_WITH_SUCCESS": "L'installation s'est terminé avec succès !",
|
||||
"OPEN_MYSTUFF_SETTINGS": "Ouvrir les paramètres MyStuff",
|
||||
"THREADS_USAGE": "Utilisation des Threads",
|
||||
"USE": "Utiliser",
|
||||
"THREADS": "threads",
|
||||
"MESSAGE_FROM_MOD_AUTHOR": "Message de l'auteur",
|
||||
"GLOBAL_MOD_SETTINGS": "Paramètre global de mod",
|
||||
"SPECIFIC_MOD_SETTINGS": "Paramètre spécifique de mod",
|
||||
"CONFIGURE_MYSTUFF_PATCH": "Configurer les patchs MyStuff",
|
||||
"DISABLED": "Désactiver",
|
||||
"ENABLED": "Activer",
|
||||
"NEW_PROFILE": "Nouveau profil",
|
||||
"DELETE_PROFILE": "Retirer un Profil",
|
||||
"ADD_MYSTUFF": "Ajouter un patch MyStuff",
|
||||
"REMOVE_MYSTUFF": "Retirer un patch MyStuff",
|
||||
"MYSTUFF_PROFILE_ALREADY_EXIST": "Ce profil MyStuff existe déjà !",
|
||||
"MYSTUFF_PROFILE_FORBIDDEN_NAME": "Ce nom de profil MyStuff ne peut pas être utilisé !",
|
||||
"SELECT_MYSTUFF": "Sélectionner un patch MyStuff",
|
||||
"TYPE_PREVIEW_WINDOW": "Type de fenêtre de prévisualisation",
|
||||
"NOT_FOUND": "introuvable",
|
||||
"TYPE_MOD_SETTINGS": "Type de paramètre de mod",
|
||||
"BMG_LAYER_MODE": "mode de couche bmg",
|
||||
"IS_NOT_IMPLEMENTED": "n'est pas implémenté",
|
||||
"IMAGE_LAYER_TYPE": "type de couche d'image",
|
||||
"OPERATION": "Opération",
|
||||
"PATH": "Chemin",
|
||||
"MODE": "Mode",
|
||||
"SOURCE": "Source",
|
||||
"OUTSIDE_ALLOWED_RANGE": "En dehors de la portée autorisée",
|
||||
"IN_PATCH": "dans le patch",
|
||||
"INSTALLING_PATCH": "Installation du patch",
|
||||
"PATCH_TITLE": "Patch",
|
||||
"PRE-PATCH_TITLE": "Pre-patch",
|
||||
"PATCHING": "Patch de",
|
||||
"FORBIDDEN_TRACK_ATTRIBUTE": "Attribut de course interdit",
|
||||
"FORBIDDEN_ARENA_ATTRIBUTE": "Attribut d'arène interdit",
|
||||
"EXTRACTING_AUTOADD_FILES": "Extraction des fichiers autoadd...",
|
||||
"EXTRACTING_ORIGINAL_TRACKS": "Extraction des courses originelles...",
|
||||
"INSTALLING_MYSTUFF": "Installation de MyStuff",
|
||||
"INSTALLING_ALL_MYSTUFF_PATCHS": "Installation de tous les patchs MyStuff",
|
||||
"PREPARING": "Preparation",
|
||||
"SPECIAL_FILE": "fichier spécial",
|
||||
"REPACKING": "Ré-archivage",
|
||||
"ALL_ARCHIVES": "toutes les archives",
|
||||
"INSTALLING_ALL": "Installation de tous",
|
||||
"CONVERTING_GAME_TO": "Conversion du jeu en",
|
||||
"DELETING_EXTRACTED_GAME": "Suppression du jeu extrait...",
|
||||
"NOT_MKW_GAME": "N'est pas un jeu Mario Kart Wii",
|
||||
"GAME_ALREADY_MODDED": "Ce jeu est déjà moddée",
|
||||
"COPYING_GAME": "Copie du jeu...",
|
||||
"EXTRACTING": "Extraction",
|
||||
"ESTIMATED_TIME_REMAINING": "temps restant estimé",
|
||||
"CHANGING_GAME_METADATA": "Changement des métadonnées du jeu...",
|
||||
"EXTRACTION": "Extraction",
|
||||
"MYSTUFF": "MyStuff",
|
||||
"PREPARING_FILES": "Preparation des fichiers",
|
||||
"PRE-PATCHING": "Pre-Patching",
|
||||
"CONVERTING_TO_GAME_FILE": "Conversion en fichier de jeu",
|
||||
"CANNOT_FIND_COLOR": "Impossible de trouver la couleur",
|
||||
"NORMALIZING_TRACKS": "Normalisation des courses",
|
||||
"INVALID_MACRO": "Macro invalide",
|
||||
"INVALID_AST_TYPE": "Type d'Ast invalide",
|
||||
"MAGIC_ATTRIBUTE_ARE_FORBIDDEN": "Les attributs magique sont interdit",
|
||||
"CANNOT_SET_ATTRIBUTE": "Impossible de changer la valeur de l'attribut",
|
||||
"CANNOT_SET_ENVIRONMENT": "Impossible de changer la valeur de l'environnement",
|
||||
"CANNOT_SET_ARGUMENT": "Impossible de changer la valeur de l'argument",
|
||||
"CALLING_FUNCTION_NOT_ALLOWED": "Appeler cette fonction n'est pas autorisé",
|
||||
"FORBIDDEN_SYNTAX": "Syntax interdite",
|
||||
"MAGIC_METHOD_FORBIDDEN": "Les méthodes magique ne sont pas autorisé",
|
||||
"CANNOT_GET_ERROR_MESSAGE": "Impossible d'obtenir le message d'erreur",
|
||||
"RAISED": "à levé",
|
||||
"CANNOT_FIND_TOOL": "Impossible de trouver l'outil",
|
||||
"IN_TOOLS_DIRECTORY": "dans le dossier des outils.",
|
||||
"CANNOT_EXTRACT_A_DIRECTORY": "Impossible d'extraire un dossier",
|
||||
"CANNOT_FIND_SLOT": "Impossible de trouver le slot",
|
||||
"FORBIDDEN_TRACKGROUP_ATTRIBUTE": "Attribut de groupe de course interdit",
|
||||
"SAFE_EVAL_ERROR": "Erreur lors d'un safe eval",
|
||||
"TEMPLATE_USED": "Modèle utilisé",
|
||||
"MORE_IN_ERROR_LOG": "Plus d'information dans le fichier error.log",
|
||||
"COPY_FUNCTION_FORBIDDEN": "Impossible de copier une fonction",
|
||||
"GET_METHOD_FORBIDDEN": "Impossible d'utiliser getattr sur une méthode",
|
||||
"CAN_ONLY_CALL_METHOD_OF_CONSTANT": "Vous ne pouvez appeler que des méthodes sur des constantes",
|
||||
"CAN_ONLY_CALL_FUNCTION_IN_ENV": "Vous ne pouvez appeler que des fonctions dans l'environnement",
|
||||
"ENABLE_DEVELOPER_MODE": "Activer le mode développeur",
|
||||
"TESTING_MOD_SETTINGS": "Paramètre de test",
|
||||
"SETTINGS_FILE": "Fichier de paramètres",
|
||||
"EXPORT_SETTINGS": "Exporter les paramètres",
|
||||
"IMPORT_SETTINGS": "Importer les paramètres",
|
||||
"PREPARING_RIIVOLUTION": "Préparation pour Riivolution",
|
||||
"CONVERTING_TO_RIIVOLUTION": "Conversion en patch Riivolution",
|
||||
"PATCHS": "patchs",
|
||||
"PRE-PATCHS": "pre-patchs",
|
||||
"CALCULATING_HASH_FOR": "Calcule du hash pour",
|
||||
"WARNING_NOT_ROOT": "Cette application nécessite les permissions root. Vous devriez lancer l'application avec 'sudo'. Continuer quand même ?",
|
||||
"WARNING_INSTALLER_PERMISSION": "Cette application nécessite les permissions d'écriture et d'exécution sur ses propres fichiers. Vous pouvez utiliser 'sudo chmod 777 -R <installer-path>' pour corriger cela. Continuer quand même ?",
|
||||
"WARNING_EMPTY_CACHE": "En vidant le cache, vous allez gagner %.2fGo, mais réinstaller un mod sera beaucoup plus long. Continuer ?",
|
||||
"EMPTY_CACHE": "Vider le cache"
|
||||
}
|
||||
"MENU_LANGUAGE_SELECTION": "Langue",
|
||||
"MENU_ADVANCED": "Avancée",
|
||||
"MENU_ADVANCED_MYSTUFF": "Paramètres MyStuff",
|
||||
"MENU_ADVANCED_THREADS": "Utilisation des threads",
|
||||
"MENU_ADVANCED_THREADS_SELECTION": "Utiliser %i threads",
|
||||
"MENU_ADVANCED_EMPTY_CACHE": "Vider le cache",
|
||||
"MENU_ADVANCED_DEVELOPER_MODE": "Activer les paramètres développeur",
|
||||
"MENU_HELP": "Aide",
|
||||
|
||||
"PART_EXTRACTION": "Extraction",
|
||||
"PART_PRE_RIIVOLUTION": "Pre-Riivolution",
|
||||
"PART_MYSTUFF": "MyStuff",
|
||||
"PART_PREPARING_FILES": "Preparation des fichiers",
|
||||
"PART_PREPATCH": "Pre-Patch",
|
||||
"PART_LECODE": "LE-CODE",
|
||||
"PART_PATCH": "Patch",
|
||||
"PART_RIIVOLUTION": "Riivolution",
|
||||
"PART_CONVERSION": "Conversion",
|
||||
|
||||
"TEXT_SOURCE_GAME": "Jeu Source",
|
||||
"TEXT_GAME_DESTINATION": "Destination du Jeu",
|
||||
"TEXT_INSTALL": "Installer",
|
||||
"TEXT_SELECT_SOURCE_GAME": "Sélectionner un jeu source",
|
||||
"TEXT_SELECT_GAME_DESTINATION": "Sélectionner la destination du jeu",
|
||||
"TEXT_WII_GAMES": "Jeux Wii",
|
||||
"TEXT_INSTALLATION_COMPLETED": "Installation Complétée",
|
||||
"TEXT_INSTALLATION_FINISHED_SUCCESSFULLY": "L'installation s'est terminée avec succès !",
|
||||
"TEXT_MESSAGE_FROM_AUTHOR": "Message de l'auteur",
|
||||
"TEXT_MOD_GLOBAL_SETTINGS": "Paramètres globaux",
|
||||
"TEXT_MOD_SPECIFIC_SETTINGS": "Paramètres spécifique",
|
||||
"TEXT_MOD_TEST_SETTINGS": "Paramètres de test",
|
||||
"TEXT_DISABLED": "Désactivé",
|
||||
"TEXT_ENABLED": "Activé",
|
||||
"TEXT_IMPORT_SETTINGS": "Importer des paramètres",
|
||||
"TEXT_EXPORT_SETTINGS": "Exporter des paramètres",
|
||||
"TEXT_SETTINGS_FILE": "Fichier paramètres",
|
||||
"TEXT_NEW_PROFILE": "Nouveau profil",
|
||||
"TEXT_DELETE_PROFILE": "Supprimer le profil",
|
||||
"TEXT_ADD_MYSTUFF": "Ajouter MyStuff",
|
||||
"TEXT_REMOVE_MYSTUFF": "Retirer MyStuff",
|
||||
"TEXT_SELECT_MYSTUFF": "Sélectionner un MyStuff",
|
||||
"TEXT_COPYING_GAME": "Copie du jeu",
|
||||
"TEXT_EXTRACTING_GAME": "Extraction du jeu - %i%% (temps restant estimé : %s)",
|
||||
"TEXT_CHANGING_GAME_METADATA": "Changement des métadonnées du jeu",
|
||||
"TEXT_EXTRACTING_AUTOADD": "Extraction des fichiers autoadd",
|
||||
"TEXT_EXTRACTING_ORIGINAL_TRACKS": "Extraction des courses originales \"%s\"",
|
||||
"TEXT_INSTALLING_MYSTUFF": "Installation des MyStuff \"%s\"",
|
||||
"TEXT_PREPARING_SPECIAL_FILE": "Preparion du fichier spécial \"%s\"",
|
||||
"TEXT_PREPARING_MAIN_DOL": "Preparation de main.dol",
|
||||
"TEXT_REPACKING_ARCHIVE": "Archivage de \"%s\"",
|
||||
"TEXT_PATCHING_LECODE": "Patch de LECODE.bin",
|
||||
"TEXT_CONVERT_GAME_TO": "Conversion du jeu en %s",
|
||||
"TEXT_DELETING_EXTRACTED_GAME": "Suppression du jeu extrait",
|
||||
"TEXT_CONVERTING_TO_RIIVOLUTION": "Conversion en Riivolution",
|
||||
"TEXT_CALCULATING_HASH": "Calcul du hash pour \"%s\"",
|
||||
"TEXT_NORMALIZING_TRACKS": "Normalisation des courses :\n%s",
|
||||
"TEXT_PATCHING": "Patch de \"%s\"",
|
||||
|
||||
"WARNING": "Attention",
|
||||
"WARNING_EMPTY_CACHE": "En vidant le cache, vous allez gagner %.2fGB, mais reinstaller un mod prendra beaucoup plus de temps. Continuer ?",
|
||||
"WARNING_DESTINATION_NOT_WRITABLE": "Le dossier de destination du jeu ne peut pas être modifié. Continuer quand même ?",
|
||||
"WARNING_LOW_SPACE_CONTINUE": "Espace faible sur le disque %s (%.2fGB). Continuer quand même ?",
|
||||
"WARNING_NOT_ROOT": "Permissions administrateur requise. Vous devriez lancer l'application avec 'sudo'. Continuer quand même ?",
|
||||
"WARNING_INSTALLER_PERMISSION": "Les permissions d'écriture et d'exécution sont requise. Vous pouvez utiliser 'sudo chmod 777 -R <chemin-de-l-installer>' pour corriger cela. Continuer quand même ?",
|
||||
|
||||
"ERROR": "Erreur",
|
||||
"ERROR_SEE_LOGS": "Voir le fichier error.log pour plus d'information",
|
||||
"ERROR_INVALID_SOURCE_GAME": "Jeu source invalide : \"%s\"",
|
||||
"ERROR_INVALID_GAME_DESTINATION": "Destination de jeu invalide : \"%s\"",
|
||||
"ERROR_MYSTUFF_PROFILE_ALREADY_EXIST": "Le profil MyStuff \"%s\" existe déjà !",
|
||||
"ERROR_MYSTUFF_PROFILE_FORBIDDEN_NAME": "Le nom de profil MyStuff \"%s\" est interdit !",
|
||||
"ERROR_NOT_MKW_GAME": "Ce jeu n'est pas un jeu Mario Kart Wii : \"%s\"",
|
||||
"ERROR_GAME_ALREADY_MODDED": "Ce jeu est déjà moddé : \"%s\"",
|
||||
"ERROR_PATH_OUTSIDE_RANGE": "Le chemin \"%s\" est en dehors de la portée autorisée : \"%s\"",
|
||||
"ERROR_PREVIEW_WINDOW_NOT_FOUND": "Type de fenêtre de prévisualisation \"%s\" introuvable",
|
||||
"ERROR_CANNOT_FIND_COLOR": "Impossible de trouver la couleur : \"%s\"",
|
||||
"ERROR_CANNOT_FIND_SLOT": "Impossible de trouver le slot : \"%s\"",
|
||||
"ERROR_MOD_SETTINGS_NOT_FOUND": "Type de paramètre de mod \"%s\" introuvable",
|
||||
"ERROR_FORBIDDEN_TRACK_ATTRIBUTE": "Attribut de course interdit : \"%s\"",
|
||||
"ERROR_FORBIDDEN_ARENA_ATTRIBUTE": "Attribut d'arène interdit : \"%s\"",
|
||||
"ERROR_FORBIDDEN_TRACKGROUP_ATTRIBUTE": "Attribut de groupe de course interdit : \"%s\"",
|
||||
"ERROR_SAFEEVAL": "Erreur de safe eval (modèle utilisé : \"%s\")",
|
||||
"ERROR_INVALID_MACRO": "Macro invalide : \"%s\"",
|
||||
"ERROR_INVALID_AST_TYPE": "Type d'AST invalide : \"%s\"",
|
||||
"ERROR_FORBIDDEN_MAGIC_ATTRIBUTE": "Les attributs magiques sont interdit : \"%s\"",
|
||||
"ERROR_FORBIDDEN_MAGIC_METHOD": "Les méthodes magiques sont interdites : \"%s\"",
|
||||
"ERROR_GETTING_METHOD_FORBIDDEN": "Récupérer une méthode est interdit : \"%s\"",
|
||||
"ERROR_CANNOT_SET_ATTRIBUTE": "Changer un attribut est interdit : \"%s\"",
|
||||
"ERROR_CANNOT_SET_ENVIRONMENT": "Changer une variable d'environnement est interdit : \"%s\"",
|
||||
"ERROR_CANNOT_SET_ARGUMENT": "Changer une variable d'argument est interdit : \"%s\"",
|
||||
"ERROR_CAN_ONLY_CALL_CONSTANT_METHOD": "Seulement appeler la méthode d'une constante est autorisé",
|
||||
"ERROR_CAN_ONLY_CALL_ENV_FUNCTION": "Seulement appeler une fonction de l'environnement est autorisé",
|
||||
"ERROR_FORBIDDEN_SYNTAX": "Syntaxe interdite : \"%s\"",
|
||||
"ERROR_FUNCTION_COPY_FORBIDDEN": "Copier une fonction est interdit",
|
||||
"ERROR_CANNOT_GET_ERROR_MESSAGE": "Impossible de récupérer le message d'erreur",
|
||||
"ERROR_WT": "%s à généré l'erreur %i :\n%s",
|
||||
"ERROR_CANNOT_FIND_TOOL": "Impossible de trouver l'outil \"%s\" dans le dossier tools",
|
||||
"ERROR_CANNOT_EXTRACT_DIRECTORY": "Un dossier ne peut pas être extrait",
|
||||
"ERROR_PATCH_MODE_NOT_IMPLEMENTED": "Le mode de Patch \"%s\" n'est pas implémenté (du patch : \"%s\")",
|
||||
"ERROR_SOURCE_NOT_IMPLEMENTED": "La source \"%s\" n'est pas implémenté (du patch : \"%s\")",
|
||||
"ERROR_OPERATION_NOT_IMPLEMENTED": "L'opération \"%s\" n'est pas implémenté",
|
||||
"ERROR_BMG_LAYER_MODE_NOT_IMPLEMENTED": "Le mode de couche bmg \"%s\" n'est pas implémenté",
|
||||
"ERROR_IMAGE_LAYER_TYPE_NOT_IMPLEMENTED": "Le type de couche d'image \"%s\" n'est pas implémenté"
|
||||
}
|
||||
}
|
|
@ -29,8 +29,8 @@ def better_gui_error(func: Callable) -> Callable:
|
|||
exc_split = exc.splitlines()
|
||||
if len(exc_split) > 10:
|
||||
# if the traceback is too long, only keep the 5 first and 5 last lines of the traceback
|
||||
exc_split = exc_split[:5] + ["..."] + exc_split[-5:] + ["", "", _("MORE_IN_ERROR_LOG")]
|
||||
exc_split = exc_split[:5] + ["..."] + exc_split[-5:] + ["", "", _("ERROR_SEE_LOGS")]
|
||||
|
||||
messagebox.showerror(_("Error"), "\n".join(exc_split))
|
||||
messagebox.showerror(_("ERROR"), "\n".join(exc_split))
|
||||
|
||||
return wrapper
|
||||
|
|
|
@ -23,16 +23,6 @@ import os
|
|||
from source.mkw.collection.Extension import Extension
|
||||
|
||||
|
||||
class SourceGameError(Exception):
|
||||
def __init__(self, path: Path | str):
|
||||
super().__init__(_(f"ERROR_INVALID_SOURCE_GAME", " : ", path))
|
||||
|
||||
|
||||
class DestinationGameError(Exception):
|
||||
def __init__(self, path: Path | str):
|
||||
super().__init__(_("ERROR_INVALID_DESTINATION_GAME", " : ", path))
|
||||
|
||||
|
||||
class InstallerState(enum.Enum):
|
||||
IDLE = 0
|
||||
INSTALLING = 1
|
||||
|
@ -50,7 +40,7 @@ class Window(tkinter.Tk):
|
|||
self.source_path = tkinter.StringVar()
|
||||
self.destination_path = tkinter.StringVar()
|
||||
|
||||
self.title(_("INSTALLER_TITLE"))
|
||||
self.title(_("TITLE_INSTALL"))
|
||||
self.resizable(False, False)
|
||||
|
||||
self.icon = tkinter.PhotoImage(file="./assets/icon.png")
|
||||
|
@ -136,7 +126,7 @@ class Menu(tkinter.Menu):
|
|||
super().__init__(master, tearoff=False)
|
||||
self.root = master.root
|
||||
|
||||
master.add_cascade(label=_("LANGUAGE_SELECTION"), menu=self)
|
||||
master.add_cascade(label=_("MENU_LANGUAGE_SELECTION"), menu=self)
|
||||
|
||||
self.lang_variable = tkinter.StringVar(value=self.root.options.language.get())
|
||||
|
||||
|
@ -155,19 +145,19 @@ class Menu(tkinter.Menu):
|
|||
super().__init__(master, tearoff=False)
|
||||
self.root = master.root
|
||||
|
||||
master.add_cascade(label=_("ADVANCED_CONFIGURATION"), menu=self)
|
||||
master.add_cascade(label=_("MENU_ADVANCED"), menu=self)
|
||||
self.add_command(
|
||||
label=_("OPEN_MYSTUFF_SETTINGS"),
|
||||
label=_("MENU_ADVANCED_MYSTUFF"),
|
||||
command=lambda: mystuff.Window(self.root.mod_config, self.root.options)
|
||||
)
|
||||
self.threads_used = self.ThreadsUsed(self)
|
||||
self.add_command(label=_("EMPTY_CACHE"), command=self.empty_cache)
|
||||
self.add_command(label=_("MENU_ADVANCED_EMPTY_CACHE"), command=self.empty_cache)
|
||||
|
||||
self.add_separator()
|
||||
|
||||
self.variable_developer_mode = tkinter.BooleanVar(value=self.root.options.developer_mode.get())
|
||||
self.add_checkbutton(
|
||||
label=_("ENABLE_DEVELOPER_MODE"),
|
||||
label=_("MENU_ADVANCED_DEVELOPER_MODE"),
|
||||
variable=self.variable_developer_mode,
|
||||
command=lambda: self.root.options.developer_mode.set(self.variable_developer_mode.get())
|
||||
)
|
||||
|
@ -184,14 +174,14 @@ class Menu(tkinter.Menu):
|
|||
def __init__(self, master: tkinter.Menu):
|
||||
super().__init__(master, tearoff=False)
|
||||
self.root = master.root
|
||||
|
||||
master.add_cascade(label=_("THREADS_USAGE"), menu=self)
|
||||
|
||||
master.add_cascade(label=_("MENU_ADVANCED_THREADS"), menu=self)
|
||||
|
||||
self.variable = tkinter.IntVar(value=self.root.options.threads.get())
|
||||
|
||||
for i in [1, 2, 4, 8, 12, 16]:
|
||||
self.add_radiobutton(
|
||||
label=_("USE", f" {i} ", "THREADS"),
|
||||
label=_("MENU_ADVANCED_THREADS_SELECTION") % i,
|
||||
value=i,
|
||||
variable=self.variable,
|
||||
command=(lambda amount: (lambda: self.root.options.threads.set(amount)))(i),
|
||||
|
@ -203,12 +193,12 @@ class Menu(tkinter.Menu):
|
|||
super().__init__(master, tearoff=False)
|
||||
self.root = master.root
|
||||
|
||||
master.add_cascade(label=_("HELP"), menu=self)
|
||||
master.add_cascade(label=_("MENU_HELP"), menu=self)
|
||||
self.menu_id = self.master.index(tkinter.END)
|
||||
|
||||
self.add_command(label=_("DISCORD"), command=lambda: webbrowser.open(discord_url))
|
||||
self.add_command(label=_("GITHUB WIKI"), command=lambda: webbrowser.open(github_wiki_url))
|
||||
self.add_command(label=_("READTHEDOCS"), command=lambda: webbrowser.open(readthedocs_url))
|
||||
self.add_command(label="Discord", command=lambda: webbrowser.open(discord_url))
|
||||
self.add_command(label="GitHub", command=lambda: webbrowser.open(github_wiki_url))
|
||||
self.add_command(label="ReadTheDocs", command=lambda: webbrowser.open(readthedocs_url))
|
||||
|
||||
def set_installation_state(self, state: InstallerState) -> bool:
|
||||
"""
|
||||
|
@ -237,7 +227,7 @@ class Menu(tkinter.Menu):
|
|||
# Select game frame
|
||||
class SourceGame(ttk.LabelFrame):
|
||||
def __init__(self, master: tkinter.Tk):
|
||||
super().__init__(master, text=_("ORIGINAL_GAME_FILE"))
|
||||
super().__init__(master, text=_("TEXT_SOURCE_GAME"))
|
||||
self.root = master.root
|
||||
|
||||
self.columnconfigure(1, weight=1)
|
||||
|
@ -254,8 +244,8 @@ class SourceGame(ttk.LabelFrame):
|
|||
:return:
|
||||
"""
|
||||
raw_path = tkinter.filedialog.askopenfilename(
|
||||
title=_("SELECT_SOURCE_GAME"),
|
||||
filetypes=[(_("WII GAMES"), "*.iso *.ciso *.wbfs *.dol")],
|
||||
title=_("TEXT_SELECT_SOURCE_GAME"),
|
||||
filetypes=[(_("TEXT_WII_GAMES"), "*.iso *.ciso *.wbfs *.dol")],
|
||||
)
|
||||
|
||||
# if the user didn't select any file, return None
|
||||
|
@ -298,7 +288,7 @@ class SourceGame(ttk.LabelFrame):
|
|||
# Select game destination frame
|
||||
class DestinationGame(ttk.LabelFrame):
|
||||
def __init__(self, master: tkinter.Tk):
|
||||
super().__init__(master, text=_("GAME_DIRECTORY_DESTINATION"))
|
||||
super().__init__(master, text=_("TEXT_GAME_DESTINATION"))
|
||||
self.root = master.root
|
||||
|
||||
self.columnconfigure(1, weight=1)
|
||||
|
@ -320,7 +310,7 @@ class DestinationGame(ttk.LabelFrame):
|
|||
:return:
|
||||
"""
|
||||
raw_path = tkinter.filedialog.askdirectory(
|
||||
title=_("SELECT_DESTINATION_GAME"),
|
||||
title=_("TEXT_SELECT_GAME_DESTINATION"),
|
||||
)
|
||||
|
||||
# if the user didn't select any directory, return None
|
||||
|
@ -333,7 +323,7 @@ class DestinationGame(ttk.LabelFrame):
|
|||
|
||||
def set_path(self, path: Path):
|
||||
if not os.access(path, os.W_OK):
|
||||
messagebox.showwarning(_("WARNING"), _("WARNING_DESTINATION_GAME_NOT_WRITABLE"))
|
||||
messagebox.showwarning(_("WARNING"), _("WARNING_DESTINATION_NOT_WRITABLE"))
|
||||
|
||||
self.entry.delete(0, tkinter.END)
|
||||
self.entry.insert(0, str(path.absolute()))
|
||||
|
@ -355,7 +345,7 @@ class DestinationGame(ttk.LabelFrame):
|
|||
# Install button
|
||||
class ButtonInstall(ttk.Button):
|
||||
def __init__(self, master: tkinter.Tk):
|
||||
super().__init__(master, text=_("INSTALL"), command=self.install)
|
||||
super().__init__(master, text=_("TEXT_INSTALL"), command=self.install)
|
||||
self.root = master.root
|
||||
|
||||
@threaded
|
||||
|
@ -364,29 +354,35 @@ class ButtonInstall(ttk.Button):
|
|||
try:
|
||||
self.root.set_state(InstallerState.INSTALLING)
|
||||
|
||||
# check if the user entered a source path
|
||||
# check if the user entered a source path. If the string is ".", then the user didn't input any path
|
||||
source_path = Path(self.root.source_path.get())
|
||||
if not source_path.exists(): raise SourceGameError(source_path)
|
||||
if str(source_path) == ".":
|
||||
messagebox.showerror(_("ERROR"), _("ERROR_INVALID_SOURCE_GAME"))
|
||||
if not source_path.exists() or str(source_path) == ".":
|
||||
messagebox.showerror(_("ERROR"), _("ERROR_INVALID_SOURCE_GAME") % source_path)
|
||||
return
|
||||
|
||||
# check if the user entered a destination path
|
||||
# check if the user entered a destination path. If the string is ".", then the user didn't input any path
|
||||
destination_path = Path(self.root.destination_path.get())
|
||||
if not destination_path.exists(): raise DestinationGameError(destination_path)
|
||||
if str(destination_path) == ".":
|
||||
messagebox.showerror(_("ERROR"), _("ERROR_INVALID_DESTINATION_GAME"))
|
||||
if not destination_path.exists() or str(destination_path) == ".":
|
||||
messagebox.showerror(_("ERROR"), _("ERROR_INVALID_GAME_DESTINATION") % source_path)
|
||||
return
|
||||
|
||||
available_space_local = shutil.disk_usage(".").free
|
||||
available_space_destination = shutil.disk_usage(destination_path).free
|
||||
|
||||
# if there is no more space on the installer drive, show a warning
|
||||
if shutil.disk_usage(".").free < minimum_space_available:
|
||||
if not messagebox.askokcancel(_("WARNING"), _("WARNING_LOW_SPACE_CONTINUE")):
|
||||
if available_space_local < minimum_space_available:
|
||||
if not messagebox.askokcancel(
|
||||
_("WARNING"),
|
||||
_("WARNING_LOW_SPACE_CONTINUE") % (Path(".").resolve().drive, available_space_local/Go)
|
||||
):
|
||||
return
|
||||
|
||||
# if there is no more space on the destination drive, show a warning
|
||||
elif shutil.disk_usage(destination_path).free < minimum_space_available:
|
||||
if not messagebox.askokcancel(_("WARNING"), _("WARNING_LOW_SPACE_CONTINUE")):
|
||||
return
|
||||
elif available_space_destination < minimum_space_available:
|
||||
if not messagebox.askokcancel(
|
||||
_("WARNING"),
|
||||
_("WARNING_LOW_SPACE_CONTINUE") % (destination_path.resolve().drive, available_space_destination/Go)
|
||||
): return
|
||||
|
||||
if system == "lin64": # if linux
|
||||
if os.getuid() != 0: # if the user is not root
|
||||
|
@ -417,9 +413,9 @@ class ButtonInstall(ttk.Button):
|
|||
)
|
||||
|
||||
messagebox.showinfo(
|
||||
_("INSTALLATION_COMPLETED"),
|
||||
f"{_('INSTALLATION_FINISHED_WITH_SUCCESS')}" + (
|
||||
f"\n{_('MESSAGE_FROM_MOD_AUTHOR')} :\n\n{message}" if message != "" else ""
|
||||
_("TEXT_INSTALLATION_COMPLETED"),
|
||||
f"{_('TEXT_INSTALLATION_FINISHED_SUCCESSFULLY')}" + (
|
||||
f"\n{_('TEXT_MESSAGE_FROM_AUTHOR')} :\n\n{message}" if message != "" else ""
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ class Window(tkinter.Toplevel):
|
|||
self.resizable(False, False)
|
||||
self.grab_set()
|
||||
|
||||
self.title(_("TITLE_MOD_SETTINGS"))
|
||||
self.rowconfigure(1, weight=1)
|
||||
self.columnconfigure(1, weight=1)
|
||||
|
||||
|
@ -32,19 +33,19 @@ class Window(tkinter.Toplevel):
|
|||
|
||||
self.frame_global_settings = FrameSettings(
|
||||
self.panel_window,
|
||||
_("GLOBAL_MOD_SETTINGS"),
|
||||
_("TEXT_MOD_GLOBAL_SETTINGS"),
|
||||
self.mod_config.global_settings
|
||||
)
|
||||
self.frame_specific_settings = FrameSettings(
|
||||
self.panel_window,
|
||||
_("SPECIFIC_MOD_SETTINGS"),
|
||||
_("TEXT_MOD_SPECIFIC_SETTINGS"),
|
||||
self.mod_config.specific_settings
|
||||
)
|
||||
|
||||
if self.options.developer_mode.get():
|
||||
self.frame_testing_settings = FrameTesting(
|
||||
self.panel_window,
|
||||
_("TESTING_MOD_SETTINGS")
|
||||
_("TEXT_MOD_TEST_SETTINGS")
|
||||
)
|
||||
|
||||
self.frame_action = FrameAction(self)
|
||||
|
@ -143,10 +144,10 @@ class FrameAction(ttk.Frame):
|
|||
super().__init__(master)
|
||||
self.root = master.root
|
||||
|
||||
self.button_import_settings = ttk.Button(self, text=_("IMPORT_SETTINGS"), width=20,
|
||||
self.button_import_settings = ttk.Button(self, text=_("TEXT_IMPORT_SETTINGS"), width=20,
|
||||
command=self.import_settings)
|
||||
self.button_import_settings.grid(row=1, column=1)
|
||||
self.button_export_settings = ttk.Button(self, text=_("EXPORT_SETTINGS"), width=20,
|
||||
self.button_export_settings = ttk.Button(self, text=_("TEXT_EXPORT_SETTINGS"), width=20,
|
||||
command=self.export_settings)
|
||||
self.button_export_settings.grid(row=1, column=2)
|
||||
|
||||
|
@ -156,8 +157,8 @@ class FrameAction(ttk.Frame):
|
|||
"""
|
||||
|
||||
path = filedialog.askopenfilename(
|
||||
title=_("IMPORT_SETTINGS"),
|
||||
filetypes=[(_("SETTINGS_FILE"), f"*{SETTINGS_FILE_EXTENSION}")]
|
||||
title=_("TEXT_IMPORT_SETTINGS"),
|
||||
filetypes=[(_("TEXT_SETTINGS_FILE"), f"*{SETTINGS_FILE_EXTENSION}")]
|
||||
)
|
||||
|
||||
# si le fichier n'a pas été choisi, ignore
|
||||
|
@ -178,8 +179,8 @@ class FrameAction(ttk.Frame):
|
|||
"""
|
||||
|
||||
path = filedialog.asksaveasfilename(
|
||||
title=_("EXPORT_SETTINGS"),
|
||||
filetypes=[(_("SETTINGS_FILE"), f"*{SETTINGS_FILE_EXTENSION}")]
|
||||
title=_("TEXT_EXPORT_SETTINGS"),
|
||||
filetypes=[(_("TEXT_SETTINGS_FILE"), f"*{SETTINGS_FILE_EXTENSION}")]
|
||||
)
|
||||
|
||||
# si le fichier n'a pas été choisi, ignore
|
||||
|
|
|
@ -24,11 +24,11 @@ class Window(tkinter.Toplevel):
|
|||
self.mod_config = mod_config
|
||||
self.options = options
|
||||
|
||||
self.title(_("CONFIGURE_MYSTUFF_PATCH"))
|
||||
self.title(_("TITLE_MYSTUFF_SETTINGS"))
|
||||
self.resizable(False, False)
|
||||
self.grab_set() # the others window will be disabled, keeping only this one activated
|
||||
|
||||
self.disabled_text: str = _("<", "DISABLED", ">")
|
||||
self.disabled_text: str = f"<{_('TEXT_DISABLED')}>"
|
||||
|
||||
self.frame_profile = ttk.Frame(self)
|
||||
self.frame_profile.grid(row=1, column=1, sticky="NEWS")
|
||||
|
@ -40,14 +40,14 @@ class Window(tkinter.Toplevel):
|
|||
|
||||
self.button_new_profile = ttk.Button(
|
||||
self.frame_profile,
|
||||
text=_("NEW_PROFILE"),
|
||||
text=_("TEXT_NEW_PROFILE"),
|
||||
command=self.new_profile
|
||||
)
|
||||
self.button_new_profile.grid(row=1, column=2, sticky="NEWS")
|
||||
|
||||
self.button_delete_profile = ttk.Button(
|
||||
self.frame_profile,
|
||||
text=_("DELETE_PROFILE"),
|
||||
text=_("TEXT_DELETE_PROFILE"),
|
||||
command=self.delete_profile
|
||||
)
|
||||
self.button_delete_profile.grid(row=1, column=3, sticky="NEWS")
|
||||
|
@ -76,14 +76,14 @@ class Window(tkinter.Toplevel):
|
|||
|
||||
self.button_add_mystuff_path = ttk.Button(
|
||||
self.frame_mystuff_paths_action,
|
||||
text=_("ADD_MYSTUFF"),
|
||||
text=_("TEXT_ADD_MYSTUFF"),
|
||||
command=self.add_mystuff_path
|
||||
)
|
||||
self.button_add_mystuff_path.grid(row=1, column=1)
|
||||
|
||||
self.button_remove_mystuff_path = ttk.Button(
|
||||
self.frame_mystuff_paths_action,
|
||||
text=_("REMOVE_MYSTUFF"),
|
||||
text=_("TEXT_REMOVE_MYSTUFF"),
|
||||
command=self.remove_mystuff_path
|
||||
)
|
||||
self.button_remove_mystuff_path.grid(row=1, column=2)
|
||||
|
@ -138,12 +138,12 @@ class Window(tkinter.Toplevel):
|
|||
|
||||
profile_name: str = self.combobox_profile.get()
|
||||
if profile_name in mystuff_packs:
|
||||
messagebox.showerror(_("ERROR"), _("MYSTUFF_PROFILE_ALREADY_EXIST"))
|
||||
messagebox.showerror(_("ERROR"), _("ERROR_MYSTUFF_PROFILE_ALREADY_EXIST") % profile_name)
|
||||
return
|
||||
|
||||
for banned_char in "<>":
|
||||
if banned_char in profile_name:
|
||||
messagebox.showerror(_("ERROR"), _("MYSTUFF_PROFILE_FORBIDDEN_NAME"))
|
||||
messagebox.showerror(_("ERROR"), _("ERROR_MYSTUFF_PROFILE_FORBIDDEN_NAME") % profile_name)
|
||||
return
|
||||
|
||||
mystuff_packs[profile_name] = {"paths": []}
|
||||
|
@ -167,7 +167,7 @@ class Window(tkinter.Toplevel):
|
|||
Add a new path to the currently selected MyStuff profile
|
||||
"""
|
||||
|
||||
if (mystuff_path := filedialog.askdirectory(title=_("SELECT_MYSTUFF"), mustexist=True)) is None: return
|
||||
if (mystuff_path := filedialog.askdirectory(title=_("TEXT_SELECT_MYSTUFF"), mustexist=True)) == "": return
|
||||
mystuff_path = Path(mystuff_path)
|
||||
|
||||
mystuff_packs = self.root.options.mystuff_packs.get()
|
||||
|
|
|
@ -9,7 +9,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class InvalidPreviewWindowName(Exception):
|
||||
def __init__(self, name: str):
|
||||
super().__init__(_("TYPE_PREVIEW_WINDOW", " '", name, "' ", "NOT_FOUND"))
|
||||
super().__init__(_("ERROR_PREVIEW_WINDOW_NOT_FOUND") % name)
|
||||
|
||||
|
||||
class AbstractPreviewWindow(tkinter.Toplevel, ABC):
|
||||
|
|
|
@ -5,6 +5,7 @@ from pathlib import Path
|
|||
from typing import Generator, IO, TYPE_CHECKING
|
||||
|
||||
from source import file_block_size
|
||||
from source.mkw import PathOutsideAllowedRange
|
||||
from source.mkw.ModConfig import ModConfig
|
||||
from source.mkw.Patch.Patch import Patch
|
||||
from source.mkw.collection.Extension import Extension
|
||||
|
@ -21,11 +22,6 @@ if TYPE_CHECKING:
|
|||
RIIVOLUTION_FOLDER_NAME: str = "riivolution"
|
||||
|
||||
|
||||
class PathOutsideMod(Exception):
|
||||
def __init__(self, forbidden_path: Path, allowed_range: Path):
|
||||
super().__init__(_("PATH", ' "', forbidden_path, '" ', "OUTSIDE_ALLOWED_RANGE", ' "', allowed_range, '" '))
|
||||
|
||||
|
||||
class ExtractedGame:
|
||||
"""
|
||||
Class that represents an extracted game
|
||||
|
@ -41,7 +37,7 @@ class ExtractedGame:
|
|||
Extract all the autoadd files from the game to destination_path
|
||||
:param destination_path: directory where the autoadd files will be extracted
|
||||
"""
|
||||
yield Progress(description=_("EXTRACTING_AUTOADD_FILES"), determinate=False)
|
||||
yield Progress(description=_("TEXT_EXTRACTING_AUTOADD"), determinate=False)
|
||||
szs.autoadd(self.path / "files/Race/Course/", destination_path)
|
||||
|
||||
def extract_original_tracks(self, destination_path: "Path | str") -> Generator[Progress, None, None]:
|
||||
|
@ -54,14 +50,13 @@ class ExtractedGame:
|
|||
|
||||
original_tracks: list[Path] = list((self.path / "files/Race/Course/").glob("*.szs"))
|
||||
yield Progress(
|
||||
description=_("EXTRACTING_ORIGINAL_TRACKS"),
|
||||
determinate=True,
|
||||
max_step=len(original_tracks),
|
||||
set_step=0,
|
||||
)
|
||||
|
||||
for track_file in original_tracks:
|
||||
yield Progress(description=_("EXTRACTING_ORIGINAL_TRACKS", " (", track_file.name, ") ..."), step=1)
|
||||
yield Progress(description=_("TEXT_EXTRACTING_ORIGINAL_TRACKS") % track_file.name, step=1)
|
||||
|
||||
if not (destination_path / track_file.name).exists(): track_file.rename(destination_path / track_file.name)
|
||||
else: track_file.unlink()
|
||||
|
@ -73,7 +68,7 @@ class ExtractedGame:
|
|||
:mystuff_path: path to the MyStuff directory
|
||||
:return:
|
||||
"""
|
||||
yield Progress(description=_("INSTALLING_MYSTUFF", ' "', mystuff_path, '" ...'))
|
||||
yield Progress(description=_("TEXT_INSTALLING_MYSTUFF") % mystuff_path)
|
||||
mystuff_path = Path(mystuff_path)
|
||||
|
||||
mystuff_rootfiles: dict[str, Path] = {}
|
||||
|
@ -90,12 +85,7 @@ class ExtractedGame:
|
|||
Install multiple mystuff patch
|
||||
:param mystuff_paths: paths to all the mystuff patch
|
||||
"""
|
||||
yield Progress(
|
||||
description=_("INSTALLING_ALL_MYSTUFF_PATCHS"),
|
||||
determinate=True,
|
||||
max_step=len(mystuff_paths),
|
||||
set_step=0
|
||||
)
|
||||
yield Progress(determinate=True, max_step=len(mystuff_paths), set_step=0)
|
||||
|
||||
for mystuff_path in mystuff_paths:
|
||||
yield Progress(step=1)
|
||||
|
@ -106,7 +96,7 @@ class ExtractedGame:
|
|||
Prepare special files for the patch
|
||||
:return: the special files dict
|
||||
"""
|
||||
yield Progress(description=_("PREPARING", " ct_icons ", "SPECIAL_FILE", "..."), determinate=False)
|
||||
yield Progress(description=_("TEXT_PREPARING_SPECIAL_FILE") % "ct_icons", determinate=False)
|
||||
ct_icons = BytesIO()
|
||||
mod_config.get_full_cticon().save(ct_icons, format="PNG")
|
||||
ct_icons.seek(0)
|
||||
|
@ -116,7 +106,7 @@ class ExtractedGame:
|
|||
"""
|
||||
Prepare main.dol and StaticR.rel files (clean them and add lecode)
|
||||
"""
|
||||
yield Progress(description="Preparing main.dol...", determinate=False)
|
||||
yield Progress(description=_("TEXT_PREPARING_MAIN_DOL"), determinate=False)
|
||||
StrPath(self.path / "sys/main.dol").patch(clean_dol=True, add_lecode=True)
|
||||
|
||||
def recreate_all_szs(self) -> Generator[Progress, None, None]:
|
||||
|
@ -125,7 +115,6 @@ class ExtractedGame:
|
|||
"""
|
||||
all_extracted_szs: list[Path] = list(filter(lambda path: path.is_dir(), self.path.rglob("*.d")))
|
||||
yield Progress(
|
||||
description=_("REPACKING", " ", "ALL_ARCHIVES"),
|
||||
determinate=True,
|
||||
max_step=len(all_extracted_szs),
|
||||
set_step=0,
|
||||
|
@ -134,7 +123,7 @@ class ExtractedGame:
|
|||
for extracted_szs in all_extracted_szs:
|
||||
# for every directory that end with a .d in the extracted game, recreate the szs
|
||||
yield Progress(
|
||||
description=_("REPACKING", ' "', extracted_szs.relative_to(self.path), '"'),
|
||||
description=_("TEXT_REPACKING_ARCHIVE") % extracted_szs.relative_to(self.path),
|
||||
step=1
|
||||
)
|
||||
|
||||
|
@ -150,7 +139,7 @@ class ExtractedGame:
|
|||
:param cache_directory: Path to the cache
|
||||
:param mod_config: mod configuration
|
||||
"""
|
||||
yield Progress(description=_("PATCHING", " LECODE.bin"))
|
||||
yield Progress(description=_("TEXT_PATCHING_LECODE"))
|
||||
cache_directory = Path(cache_directory)
|
||||
cttracks_directory = Path(cttracks_directory)
|
||||
ogtracks_directory = Path(ogtracks_directory)
|
||||
|
@ -161,7 +150,7 @@ class ExtractedGame:
|
|||
|
||||
lpar_dir: Path = mod_config.path.parent / "_LPAR/"
|
||||
lpar: Path = lpar_dir / mod_config.multiple_safe_eval(mod_config.lpar_template)()
|
||||
if not lpar.is_relative_to(lpar_dir): raise PathOutsideMod(lpar, lpar_dir)
|
||||
if not lpar.is_relative_to(lpar_dir): raise PathOutsideAllowedRange(lpar, lpar_dir)
|
||||
|
||||
for lecode_file in (self.path / "files/rel/").glob("lecode-*.bin"):
|
||||
lec.patch(
|
||||
|
@ -178,12 +167,16 @@ class ExtractedGame:
|
|||
for all the subdirectory named by the patch_directory_name, apply the patch
|
||||
:param mod_config: the mod to install
|
||||
"""
|
||||
# yield an empty dict so that if nothing is yielded by the Patch, still is considered a generator
|
||||
yield Progress()
|
||||
|
||||
patch_directories: list[Path] = []
|
||||
for part_directory in mod_config.get_mod_directory().glob("[!_]*"):
|
||||
for patch_directory in part_directory.glob(patch_directory_name):
|
||||
yield from Patch(patch_directory, mod_config, self._special_file).install(self)
|
||||
patch_directories.append(patch_directory)
|
||||
|
||||
yield Progress(determinate=True, max_step=len(patch_directories)+1, set_step=0)
|
||||
|
||||
for patch_directory in patch_directories:
|
||||
yield Progress(step=1)
|
||||
yield from Patch(patch_directory, mod_config, self._special_file).install(self)
|
||||
|
||||
def install_all_prepatch(self, mod_config: ModConfig) -> Generator[Progress, None, None]:
|
||||
"""
|
||||
|
@ -191,7 +184,6 @@ class ExtractedGame:
|
|||
Used before the lecode patch is applied
|
||||
:param mod_config: the mod to install
|
||||
"""
|
||||
yield Progress(description=_("INSTALLING_ALL", " ", "PRE-PATCHS", "..."), determinate=False)
|
||||
yield from self._install_all_patch(mod_config, "_PREPATCH/")
|
||||
|
||||
def install_all_patch(self, mod_config: ModConfig) -> Generator[Progress, None, None]:
|
||||
|
@ -200,7 +192,6 @@ class ExtractedGame:
|
|||
Used after the lecode patch is applied
|
||||
:param mod_config: the mod to install
|
||||
"""
|
||||
yield Progress(description=_("INSTALLING_ALL", " ", "PATCHS", "..."), determinate=False)
|
||||
yield from self._install_all_patch(mod_config, "_PATCH/")
|
||||
|
||||
def convert_to(self, output_type: Extension) -> Generator[Progress, None, wit.WITPath | None]:
|
||||
|
@ -209,7 +200,7 @@ class ExtractedGame:
|
|||
:param output_type: path to the destination of the game
|
||||
:output_type: format of the destination game
|
||||
"""
|
||||
yield Progress(description=_("CONVERTING_GAME_TO", " ", output_type.name), determinate=False)
|
||||
yield Progress(description=_("TEXT_CONVERT_GAME_TO") % output_type.name, determinate=False)
|
||||
if output_type == Extension.FST: return
|
||||
|
||||
destination_file = self.path.with_suffix(self.path.suffix + output_type.value)
|
||||
|
@ -225,7 +216,7 @@ class ExtractedGame:
|
|||
destination_file=destination_file,
|
||||
)
|
||||
|
||||
yield Progress(description=_("DELETING_EXTRACTED_GAME"), determinate=False)
|
||||
yield Progress(description=_("TEXT_DELETING_EXTRACTED_GAME"), determinate=False)
|
||||
shutil.rmtree(self.path)
|
||||
|
||||
return converted_game
|
||||
|
@ -241,7 +232,7 @@ class ExtractedGame:
|
|||
|
||||
game_files: list[Path] = list(filter(lambda file: file.is_file(), self.path.rglob("*")))
|
||||
yield Progress(
|
||||
description=_("CONVERTING_TO_RIIVOLUTION"),
|
||||
description=_("TEXT_CONVERTING_TO_RIIVOLUTION"),
|
||||
determinate=True,
|
||||
max_step=len(game_files),
|
||||
set_step=0,
|
||||
|
@ -316,7 +307,7 @@ class ExtractedGame:
|
|||
rel_path: str = str(fp.relative_to(self.path))
|
||||
|
||||
yield Progress(
|
||||
description=_(f"CALCULATING_HASH_FOR", ' "', rel_path, '"'),
|
||||
description=_("TEXT_CALCULATING_HASH") % rel_path,
|
||||
step=1
|
||||
)
|
||||
|
||||
|
|
|
@ -13,14 +13,12 @@ from source.translation import translate as _
|
|||
|
||||
class NotMKWGameError(Exception):
|
||||
def __init__(self, path: "Path | str"):
|
||||
path = Path(path)
|
||||
super().__init__(_("NOT_MKW_GAME", ' : "', path.name, '"'))
|
||||
super().__init__(_("ERROR_NOT_MKW_GAME") % Path(path).name)
|
||||
|
||||
|
||||
class NotVanillaError(Exception):
|
||||
def __init__(self, path: "Path | str"):
|
||||
path = Path(path)
|
||||
super().__init__(_("GAME_ALREADY_MODDED", ' : "', path.name, '"'))
|
||||
super().__init__(_("ERROR_GAME_ALREADY_MODDED") % Path(path).name)
|
||||
|
||||
|
||||
class Game:
|
||||
|
@ -49,7 +47,7 @@ class Game:
|
|||
gen = self.wit_path.progress_extract_all(dest)
|
||||
|
||||
if self.wit_path.extension == Extension.FST:
|
||||
for __ in gen: yield Progress(description=_("COPYING_GAME"), determinate=False)
|
||||
for __ in gen: yield Progress(description=_("TEXT_COPYING_GAME"), determinate=False)
|
||||
try: next(gen)
|
||||
except StopIteration as e: return e.value
|
||||
|
||||
|
@ -57,17 +55,20 @@ class Game:
|
|||
yield Progress(determinate=True, max_step=100)
|
||||
|
||||
for gen_data in gen:
|
||||
percentage: int = gen_data["percentage"]
|
||||
estimation: str = gen_data["estimation"] if gen_data["estimation"] is not None else "-:--"
|
||||
|
||||
yield Progress(
|
||||
description=_("EXTRACTING", " - ", gen_data["percentage"], "% - (", "ESTIMATED_TIME_REMAINING", ": "
|
||||
f'{gen_data["estimation"] if gen_data["estimation"] is not None else "-:--"})'),
|
||||
set_step=gen_data["percentage"],
|
||||
description=_("TEXT_EXTRACTING_GAME") % (percentage, estimation),
|
||||
set_step=percentage,
|
||||
)
|
||||
|
||||
try: next(gen)
|
||||
except StopIteration as e:
|
||||
return e.value
|
||||
|
||||
def edit(self, mod_config: ModConfig) -> Generator[Progress, None, None]:
|
||||
yield Progress(description=_("CHANGING_GAME_METADATA"), determinate=False)
|
||||
yield Progress(description=_("TEXT_CHANGING_GAME_METADATA"), determinate=False)
|
||||
self.wit_path.edit(
|
||||
name=mod_config.name,
|
||||
game_id=self.wit_path.id[:4] + mod_config.variant
|
||||
|
@ -120,23 +121,23 @@ class Game:
|
|||
if not self.is_vanilla(): raise NotVanillaError(self.wit_path.path)
|
||||
|
||||
# extract the game
|
||||
yield Progress(title=_("EXTRACTION"), set_part=1)
|
||||
yield Progress(title=_("PART_EXTRACTION"), set_part=1)
|
||||
yield from self.extract(extracted_game.path)
|
||||
|
||||
# Get the original file hash map for comparaison with the post-patched game
|
||||
yield Progress(title=_("PREPARING_RIIVOLUTION"), set_part=2)
|
||||
yield Progress(title=_("PART_PRE_RIIVOLUTION"), set_part=2)
|
||||
riivolution_original_hash_map: dict[str, str] | None = None
|
||||
if output_type.is_riivolution():
|
||||
riivolution_original_hash_map = yield from extracted_game.get_hash_map()
|
||||
|
||||
# install mystuff
|
||||
yield Progress(title=_("MYSTUFF"), set_part=3)
|
||||
yield Progress(title=_("PART_MYSTUFF"), set_part=3)
|
||||
mystuff_packs = options.mystuff_packs.get()
|
||||
mystuff_data = mystuff_packs.get(options.mystuff_pack_selected.get())
|
||||
if mystuff_data is not None: yield from extracted_game.install_multiple_mystuff(mystuff_data["paths"])
|
||||
|
||||
# prepare the cache
|
||||
yield Progress(title=_("PREPARING_FILES"), set_part=4)
|
||||
yield Progress(title=_("PART_PREPARING_FILES"), set_part=4)
|
||||
yield from extracted_game.extract_autoadd(cache_autoadd_directory)
|
||||
yield from extracted_game.extract_original_tracks(cache_ogtracks_directory)
|
||||
yield from mod_config.normalize_all_tracks(
|
||||
|
@ -149,10 +150,10 @@ class Game:
|
|||
yield from extracted_game.prepare_special_file(mod_config)
|
||||
|
||||
# prepatch the game
|
||||
yield Progress(title=_("PRE-PATCH_TITLE"), set_part=5)
|
||||
yield from extracted_game.install_all_prepatch(mod_config) # PROGRESS
|
||||
yield Progress(title=_("PART_PREPATCH"), set_part=5)
|
||||
yield from extracted_game.install_all_prepatch(mod_config)
|
||||
|
||||
yield Progress(title="LE-CODE", set_part=6)
|
||||
yield Progress(title=_("PART_LECODE"), set_part=6)
|
||||
yield from extracted_game.patch_lecode( # PROGRESS
|
||||
mod_config,
|
||||
cache_directory,
|
||||
|
@ -160,17 +161,17 @@ class Game:
|
|||
cache_ogtracks_directory,
|
||||
)
|
||||
|
||||
yield Progress(title=_("PATCH_TITLE"), set_part=7)
|
||||
yield from extracted_game.install_all_patch(mod_config) # PROGRESS
|
||||
yield Progress(title=_("PART_PATCH"), set_part=7)
|
||||
yield from extracted_game.install_all_patch(mod_config)
|
||||
yield from extracted_game.recreate_all_szs()
|
||||
|
||||
if output_type.is_riivolution():
|
||||
yield Progress(title=_("CONVERTING_TO_RIIVOLUTION"), set_part=8)
|
||||
yield Progress(title=_("PART_RIIVOLUTION"), set_part=8)
|
||||
yield from extracted_game.convert_to_riivolution(mod_config, riivolution_original_hash_map)
|
||||
|
||||
else:
|
||||
# convert the extracted game into a file
|
||||
yield Progress(title=_("CONVERTING_TO_GAME_FILE"), set_part=8)
|
||||
yield Progress(title=_("PART_CONVERSION"), set_part=8)
|
||||
converted_game: WITPath = yield from extracted_game.convert_to(output_type)
|
||||
if converted_game is not None: yield from Game(converted_game.path).edit(mod_config)
|
||||
|
||||
|
|
|
@ -422,7 +422,7 @@ class ModConfig:
|
|||
nonlocal normalize_threads
|
||||
|
||||
yield Progress(
|
||||
description=_("NORMALIZING_TRACKS", " :\n" + "\n".join(thread['name'] for thread in normalize_threads))
|
||||
description=_("TEXT_NORMALIZING_TRACKS") % "\n".join(thread['name'] for thread in normalize_threads)
|
||||
)
|
||||
|
||||
normalize_threads = list(filter(lambda thread: thread["thread"].is_alive(), normalize_threads))
|
||||
|
@ -433,7 +433,6 @@ class ModConfig:
|
|||
)
|
||||
|
||||
yield Progress(
|
||||
description=_("NORMALIZING_TRACKS"),
|
||||
determinate=True,
|
||||
max_step=len(all_arenas_tracks)+1,
|
||||
set_step=0,
|
||||
|
|
|
@ -9,7 +9,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class InvalidSettingsType(Exception):
|
||||
def __init__(self, settings_type: str):
|
||||
super().__init__(_("TYPE_MOD_SETTINGS", " '", settings_type, "' ", "NOT_FOUND"))
|
||||
super().__init__(_("ERROR_MOD_SETTINGS_NOT_FOUND") % settings_type)
|
||||
|
||||
|
||||
class AbstractModSettings(ABC):
|
||||
|
|
|
@ -17,9 +17,9 @@ class Boolean(AbstractModSettings):
|
|||
super().tkinter_show(master, checkbox)
|
||||
variable = self.tkinter_variable(tkinter.BooleanVar)
|
||||
|
||||
radiobutton_on = ttk.Radiobutton(master, text=_("DISABLED"), variable=variable, value=False)
|
||||
radiobutton_on = ttk.Radiobutton(master, text=_("TEXT_DISABLED"), variable=variable, value=False)
|
||||
radiobutton_on.grid(row=1, column=1, sticky="E")
|
||||
radiobutton_off = ttk.Radiobutton(master, text=_("ENABLED"), variable=variable, value=True)
|
||||
radiobutton_off = ttk.Radiobutton(master, text=_("TEXT_ENABLED"), variable=variable, value=True)
|
||||
radiobutton_off.grid(row=1, column=2, sticky="E")
|
||||
|
||||
self.tkinter_bind(master, checkbox)
|
||||
|
|
|
@ -29,7 +29,7 @@ class Patch:
|
|||
:param extracted_game: the extracted game
|
||||
"""
|
||||
from source.mkw.Patch.PatchDirectory import PatchDirectory
|
||||
yield Progress(description=_("INSTALLING_PATCH"), determinate=False)
|
||||
yield Progress()
|
||||
|
||||
# take all the files in the root directory, and patch them into the game.
|
||||
# Patch is not directly applied to the root to avoid custom configuration
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from pathlib import Path
|
||||
from typing import Generator, TYPE_CHECKING
|
||||
|
||||
from source.mkw.Patch import PathOutsidePatch, InvalidPatchMode
|
||||
from source.mkw import PathOutsideAllowedRange
|
||||
from source.mkw.Patch import InvalidPatchMode
|
||||
from source.mkw.Patch.PatchObject import PatchObject
|
||||
from source.progress import Progress
|
||||
from source.translation import translate as _
|
||||
|
@ -28,7 +29,7 @@ class PatchDirectory(PatchObject):
|
|||
"""
|
||||
patch a subdirectory of the game with the PatchDirectory
|
||||
"""
|
||||
yield Progress(description=_("PATCHING", ' "', game_subpath.relative_to(extracted_game.path), '"'))
|
||||
yield Progress(description=_("TEXT_PATCHING") % game_subpath.relative_to(extracted_game.path))
|
||||
|
||||
# check if the directory should be patched
|
||||
if not self.is_enabled(extracted_game): return
|
||||
|
@ -47,7 +48,7 @@ class PatchDirectory(PatchObject):
|
|||
for game_subfile in game_subpath.parent.glob(self.configuration["match_regex"]):
|
||||
# disallow patching files outside of the game
|
||||
if not game_subfile.relative_to(extracted_game.path):
|
||||
raise PathOutsidePatch(game_subfile, extracted_game.path)
|
||||
raise PathOutsideAllowedRange(game_subfile, extracted_game.path)
|
||||
|
||||
# patch the game with the subpatch
|
||||
# if the subfile is a szs archive, replace it with a .d extension
|
||||
|
|
|
@ -2,7 +2,8 @@ from io import BytesIO
|
|||
from pathlib import Path
|
||||
from typing import Generator, IO, TYPE_CHECKING
|
||||
|
||||
from source.mkw.Patch import PathOutsidePatch, InvalidPatchMode, InvalidSourceMode
|
||||
from source.mkw import PathOutsideAllowedRange
|
||||
from source.mkw.Patch import InvalidPatchMode, InvalidSourceMode
|
||||
from source.mkw.Patch.PatchOperation import AbstractPatchOperation
|
||||
from source.mkw.Patch.PatchObject import PatchObject
|
||||
from source.progress import Progress
|
||||
|
@ -82,7 +83,7 @@ class PatchFile(PatchObject):
|
|||
"""
|
||||
patch a subfile of the game with the PatchFile
|
||||
"""
|
||||
yield Progress(description=translate("PATCHING", ' "', game_subpath.relative_to(extracted_game.path), '"'))
|
||||
yield Progress(description=translate("TEXT_PATCHING") % game_subpath.relative_to(extracted_game.path))
|
||||
# translate is not renamed "_" here because it is used to drop useless value in unpacking
|
||||
|
||||
# check if the file should be patched
|
||||
|
@ -119,9 +120,9 @@ class PatchFile(PatchObject):
|
|||
for game_subfile in game_subpath.parent.glob(self.configuration["match_regex"]):
|
||||
# disallow patching files outside of the game
|
||||
if not game_subfile.relative_to(extracted_game.path):
|
||||
raise PathOutsidePatch(game_subfile, extracted_game.path)
|
||||
raise PathOutsideAllowedRange(game_subfile, extracted_game.path)
|
||||
|
||||
yield Progress(description=translate("PATCHING", " ", game_subfile))
|
||||
yield Progress(description=translate("TEXT_PATCHING") % game_subfile)
|
||||
|
||||
# if the source is the game, then recalculate the content for every game subfile
|
||||
if self.configuration["source"] == "game":
|
||||
|
|
|
@ -11,7 +11,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class InvalidBmgLayerMode(Exception):
|
||||
def __init__(self, layer_mode: str):
|
||||
super().__init__(_("BMG_LAYER_MODE", ' "', layer_mode, '" ', "IS_NOT_IMPLEMENTED"))
|
||||
super().__init__(_("ERROR_BMG_LAYER_MODE_NOT_IMPLEMENTED") % layer_mode)
|
||||
|
||||
|
||||
class AbstractLayer(ABC):
|
||||
|
|
|
@ -2,8 +2,8 @@ from typing import TYPE_CHECKING
|
|||
|
||||
from PIL import Image
|
||||
|
||||
from source.mkw import PathOutsideAllowedRange
|
||||
from source.mkw.Patch.PatchOperation.ImageEditor import AbstractLayer
|
||||
from source.mkw.Patch import PathOutsidePatch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from source.mkw.Patch import Patch
|
||||
|
@ -27,7 +27,7 @@ class ImageLayer(AbstractLayer):
|
|||
# check if the path is outside of the allowed directory
|
||||
layer_image_path = patch.path / self.image_path
|
||||
if not layer_image_path.is_relative_to(patch.path):
|
||||
raise PathOutsidePatch(layer_image_path, patch.path)
|
||||
raise PathOutsideAllowedRange(layer_image_path, patch.path)
|
||||
|
||||
# load the image that will be pasted
|
||||
layer_image = Image.open(layer_image_path.resolve()) \
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
|||
|
||||
from PIL import ImageFont, ImageDraw, Image
|
||||
|
||||
from source.mkw.Patch import PathOutsidePatch
|
||||
from source.mkw import PathOutsideAllowedRange
|
||||
from source.mkw.Patch.PatchOperation.ImageEditor import AbstractLayer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -33,7 +33,7 @@ class TextLayer(AbstractLayer):
|
|||
if self.font_path is not None:
|
||||
font_image_path = patch.path / self.font_path
|
||||
if not font_image_path.is_relative_to(patch.path):
|
||||
raise PathOutsidePatch(font_image_path, patch.path)
|
||||
raise PathOutsideAllowedRange(font_image_path, patch.path)
|
||||
else:
|
||||
font_image_path = None
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class InvalidImageLayerType(Exception):
|
||||
def __init__(self, layer_type: str):
|
||||
super().__init__(_("IMAGE_LAYER_TYPE", ' "', layer_type, '" ', "IS_NOT_IMPLEMENTED"))
|
||||
super().__init__(_("ERROR_IMAGE_LAYER_TYPE_NOT_IMPLEMENTED") % layer_type)
|
||||
|
||||
|
||||
class AbstractLayer(ABC):
|
||||
|
|
|
@ -2,7 +2,7 @@ from io import BytesIO
|
|||
from pathlib import Path
|
||||
from typing import IO, TYPE_CHECKING
|
||||
|
||||
from source.mkw.Patch import PathOutsidePatch
|
||||
from source.mkw import PathOutsideAllowedRange
|
||||
from source.mkw.Patch.PatchOperation import AbstractPatchOperation
|
||||
from source.wt import wstrt
|
||||
|
||||
|
@ -31,7 +31,7 @@ class StrEditor(AbstractPatchOperation):
|
|||
for section in self.sections if self.sections is not None else []:
|
||||
section_path = patch.path / section
|
||||
if not section_path.is_relative_to(patch.path):
|
||||
raise PathOutsidePatch(section_path, patch.path)
|
||||
raise PathOutsideAllowedRange(section_path, patch.path)
|
||||
|
||||
checked_sections += section_path
|
||||
# for every file in the sections, check if they are inside the patch.
|
||||
|
|
|
@ -9,7 +9,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class InvalidPatchOperation(Exception):
|
||||
def __init__(self, operation: str):
|
||||
super().__init__(_("OPERATION", ' "', operation, '" ', "IS_NOT_IMPLEMENTED"))
|
||||
super().__init__(_("ERROR_OPERATION_NOT_IMPLEMENTED") % operation)
|
||||
|
||||
|
||||
class AbstractPatchOperation(ABC):
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from source.translation import translate as _
|
||||
|
||||
|
@ -7,18 +6,11 @@ if TYPE_CHECKING:
|
|||
from source.mkw.Patch.PatchObject import PatchObject
|
||||
|
||||
|
||||
class PathOutsidePatch(Exception):
|
||||
def __init__(self, forbidden_path: Path, allowed_range: Path):
|
||||
super().__init__(_("PATH", ' "', forbidden_path, '" ', "OUTSIDE_ALLOWED_RANGE", ' "', {allowed_range}, '" '))
|
||||
|
||||
|
||||
class InvalidPatchMode(Exception):
|
||||
def __init__(self, patch: "PatchObject", mode: str):
|
||||
super().__init__(_("MODE", ' "', mode, '" ', "IS_NOT_IMPLEMENTED",
|
||||
"(", "IN_PATCH", ' : "', patch.full_path, '")'))
|
||||
super().__init__(_("ERROR_PATCH_MODE_NOT_IMPLEMENTED") % (mode, patch.full_path))
|
||||
|
||||
|
||||
class InvalidSourceMode(Exception):
|
||||
def __init__(self, patch: "PatchObject", source: str):
|
||||
super().__init__(_("SOURCE", ' "', source, '" ', "IS_NOT_IMPLEMENTED",
|
||||
"(", "IN_PATCH", ' : "', patch.full_path, '")'))
|
||||
super().__init__(_("ERROR_SOURCE_NOT_IMPLEMENTED") % (source, patch.full_path))
|
||||
|
|
|
@ -11,7 +11,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class TrackForbiddenCustomAttribute(Exception):
|
||||
def __init__(self, attribute_name: str):
|
||||
super().__init__(_("FORBIDDEN_TRACK_ATTRIBUTE", " : ", repr(attribute_name)))
|
||||
super().__init__(_("ERROR_FORBIDDEN_TRACK_ATTRIBUTE") % attribute_name)
|
||||
|
||||
|
||||
class AbstractTrack(ABC):
|
||||
|
@ -35,7 +35,6 @@ class AbstractTrack(ABC):
|
|||
for key, value in kwargs.items():
|
||||
# if the attribute start with __, this is a magic attribute, and it should not be modified
|
||||
if "__" in key: raise TrackForbiddenCustomAttribute(key)
|
||||
# TODO: check potential security issue with setattr and already implemented method and attribute
|
||||
setattr(self, key, value)
|
||||
|
||||
def __repr__(self):
|
||||
|
|
|
@ -12,7 +12,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class ArenaForbiddenCustomAttribute(Exception):
|
||||
def __init__(self, attribute_name: str):
|
||||
super().__init__(_("FORBIDDEN_ARENA_ATTRIBUTE", " : ", repr(attribute_name)))
|
||||
super().__init__(_("ERROR_FORBIDDEN_ARENA_ATTRIBUTE") % attribute_name)
|
||||
|
||||
|
||||
class Arena(RealArenaTrack):
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from source.mkw.Track.AbstractTrack import AbstractTrack
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from source.mkw.ModConfig import ModConfig
|
||||
|
||||
|
||||
class DefaultTrack(AbstractTrack):
|
||||
def repr_format(self, template: str) -> str:
|
||||
|
|
|
@ -11,7 +11,7 @@ if TYPE_CHECKING:
|
|||
|
||||
class TrackGroupForbiddenCustomAttribute(Exception):
|
||||
def __init__(self, attribute_name: str):
|
||||
super().__init__(_("FORBIDDEN_TRACKGROUP_ATTRIBUTE", " : ", repr(attribute_name)))
|
||||
super().__init__(_("ERROR_FORBIDDEN_TRACKGROUP_ATTRIBUTE") % attribute_name)
|
||||
|
||||
|
||||
class TrackGroup:
|
||||
|
@ -61,7 +61,7 @@ class TrackGroup:
|
|||
return the ctfile of the track group
|
||||
:return: ctfile
|
||||
"""
|
||||
ctfile = f'T T11; T11; 0x02; "-"; "info"; "-"\n'
|
||||
ctfile = f'T T11; T11; 0x02; "-"; "-"; "-"\n'
|
||||
for track in self.get_tracks():
|
||||
ctfile += track.get_ctfile(template=template, hidden=True)
|
||||
|
||||
|
|
|
@ -1 +1,12 @@
|
|||
from typing import TYPE_CHECKING
|
||||
from source.translation import translate as _
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
Tag = str
|
||||
|
||||
|
||||
class PathOutsideAllowedRange(Exception):
|
||||
def __init__(self, forbidden_path: "Path", allowed_range: "Path"):
|
||||
super().__init__(_("ERROR_PATH_OUTSIDE_RANGE") % (forbidden_path, allowed_range))
|
|
@ -5,7 +5,7 @@ from source.translation import translate as _
|
|||
|
||||
class ColorNotFound(Exception):
|
||||
def __init__(self, color_data: any):
|
||||
super().__init__(_("CANNOT_FIND_COLOR", ' "', color_data, '"'))
|
||||
super().__init__(_("ERROR_CANNOT_FIND_COLOR") % color_data)
|
||||
|
||||
|
||||
@dataclass(init=True, slots=True)
|
||||
|
|
|
@ -4,7 +4,7 @@ from source.translation import translate as _
|
|||
|
||||
class SlotNotFound(Exception):
|
||||
def __init__(self, slot_data: any):
|
||||
super().__init__(_("CANNOT_FIND_SLOT", ' "', slot_data, '" '))
|
||||
super().__init__(_("ERROR_CANNOT_FIND_SLOT") % slot_data)
|
||||
|
||||
|
||||
@dataclass(init=True, slots=True, frozen=True, repr=True)
|
||||
|
|
|
@ -6,7 +6,7 @@ from source.utils import restart_program
|
|||
|
||||
class OptionLoadingError(Exception):
|
||||
def __init__(self):
|
||||
super().__init__(f"An error occured while loading options. Try deleting the option.json file.")
|
||||
super().__init__(f"An error occurred while loading options. Try deleting the option.json file.")
|
||||
|
||||
|
||||
class Option:
|
||||
|
|
|
@ -4,7 +4,7 @@ from source.translation import translate as _
|
|||
|
||||
class BetterSafeEvalError(Exception):
|
||||
def __init__(self, template: str):
|
||||
super().__init__(_("SAFE_EVAL_ERROR", " (", "TEMPLATE_USED", " : ", repr(template), ")"))
|
||||
super().__init__(_("ERROR_SAFEEVAL") % template)
|
||||
|
||||
|
||||
def better_safe_eval_error(func: Callable, template: str):
|
||||
|
|
|
@ -12,7 +12,7 @@ MACRO_START, MACRO_END = "##", "##"
|
|||
|
||||
class NotImplementedMacro(Exception):
|
||||
def __init__(self, macro: str):
|
||||
super().__init__(_("INVALID_MACRO", ' : "', macro, '"'))
|
||||
super().__init__(_("ERROR_INVALID_MACRO") % macro)
|
||||
|
||||
|
||||
def replace_macro(template: str, macros: dict[str, "TemplateSafeEval"]) -> str:
|
||||
|
|
|
@ -60,7 +60,7 @@ def safe_eval(template: "TemplateSafeEval", env: "Env" = None, macros: dict[str,
|
|||
# convert the template to an ast expression
|
||||
stmt: ast.stmt = ast.parse(template).body[0]
|
||||
if not isinstance(stmt, ast.Expr):
|
||||
raise SafeEvalException(_("INVALID_AST_TYPE", ' : "', type(stmt).__name__, '"'))
|
||||
raise SafeEvalException(_("ERROR_INVALID_AST_TYPE") % type(stmt).__name__)
|
||||
|
||||
# check every node for disabled expression
|
||||
for node in ast.walk(stmt):
|
||||
|
@ -70,20 +70,20 @@ def safe_eval(template: "TemplateSafeEval", env: "Env" = None, macros: dict[str,
|
|||
case ast.Attribute:
|
||||
# ban all magical function, disabling the __class__.__bases__[0] ... tricks
|
||||
if "__" in node.attr:
|
||||
raise SafeEvalException(_("MAGIC_ATTRIBUTE_ARE_FORBIDDEN", ' : "', node.attr, '"'))
|
||||
raise SafeEvalException(_("ERROR_FORBIDDEN_MAGIC_ATTRIBUTE") % node.attr)
|
||||
|
||||
# ban modification to environment
|
||||
if isinstance(node.ctx, ast.Store):
|
||||
raise SafeEvalException(_("CANNOT_SET_ATTRIBUTE", ' : "', node.attr, '"'))
|
||||
raise SafeEvalException(_("ERROR_CANNOT_SET_ATTRIBUTE") % node.attr)
|
||||
|
||||
# when accessing any variable
|
||||
case ast.Name:
|
||||
# ban modification to environment, but allow custom variable to be changed
|
||||
if isinstance(node.ctx, ast.Store):
|
||||
if node.id in globals_ | locals_:
|
||||
raise SafeEvalException(_("CANNOT_SET_ENVIRONMENT", ' : "', node.id, '"'))
|
||||
raise SafeEvalException(_("ERROR_CANNOT_SET_ENVIRONMENT") % node.id)
|
||||
elif node.id in args:
|
||||
raise SafeEvalException(_("CANNOT_SET_ARGUMENT", ' : "', node.id, '"'))
|
||||
raise SafeEvalException(_("ERROR_CANNOT_SET_ARGUMENT") % node.id)
|
||||
|
||||
# when assigning a value with ":="
|
||||
case ast.NamedExpr:
|
||||
|
@ -96,13 +96,14 @@ def safe_eval(template: "TemplateSafeEval", env: "Env" = None, macros: dict[str,
|
|||
case ast.Call:
|
||||
if isinstance(node.func, ast.Attribute): # if this is a method
|
||||
if not isinstance(node.func.value, ast.Constant): # if the method is not on a constant
|
||||
raise SafeEvalException(_("CAN_ONLY_CALL_METHOD_OF_CONSTANT"))
|
||||
raise SafeEvalException(_("ERROR_CAN_ONLY_CALL_CONSTANT_METHOD"))
|
||||
|
||||
elif isinstance(node.func, ast.Name): # if this is a direct function call
|
||||
if node.func.id not in globals_ | locals_: # if the function is not in env
|
||||
raise SafeEvalException(_("CAN_ONLY_CALL_FUNCTION_IN_ENV"))
|
||||
raise SafeEvalException(_("ERROR_CAN_ONLY_CALL_ENV_FUNCTION"))
|
||||
|
||||
else: raise SafeEvalException(_("CAN_ONLY_CALL_FUNCTION_IN_ENV")) # else don't allow the function call
|
||||
else: # else don't allow the function call
|
||||
raise SafeEvalException(_("ERROR_CAN_ONLY_CALL_ENV_FUNCTION"))
|
||||
|
||||
# Forbidden type. Some of them can't be accessed with the eval mode, but just in case, still ban them
|
||||
case (
|
||||
|
@ -117,7 +118,7 @@ def safe_eval(template: "TemplateSafeEval", env: "Env" = None, macros: dict[str,
|
|||
# comprehension are extremely dangerous since their can associate value
|
||||
ast.ListComp | ast.SetComp | ast.DictComp | ast.GeneratorExp
|
||||
):
|
||||
raise SafeEvalException(_("FORBIDDEN_SYNTAX", ' : "', type(node).__name__, '"'))
|
||||
raise SafeEvalException(_("ERROR_FORBIDDEN_SYNTAX") % type(node).__name__)
|
||||
|
||||
# embed the whole expression into a lambda expression
|
||||
stmt.value = ast.Lambda(
|
||||
|
|
|
@ -36,9 +36,9 @@ class safe_function:
|
|||
"""
|
||||
Same as normal getattr, but magic attribute are banned
|
||||
"""
|
||||
if "__" in name: raise Exception(_("MAGIC_METHOD_FORBIDDEN", ' : "', name, '"'))
|
||||
if "__" in name: raise Exception(_("ERROR_FORBIDDEN_MAGIC_METHOD") % name)
|
||||
attr = getattr(obj, name, default)
|
||||
if callable(attr): raise Exception(_("GET_METHOD_FORBIDDEN", ' : "', name, '"'))
|
||||
if callable(attr): raise Exception(_("ERROR_GETTING_METHOD_FORBIDDEN") % name)
|
||||
return attr
|
||||
|
||||
@staticmethod
|
||||
|
@ -63,5 +63,5 @@ class safe_function:
|
|||
:param obj: the object to copy
|
||||
:return: the copied object
|
||||
"""
|
||||
if callable(obj): raise Exception(_("COPY_FUNCTION_FORBIDDEN", ' : "', obj.__name__, '"'))
|
||||
if callable(obj): raise Exception(_("ERROR_FUNCTION_COPY_FORBIDDEN") % obj.__name__)
|
||||
return copy.deepcopy(obj)
|
||||
|
|
|
@ -19,17 +19,13 @@ def load_language(language: str):
|
|||
self._language_data = json.loads(Path(f"./assets/language/{language}.json").read_text(encoding="utf8"))
|
||||
|
||||
|
||||
def translate(*text) -> str:
|
||||
def translate(text) -> str:
|
||||
"""
|
||||
Translate a text to the loaded language.
|
||||
:param text: list of text to translate
|
||||
:return: translated text
|
||||
"""
|
||||
return "".join([
|
||||
self._language_data.get("translation", {}).get(word, word) if isinstance(word, str)
|
||||
else str(word)
|
||||
for word in text
|
||||
])
|
||||
return self._language_data.get("translation", {}).get(text, text)
|
||||
|
||||
|
||||
def translate_external(mod_config: "ModConfig", language: str, message_texts: dict[str, str], default: str = "") -> str:
|
||||
|
|
|
@ -21,15 +21,15 @@ class WTError(Exception):
|
|||
check=True,
|
||||
**subprocess_kwargs
|
||||
).stdout.decode()
|
||||
except subprocess.CalledProcessError as e:
|
||||
error = _("- ", "CANNOT_GET_ERROR_MESSAGE", " -")
|
||||
except subprocess.CalledProcessError:
|
||||
error = _("ERROR_CANNOT_GET_ERROR_MESSAGE")
|
||||
|
||||
super().__init__(_(tools_path, " ", "RAISED", " ", return_code, ":\n", error, "\n"))
|
||||
super().__init__(_("ERROR_WT") % (tools_path, return_code, error))
|
||||
|
||||
|
||||
class MissingWTError(Exception):
|
||||
def __init__(self, tool_name: str):
|
||||
super().__init__(_("CANNOT_FIND_TOOL", ' "', tool_name, '" ', "IN_TOOLS_DIRECTORY"))
|
||||
super().__init__(_("ERROR_CANNOT_FIND_TOOL") % tool_name)
|
||||
|
||||
|
||||
try: tools_szs_dir = next(tools_dir.glob("./szs*/")) / system
|
||||
|
|
|
@ -192,7 +192,7 @@ class SZSSubPath:
|
|||
:param dest: destination path
|
||||
:return: the extracted file path
|
||||
"""
|
||||
if self.is_dir(): raise ValueError(_("CANNOT_EXTRACT_A_DIRECTORY"))
|
||||
if self.is_dir(): raise ValueError(_("ERROR_CANNOT_EXTRACT_DIRECTORY"))
|
||||
|
||||
dest: Path = Path(dest)
|
||||
if dest.is_dir(): dest /= self.basename()
|
||||
|
|
|
@ -202,7 +202,7 @@ class WITSubPath:
|
|||
if self.wit_path.extension == Extension.FST:
|
||||
# if flat is used, extract the file / dir into the destination directory, without subdirectory
|
||||
if flat:
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
dest.mkdir(parents=True, exist_ok=True)
|
||||
# if we are extracting a directory, we need to extract every file recursively
|
||||
if self.is_dir():
|
||||
for file in (self._get_fst_path()).rglob("*"):
|
||||
|
|
Loading…
Reference in a new issue