diff --git a/locales/en.json b/locales/en.json index 6d1cbf03..0f1ed6c9 100644 --- a/locales/en.json +++ b/locales/en.json @@ -830,7 +830,8 @@ "filenameCannotBeEmpty": "File name cannot be empty", "renameFailed": "Failed to rename file: {message}", "moveFailed": "Failed to move model(s): {message}", - "pleaseSelectRoot": "Please select a {type} root directory" + "pleaseSelectRoot": "Please select a {type} root directory", + "nameTooLong": "Model name is limited to 100 characters" }, "search": { "atLeastOneOption": "At least one search option must be selected" @@ -887,7 +888,7 @@ "tooLong": "Trigger word should not exceed 30 words", "tooMany": "Maximum 30 trigger words allowed", "alreadyExists": "This trigger word already exists", - "updated": "Trigger words updated successfully", + "updateSuccess": "Trigger words updated successfully", "updateFailed": "Failed to update trigger words", "copyFailed": "Copy failed" }, @@ -923,6 +924,34 @@ "checkError": "Error checking for example images", "missingHash": "Missing model hash information.", "noRemoteImages": "No remote example images available for this model on Civitai" + }, + "api": { + "fetchFailed": "Failed to fetch {type}s: {message}", + "reloadFailed": "Failed to reload {type}s: {message}", + "deleteSuccess": "{type} deleted successfully", + "deleteFailed": "Failed to delete {type}: {message}", + "excludeSuccess": "{type} excluded successfully", + "excludeFailed": "Failed to exclude {type}: {message}", + "fileNameUpdated": "File name updated successfully", + "fileRenameFailed": "Failed to rename file: {error}", + "previewUpdated": "Preview updated successfully", + "previewUploadFailed": "Failed to upload preview image", + "refreshComplete": "{action} complete", + "refreshFailed": "Failed to {action} {type}s", + "metadataUpdateComplete": "Metadata update complete", + "metadataFetchFailed": "Failed to fetch metadata: {message}", + "bulkMetadataFailed": "Failed to refresh metadata: {message}", + "moveNotSupported": "Moving {type}s is not supported", + "alreadyInFolder": "{type} is already in the selected folder", + "moveInfo": "{message}", + "moveSuccess": "{type} moved successfully", + "bulkMoveNotSupported": "Moving {type}s is not supported", + "allAlreadyInFolder": "All selected {type}s are already in the target folder", + "bulkMovePartial": "Moved {successCount} {type}s, {failureCount} failed", + "bulkMoveFailures": "Failed moves:\n{failures}", + "bulkMoveSuccess": "Successfully moved {successCount} {type}s", + "exampleImagesDownloadSuccess": "Successfully downloaded example images!", + "exampleImagesDownloadFailed": "Failed to download example images: {message}" } } } diff --git a/locales/zh-CN.json b/locales/zh-CN.json index eb882abd..d976309b 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -786,15 +786,91 @@ "deleteFailed": "错误:{error}", "deleteFailedGeneral": "删除模型失败", "selectedAdditional": "额外选择了 {count} 个{type}", - "refreshMetadataFailed": "刷新元数据失败" + "refreshMetadataFailed": "刷新元数据失败", + "nameCannotBeEmpty": "模型名称不能为空", + "nameUpdatedSuccessfully": "模型名称更新成功", + "nameUpdateFailed": "模型名称更新失败", + "baseModelUpdated": "基础模型更新成功", + "baseModelUpdateFailed": "基础模型更新失败", + "invalidCharactersRemoved": "文件名中的无效字符已移除", + "filenameCannotBeEmpty": "文件名不能为空", + "renameFailed": "重命名文件失败:{message}", + "moveFailed": "移动模型失败:{message}", + "pleaseSelectRoot": "请选择 {type} 根目录", + "nameTooLong": "模型名称限制为100个字符" }, "search": { "atLeastOneOption": "至少需要选择一个搜索选项" }, + "settings": { + "loraRootsFailed": "加载 LoRA 根目录失败:{message}", + "checkpointRootsFailed": "加载检查点根目录失败:{message}", + "embeddingRootsFailed": "加载嵌入根目录失败:{message}", + "mappingsUpdated": "基础模型路径映射已更新 ({count} 个映射{plural})", + "mappingsCleared": "基础模型路径映射已清除", + "mappingSaveFailed": "保存基础模型映射失败:{message}", + "downloadTemplatesUpdated": "下载路径模板已更新", + "downloadTemplatesFailed": "保存下载路径模板失败:{message}", + "settingsUpdated": "设置已更新:{setting}", + "compactModeToggled": "紧凑模式 {state}", + "compactModeEnabled": "已启用", + "compactModeDisabled": "已禁用", + "settingSaveFailed": "保存设置失败:{message}", + "displayDensitySet": "显示密度设置为 {density}", + "languageChangeFailed": "更改语言失败:{message}", + "cacheCleared": "缓存文件已成功清除。缓存将在下次操作时重建。", + "cacheClearFailed": "清除缓存失败:{error}", + "cacheClearError": "清除缓存错误:{message}" + }, + "import": { + "enterRecipeName": "请输入配方名称", + "selectImageFirst": "请先选择图像", + "folderTreeFailed": "加载文件夹树失败", + "folderTreeError": "加载文件夹树错误", + "imagesImported": "示例图片导入成功", + "importFailed": "导入示例图片失败:{message}" + }, "virtual": { "loadFailed": "加载项目失败", "loadMoreFailed": "加载更多项目失败", "loadPositionFailed": "在此位置加载项目失败" + }, + "triggerWords": { + "loadFailed": "无法加载训练词汇", + "tooLong": "触发词不应超过30个单词", + "tooMany": "最多允许30个触发词", + "alreadyExists": "此触发词已存在", + "updateSuccess": "触发词更新成功", + "updateFailed": "触发词更新失败", + "copyFailed": "复制失败" + }, + "api": { + "fetchFailed": "获取 {type} 失败:{message}", + "reloadFailed": "重新加载 {type} 失败:{message}", + "deleteSuccess": "{type} 删除成功", + "deleteFailed": "删除 {type} 失败:{message}", + "excludeSuccess": "{type} 排除成功", + "excludeFailed": "排除 {type} 失败:{message}", + "fileNameUpdated": "文件名更新成功", + "fileRenameFailed": "重命名文件失败:{error}", + "previewUpdated": "预览图更新成功", + "previewUploadFailed": "上传预览图失败", + "refreshComplete": "{action} 完成", + "refreshFailed": "{action} {type} 失败", + "metadataUpdateComplete": "元数据更新完成", + "metadataFetchFailed": "获取元数据失败:{message}", + "bulkMetadataFailed": "刷新元数据失败:{message}", + "moveNotSupported": "不支持移动 {type}", + "alreadyInFolder": "{type} 已在所选文件夹中", + "moveInfo": "{message}", + "moveSuccess": "{type} 移动成功", + "bulkMoveNotSupported": "不支持移动 {type}", + "allAlreadyInFolder": "所选的所有 {type} 已在目标文件夹中", + "bulkMovePartial": "已移动 {successCount} 个 {type},{failureCount} 个失败", + "bulkMoveFailures": "移动失败:\n{failures}", + "bulkMoveSuccess": "成功移动 {successCount} 个 {type}", + "exampleImagesDownloadSuccess": "示例图片下载成功!", + "exampleImagesDownloadFailed": "示例图片下载失败:{message}" } } } diff --git a/static/js/api/baseModelApi.js b/static/js/api/baseModelApi.js index 0e96dfa5..ec7da5b0 100644 --- a/static/js/api/baseModelApi.js +++ b/static/js/api/baseModelApi.js @@ -76,7 +76,7 @@ export class BaseModelApiClient { } catch (error) { console.error(`Error fetching ${this.apiConfig.config.displayName}s:`, error); - showToast(`Failed to fetch ${this.apiConfig.config.displayName}s: ${error.message}`, 'error'); + showToast('toast.api.fetchFailed', { type: this.apiConfig.config.displayName, message: error.message }, 'error'); throw error; } } @@ -110,7 +110,7 @@ export class BaseModelApiClient { return result; } catch (error) { console.error(`Error reloading ${this.apiConfig.config.displayName}s:`, error); - showToast(`Failed to reload ${this.apiConfig.config.displayName}s: ${error.message}`, 'error'); + showToast('toast.api.reloadFailed', { type: this.apiConfig.config.displayName, message: error.message }, 'error'); throw error; } finally { pageState.isLoading = false; @@ -138,14 +138,14 @@ export class BaseModelApiClient { if (state.virtualScroller) { state.virtualScroller.removeItemByFilePath(filePath); } - showToast(`${this.apiConfig.config.displayName} deleted successfully`, 'success'); + showToast('toast.api.deleteSuccess', { type: this.apiConfig.config.displayName }, 'success'); return true; } else { throw new Error(data.error || `Failed to delete ${this.apiConfig.config.singularName}`); } } catch (error) { console.error(`Error deleting ${this.apiConfig.config.singularName}:`, error); - showToast(`Failed to delete ${this.apiConfig.config.singularName}: ${error.message}`, 'error'); + showToast('toast.api.deleteFailed', { type: this.apiConfig.config.singularName, message: error.message }, 'error'); return false; } finally { state.loadingManager.hide(); @@ -172,14 +172,14 @@ export class BaseModelApiClient { if (state.virtualScroller) { state.virtualScroller.removeItemByFilePath(filePath); } - showToast(`${this.apiConfig.config.displayName} excluded successfully`, 'success'); + showToast('toast.api.excludeSuccess', { type: this.apiConfig.config.displayName }, 'success'); return true; } else { throw new Error(data.error || `Failed to exclude ${this.apiConfig.config.singularName}`); } } catch (error) { console.error(`Error excluding ${this.apiConfig.config.singularName}:`, error); - showToast(`Failed to exclude ${this.apiConfig.config.singularName}: ${error.message}`, 'error'); + showToast('toast.api.excludeFailed', { type: this.apiConfig.config.singularName, message: error.message }, 'error'); return false; } finally { state.loadingManager.hide(); @@ -208,9 +208,9 @@ export class BaseModelApiClient { preview_url: result.new_preview_path }); - showToast('File name updated successfully', 'success'); + showToast('toast.api.fileNameUpdated', {}, 'success'); } else { - showToast('Failed to rename file: ' + (result.error || 'Unknown error'), 'error'); + showToast('toast.api.fileRenameFailed', { error: result.error || 'Unknown error' }, 'error'); } return result; @@ -272,10 +272,10 @@ export class BaseModelApiClient { }; state.virtualScroller.updateSingleItem(filePath, updateData); - showToast('Preview updated successfully', 'success'); + showToast('toast.api.previewUpdated', {}, 'success'); } catch (error) { console.error('Error uploading preview:', error); - showToast('Failed to upload preview image', 'error'); + showToast('toast.api.previewUploadFailed', {}, 'error'); } finally { state.loadingManager.hide(); } @@ -322,10 +322,10 @@ export class BaseModelApiClient { resetAndReload(true); - showToast(`${fullRebuild ? 'Full rebuild' : 'Refresh'} complete`, 'success'); + showToast('toast.api.refreshComplete', { action: fullRebuild ? 'Full rebuild' : 'Refresh' }, 'success'); } catch (error) { console.error('Refresh failed:', error); - showToast(`Failed to ${fullRebuild ? 'rebuild' : 'refresh'} ${this.apiConfig.config.displayName}s`, 'error'); + showToast('toast.api.refreshFailed', { action: fullRebuild ? 'rebuild' : 'refresh', type: this.apiConfig.config.displayName }, 'error'); } finally { state.loadingManager.hide(); state.loadingManager.restoreProgressBar(); @@ -353,14 +353,14 @@ export class BaseModelApiClient { state.virtualScroller.updateSingleItem(filePath, data.metadata); } - showToast('Metadata refreshed successfully', 'success'); + showToast('toast.api.metadataRefreshed', {}, 'success'); return true; } else { throw new Error(data.error || 'Failed to refresh metadata'); } } catch (error) { console.error('Error refreshing metadata:', error); - showToast(error.message, 'error'); + showToast('toast.api.metadataRefreshFailed', { message: error.message }, 'error'); return false; } finally { state.loadingManager.hide(); @@ -432,10 +432,10 @@ export class BaseModelApiClient { await operationComplete; resetAndReload(false); - showToast('Metadata update complete', 'success'); + showToast('toast.api.metadataUpdateComplete', {}, 'success'); } catch (error) { console.error('Error fetching metadata:', error); - showToast('Failed to fetch metadata: ' + error.message, 'error'); + showToast('toast.api.metadataFetchFailed', { message: error.message }, 'error'); } finally { if (ws) { ws.close(); @@ -534,7 +534,7 @@ export class BaseModelApiClient { } catch (error) { console.error('Error in bulk metadata refresh:', error); - showToast(`Failed to refresh metadata: ${error.message}`, 'error'); + showToast('toast.api.bulkMetadataFailed', { message: error.message }, 'error'); await progressController.complete('Operation failed'); throw error; } @@ -708,11 +708,11 @@ export class BaseModelApiClient { async moveSingleModel(filePath, targetPath) { // Only allow move if supported if (!this.apiConfig.config.supportsMove) { - showToast(`Moving ${this.apiConfig.config.displayName}s is not supported`, 'warning'); + showToast('toast.api.moveNotSupported', { type: this.apiConfig.config.displayName }, 'warning'); return null; } if (filePath.substring(0, filePath.lastIndexOf('/')) === targetPath) { - showToast(`${this.apiConfig.config.displayName} is already in the selected folder`, 'info'); + showToast('toast.api.alreadyInFolder', { type: this.apiConfig.config.displayName }, 'info'); return null; } @@ -737,9 +737,9 @@ export class BaseModelApiClient { } if (result && result.message) { - showToast(result.message, 'info'); + showToast('toast.api.moveInfo', { message: result.message }, 'info'); } else { - showToast(`${this.apiConfig.config.displayName} moved successfully`, 'success'); + showToast('toast.api.moveSuccess', { type: this.apiConfig.config.displayName }, 'success'); } if (result.success) { @@ -753,7 +753,7 @@ export class BaseModelApiClient { async moveBulkModels(filePaths, targetPath) { if (!this.apiConfig.config.supportsMove) { - showToast(`Moving ${this.apiConfig.config.displayName}s is not supported`, 'warning'); + showToast('toast.api.bulkMoveNotSupported', { type: this.apiConfig.config.displayName }, 'warning'); return []; } const movedPaths = filePaths.filter(path => { @@ -761,7 +761,7 @@ export class BaseModelApiClient { }); if (movedPaths.length === 0) { - showToast(`All selected ${this.apiConfig.config.displayName}s are already in the target folder`, 'info'); + showToast('toast.api.allAlreadyInFolder', { type: this.apiConfig.config.displayName }, 'info'); return []; } @@ -784,7 +784,11 @@ export class BaseModelApiClient { if (result.success) { if (result.failure_count > 0) { - showToast(`Moved ${result.success_count} ${this.apiConfig.config.displayName}s, ${result.failure_count} failed`, 'warning'); + showToast('toast.api.bulkMovePartial', { + successCount: result.success_count, + type: this.apiConfig.config.displayName, + failureCount: result.failure_count + }, 'warning'); console.log('Move operation results:', result.results); const failedFiles = result.results .filter(r => !r.success) @@ -796,10 +800,13 @@ export class BaseModelApiClient { const failureMessage = failedFiles.length <= 3 ? failedFiles.join('\n') : failedFiles.slice(0, 3).join('\n') + `\n(and ${failedFiles.length - 3} more)`; - showToast(`Failed moves:\n${failureMessage}`, 'warning', 6000); + showToast('toast.api.bulkMoveFailures', { failures: failureMessage }, 'warning', 6000); } } else { - showToast(`Successfully moved ${result.success_count} ${this.apiConfig.config.displayName}s`, 'success'); + showToast('toast.api.bulkMoveSuccess', { + successCount: result.success_count, + type: this.apiConfig.config.displayName + }, 'success'); } // Return the results array with original_file_path and new_file_path @@ -931,12 +938,12 @@ export class BaseModelApiClient { // Wait for the operation to complete via WebSocket await operationComplete; - showToast('Successfully downloaded example images!', 'success'); + showToast('toast.api.exampleImagesDownloadSuccess', {}, 'success'); return true; } catch (error) { console.error('Error downloading example images:', error); - showToast(`Failed to download example images: ${error.message}`, 'error'); + showToast('toast.api.exampleImagesDownloadFailed', { message: error.message }, 'error'); throw error; } finally { if (ws) { diff --git a/static/js/api/checkpointApi.js b/static/js/api/checkpointApi.js index ce69e999..6181ccac 100644 --- a/static/js/api/checkpointApi.js +++ b/static/js/api/checkpointApi.js @@ -1,5 +1,4 @@ import { BaseModelApiClient } from './baseModelApi.js'; -import { showToast } from '../utils/uiHelpers.js'; /** * Checkpoint-specific API client diff --git a/static/js/api/embeddingApi.js b/static/js/api/embeddingApi.js index e266550e..d7eb7c2a 100644 --- a/static/js/api/embeddingApi.js +++ b/static/js/api/embeddingApi.js @@ -1,5 +1,4 @@ import { BaseModelApiClient } from './baseModelApi.js'; -import { showToast } from '../utils/uiHelpers.js'; /** * Embedding-specific API client diff --git a/static/js/components/controls/CheckpointsControls.js b/static/js/components/controls/CheckpointsControls.js index 2ddeb990..b9333d82 100644 --- a/static/js/components/controls/CheckpointsControls.js +++ b/static/js/components/controls/CheckpointsControls.js @@ -47,7 +47,7 @@ export class CheckpointsControls extends PageControls { // No clearCustomFilter implementation is needed for checkpoints // as custom filters are currently only used for LoRAs clearCustomFilter: async () => { - showToast('No custom filter to clear', 'info'); + showToast('toast.filters.noCustomFilterToClear', {}, 'info'); } }; diff --git a/static/js/components/controls/EmbeddingsControls.js b/static/js/components/controls/EmbeddingsControls.js index 612ece4c..57527a72 100644 --- a/static/js/components/controls/EmbeddingsControls.js +++ b/static/js/components/controls/EmbeddingsControls.js @@ -47,7 +47,7 @@ export class EmbeddingsControls extends PageControls { // No clearCustomFilter implementation is needed for embeddings // as custom filters are currently only used for LoRAs clearCustomFilter: async () => { - showToast('No custom filter to clear', 'info'); + showToast('toast.filters.noCustomFilterToClear', {}, 'info'); } }; diff --git a/static/js/components/shared/ModelMetadata.js b/static/js/components/shared/ModelMetadata.js index a3089334..9d63ed0b 100644 --- a/static/js/components/shared/ModelMetadata.js +++ b/static/js/components/shared/ModelMetadata.js @@ -83,8 +83,7 @@ export function setupModelNameEditing(filePath) { sel.removeAllRanges(); sel.addRange(range); - const text = translate('modelMetadata.validation.nameTooLong', {}, 'Model name is limited to 100 characters'); - showToast(text, 'warning'); + showToast('toast.models.nameTooLong', {}, 'warning'); } }); @@ -99,7 +98,7 @@ export function setupModelNameEditing(filePath) { if (!newModelName) { // Restore original value if empty this.textContent = originalValue; - showToast('Model name cannot be empty', 'error'); + showToast('toast.models.nameCannotBeEmpty', {}, 'error'); exitEditMode(); return; } @@ -116,11 +115,11 @@ export function setupModelNameEditing(filePath) { await getModelApiClient().saveModelMetadata(filePath, { model_name: newModelName }); - showToast('Model name updated successfully', 'success'); + showToast('toast.models.nameUpdatedSuccessfully', {}, 'success'); } catch (error) { console.error('Error updating model name:', error); this.textContent = originalValue; // Restore original model name - showToast('Failed to update model name', 'error'); + showToast('toast.models.nameUpdateFailed', {}, 'error'); } finally { exitEditMode(); } @@ -302,9 +301,9 @@ async function saveBaseModel(filePath, originalValue) { try { await getModelApiClient().saveModelMetadata(filePath, { base_model: newBaseModel }); - showToast('Base model updated successfully', 'success'); + showToast('toast.models.baseModelUpdated', {}, 'success'); } catch (error) { - showToast('Failed to update base model', 'error'); + showToast('toast.models.baseModelUpdateFailed', {}, 'error'); } } @@ -390,7 +389,7 @@ export function setupFileNameEditing(filePath) { sel.addRange(range); } - showToast('Invalid characters removed from filename', 'warning'); + showToast('toast.models.invalidCharactersRemoved', {}, 'warning'); } }); @@ -405,7 +404,7 @@ export function setupFileNameEditing(filePath) { if (!newFileName) { // Restore original value if empty this.textContent = originalValue; - showToast('File name cannot be empty', 'error'); + showToast('toast.models.filenameCannotBeEmpty', {}, 'error'); exitEditMode(); return; } @@ -424,7 +423,7 @@ export function setupFileNameEditing(filePath) { } catch (error) { console.error('Error renaming file:', error); this.textContent = originalValue; // Restore original file name - showToast(`Failed to rename file: ${error.message}`, 'error'); + showToast('toast.models.renameFailed', { message: error.message }, 'error'); } finally { exitEditMode(); } diff --git a/static/js/components/shared/TriggerWords.js b/static/js/components/shared/TriggerWords.js index 26323e9b..c73dacfe 100644 --- a/static/js/components/shared/TriggerWords.js +++ b/static/js/components/shared/TriggerWords.js @@ -26,7 +26,7 @@ async function fetchTrainedWords(filePath) { } } catch (error) { console.error('Error fetching trained words:', error); - showToast('Could not load trained words', 'error'); + showToast('toast.triggerWords.loadFailed', {}, 'error'); return { trainedWords: [], classTokens: null }; } } @@ -499,21 +499,21 @@ function addNewTriggerWord(word) { // Validation: Check length if (word.split(/\s+/).length > 30) { - showToast('Trigger word should not exceed 30 words', 'error'); + showToast('toast.triggerWords.tooLong', {}, 'error'); return; } // Validation: Check total number const currentTags = tagsContainer.querySelectorAll('.trigger-word-tag'); if (currentTags.length >= 30) { - showToast('Maximum 30 trigger words allowed', 'error'); + showToast('toast.triggerWords.tooMany', {}, 'error'); return; } // Validation: Check for duplicates const existingWords = Array.from(currentTags).map(tag => tag.dataset.word); if (existingWords.includes(word)) { - showToast('This trigger word already exists', 'error'); + showToast('toast.triggerWords.alreadyExists', {}, 'error'); return; } @@ -628,10 +628,10 @@ async function saveTriggerWords() { if (tagsContainer) tagsContainer.style.display = 'none'; } - showToast('Trigger words updated successfully', 'success'); + showToast('toast.triggerWords.updateSuccess', {}, 'success'); } catch (error) { console.error('Error saving trigger words:', error); - showToast('Failed to update trigger words', 'error'); + showToast('toast.triggerWords.updateFailed', {}, 'error'); } } @@ -644,6 +644,6 @@ window.copyTriggerWord = async function(word) { await copyToClipboard(word, 'Trigger word copied'); } catch (err) { console.error('Copy failed:', err); - showToast('Copy failed', 'error'); + showToast('toast.triggerWords.copyFailed', {}, 'error'); } }; \ No newline at end of file diff --git a/static/js/core.js b/static/js/core.js index 542727dc..eba47200 100644 --- a/static/js/core.js +++ b/static/js/core.js @@ -10,7 +10,7 @@ import { bulkManager } from './managers/BulkManager.js'; import { exampleImagesManager } from './managers/ExampleImagesManager.js'; import { helpManager } from './managers/HelpManager.js'; import { bannerService } from './managers/BannerService.js'; -import { showToast, initTheme, initBackToTop } from './utils/uiHelpers.js'; +import { initTheme, initBackToTop } from './utils/uiHelpers.js'; import { initializeInfiniteScroll } from './utils/infiniteScroll.js'; import { migrateStorageItems } from './utils/storageHelpers.js'; import { i18n } from './i18n/index.js'; @@ -75,11 +75,6 @@ export class AppCore { return body.dataset.page || 'unknown'; } - // Show toast messages - showToast(key, params = {}, type = 'info') { - showToast(key, params, type); - } - // Initialize common UI features based on page type initializePageFeatures() { const pageType = this.getPageType(); diff --git a/static/js/managers/BulkManager.js b/static/js/managers/BulkManager.js index 0f75190a..5dc2bc97 100644 --- a/static/js/managers/BulkManager.js +++ b/static/js/managers/BulkManager.js @@ -350,11 +350,11 @@ export class BulkManager { if (missingLoras.length > 0) { console.warn('Missing metadata for some selected loras:', missingLoras); - showToast(`Missing data for ${missingLoras.length} LoRAs`, 'warning'); + showToast('toast.loras.missingDataForLoras', { count: missingLoras.length }, 'warning'); } if (loraSyntaxes.length === 0) { - showToast('No valid LoRAs to send', 'error'); + showToast('toast.loras.noValidLorasToSend', {}, 'error'); return; } @@ -363,7 +363,7 @@ export class BulkManager { showBulkDeleteModal() { if (state.selectedModels.size === 0) { - showToast('No models selected', 'warning'); + showToast('toast.models.noModelsSelected', {}, 'warning'); return; } @@ -377,7 +377,7 @@ export class BulkManager { async confirmBulkDelete() { if (state.selectedModels.size === 0) { - showToast('No models selected', 'warning'); + showToast('toast.models.noModelsSelected', {}, 'warning'); modalManager.closeModal('bulkDeleteModal'); return; } @@ -392,7 +392,10 @@ export class BulkManager { if (result.success) { const currentConfig = MODEL_CONFIG[state.currentPageType]; - showToast(`Successfully deleted ${result.deleted_count} ${currentConfig.displayName.toLowerCase()}(s)`, 'success'); + showToast('toast.models.deletedSuccessfully', { + count: result.deleted_count, + type: currentConfig.displayName.toLowerCase() + }, 'success'); filePaths.forEach(path => { state.virtualScroller.removeItemByFilePath(path); @@ -403,11 +406,11 @@ export class BulkManager { window.modelDuplicatesManager.updateDuplicatesBadgeAfterRefresh(); } } else { - showToast(`Error: ${result.error || 'Failed to delete models'}`, 'error'); + showToast('toast.models.deleteFailed', { error: result.error || 'Failed to delete models' }, 'error'); } } catch (error) { console.error('Error during bulk delete:', error); - showToast('Failed to delete models', 'error'); + showToast('toast.models.deleteFailedGeneral', {}, 'error'); } } @@ -538,7 +541,7 @@ export class BulkManager { selectAllVisibleModels() { if (!state.virtualScroller || !state.virtualScroller.items) { - showToast('Unable to select all items', 'error'); + showToast('toast.bulk.unableToSelectAll', {}, 'error'); return; } @@ -565,7 +568,10 @@ export class BulkManager { const newlySelected = state.selectedModels.size - oldCount; const currentConfig = MODEL_CONFIG[state.currentPageType]; - showToast(`Selected ${newlySelected} additional ${currentConfig.displayName.toLowerCase()}(s)`, 'success'); + showToast('toast.models.selectedAdditional', { + count: newlySelected, + type: currentConfig.displayName.toLowerCase() + }, 'success'); if (this.isStripVisible) { this.updateThumbnailStrip(); @@ -574,7 +580,7 @@ export class BulkManager { async refreshAllMetadata() { if (state.selectedModels.size === 0) { - showToast('No models selected', 'warning'); + showToast('toast.models.noModelsSelected', {}, 'warning'); return; } @@ -610,7 +616,7 @@ export class BulkManager { } catch (error) { console.error('Error during bulk metadata refresh:', error); - showToast('Failed to refresh metadata', 'error'); + showToast('toast.models.refreshMetadataFailed', {}, 'error'); } } } diff --git a/static/js/managers/FilterManager.js b/static/js/managers/FilterManager.js index e29a86f1..3fba35f5 100644 --- a/static/js/managers/FilterManager.js +++ b/static/js/managers/FilterManager.js @@ -321,7 +321,7 @@ export class FilterManager { await getModelApiClient().loadMoreWithVirtualScroll(true, true); } - showToast(`Filters cleared`, 'info'); + showToast('toast.filters.cleared', {}, 'info'); } loadFiltersFromStorage() { diff --git a/static/js/managers/ImportManager.js b/static/js/managers/ImportManager.js index 1681b478..c8649c8b 100644 --- a/static/js/managers/ImportManager.js +++ b/static/js/managers/ImportManager.js @@ -261,7 +261,7 @@ export class ImportManager { this.updateTargetPath(); } catch (error) { - showToast(error.message, 'error'); + showToast('toast.import.importFailed', { message: error.message }, 'error'); } } @@ -350,11 +350,11 @@ export class ImportManager { 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/MoveManager.js b/static/js/managers/MoveManager.js index 3299fc32..528b2847 100644 --- a/static/js/managers/MoveManager.js +++ b/static/js/managers/MoveManager.js @@ -45,7 +45,7 @@ class MoveManager { if (filePath === 'bulk') { const selectedPaths = Array.from(state.selectedModels); if (selectedPaths.length === 0) { - showToast('No models selected', 'warning'); + showToast('toast.models.noModelsSelected', {}, 'warning'); return; } this.bulkFilePaths = selectedPaths; @@ -116,7 +116,7 @@ class MoveManager { } catch (error) { console.error(`Error fetching ${modelConfig.displayName.toLowerCase()} roots or folders:`, error); - showToast(error.message, 'error'); + showToast('toast.models.moveFailed', { message: error.message }, 'error'); } } @@ -131,11 +131,11 @@ class MoveManager { 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'); } } @@ -163,7 +163,7 @@ class MoveManager { const config = apiClient.apiConfig.config; if (!selectedRoot) { - showToast(`Please select a ${config.displayName.toLowerCase()} root directory`, 'error'); + showToast('toast.models.pleaseSelectRoot', { type: config.displayName.toLowerCase() }, 'error'); return; } @@ -236,7 +236,7 @@ class MoveManager { } catch (error) { console.error('Error moving model(s):', error); - showToast('Failed to move model(s): ' + error.message, 'error'); + showToast('toast.models.moveFailed', { message: error.message }, 'error'); } } } diff --git a/static/js/managers/SettingsManager.js b/static/js/managers/SettingsManager.js index 914d5663..9001dd45 100644 --- a/static/js/managers/SettingsManager.js +++ b/static/js/managers/SettingsManager.js @@ -314,7 +314,7 @@ export class SettingsManager { } catch (error) { console.error('Error loading LoRA roots:', error); - showToast('Failed to load LoRA roots: ' + error.message, 'error'); + showToast('toast.settings.loraRootsFailed', { message: error.message }, 'error'); } } @@ -353,7 +353,7 @@ export class SettingsManager { } catch (error) { console.error('Error loading checkpoint roots:', error); - showToast('Failed to load checkpoint roots: ' + error.message, 'error'); + showToast('toast.settings.checkpointRootsFailed', { message: error.message }, 'error'); } } @@ -392,7 +392,7 @@ export class SettingsManager { } catch (error) { console.error('Error loading embedding roots:', error); - showToast('Failed to load embedding roots: ' + error.message, 'error'); + showToast('toast.settings.embeddingRootsFailed', { message: error.message }, 'error'); } } @@ -560,14 +560,17 @@ export class SettingsManager { // Show success toast const mappingCount = Object.keys(state.global.settings.base_model_path_mappings).length; if (mappingCount > 0) { - showToast(`Base model path mappings updated (${mappingCount} mapping${mappingCount !== 1 ? 's' : ''})`, 'success'); + showToast('toast.settings.mappingsUpdated', { + count: mappingCount, + plural: mappingCount !== 1 ? 's' : '' + }, 'success'); } else { - showToast('Base model path mappings cleared', 'success'); + showToast('toast.settings.mappingsCleared', {}, 'success'); } } catch (error) { console.error('Error saving base model mappings:', error); - showToast('Failed to save base model mappings: ' + error.message, 'error'); + showToast('toast.settings.mappingSaveFailed', { message: error.message }, 'error'); } } @@ -744,11 +747,11 @@ export class SettingsManager { throw new Error('Failed to save download path templates'); } - showToast('Download path templates updated', 'success'); + showToast('toast.settings.downloadTemplatesUpdated', {}, 'success'); } catch (error) { console.error('Error saving download path templates:', error); - showToast('Failed to save download path templates: ' + error.message, 'error'); + showToast('toast.settings.downloadTemplatesFailed', { message: error.message }, 'error'); } } @@ -809,7 +812,7 @@ export class SettingsManager { } } - showToast(`Settings updated: ${settingKey.replace(/_/g, ' ')}`, 'success'); + showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success'); // Apply frontend settings immediately this.applyFrontendSettings(); @@ -830,11 +833,13 @@ export class SettingsManager { // Recalculate layout when compact mode changes if (settingKey === 'compact_mode' && state.virtualScroller) { state.virtualScroller.calculateLayout(); - showToast(`Compact Mode ${value ? 'enabled' : 'disabled'}`, 'success'); + showToast('toast.settings.compactModeToggled', { + state: value ? 'toast.settings.compactModeEnabled' : 'toast.settings.compactModeDisabled' + }, 'success'); } } catch (error) { - showToast('Failed to save setting: ' + error.message, 'error'); + showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error'); } } @@ -888,7 +893,7 @@ export class SettingsManager { throw new Error('Failed to save setting'); } - showToast(`Settings updated: ${settingKey.replace(/_/g, ' ')}`, 'success'); + showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success'); } // Apply frontend settings immediately @@ -902,11 +907,11 @@ export class SettingsManager { if (value === 'medium') densityName = "Medium"; if (value === 'compact') densityName = "Compact"; - showToast(`Display Density set to ${densityName}`, 'success'); + showToast('toast.settings.displayDensitySet', { density: densityName }, 'success'); } } catch (error) { - showToast('Failed to save setting: ' + error.message, 'error'); + showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error'); } } @@ -945,10 +950,10 @@ export class SettingsManager { throw new Error('Failed to save setting'); } - showToast(`Settings updated: ${settingKey.replace(/_/g, ' ')}`, 'success'); + showToast('toast.settings.settingsUpdated', { setting: settingKey.replace(/_/g, ' ') }, 'success'); } catch (error) { - showToast('Failed to save setting: ' + error.message, 'error'); + showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error'); } } @@ -984,7 +989,7 @@ export class SettingsManager { window.location.reload(); } catch (error) { - showToast('Failed to change language: ' + error.message, 'error'); + showToast('toast.settings.languageChangeFailed', { message: error.message }, 'error'); } } @@ -1019,15 +1024,15 @@ export class SettingsManager { const result = await response.json(); if (result.success) { - showToast('Cache files have been cleared successfully. Cache will rebuild on next action.', 'success'); + showToast('toast.settings.cacheCleared', {}, 'success'); } else { - showToast(`Failed to clear cache: ${result.error}`, 'error'); + showToast('toast.settings.cacheClearFailed', { error: result.error }, 'error'); } // Close the confirmation modal modalManager.closeModal('clearCacheModal'); } catch (error) { - showToast(`Error clearing cache: ${error.message}`, 'error'); + showToast('toast.settings.cacheClearError', { message: error.message }, 'error'); modalManager.closeModal('clearCacheModal'); } } diff --git a/static/js/managers/import/ImageProcessor.js b/static/js/managers/import/ImageProcessor.js index 264c2d3d..33f5d429 100644 --- a/static/js/managers/import/ImageProcessor.js +++ b/static/js/managers/import/ImageProcessor.js @@ -156,7 +156,7 @@ export class ImageProcessor { async uploadAndAnalyzeImage() { if (!this.importManager.recipeImage) { - showToast('Please select an image first', 'error'); + showToast('toast.import.selectImageFirst', {}, 'error'); return; } diff --git a/static/js/managers/import/RecipeDataManager.js b/static/js/managers/import/RecipeDataManager.js index 6614d4d5..07543e5d 100644 --- a/static/js/managers/import/RecipeDataManager.js +++ b/static/js/managers/import/RecipeDataManager.js @@ -406,7 +406,7 @@ export class RecipeDataManager { proceedFromDetails() { // Validate recipe name if (!this.importManager.recipeName) { - showToast('Please enter a recipe name', 'error'); + showToast('toast.import.enterRecipeName', {}, 'error'); return; }