From 25465803773bca7a11c3111d211d3a181bd38cf2 Mon Sep 17 00:00:00 2001
From: Will Miao <13051207myq@gmail.com>
Date: Wed, 3 Sep 2025 22:23:35 +0800
Subject: [PATCH 08/10] fix(localization): update French translations for
"recipe" to ensure consistency in terminology
---
locales/fr.json | 130 ++++++++++++++++++++++++------------------------
1 file changed, 65 insertions(+), 65 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 15ed204b..9022dd8d 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -125,7 +125,7 @@
"appTitle": "LoRA Manager",
"navigation": {
"loras": "LoRAs",
- "recipes": "Recettes",
+ "recipes": "Recipes",
"checkpoints": "Checkpoints",
"embeddings": "Embeddings",
"statistics": "Statistiques"
@@ -134,7 +134,7 @@
"placeholder": "Rechercher...",
"placeholders": {
"loras": "Rechercher des LoRAs...",
- "recipes": "Rechercher des recettes...",
+ "recipes": "Rechercher des recipes...",
"checkpoints": "Rechercher des checkpoints...",
"embeddings": "Rechercher des embeddings..."
},
@@ -146,7 +146,7 @@
"modelname": "Nom du modèle",
"tags": "Tags",
"creator": "Créateur",
- "title": "Titre de la recette",
+ "title": "Titre de la recipe",
"loraName": "Nom de fichier LoRA",
"loraModel": "Nom du modèle LoRA"
}
@@ -332,7 +332,7 @@
"relinkCivitai": "Relier à nouveau à Civitai",
"copySyntax": "Copier la syntaxe LoRA",
"copyFilename": "Copier le nom de fichier du modèle",
- "copyRecipeSyntax": "Copier la syntaxe de la recette",
+ "copyRecipeSyntax": "Copier la syntaxe de la recipe",
"sendToWorkflowAppend": "Envoyer vers le workflow (Ajouter)",
"sendToWorkflowReplace": "Envoyer vers le workflow (Remplacer)",
"openExamples": "Ouvrir le dossier d'exemples",
@@ -342,33 +342,33 @@
"moveToFolder": "Déplacer vers un dossier",
"excludeModel": "Exclure le modèle",
"deleteModel": "Supprimer le modèle",
- "shareRecipe": "Partager la recette",
+ "shareRecipe": "Partager la recipe",
"viewAllLoras": "Voir tous les LoRAs",
"downloadMissingLoras": "Télécharger les LoRAs manquants",
- "deleteRecipe": "Supprimer la recette"
+ "deleteRecipe": "Supprimer la recipe"
}
},
"recipes": {
- "title": "Recettes LoRA",
+ "title": "LoRA Recipes",
"controls": {
"import": {
"action": "Importer",
- "title": "Importer une recette depuis une image ou une URL",
+ "title": "Importer une recipe depuis une image ou une URL",
"urlLocalPath": "URL / Chemin local",
"uploadImage": "Téléverser une image",
- "urlSectionDescription": "Saisissez une URL d'image Civitai ou un chemin de fichier local pour l'importer comme recette.",
+ "urlSectionDescription": "Saisissez une URL d'image Civitai ou un chemin de fichier local pour l'importer comme recipe.",
"imageUrlOrPath": "URL d'image ou chemin de fichier :",
"urlPlaceholder": "https://civitai.com/images/... ou C:/chemin/vers/image.png",
"fetchImage": "Récupérer l'image",
- "uploadSectionDescription": "Téléversez une image avec des métadonnées LoRA pour l'importer comme recette.",
+ "uploadSectionDescription": "Téléversez une image avec des métadonnées LoRA pour l'importer comme recipe.",
"selectImage": "Sélectionner une image",
- "recipeName": "Nom de la recette",
- "recipeNamePlaceholder": "Entrez le nom de la recette",
+ "recipeName": "Nom de la recipe",
+ "recipeNamePlaceholder": "Entrez le nom de la recipe",
"tagsOptional": "Tags (optionnel)",
"addTagPlaceholder": "Ajouter un tag",
"addTag": "Ajouter",
"noTagsAdded": "Aucun tag ajouté",
- "lorasInRecipe": "LoRAs dans cette recette",
+ "lorasInRecipe": "LoRAs dans cette recipe",
"downloadLocationPreview": "Aperçu de l'emplacement de téléchargement :",
"useDefaultPath": "Utiliser le chemin par défaut",
"useDefaultPathTooltip": "Lorsque activé, les fichiers sont automatiquement organisés selon les modèles de chemin configurés",
@@ -378,14 +378,14 @@
"createNewFolder": "Créer un nouveau dossier",
"root": "Racine",
"browseFolders": "Parcourir les dossiers :",
- "downloadAndSaveRecipe": "Télécharger et sauvegarder la recette",
+ "downloadAndSaveRecipe": "Télécharger et sauvegarder la recipe",
"downloadMissingLoras": "Télécharger les LoRAs manquants",
- "saveRecipe": "Sauvegarder la recette",
+ "saveRecipe": "Sauvegarder la recipe",
"loraCountInfo": "({existing}/{total} dans la bibliothèque)",
"processingInput": "Traitement de l'entrée...",
"analyzingMetadata": "Analyse des métadonnées de l'image...",
"downloadingLoras": "Téléchargement des LoRAs...",
- "savingRecipe": "Sauvegarde de la recette...",
+ "savingRecipe": "Sauvegarde de la recipe...",
"startingDownload": "Début du téléchargement pour le LoRA {current}/{total}",
"deletedFromCivitai": "Supprimé de Civitai",
"inLibrary": "Dans la bibliothèque",
@@ -394,12 +394,12 @@
"earlyAccessEnds": "L'accès anticipé se termine le {date}.",
"earlyAccess": "Accès anticipé",
"verifyEarlyAccess": "Vérifiez que vous avez acheté l'accès anticipé avant de télécharger.",
- "duplicateRecipesFound": "{count} recette(s) identique(s) trouvée(s) dans votre bibliothèque",
- "duplicateRecipesDescription": "Ces recettes contiennent les mêmes LoRAs avec des poids identiques.",
+ "duplicateRecipesFound": "{count} recipe(s) identique(s) trouvée(s) dans votre bibliothèque",
+ "duplicateRecipesDescription": "Ces recipes contiennent les mêmes LoRAs avec des poids identiques.",
"showDuplicates": "Afficher les doublons",
"hideDuplicates": "Masquer les doublons",
"loraCount": "{count} LoRAs",
- "recipePreviewAlt": "Aperçu de la recette",
+ "recipePreviewAlt": "Aperçu de la recipe",
"loraPreviewAlt": "Aperçu LoRA",
"errors": {
"selectImageFile": "Veuillez sélectionner un fichier image",
@@ -408,7 +408,7 @@
}
},
"refresh": {
- "title": "Actualiser la liste des recettes"
+ "title": "Actualiser la liste des recipes"
},
"filteredByLora": "Filtré par LoRA"
},
@@ -419,20 +419,20 @@
},
"contextMenu": {
"copyRecipe": {
- "missingId": "Impossible de copier la recette : ID de recette manquant",
- "failed": "Échec de la copie de la syntaxe de la recette"
+ "missingId": "Impossible de copier la recipe : ID de recipe manquant",
+ "failed": "Échec de la copie de la syntaxe de la recipe"
},
"sendRecipe": {
- "missingId": "Impossible d'envoyer la recette : ID de recette manquant",
- "failed": "Échec de l'envoi de la recette vers le workflow"
+ "missingId": "Impossible d'envoyer la recipe : ID de recipe manquant",
+ "failed": "Échec de l'envoi de la recipe vers le workflow"
},
"viewLoras": {
- "missingId": "Impossible de voir les LoRAs : ID de recette manquant",
- "noLorasFound": "Aucun LoRA trouvé dans cette recette",
- "loadError": "Erreur lors du chargement des LoRAs de la recette : {message}"
+ "missingId": "Impossible de voir les LoRAs : ID de recipe manquant",
+ "noLorasFound": "Aucun LoRA trouvé dans cette recipe",
+ "loadError": "Erreur lors du chargement des LoRAs de la recipe : {message}"
},
"downloadMissing": {
- "missingId": "Impossible de télécharger les LoRAs : ID de recette manquant",
+ "missingId": "Impossible de télécharger les LoRAs : ID de recipe manquant",
"noMissingLoras": "Aucun LoRA manquant à télécharger",
"getInfoFailed": "Échec de l'obtention des informations pour les LoRAs manquants",
"prepareError": "Erreur lors de la préparation des LoRAs pour le téléchargement : {message}"
@@ -552,9 +552,9 @@
"message": "Êtes-vous sûr de vouloir exclure ce modèle ? Les modèles exclus n'apparaîtront pas dans les recherches ou listes de modèles."
},
"deleteDuplicateRecipes": {
- "title": "Supprimer les recettes dupliquées",
- "message": "Êtes-vous sûr de vouloir supprimer les recettes dupliquées sélectionnées ?",
- "countMessage": "recettes seront définitivement supprimées."
+ "title": "Supprimer les recipes dupliquées",
+ "message": "Êtes-vous sûr de vouloir supprimer les recipes dupliquées sélectionnées ?",
+ "countMessage": "recipes seront définitivement supprimées."
},
"deleteDuplicateModels": {
"title": "Supprimer les modèles dupliqués",
@@ -685,12 +685,12 @@
"tabs": {
"examples": "Exemples",
"description": "Description du modèle",
- "recipes": "Recettes"
+ "recipes": "Recipes"
},
"loading": {
"exampleImages": "Chargement des images d'exemple...",
"description": "Chargement de la description du modèle...",
- "recipes": "Chargement des recettes...",
+ "recipes": "Chargement des recipes...",
"examples": "Chargement des exemples..."
}
}
@@ -733,8 +733,8 @@
"message": "Scan et construction du cache embedding. Cela peut prendre quelques minutes..."
},
"recipes": {
- "title": "Initialisation du gestionnaire de recettes",
- "message": "Chargement et traitement des recettes. Cela peut prendre quelques minutes..."
+ "title": "Initialisation du gestionnaire de recipes",
+ "message": "Chargement et traitement des recipes. Cela peut prendre quelques minutes..."
},
"statistics": {
"title": "Initialisation des statistiques",
@@ -753,9 +753,9 @@
"alt": "Téléchargement Civitai"
},
"recipes": {
- "title": "Sauvegarder les recettes",
- "description": "Créez des recettes pour sauvegarder vos combinaisons de modèles préférées pour une utilisation future.",
- "alt": "Recettes"
+ "title": "Sauvegarder les recipes",
+ "description": "Créez des recipes pour sauvegarder vos combinaisons de modèles préférées pour une utilisation future.",
+ "alt": "Recipes"
},
"filter": {
"title": "Filtrage rapide",
@@ -796,12 +796,12 @@
"loraAdded": "LoRA ajouté au workflow",
"loraReplaced": "LoRA remplacé dans le workflow",
"loraFailedToSend": "Échec de l'envoi du LoRA au workflow",
- "recipeAdded": "Recette ajoutée au workflow",
- "recipeReplaced": "Recette remplacée dans le workflow",
- "recipeFailedToSend": "Échec de l'envoi de la recette au workflow"
+ "recipeAdded": "Recipe ajoutée au workflow",
+ "recipeReplaced": "Recipe remplacée dans le workflow",
+ "recipeFailedToSend": "Échec de l'envoi de la recipe au workflow"
},
"nodeSelector": {
- "recipe": "Recette",
+ "recipe": "Recipe",
"lora": "LoRA",
"replace": "Remplacer",
"append": "Ajouter",
@@ -835,7 +835,7 @@
"general": "Général",
"troubleshooting": "Dépannage",
"modelManagement": "Gestion des modèles",
- "recipes": "Recettes",
+ "recipes": "Recipes",
"settings": "Paramètres & Configuration",
"extensions": "Extensions",
"newBadge": "NOUVEAU"
@@ -927,42 +927,42 @@
"downloadCompleted": "Téléchargement terminé avec succès"
},
"recipes": {
- "fetchFailed": "Échec de la récupération des recettes : {message}",
+ "fetchFailed": "Échec de la récupération des recipes : {message}",
"reloadFailed": "Échec du rechargement des {modelType}s : {message}",
"loadFailed": "Échec du chargement des {modelType}s : {message}",
"refreshComplete": "Actualisation terminée",
- "refreshFailed": "Échec de l'actualisation des recettes : {message}",
- "updateFailed": "Échec de la mise à jour de la recette : {error}",
- "updateError": "Erreur lors de la mise à jour de la recette : {message}",
- "nameSaved": "Recette \"{name}\" sauvegardée avec succès",
- "nameUpdated": "Nom de la recette mis à jour avec succès",
- "tagsUpdated": "Tags de la recette mis à jour avec succès",
+ "refreshFailed": "Échec de l'actualisation des recipes : {message}",
+ "updateFailed": "Échec de la mise à jour de la recipe : {error}",
+ "updateError": "Erreur lors de la mise à jour de la recipe : {message}",
+ "nameSaved": "Recipe \"{name}\" sauvegardée avec succès",
+ "nameUpdated": "Nom de la recipe mis à jour avec succès",
+ "tagsUpdated": "Tags de la recipe mis à jour avec succès",
"sourceUrlUpdated": "URL source mise à jour avec succès",
- "noRecipeId": "Aucun ID de recette disponible",
- "copyFailed": "Erreur lors de la copie de la syntaxe de la recette : {message}",
+ "noRecipeId": "Aucun ID de recipe disponible",
+ "copyFailed": "Erreur lors de la copie de la syntaxe de la recipe : {message}",
"noMissingLoras": "Aucun LoRA manquant à télécharger",
"missingLorasInfoFailed": "Échec de l'obtention des informations pour les LoRAs manquants",
"preparingForDownloadFailed": "Erreur lors de la préparation des LoRAs pour le téléchargement",
"enterLoraName": "Veuillez entrer un nom ou une syntaxe LoRA",
"reconnectedSuccessfully": "LoRA reconnecté avec succès",
"reconnectFailed": "Erreur lors de la reconnexion du LoRA : {message}",
- "cannotSend": "Impossible d'envoyer la recette : ID de recette manquant",
- "sendFailed": "Échec de l'envoi de la recette vers le workflow",
- "sendError": "Erreur lors de l'envoi de la recette vers le workflow",
- "cannotDelete": "Impossible de supprimer la recette : ID de recette manquant",
+ "cannotSend": "Impossible d'envoyer la recipe : ID de recipe manquant",
+ "sendFailed": "Échec de l'envoi de la recipe vers le workflow",
+ "sendError": "Erreur lors de l'envoi de la recipe vers le workflow",
+ "cannotDelete": "Impossible de supprimer la recipe : ID de recipe manquant",
"deleteConfirmationError": "Erreur lors de l'affichage de la confirmation de suppression",
- "deletedSuccessfully": "Recette supprimée avec succès",
- "deleteFailed": "Erreur lors de la suppression de la recette : {message}",
- "cannotShare": "Impossible de partager la recette : ID de recette manquant",
- "preparingForSharing": "Préparation de la recette pour le partage...",
- "downloadStarted": "Téléchargement de la recette démarré",
- "shareError": "Erreur lors du partage de la recette : {message}",
- "sharePreparationError": "Erreur lors de la préparation de la recette pour le partage",
+ "deletedSuccessfully": "Recipe supprimée avec succès",
+ "deleteFailed": "Erreur lors de la suppression de la recipe : {message}",
+ "cannotShare": "Impossible de partager la recipe : ID de recipe manquant",
+ "preparingForSharing": "Préparation de la recipe pour le partage...",
+ "downloadStarted": "Téléchargement de la recipe démarré",
+ "shareError": "Erreur lors du partage de la recipe : {message}",
+ "sharePreparationError": "Erreur lors de la préparation de la recipe pour le partage",
"selectImageFirst": "Veuillez d'abord sélectionner une image",
- "enterRecipeName": "Veuillez entrer un nom de recette",
+ "enterRecipeName": "Veuillez entrer un nom de recipe",
"processingError": "Erreur de traitement : {message}",
"folderBrowserError": "Erreur lors du chargement du navigateur de dossiers : {message}",
- "recipeSaveFailed": "Échec de la sauvegarde de la recette : {error}",
+ "recipeSaveFailed": "Échec de la sauvegarde de la recipe : {error}",
"importFailed": "Échec de l'importation : {message}",
"folderTreeFailed": "Échec du chargement de l'arborescence des dossiers",
"folderTreeError": "Erreur lors du chargement de l'arborescence des dossiers"
From f041f4a11434b97e18382055fcfa97c4651fd594 Mon Sep 17 00:00:00 2001
From: Will Miao <13051207myq@gmail.com>
Date: Wed, 3 Sep 2025 22:48:29 +0800
Subject: [PATCH 09/10] feat(onboarding): prevent onboarding from starting if
version-mismatch banner is visible
---
static/js/core.js | 5 ++++-
static/js/managers/BannerService.js | 10 ++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/static/js/core.js b/static/js/core.js
index 36376d89..1a250aca 100644
--- a/static/js/core.js
+++ b/static/js/core.js
@@ -68,7 +68,10 @@ export class AppCore {
// Start onboarding if needed (after everything is initialized)
setTimeout(() => {
- onboardingManager.start();
+ // Do not show onboarding if version-mismatch banner is visible
+ if (!bannerService.isBannerVisible('version-mismatch')) {
+ onboardingManager.start();
+ }
}, 1000); // Small delay to ensure all elements are rendered
// Return the core instance for chaining
diff --git a/static/js/managers/BannerService.js b/static/js/managers/BannerService.js
index c2226fce..808bfb12 100644
--- a/static/js/managers/BannerService.js
+++ b/static/js/managers/BannerService.js
@@ -171,6 +171,16 @@ class BannerService {
}
}
+ /**
+ * Check if a banner is currently rendered and visible
+ * @param {string} bannerId
+ * @returns {boolean}
+ */
+ isBannerVisible(bannerId) {
+ const el = document.querySelector(`[data-banner-id="${bannerId}"]`);
+ return !!el && el.offsetParent !== null;
+ }
+
/**
* Update container visibility based on active banners
*/
From 192bc237bfdd115a5c0a5e43932b2e46bb950368 Mon Sep 17 00:00:00 2001
From: Will Miao <13051207myq@gmail.com>
Date: Wed, 3 Sep 2025 23:04:06 +0800
Subject: [PATCH 10/10] fix(onboarding): update language selection button text
and remove skip option from translations
---
locales/de.json | 1 -
locales/en.json | 1 -
locales/es.json | 1 -
locales/fr.json | 1 -
locales/ja.json | 1 -
locales/ko.json | 1 -
locales/ru.json | 1 -
locales/zh-CN.json | 1 -
locales/zh-TW.json | 1 -
static/js/managers/OnboardingManager.js | 16 ++++++----------
10 files changed, 6 insertions(+), 19 deletions(-)
diff --git a/locales/de.json b/locales/de.json
index f2085f98..064b7306 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "Willkommen beim LoRA Manager",
- "skip": "Überspringen",
"continue": "Weiter",
"changeFailed": "Fehler beim Ändern der Sprache: {message}"
},
diff --git a/locales/en.json b/locales/en.json
index 6076f0af..c518574a 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "Welcome to LoRA Manager",
- "skip": "Skip",
"continue": "Continue",
"changeFailed": "Failed to change language: {message}"
},
diff --git a/locales/es.json b/locales/es.json
index 471eb111..db682c59 100644
--- a/locales/es.json
+++ b/locales/es.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "Bienvenido a LoRA Manager",
- "skip": "Saltar",
"continue": "Continuar",
"changeFailed": "Error al cambiar el idioma: {message}"
},
diff --git a/locales/fr.json b/locales/fr.json
index 9022dd8d..5739e7cf 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "Bienvenue dans LoRA Manager",
- "skip": "Passer",
"continue": "Continuer",
"changeFailed": "Échec du changement de langue : {message}"
},
diff --git a/locales/ja.json b/locales/ja.json
index 99b63861..d1fc6bd5 100644
--- a/locales/ja.json
+++ b/locales/ja.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "LoRA Managerへようこそ",
- "skip": "スキップ",
"continue": "続行",
"changeFailed": "言語の変更に失敗しました:{message}"
},
diff --git a/locales/ko.json b/locales/ko.json
index 51abf06b..5d1b5447 100644
--- a/locales/ko.json
+++ b/locales/ko.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "LoRA Manager에 오신 것을 환영합니다",
- "skip": "건너뛰기",
"continue": "계속",
"changeFailed": "언어 변경 실패: {message}"
},
diff --git a/locales/ru.json b/locales/ru.json
index 73e9afb6..d3d13607 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "Добро пожаловать в LoRA Manager",
- "skip": "Пропустить",
"continue": "Продолжить",
"changeFailed": "Не удалось изменить язык: {message}"
},
diff --git a/locales/zh-CN.json b/locales/zh-CN.json
index f1426183..c843ed9d 100644
--- a/locales/zh-CN.json
+++ b/locales/zh-CN.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "欢迎使用 LoRA 管理器",
- "skip": "跳过",
"continue": "继续",
"changeFailed": "切换语言失败:{message}"
},
diff --git a/locales/zh-TW.json b/locales/zh-TW.json
index 9047526e..c04f39ae 100644
--- a/locales/zh-TW.json
+++ b/locales/zh-TW.json
@@ -43,7 +43,6 @@
"onboarding": {
"languageSelection": {
"title": "歡迎使用 LoRA 管理器",
- "skip": "跳過",
"continue": "繼續",
"changeFailed": "切換語言失敗:{message}"
},
diff --git a/static/js/managers/OnboardingManager.js b/static/js/managers/OnboardingManager.js
index e60c5217..ccbb971f 100644
--- a/static/js/managers/OnboardingManager.js
+++ b/static/js/managers/OnboardingManager.js
@@ -127,7 +127,7 @@ export class OnboardingManager {
`).join('')}