From e5b557504e4a545eb3074d0791464e37432a6c6b Mon Sep 17 00:00:00 2001 From: Will Miao Date: Sun, 28 Dec 2025 17:50:22 +0800 Subject: [PATCH] feat: Add context menu option to move checkpoint models between type folders and complete various UI translations. --- locales/de.json | 23 ++++++++++----- locales/en.json | 9 +++++- locales/es.json | 23 ++++++++++----- locales/fr.json | 23 ++++++++++----- locales/he.json | 23 ++++++++++----- locales/ja.json | 23 ++++++++++----- locales/ko.json | 23 ++++++++++----- locales/ru.json | 23 ++++++++++----- locales/zh-CN.json | 23 ++++++++++----- locales/zh-TW.json | 23 ++++++++++----- .../ContextMenu/CheckpointContextMenu.js | 29 ++++++++++++++++--- templates/checkpoints.html | 1 + 12 files changed, 169 insertions(+), 77 deletions(-) diff --git a/locales/de.json b/locales/de.json index db8ff981..b8d57be9 100644 --- a/locales/de.json +++ b/locales/de.json @@ -532,7 +532,7 @@ "replacePreview": "Vorschau ersetzen", "setContentRating": "Inhaltsbewertung festlegen", "moveToFolder": "In Ordner verschieben", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "Metadaten reparieren", "excludeModel": "Modell ausschließen", "deleteModel": "Modell löschen", "shareRecipe": "Rezept teilen", @@ -650,16 +650,23 @@ "prepareError": "Fehler beim Vorbereiten der LoRAs für den Download: {message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "Rezept-Metadaten werden repariert...", + "success": "Rezept-Metadaten erfolgreich repariert", + "skipped": "Rezept bereits in der neuesten Version, keine Reparatur erforderlich", + "failed": "Rezept-Reparatur fehlgeschlagen: {message}", + "missingId": "Rezept kann nicht repariert werden: Fehlende Rezept-ID" } } }, "checkpoints": { - "title": "Checkpoint-Modelle" + "title": "Checkpoint-Modelle", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "In {otherType}-Ordner verschieben" + } }, "embeddings": { "title": "Embedding-Modelle" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index 9a42f6b2..3ffce319 100644 --- a/locales/en.json +++ b/locales/en.json @@ -659,7 +659,14 @@ } }, "checkpoints": { - "title": "Checkpoint Models" + "title": "Checkpoint Models", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "Move to {otherType} Folder" + } }, "embeddings": { "title": "Embedding Models" diff --git a/locales/es.json b/locales/es.json index 5db138f9..492b2c0e 100644 --- a/locales/es.json +++ b/locales/es.json @@ -532,7 +532,7 @@ "replacePreview": "Reemplazar vista previa", "setContentRating": "Establecer clasificación de contenido", "moveToFolder": "Mover a carpeta", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "Reparar metadatos", "excludeModel": "Excluir modelo", "deleteModel": "Eliminar modelo", "shareRecipe": "Compartir receta", @@ -650,16 +650,23 @@ "prepareError": "Error preparando LoRAs para descarga: {message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "Reparando metadatos de la receta...", + "success": "Metadatos de la receta reparados con éxito", + "skipped": "La receta ya está en la última versión, no se necesita reparación", + "failed": "Error al reparar la receta: {message}", + "missingId": "No se puede reparar la receta: falta el ID de la receta" } } }, "checkpoints": { - "title": "Modelos checkpoint" + "title": "Modelos checkpoint", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "Mover a la carpeta {otherType}" + } }, "embeddings": { "title": "Modelos embedding" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/locales/fr.json b/locales/fr.json index f6b7c4e4..ceb9f575 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -532,7 +532,7 @@ "replacePreview": "Remplacer l'aperçu", "setContentRating": "Définir la classification du contenu", "moveToFolder": "Déplacer vers un dossier", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "Réparer les métadonnées", "excludeModel": "Exclure le modèle", "deleteModel": "Supprimer le modèle", "shareRecipe": "Partager la recipe", @@ -650,16 +650,23 @@ "prepareError": "Erreur lors de la préparation des LoRAs pour le téléchargement : {message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "Réparation des métadonnées de la recette...", + "success": "Métadonnées de la recette réparées avec succès", + "skipped": "Recette déjà à la version la plus récente, aucune réparation nécessaire", + "failed": "Échec de la réparation de la recette : {message}", + "missingId": "Impossible de réparer la recette : ID de recette manquant" } } }, "checkpoints": { - "title": "Modèles Checkpoint" + "title": "Modèles Checkpoint", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "Déplacer vers le dossier {otherType}" + } }, "embeddings": { "title": "Modèles Embedding" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/locales/he.json b/locales/he.json index 88a325ed..9ab2df93 100644 --- a/locales/he.json +++ b/locales/he.json @@ -532,7 +532,7 @@ "replacePreview": "החלף תצוגה מקדימה", "setContentRating": "הגדר דירוג תוכן", "moveToFolder": "העבר לתיקייה", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "תיקון מטא-דאטה", "excludeModel": "החרג מודל", "deleteModel": "מחק מודל", "shareRecipe": "שתף מתכון", @@ -650,16 +650,23 @@ "prepareError": "שגיאה בהכנת LoRAs להורדה: {message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "מתקן מטא-דאטה של מתכון...", + "success": "מטא-דאטה של מתכון תוקן בהצלחה", + "skipped": "המתכון כבר בגרסה העדכנית ביותר, אין צורך בתיקון", + "failed": "תיקון המתכון נכשל: {message}", + "missingId": "לא ניתן לתקן את המתכון: חסר מזהה מתכון" } } }, "checkpoints": { - "title": "מודלי Checkpoint" + "title": "מודלי Checkpoint", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "העבר לתיקיית {otherType}" + } }, "embeddings": { "title": "מודלי Embedding" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/locales/ja.json b/locales/ja.json index 2e6e44e3..cb915db6 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -532,7 +532,7 @@ "replacePreview": "プレビューを置換", "setContentRating": "コンテンツレーティングを設定", "moveToFolder": "フォルダに移動", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "メタデータを修復", "excludeModel": "モデルを除外", "deleteModel": "モデルを削除", "shareRecipe": "レシピを共有", @@ -650,16 +650,23 @@ "prepareError": "ダウンロード用LoRAの準備中にエラー:{message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "レシピのメタデータを修復中...", + "success": "レシピのメタデータが正常に修復されました", + "skipped": "レシピはすでに最新バージョンです。修復は不要です", + "failed": "レシピの修復に失敗しました: {message}", + "missingId": "レシピを修復できません: レシピIDがありません" } } }, "checkpoints": { - "title": "Checkpointモデル" + "title": "Checkpointモデル", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "{otherType} フォルダに移動" + } }, "embeddings": { "title": "Embeddingモデル" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/locales/ko.json b/locales/ko.json index 35d83a25..931b0d4a 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -532,7 +532,7 @@ "replacePreview": "미리보기 교체", "setContentRating": "콘텐츠 등급 설정", "moveToFolder": "폴더로 이동", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "메타데이터 복구", "excludeModel": "모델 제외", "deleteModel": "모델 삭제", "shareRecipe": "레시피 공유", @@ -650,16 +650,23 @@ "prepareError": "LoRA 다운로드 준비 중 오류: {message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "레시피 메타데이터 복구 중...", + "success": "레시피 메타데이터가 성공적으로 복구되었습니다", + "skipped": "레시피가 이미 최신 버전입니다. 복구가 필요하지 않습니다", + "failed": "레시피 복구 실패: {message}", + "missingId": "레시피를 복구할 수 없음: 레시피 ID 누락" } } }, "checkpoints": { - "title": "Checkpoint 모델" + "title": "Checkpoint 모델", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "{otherType} 폴더로 이동" + } }, "embeddings": { "title": "Embedding 모델" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/locales/ru.json b/locales/ru.json index 3f84c47a..b95ff490 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -532,7 +532,7 @@ "replacePreview": "Заменить превью", "setContentRating": "Установить рейтинг контента", "moveToFolder": "Переместить в папку", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "Восстановить метаданные", "excludeModel": "Исключить модель", "deleteModel": "Удалить модель", "shareRecipe": "Поделиться рецептом", @@ -650,16 +650,23 @@ "prepareError": "Ошибка подготовки LoRAs для загрузки: {message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "Восстановление метаданных рецепта...", + "success": "Метаданные рецепта успешно восстановлены", + "skipped": "Рецепт уже последней версии, восстановление не требуется", + "failed": "Не удалось восстановить рецепт: {message}", + "missingId": "Не удалось восстановить рецепт: отсутствует ID рецепта" } } }, "checkpoints": { - "title": "Модели Checkpoint" + "title": "Модели Checkpoint", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "Переместить в папку {otherType}" + } }, "embeddings": { "title": "Модели Embedding" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 223cce17..968beb8e 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -532,7 +532,7 @@ "replacePreview": "替换预览", "setContentRating": "设置内容评级", "moveToFolder": "移动到文件夹", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "修复元数据", "excludeModel": "排除模型", "deleteModel": "删除模型", "shareRecipe": "分享配方", @@ -650,16 +650,23 @@ "prepareError": "准备下载 LoRA 时出错:{message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "正在修复配方元数据...", + "success": "配方元数据修复成功", + "skipped": "配方已是最新版本,无需修复", + "failed": "修复配方失败:{message}", + "missingId": "无法修复配方:缺少配方 ID" } } }, "checkpoints": { - "title": "Checkpoint 模型" + "title": "Checkpoint 模型", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "移动到 {otherType} 文件夹" + } }, "embeddings": { "title": "Embedding 模型" @@ -1518,4 +1525,4 @@ "learnMore": "浏览器插件教程" } } -} +} \ No newline at end of file diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 20761107..77a713d0 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -532,7 +532,7 @@ "replacePreview": "更換預覽圖", "setContentRating": "設定內容分級", "moveToFolder": "移動到資料夾", - "repairMetadata": "[TODO: Translate] Repair metadata", + "repairMetadata": "修復元數據", "excludeModel": "排除模型", "deleteModel": "刪除模型", "shareRecipe": "分享配方", @@ -650,16 +650,23 @@ "prepareError": "準備下載 LoRA 時發生錯誤:{message}" }, "repair": { - "starting": "[TODO: Translate] Repairing recipe metadata...", - "success": "[TODO: Translate] Recipe metadata repaired successfully", - "skipped": "[TODO: Translate] Recipe already at latest version, no repair needed", - "failed": "[TODO: Translate] Failed to repair recipe: {message}", - "missingId": "[TODO: Translate] Cannot repair recipe: Missing recipe ID" + "starting": "正在修復配方元數據...", + "success": "配方元數據修復成功", + "skipped": "配方已是最新版本,無需修復", + "failed": "修復配方失敗:{message}", + "missingId": "無法修復配方:缺少配方 ID" } } }, "checkpoints": { - "title": "Checkpoint 模型" + "title": "Checkpoint 模型", + "modelTypes": { + "checkpoint": "Checkpoint", + "diffusion_model": "Diffusion Model" + }, + "contextMenu": { + "moveToOtherTypeFolder": "移動到 {otherType} 資料夾" + } }, "embeddings": { "title": "Embedding 模型" @@ -1518,4 +1525,4 @@ "learnMore": "LM Civitai Extension Tutorial" } } -} +} \ No newline at end of file diff --git a/static/js/components/ContextMenu/CheckpointContextMenu.js b/static/js/components/ContextMenu/CheckpointContextMenu.js index 0375784c..9c2f88a4 100644 --- a/static/js/components/ContextMenu/CheckpointContextMenu.js +++ b/static/js/components/ContextMenu/CheckpointContextMenu.js @@ -3,6 +3,7 @@ import { ModelContextMenuMixin } from './ModelContextMenuMixin.js'; import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { showDeleteModal, showExcludeModal } from '../../utils/modalUtils.js'; import { moveManager } from '../../managers/MoveManager.js'; +import { i18n } from '../../i18n/index.js'; export class CheckpointContextMenu extends BaseContextMenu { constructor() { @@ -10,15 +11,28 @@ export class CheckpointContextMenu extends BaseContextMenu { this.nsfwSelector = document.getElementById('nsfwLevelSelector'); this.modelType = 'checkpoint'; this.resetAndReload = resetAndReload; - + this.initNSFWSelector(); } - + // Implementation needed by the mixin async saveModelMetadata(filePath, data) { return getModelApiClient().saveModelMetadata(filePath, data); } - + + showMenu(x, y, card) { + super.showMenu(x, y, card); + + // Update the "Move to other root" label based on current model type + const moveOtherItem = this.menu.querySelector('[data-action="move-other"]'); + if (moveOtherItem) { + const currentType = card.dataset.model_type || 'checkpoint'; + const otherType = currentType === 'checkpoint' ? 'diffusion_model' : 'checkpoint'; + const typeLabel = i18n.t(`checkpoints.modelTypes.${otherType}`); + moveOtherItem.innerHTML = ` ${i18n.t('checkpoints.contextMenu.moveToOtherTypeFolder', { otherType: typeLabel })}`; + } + } + handleMenuAction(action) { // First try to handle with common actions if (ModelContextMenuMixin.handleCommonMenuActions.call(this, action)) { @@ -28,7 +42,7 @@ export class CheckpointContextMenu extends BaseContextMenu { const apiClient = getModelApiClient(); // Otherwise handle checkpoint-specific actions - switch(action) { + switch (action) { case 'details': // Show checkpoint details this.currentCard.click(); @@ -53,6 +67,13 @@ export class CheckpointContextMenu extends BaseContextMenu { case 'move': moveManager.showMoveModal(this.currentCard.dataset.filepath, this.currentCard.dataset.model_type); break; + case 'move-other': + { + const currentType = this.currentCard.dataset.model_type || 'checkpoint'; + const otherType = currentType === 'checkpoint' ? 'diffusion_model' : 'checkpoint'; + moveManager.showMoveModal(this.currentCard.dataset.filepath, otherType); + } + break; case 'exclude': showExcludeModal(this.currentCard.dataset.filepath); break; diff --git a/templates/checkpoints.html b/templates/checkpoints.html index fd3498da..26f7368e 100644 --- a/templates/checkpoints.html +++ b/templates/checkpoints.html @@ -19,6 +19,7 @@
{{ t('loras.contextMenu.setContentRating') }}
{{ t('loras.contextMenu.moveToFolder') }}
+
{{ t('checkpoints.contextMenu.moveToOtherTypeFolder', {otherType: '...'}) }}
{{ t('loras.contextMenu.excludeModel') }}
{{ t('loras.contextMenu.deleteModel') }}