feat(localization): update toast messages for improved user feedback and localization support across various components

This commit is contained in:
Will Miao
2025-08-31 16:52:58 +08:00
parent b2428f607c
commit 7bef562541
12 changed files with 68 additions and 95 deletions

View File

@@ -587,17 +587,6 @@
"recipes": "Loading recipes...",
"examples": "Loading examples..."
},
"tags": {
"messages": {
"updated": "Tags updated successfully",
"updateFailed": "Failed to update tags"
},
"validation": {
"maxLength": "Tag should not exceed 30 characters",
"maxCount": "Maximum 30 tags allowed",
"duplicate": "This tag already exists"
}
},
"recipeTab": {
"noRecipesFound": "No recipes found that use this Lora.",
"loadingRecipes": "Loading recipes...",
@@ -716,11 +705,6 @@
"finalizing": "Finalizing..."
}
},
"showcase": {
"exampleImages": {
"deleteFailed": "Failed to delete example image: {error}"
}
},
"duplicates": {
"found": "Found {count} duplicate groups",
"showNotification": "Show Duplicates Notification",
@@ -900,7 +884,11 @@
"renameFailed": "Failed to rename file: {message}",
"moveFailed": "Failed to move model(s): {message}",
"pleaseSelectRoot": "Please select a {type} root directory",
"nameTooLong": "Model name is limited to 100 characters"
"nameTooLong": "Model name is limited to 100 characters",
"verificationAlreadyDone": "This group has already been verified",
"verificationCompleteMismatch": "Verification complete. {count} file(s) have different actual hashes.",
"verificationCompleteSuccess": "Verification complete. All files are confirmed duplicates.",
"verificationFailed": "Failed to verify hashes: {message}"
},
"search": {
"atLeastOneOption": "At least one search option must be selected"
@@ -930,17 +918,6 @@
"cleared": "Filters cleared"
},
"downloads": {
"selectVersion": "Please select a version",
"versionExists": "This version already exists in your library",
"completed": "Download completed successfully",
"alreadyInProgress": "Download already in progress",
"enterLocationFirst": "Please enter a download location first",
"started": "Example images download started",
"startFailed": "Failed to start download",
"paused": "Download paused",
"pauseFailed": "Failed to pause download",
"resumed": "Download resumed",
"resumeFailed": "Failed to resume download",
"imagesCompleted": "Example images {action} completed",
"imagesFailed": "Example images {action} failed",
"loadError": "Error loading downloads: {message}",
@@ -966,12 +943,6 @@
"updateFailed": "Failed to update trigger words",
"copyFailed": "Copy failed"
},
"examples": {
"pathUpdated": "Example images path updated successfully",
"deleted": "Example image deleted",
"deleteFailed": "Failed to delete example image",
"setPreviewFailed": "Failed to set preview image"
},
"virtual": {
"loadFailed": "Failed to load items",
"loadMoreFailed": "Failed to load more items",
@@ -980,19 +951,28 @@
"bulk": {
"unableToSelectAll": "Unable to select all items"
},
"tags": {
"tagTooLong": "Tag is too long (max {max} characters)",
"tooManyTags": "Too many tags (max {max} tags)",
"tagAlreadyExists": "Tag already exists"
"duplicates": {
"findFailed": "Failed to find duplicates: {message}",
"noDuplicatesFound": "No duplicate {type} found",
"noItemsSelected": "No {type} selected for deletion",
"deleteError": "Error: {message}",
"deleteSuccess": "Successfully deleted {count} {type}",
"deleteFailed": "Failed to delete {type}: {message}"
},
"favorites": {
"added": "Added to favorites",
"removed": "Removed from favorites",
"updateFailed": "Failed to update favorite status"
"controls": {
"reloadFailed": "Failed to reload {pageType}: {message}",
"refreshFailed": "Failed to {action} {pageType}: {message}",
"fetchMetadataFailed": "Failed to fetch metadata: {message}",
"clearFilterFailed": "Failed to clear custom filter: {message}"
},
"workflow": {
"checkpointNotImplemented": "Send checkpoint to workflow - feature to be implemented",
"failedToSend": "Failed to send LoRA to workflow"
"contextMenu": {
"contentRatingSet": "Content rating set to {level}",
"contentRatingFailed": "Failed to set content rating: {message}",
"relinkSuccess": "Model successfully re-linked to Civitai",
"relinkFailed": "Error: {message}",
"fetchMetadataFirst": "Please fetch metadata from CivitAI first",
"noCivitaiInfo": "No CivitAI information available",
"missingHash": "Model hash not available"
},
"exampleImages": {
"checkError": "Error checking for example images",

View File

@@ -587,17 +587,6 @@
"recipes": "正在加载配方...",
"examples": "正在加载示例..."
},
"tags": {
"messages": {
"updated": "标签更新成功",
"updateFailed": "更新标签失败"
},
"validation": {
"maxLength": "标签长度不能超过30个字符",
"maxCount": "最多允许30个标签",
"duplicate": "该标签已存在"
}
},
"recipeTab": {
"noRecipesFound": "未找到使用此 LoRA 的配方。",
"loadingRecipes": "正在加载配方...",
@@ -897,7 +886,11 @@
"renameFailed": "重命名文件失败:{message}",
"moveFailed": "移动模型失败:{message}",
"pleaseSelectRoot": "请选择 {type} 根目录",
"nameTooLong": "模型名称限制为100个字符"
"nameTooLong": "模型名称限制为100个字符",
"verificationAlreadyDone": "This group has already been verified",
"verificationCompleteMismatch": "Verification complete. {count} file(s) have different actual hashes.",
"verificationCompleteSuccess": "Verification complete. All files are confirmed duplicates.",
"verificationFailed": "Failed to verify hashes: {message}"
},
"search": {
"atLeastOneOption": "至少需要选择一个搜索选项"

View File

@@ -25,10 +25,10 @@ export const ModelContextMenuMixin = {
try {
await this.saveModelMetadata(filePath, { preview_nsfw_level: level });
showToast(`Content rating set to ${getNSFWLevelName(level)}`, 'success');
showToast('toast.contextMenu.contentRatingSet', { level: getNSFWLevelName(level) }, 'success');
this.nsfwSelector.style.display = 'none';
} catch (error) {
showToast(`Failed to set content rating: ${error.message}`, 'error');
showToast('toast.contextMenu.contentRatingFailed', { message: error.message }, 'error');
}
});
});
@@ -147,7 +147,7 @@ export const ModelContextMenuMixin = {
const data = await response.json();
if (data.success) {
showToast('Model successfully re-linked to Civitai', 'success');
showToast('toast.contextMenu.relinkSuccess', {}, 'success');
// Reload the current view to show updated data
await this.resetAndReload();
} else {
@@ -155,7 +155,7 @@ export const ModelContextMenuMixin = {
}
} catch (error) {
console.error('Error re-linking model:', error);
showToast(`Error: ${error.message}`, 'error');
showToast('toast.contextMenu.relinkFailed', { message: error.message }, 'error');
} finally {
state.loadingManager.hide();
}
@@ -211,10 +211,10 @@ export const ModelContextMenuMixin = {
if (this.currentCard.querySelector('.fa-globe')) {
this.currentCard.querySelector('.fa-globe').click();
} else {
showToast('Please fetch metadata from CivitAI first', 'info');
showToast('toast.contextMenu.fetchMetadataFirst', {}, 'info');
}
} else {
showToast('No CivitAI information available', 'info');
showToast('toast.contextMenu.noCivitaiInfo', {}, 'info');
}
return true;
case 'relink-civitai':
@@ -232,7 +232,7 @@ export const ModelContextMenuMixin = {
async downloadExampleImages() {
const modelHash = this.currentCard.dataset.sha256;
if (!modelHash) {
showToast('Model hash not available', 'error');
showToast('toast.contextMenu.missingHash', {}, 'error');
return;
}

View File

@@ -26,7 +26,7 @@ export class DuplicatesManager {
this.duplicateGroups = data.duplicate_groups || [];
if (this.duplicateGroups.length === 0) {
showToast('No duplicate recipes found', 'info');
showToast('toast.duplicates.noDuplicatesFound', { type: 'recipes' }, 'info');
return false;
}
@@ -34,7 +34,7 @@ export class DuplicatesManager {
return true;
} catch (error) {
console.error('Error finding duplicates:', error);
showToast('Failed to find duplicates: ' + error.message, 'error');
showToast('toast.duplicates.findFailed', { message: error.message }, 'error');
return false;
}
}
@@ -325,7 +325,7 @@ export class DuplicatesManager {
async deleteSelectedDuplicates() {
if (this.selectedForDeletion.size === 0) {
showToast('No recipes selected for deletion', 'info');
showToast('toast.duplicates.noItemsSelected', { type: 'recipes' }, 'info');
return;
}
@@ -340,7 +340,7 @@ export class DuplicatesManager {
modalManager.showModal('duplicateDeleteModal');
} catch (error) {
console.error('Error preparing delete:', error);
showToast('Error: ' + error.message, 'error');
showToast('toast.duplicates.deleteError', { message: error.message }, 'error');
}
}
@@ -371,7 +371,7 @@ export class DuplicatesManager {
throw new Error(data.error || 'Unknown error deleting recipes');
}
showToast(`Successfully deleted ${data.total_deleted} recipes`, 'success');
showToast('toast.duplicates.deleteSuccess', { count: data.total_deleted, type: 'recipes' }, 'success');
// Exit duplicate mode if deletions were successful
if (data.total_deleted > 0) {
@@ -380,7 +380,7 @@ export class DuplicatesManager {
} catch (error) {
console.error('Error deleting recipes:', error);
showToast('Failed to delete recipes: ' + error.message, 'error');
showToast('toast.duplicates.deleteFailed', { type: 'recipes', message: error.message }, 'error');
}
}
}

View File

@@ -122,7 +122,7 @@ export class ModelDuplicatesManager {
this.updateDuplicatesBadge(this.duplicateGroups.length);
if (this.duplicateGroups.length === 0) {
showToast('No duplicate models found', 'info');
showToast('toast.duplicates.noDuplicatesFound', { type: this.modelType }, 'info');
return false;
}
@@ -130,7 +130,7 @@ export class ModelDuplicatesManager {
return true;
} catch (error) {
console.error('Error finding duplicates:', error);
showToast('Failed to find duplicates: ' + error.message, 'error');
showToast('toast.duplicates.findFailed', { message: error.message }, 'error');
return false;
}
}
@@ -594,7 +594,7 @@ export class ModelDuplicatesManager {
async deleteSelectedDuplicates() {
if (this.selectedForDeletion.size === 0) {
showToast('No models selected for deletion', 'info');
showToast('toast.duplicates.noItemsSelected', { type: this.modelType }, 'info');
return;
}
@@ -609,7 +609,7 @@ export class ModelDuplicatesManager {
modalManager.showModal('modelDuplicateDeleteModal');
} catch (error) {
console.error('Error preparing delete:', error);
showToast('Error: ' + error.message, 'error');
showToast('toast.duplicates.deleteError', { message: error.message }, 'error');
}
}
@@ -640,7 +640,7 @@ export class ModelDuplicatesManager {
throw new Error(data.error || 'Unknown error deleting models');
}
showToast(`Successfully deleted ${data.total_deleted} models`, 'success');
showToast('toast.duplicates.deleteSuccess', { count: data.total_deleted, type: this.modelType }, 'success');
// If models were successfully deleted
if (data.total_deleted > 0) {
@@ -678,7 +678,7 @@ export class ModelDuplicatesManager {
} catch (error) {
console.error('Error deleting models:', error);
showToast('Failed to delete models: ' + error.message, 'error');
showToast('toast.duplicates.deleteFailed', { type: this.modelType, message: error.message }, 'error');
}
}
@@ -745,7 +745,7 @@ export class ModelDuplicatesManager {
// Check if already verified
if (this.verifiedGroups.has(groupHash)) {
showToast('This group has already been verified', 'info');
showToast('toast.models.verificationAlreadyDone', {}, 'info');
return;
}
@@ -793,14 +793,14 @@ export class ModelDuplicatesManager {
// Show appropriate toast message
if (mismatchedFiles.length > 0) {
showToast(`Verification complete. ${mismatchedFiles.length} file(s) have different actual hashes.`, 'warning');
showToast('toast.models.verificationCompleteMismatch', { count: mismatchedFiles.length }, 'warning');
} else {
showToast('Verification complete. All files are confirmed duplicates.', 'success');
showToast('toast.models.verificationCompleteSuccess', {}, 'success');
}
} catch (error) {
console.error('Error verifying hashes:', error);
showToast('Failed to verify hashes: ' + error.message, 'error');
showToast('toast.models.verificationFailed', { message: error.message }, 'error');
} finally {
// Hide loading state
state.loadingManager.hide();

View File

@@ -293,7 +293,7 @@ export class PageControls {
}
} catch (error) {
console.error(`Error reloading ${this.pageType}:`, error);
showToast(`Failed to reload ${this.pageType}: ${error.message}`, 'error');
showToast('toast.controls.reloadFailed', { pageType: this.pageType, message: error.message }, 'error');
}
}
@@ -316,7 +316,7 @@ export class PageControls {
}
} catch (error) {
console.error(`Error ${fullRebuild ? 'rebuilding' : 'refreshing'} ${this.pageType}:`, error);
showToast(`Failed to ${fullRebuild ? 'rebuild' : 'refresh'} ${this.pageType}: ${error.message}`, 'error');
showToast('toast.controls.refreshFailed', { action: fullRebuild ? 'rebuild' : 'refresh', pageType: this.pageType, message: error.message }, 'error');
}
if (window.modelDuplicatesManager) {
@@ -338,7 +338,7 @@ export class PageControls {
await this.api.fetchFromCivitai();
} catch (error) {
console.error('Error fetching metadata:', error);
showToast('Failed to fetch metadata: ' + error.message, 'error');
showToast('toast.controls.fetchMetadataFailed', { message: error.message }, 'error');
}
}
@@ -374,7 +374,7 @@ export class PageControls {
await this.api.clearCustomFilter();
} catch (error) {
console.error('Error clearing custom filter:', error);
showToast('Failed to clear custom filter: ' + error.message, 'error');
showToast('toast.controls.clearFilterFailed', { message: error.message }, 'error');
}
}

View File

@@ -162,7 +162,7 @@ function getLoraStatusTitle(totalCount, missingCount) {
*/
function copyRecipeSyntax(recipeId) {
if (!recipeId) {
showToast('Cannot copy recipe syntax: Missing recipe ID', 'error');
showToast('recipeTab.noRecipeId', {}, 'error');
return;
}
@@ -177,7 +177,7 @@ function copyRecipeSyntax(recipeId) {
})
.catch(err => {
console.error('Failed to copy: ', err);
showToast('Failed to copy recipe syntax', 'error');
showToast('recipeTab.copyFailed', {}, 'error');
});
}

View File

@@ -445,7 +445,7 @@ export function initMediaControlHandlers(container) {
state.virtualScroller.updateSingleItem(result.model_file_path, updateData);
} else {
// Show error message
showToast('showcase.exampleImages.deleteFailed', { error: result.error }, 'error');
showToast('toast.exampleImages.deleteFailed', { error: result.error }, 'error');
// Reset button state
this.disabled = false;

View File

@@ -430,7 +430,7 @@ async function handleImportFiles(files, modelHash, importContainer) {
}
} catch (error) {
console.error('Error importing examples:', error);
showToast(`Failed to import example images: ${error.message}`, 'error');
showToast('import.importFailed', { message: error.message }, 'error');
}
}

View File

@@ -343,7 +343,7 @@ export class DownloadManager {
this.updateTargetPath();
} catch (error) {
showToast('downloads.loadError', { message: error.message }, 'error');
showToast('toast.downloads.loadError', { message: error.message }, 'error');
}
}
@@ -418,7 +418,7 @@ export class DownloadManager {
const config = this.apiClient.apiConfig.config;
if (!modelRoot) {
showToast(`Please select a ${config.displayName} root directory`, 'error');
showToast('models.pleaseSelectRoot', { type: config.displayName }, 'error');
return;
}
@@ -507,7 +507,7 @@ export class DownloadManager {
await resetAndReload(true);
} catch (error) {
showToast('downloads.downloadError', { message: error.message }, 'error');
showToast('toast.downloads.downloadError', { message: error.message }, 'error');
} finally {
this.loadingManager.hide();
}

View File

@@ -399,7 +399,7 @@ class ExampleImagesManager {
if (data.status.status === 'completed' && !this.hasShownCompletionToast) {
const actionType = this.isMigrating ? 'migration' : 'download';
showToast(`Example images ${actionType} completed`, 'success');
showToast('toast.downloads.imagesCompleted', { action: actionType }, 'success');
// Mark as shown to prevent duplicate toasts
this.hasShownCompletionToast = true;
// Reset migration flag
@@ -408,7 +408,7 @@ class ExampleImagesManager {
setTimeout(() => this.hideProgressPanel(), 5000);
} else if (data.status.status === 'error') {
const actionType = this.isMigrating ? 'migration' : 'download';
showToast(`Example images ${actionType} failed`, 'error');
showToast('toast.downloads.imagesFailed', { action: actionType }, 'error');
this.isMigrating = false;
}
}

View File

@@ -447,7 +447,7 @@ async function sendToSpecificNode(nodeIds, loraSyntax, replaceMode, syntaxType)
} else {
const messageKey = syntaxType === 'recipe' ?
'uiHelpers.workflow.recipeFailedToSend' :
'toast.workflow.failedToSend';
'uiHelpers.workflow.loraFailedToSend';
showToast(messageKey, {}, 'error');
return false;
}
@@ -455,7 +455,7 @@ async function sendToSpecificNode(nodeIds, loraSyntax, replaceMode, syntaxType)
console.error('Failed to send to workflow:', error);
const messageKey = syntaxType === 'recipe' ?
'uiHelpers.workflow.recipeFailedToSend' :
'toast.workflow.failedToSend';
'uiHelpers.workflow.loraFailedToSend';
showToast(messageKey, {}, 'error');
return false;
}