diff --git a/locales/en.json b/locales/en.json index 0f1ed6c9..c1e07b90 100644 --- a/locales/en.json +++ b/locales/en.json @@ -786,9 +786,20 @@ "syntaxCopiedWithGroups": "LoRA syntax with trigger word groups copied to clipboard", "downloadSuccessful": "LoRAs downloaded successfully", "allDownloadSuccessful": "All {count} LoRAs downloaded successfully", - "downloadPartialSuccess": "Downloaded {completed} of {total} LoRAs" + "downloadPartialSuccess": "Downloaded {completed} of {total} LoRAs", + "downloadPartialWithAccess": "Downloaded {completed} of {total} LoRAs. {accessFailures} failed due to access restrictions. Check your API key in settings or early access status.", + "pleaseSelectVersion": "Please select a version", + "versionExists": "This version already exists in your library", + "downloadCompleted": "Download completed successfully" }, "recipes": { + "fetchFailed": "Failed to fetch recipes: {message}", + "reloadFailed": "Failed to reload {modelType}s: {message}", + "loadFailed": "Failed to load {modelType}s: {message}", + "refreshComplete": "Refresh complete", + "refreshFailed": "Failed to refresh recipes: {message}", + "updateFailed": "Failed to update recipe: {error}", + "updateError": "Error updating recipe: {message}", "nameSaved": "Recipe \"{name}\" saved successfully", "nameUpdated": "Recipe name updated successfully", "tagsUpdated": "Recipe tags updated successfully", @@ -923,7 +934,19 @@ "exampleImages": { "checkError": "Error checking for example images", "missingHash": "Missing model hash information.", - "noRemoteImages": "No remote example images available for this model on Civitai" + "noRemoteImages": "No remote example images available for this model on Civitai", + "pathUpdated": "Example images path updated successfully", + "downloadInProgress": "Download already in progress", + "enterLocationFirst": "Please enter a download location first", + "downloadStarted": "Example images download started", + "downloadStartFailed": "Failed to start download", + "downloadPaused": "Download paused", + "pauseFailed": "Failed to pause download", + "downloadResumed": "Download resumed", + "resumeFailed": "Failed to resume download", + "deleted": "Example image deleted", + "deleteFailed": "Failed to delete example image", + "setPreviewFailed": "Failed to set preview image" }, "api": { "fetchFailed": "Failed to fetch {type}s: {message}", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index d976309b..e6ad6d89 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -778,7 +778,49 @@ "syntaxCopiedWithGroups": "LoRA 语法与触发词组已复制到剪贴板", "downloadSuccessful": "LoRA 下载成功", "allDownloadSuccessful": "所有 {count} 个 LoRA 下载成功", - "downloadPartialSuccess": "已下载 {completed} / {total} 个 LoRA" + "downloadPartialSuccess": "已下载 {completed} / {total} 个 LoRA", + "pleaseSelectVersion": "请选择一个版本", + "versionExists": "此版本已存在于您的库中", + "downloadCompleted": "下载成功完成" + }, + "exampleImages": { + "pathUpdated": "示例图片路径更新成功", + "downloadInProgress": "下载已在进行中", + "enterLocationFirst": "请先输入下载位置", + "downloadStarted": "示例图片下载已开始", + "downloadStartFailed": "下载启动失败", + "downloadPaused": "下载已暂停", + "pauseFailed": "暂停下载失败", + "downloadResumed": "下载已恢复", + "resumeFailed": "恢复下载失败", + "deleted": "示例图片已删除", + "deleteFailed": "删除示例图片失败", + "setPreviewFailed": "设置预览图片失败" + }, + "recipes": { + "created": "配方已创建", + "creationFailed": "配方创建失败", + "updated": "配方已更新", + "updateFailed": "配方更新失败", + "deleted": "配方已删除", + "deleteFailed": "配方删除失败", + "bulkDeleted": "批量删除完成:成功删除 {successCount} 个配方,{failureCount} 个失败", + "imported": "配方已导入", + "importFailed": "配方导入失败", + "copied": "配方语法已复制到剪贴板", + "copyFailed": "复制配方语法失败", + "sentToWorkflow": "配方已发送到工作流", + "sendToWorkflowFailed": "发送配方到工作流失败", + "missingLoras": "缺少 {count} 个 LoRA", + "downloadMissing": "开始下载缺少的 LoRA:{count} 个", + "downloadMissingFailed": "下载缺少的 LoRA 失败", + "reconnectDeleted": "重新连接删除的配方", + "findDuplicates": "查找重复配方", + "duplicatesFound": "发现 {count} 个重复配方", + "missingLorasInfo": "缺少 LoRA:{missingLoras}", + "deletedLorasInfo": "已删除 LoRA:{deletedLoras}", + "saveRecipe": "保存配方", + "recipeDetails": "配方详情" }, "models": { "noModelsSelected": "未选择任何模型", diff --git a/static/js/api/recipeApi.js b/static/js/api/recipeApi.js index e9e83ca7..fec0d02f 100644 --- a/static/js/api/recipeApi.js +++ b/static/js/api/recipeApi.js @@ -89,7 +89,7 @@ export async function fetchRecipesPage(page = 1, pageSize = 100) { }; } catch (error) { console.error('Error fetching recipes:', error); - showToast(`Failed to fetch recipes: ${error.message}`, 'error'); + showToast('toast.recipes.fetchFailed', { message: error.message }, 'error'); throw error; } } @@ -131,7 +131,7 @@ export async function resetAndReloadWithVirtualScroll(options = {}) { return result; } catch (error) { console.error(`Error reloading ${modelType}s:`, error); - showToast(`Failed to reload ${modelType}s: ${error.message}`, 'error'); + showToast('toast.recipes.reloadFailed', { modelType: modelType, message: error.message }, 'error'); throw error; } finally { pageState.isLoading = false; @@ -179,7 +179,7 @@ export async function loadMoreWithVirtualScroll(options = {}) { return result; } catch (error) { console.error(`Error loading ${modelType}s:`, error); - showToast(`Failed to load ${modelType}s: ${error.message}`, 'error'); + showToast('toast.recipes.loadFailed', { modelType: modelType, message: error.message }, 'error'); throw error; } finally { pageState.isLoading = false; @@ -217,10 +217,10 @@ export async function refreshRecipes() { // After successful cache rebuild, reload the recipes await resetAndReload(); - showToast('Refresh complete', 'success'); + showToast('toast.recipes.refreshComplete', {}, 'success'); } catch (error) { console.error('Error refreshing recipes:', error); - showToast(error.message || 'Failed to refresh recipes', 'error'); + showToast('toast.recipes.refreshFailed', { message: error.message }, 'error'); } finally { state.loadingManager.hide(); state.loadingManager.restoreProgressBar(); @@ -285,7 +285,7 @@ export async function updateRecipeMetadata(filePath, updates) { const data = await response.json(); if (!data.success) { - showToast(`Failed to update recipe: ${data.error}`, 'error'); + showToast('toast.recipes.updateFailed', { error: data.error }, 'error'); throw new Error(data.error || 'Failed to update recipe'); } @@ -294,7 +294,7 @@ export async function updateRecipeMetadata(filePath, updates) { return data; } catch (error) { console.error('Error updating recipe:', error); - showToast(`Error updating recipe: ${error.message}`, 'error'); + showToast('toast.recipes.updateError', { message: error.message }, 'error'); throw error; } finally { state.loadingManager.hide(); diff --git a/static/js/components/RecipeCard.js b/static/js/components/RecipeCard.js index d8fd9b56..0eaa68ad 100644 --- a/static/js/components/RecipeCard.js +++ b/static/js/components/RecipeCard.js @@ -199,7 +199,7 @@ class RecipeCard { // Get recipe ID const recipeId = this.recipe.id; if (!recipeId) { - showToast('Cannot send recipe: Missing recipe ID', 'error'); + showToast('toast.recipes.cannotSend', {}, 'error'); return; } @@ -214,11 +214,11 @@ class RecipeCard { }) .catch(err => { console.error('Failed to send recipe to workflow: ', err); - showToast('Failed to send recipe to workflow', 'error'); + showToast('toast.recipes.sendFailed', {}, 'error'); }); } catch (error) { console.error('Error sending recipe to workflow:', error); - showToast('Error sending recipe to workflow', 'error'); + showToast('toast.recipes.sendError', {}, 'error'); } } @@ -228,7 +228,7 @@ class RecipeCard { const recipeId = this.recipe.id; const filePath = this.recipe.file_path; if (!recipeId) { - showToast('Cannot delete recipe: Missing recipe ID', 'error'); + showToast('toast.recipes.cannotDelete', {}, 'error'); return; } @@ -278,7 +278,7 @@ class RecipeCard { } catch (error) { console.error('Error showing delete confirmation:', error); - showToast('Error showing delete confirmation', 'error'); + showToast('toast.recipes.deleteConfirmationError', {}, 'error'); } } @@ -287,7 +287,7 @@ class RecipeCard { const recipeId = deleteModal.dataset.recipeId; if (!recipeId) { - showToast('Cannot delete recipe: Missing recipe ID', 'error'); + showToast('toast.recipes.cannotDelete', {}, 'error'); modalManager.closeModal('deleteModal'); return; } @@ -312,7 +312,7 @@ class RecipeCard { return response.json(); }) .then(data => { - showToast('Recipe deleted successfully', 'success'); + showToast('toast.recipes.deletedSuccessfully', {}, 'success'); state.virtualScroller.removeItemByFilePath(deleteModal.dataset.filePath); @@ -320,7 +320,7 @@ class RecipeCard { }) .catch(error => { console.error('Error deleting recipe:', error); - showToast('Error deleting recipe: ' + error.message, 'error'); + showToast('toast.recipes.deleteFailed', { message: error.message }, 'error'); // Reset button state deleteBtn.textContent = originalText; @@ -333,12 +333,12 @@ class RecipeCard { // Get recipe ID const recipeId = this.recipe.id; if (!recipeId) { - showToast('Cannot share recipe: Missing recipe ID', 'error'); + showToast('toast.recipes.cannotShare', {}, 'error'); return; } // Show loading toast - showToast('Preparing recipe for sharing...', 'info'); + showToast('toast.recipes.preparingForSharing', {}, 'info'); // Call the API to process the image with metadata fetch(`/api/recipe/${recipeId}/share`) @@ -363,15 +363,15 @@ class RecipeCard { downloadLink.click(); document.body.removeChild(downloadLink); - showToast('Recipe download started', 'success'); + showToast('toast.recipes.downloadStarted', {}, 'success'); }) .catch(error => { console.error('Error sharing recipe:', error); - showToast('Error sharing recipe: ' + error.message, 'error'); + showToast('toast.recipes.shareError', { message: error.message }, 'error'); }); } catch (error) { console.error('Error sharing recipe:', error); - showToast('Error preparing recipe for sharing', 'error'); + showToast('toast.recipes.sharePreparationError', {}, 'error'); } } } diff --git a/static/js/components/RecipeModal.js b/static/js/components/RecipeModal.js index f4de7dd5..ffbfa2aa 100644 --- a/static/js/components/RecipeModal.js +++ b/static/js/components/RecipeModal.js @@ -526,7 +526,7 @@ class RecipeModal { updateRecipeMetadata(this.filePath, { title: newTitle }) .then(data => { // Show success toast - showToast('Recipe name updated successfully', 'success'); + showToast('toast.recipes.nameUpdated', {}, 'success'); // Update the current recipe object this.currentRecipe.title = newTitle; @@ -596,7 +596,7 @@ class RecipeModal { updateRecipeMetadata(this.filePath, { tags: newTags }) .then(data => { // Show success toast - showToast('Recipe tags updated successfully', 'success'); + showToast('toast.recipes.tagsUpdated', {}, 'success'); // Update the current recipe object this.currentRecipe.tags = newTags; @@ -717,7 +717,7 @@ class RecipeModal { updateRecipeMetadata(this.filePath, { source_path: newSourceUrl }) .then(data => { // Show success toast - showToast('Source URL updated successfully', 'success'); + showToast('toast.recipes.sourceUrlUpdated', {}, 'success'); // Update source URL in the UI sourceUrlText.textContent = newSourceUrl || 'No source URL'; @@ -778,7 +778,7 @@ class RecipeModal { // Fetch recipe syntax from backend and copy to clipboard async fetchAndCopyRecipeSyntax() { if (!this.recipeId) { - showToast('No recipe ID available', 'error'); + showToast('toast.recipes.noRecipeId', {}, 'error'); return; } @@ -800,7 +800,7 @@ class RecipeModal { } } catch (error) { console.error('Error fetching recipe syntax:', error); - showToast(`Error copying recipe syntax: ${error.message}`, 'error'); + showToast('toast.recipes.copyFailed', { message: error.message }, 'error'); } } @@ -817,7 +817,7 @@ class RecipeModal { console.log("missingLoras", missingLoras); if (missingLoras.length === 0) { - showToast('No missing LoRAs to download', 'info'); + showToast('toast.recipes.noMissingLoras', {}, 'info'); return; } @@ -856,7 +856,7 @@ class RecipeModal { const validLoras = lorasWithVersionInfo.filter(lora => lora !== null); if (validLoras.length === 0) { - showToast('Failed to get information for missing LoRAs', 'error'); + showToast('toast.recipes.missingLorasInfoFailed', {}, 'error'); return; } @@ -902,7 +902,7 @@ class RecipeModal { window.importManager.downloadMissingLoras(recipeData, this.currentRecipe.id); } catch (error) { console.error("Error downloading missing LoRAs:", error); - showToast('Error preparing LoRAs for download', 'error'); + showToast('toast.recipes.preparingForDownloadFailed', {}, 'error'); } finally { state.loadingManager.hide(); } @@ -988,7 +988,7 @@ class RecipeModal { async reconnectLora(loraIndex, inputValue) { if (!inputValue || !inputValue.trim()) { - showToast('Please enter a LoRA name or syntax', 'error'); + showToast('toast.recipes.enterLoraName', {}, 'error'); return; } @@ -1026,7 +1026,7 @@ class RecipeModal { this.currentRecipe.loras[loraIndex] = result.updated_lora; // Show success message - showToast('LoRA reconnected successfully', 'success'); + showToast('toast.recipes.reconnectedSuccessfully', {}, 'success'); // Refresh modal to show updated content setTimeout(() => { @@ -1037,11 +1037,11 @@ class RecipeModal { loras: this.currentRecipe.loras }); } else { - showToast(`Error: ${result.error}`, 'error'); + showToast('toast.recipes.reconnectFailed', { message: result.error }, 'error'); } } catch (error) { console.error('Error reconnecting LoRA:', error); - showToast(`Error reconnecting LoRA: ${error.message}`, 'error'); + showToast('toast.recipes.reconnectFailed', { message: error.message }, 'error'); } finally { state.loadingManager.hide(); } diff --git a/static/js/components/shared/showcase/MediaUtils.js b/static/js/components/shared/showcase/MediaUtils.js index 4e8d0d4b..685a85c4 100644 --- a/static/js/components/shared/showcase/MediaUtils.js +++ b/static/js/components/shared/showcase/MediaUtils.js @@ -278,7 +278,7 @@ export function initMetadataPanelHandlers(container) { await copyToClipboard(promptElement.textContent, 'Prompt copied to clipboard'); } catch (err) { console.error('Copy failed:', err); - showToast('Copy failed', 'error'); + showToast('toast.triggerWords.copyFailed', {}, 'error'); } }); }); @@ -432,7 +432,7 @@ export function initMediaControlHandlers(container) { }, 600); // Show success toast - showToast('Example image deleted', 'success'); + showToast('toast.exampleImages.deleted', {}, 'success'); // Create an update object with only the necessary properties const updateData = { @@ -456,7 +456,7 @@ export function initMediaControlHandlers(container) { } } catch (error) { console.error('Error deleting example image:', error); - showToast('Failed to delete example image', 'error'); + showToast('toast.exampleImages.deleteFailed', {}, 'error'); // Reset button state this.disabled = false; @@ -536,7 +536,7 @@ function initSetPreviewHandlers(container) { } } catch (error) { console.error('Error setting preview:', error); - showToast('Failed to set preview image', 'error'); + showToast('toast.exampleImages.setPreviewFailed', {}, 'error'); } finally { // Restore button state this.innerHTML = ''; diff --git a/static/js/components/shared/showcase/ShowcaseView.js b/static/js/components/shared/showcase/ShowcaseView.js index d57725e8..85f9c6f9 100644 --- a/static/js/components/shared/showcase/ShowcaseView.js +++ b/static/js/components/shared/showcase/ShowcaseView.js @@ -412,7 +412,7 @@ async function handleImportFiles(files, modelHash, importContainer) { // Initialize the import UI for the new content initExampleImport(modelHash, showcaseTab); - showToast('Example images imported successfully', 'success'); + showToast('toast.import.imagesImported', {}, 'success'); // Update VirtualScroller if available if (state.virtualScroller && result.model_file_path) { diff --git a/static/js/managers/DownloadManager.js b/static/js/managers/DownloadManager.js index 19849c23..65971ccc 100644 --- a/static/js/managers/DownloadManager.js +++ b/static/js/managers/DownloadManager.js @@ -283,13 +283,13 @@ export class DownloadManager { async proceedToLocation() { if (!this.currentVersion) { - showToast('Please select a version', 'error'); + showToast('toast.loras.pleaseSelectVersion', {}, 'error'); return; } const existsLocally = this.currentVersion.existsLocally; if (existsLocally) { - showToast('This version already exists in your library', 'info'); + showToast('toast.loras.versionExists', {}, 'info'); return; } @@ -480,7 +480,7 @@ export class DownloadManager { downloadId ); - showToast('Download completed successfully', 'success'); + showToast('toast.loras.downloadCompleted', {}, 'success'); modalManager.closeModal('downloadModal'); ws.close(); @@ -523,11 +523,11 @@ export class DownloadManager { await this.folderTreeManager.loadTree(treeData.tree); } else { console.error('Failed to fetch folder tree:', treeData.error); - showToast('Failed to load folder tree', 'error'); + showToast('toast.import.folderTreeFailed', {}, 'error'); } } catch (error) { console.error('Error initializing folder tree:', error); - showToast('Error loading folder tree', 'error'); + showToast('toast.import.folderTreeError', {}, 'error'); } } diff --git a/static/js/managers/ExampleImagesManager.js b/static/js/managers/ExampleImagesManager.js index 396bf95b..f922af45 100644 --- a/static/js/managers/ExampleImagesManager.js +++ b/static/js/managers/ExampleImagesManager.js @@ -142,7 +142,7 @@ class ExampleImagesManager { if (!data.success) { console.error('Failed to update example images path in backend:', data.error); } else { - showToast('Example images path updated successfully', 'success'); + showToast('toast.exampleImages.pathUpdated', {}, 'success'); } } catch (error) { console.error('Failed to update example images path:', error); @@ -187,7 +187,7 @@ class ExampleImagesManager { this.startDownload(); } else { // If download is in progress, show info toast - showToast('Download already in progress', 'info'); + showToast('toast.exampleImages.downloadInProgress', {}, 'info'); } } @@ -243,7 +243,7 @@ class ExampleImagesManager { async startDownload() { if (this.isDownloading) { - showToast('Download already in progress', 'warning'); + showToast('toast.exampleImages.downloadInProgress', {}, 'warning'); return; } @@ -251,7 +251,7 @@ class ExampleImagesManager { const outputDir = document.getElementById('exampleImagesPath').value || ''; if (!outputDir) { - showToast('Please enter a download location first', 'warning'); + showToast('toast.exampleImages.enterLocationFirst', {}, 'warning'); return; } @@ -280,7 +280,7 @@ class ExampleImagesManager { this.showProgressPanel(); this.startProgressUpdates(); this.updateDownloadButtonText(); - showToast('Example images download started', 'success'); + showToast('toast.exampleImages.downloadStarted', {}, 'success'); // Close settings modal modalManager.closeModal('settingsModal'); @@ -289,7 +289,7 @@ class ExampleImagesManager { } } catch (error) { console.error('Failed to start download:', error); - showToast('Failed to start download', 'error'); + showToast('toast.exampleImages.downloadStartFailed', {}, 'error'); } } @@ -319,13 +319,13 @@ class ExampleImagesManager { } this.updateDownloadButtonText(); - showToast('Download paused', 'info'); + showToast('toast.exampleImages.downloadPaused', {}, 'info'); } else { showToast(data.error || 'Failed to pause download', 'error'); } } catch (error) { console.error('Failed to pause download:', error); - showToast('Failed to pause download', 'error'); + showToast('toast.exampleImages.pauseFailed', {}, 'error'); } } @@ -355,13 +355,13 @@ class ExampleImagesManager { } this.updateDownloadButtonText(); - showToast('Download resumed', 'success'); + showToast('toast.exampleImages.downloadResumed', {}, 'success'); } else { showToast(data.error || 'Failed to resume download', 'error'); } } catch (error) { console.error('Failed to resume download:', error); - showToast('Failed to resume download', 'error'); + showToast('toast.exampleImages.resumeFailed', {}, 'error'); } } diff --git a/static/js/managers/FilterManager.js b/static/js/managers/FilterManager.js index 3fba35f5..012f2e24 100644 --- a/static/js/managers/FilterManager.js +++ b/static/js/managers/FilterManager.js @@ -287,7 +287,7 @@ export class FilterManager { } else { this.filterButton.classList.remove('active'); if (showToastNotification) { - showToast('Filters cleared', 'info'); + showToast('toast.filters.cleared', {}, 'info'); } } } diff --git a/static/js/managers/import/DownloadManager.js b/static/js/managers/import/DownloadManager.js index 8ca178b2..55424bf4 100644 --- a/static/js/managers/import/DownloadManager.js +++ b/static/js/managers/import/DownloadManager.js @@ -13,7 +13,7 @@ export class DownloadManager { const isDownloadOnly = !!this.importManager.recipeId; if (!isDownloadOnly && !this.importManager.recipeName) { - showToast('Please enter a recipe name', 'error'); + showToast('toast.import.enterRecipeName', {}, 'error'); return; } @@ -93,10 +93,10 @@ export class DownloadManager { // Show success message if (isDownloadOnly) { if (failedDownloads === 0) { - showToast('LoRAs downloaded successfully', 'success'); + showToast('toast.loras.downloadSuccessful', {}, 'success'); } } else { - showToast(`Recipe "${this.importManager.recipeName}" saved successfully`, 'success'); + showToast('toast.recipes.nameSaved', { name: this.importManager.recipeName }, 'success'); } // Close modal @@ -238,15 +238,19 @@ export class DownloadManager { // Show appropriate completion message based on results if (failedDownloads === 0) { - showToast(`All ${completedDownloads} LoRAs downloaded successfully`, 'success'); + showToast('toast.loras.allDownloadSuccessful', { count: completedDownloads }, 'success'); } else { if (accessFailures > 0) { - showToast( - `Downloaded ${completedDownloads} of ${this.importManager.downloadableLoRAs.length} LoRAs. ${accessFailures} failed due to access restrictions. Check your API key in settings or early access status.`, - 'error' - ); + showToast('toast.loras.downloadPartialWithAccess', { + completed: completedDownloads, + total: this.importManager.downloadableLoRAs.length, + accessFailures: accessFailures + }, 'error'); } else { - showToast(`Downloaded ${completedDownloads} of ${this.importManager.downloadableLoRAs.length} LoRAs`, 'error'); + showToast('toast.loras.downloadPartialSuccess', { + completed: completedDownloads, + total: this.importManager.downloadableLoRAs.length + }, 'error'); } }