mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-24 14:42:11 -03:00
Add Chinese (Simplified and Traditional) localization files and implement i18n tests
- Created zh-CN.json and zh-TW.json for Simplified and Traditional Chinese translations respectively. - Added comprehensive test suite in test_i18n.py to validate JSON structure, server-side i18n functionality, and translation completeness across multiple languages.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{% block title %}LoRA Manager{% endblock %}</title>
|
||||
<title>{% block title %}{{ t('header.appTitle') }}{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/loras_static/css/style.css">
|
||||
{% block page_css %}{% endblock %}
|
||||
@@ -77,7 +77,7 @@
|
||||
{% block additional_components %}{% endblock %}
|
||||
|
||||
<!-- Add back-to-top button here -->
|
||||
<button id="backToTopBtn" class="back-to-top" title="Back to top">
|
||||
<button id="backToTopBtn" class="back-to-top" title="{{ t('common.actions.backToTop') }}">
|
||||
<i class="fas fa-chevron-up"></i>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Checkpoints Manager{% endblock %}
|
||||
{% block title %}{{ t('checkpoints.title') }}{% endblock %}
|
||||
{% block page_id %}checkpoints{% endblock %}
|
||||
|
||||
{% block preload %}
|
||||
<link rel="preload" href="/loras_static/js/checkpoints.js" as="script" crossorigin="anonymous">
|
||||
{% endblock %}
|
||||
|
||||
{% block init_title %}Initializing Checkpoints Manager{% endblock %}
|
||||
{% block init_message %}Scanning and building checkpoints cache. This may take a few moments...{% endblock %}
|
||||
{% block init_title %}{{ t('initialization.checkpoints.title') }}{% endblock %}
|
||||
{% block init_message %}{{ t('initialization.checkpoints.message') }}{% endblock %}
|
||||
{% block init_check_url %}/api/checkpoints/list?page=1&page_size=1{% endblock %}
|
||||
|
||||
{% block additional_components %}
|
||||
|
||||
<div id="checkpointContextMenu" class="context-menu" style="display: none;">
|
||||
<div class="context-menu-item" data-action="refresh-metadata"><i class="fas fa-sync"></i> Refresh Civitai Data</div>
|
||||
<div class="context-menu-item" data-action="relink-civitai"><i class="fas fa-link"></i> Re-link to Civitai</div>
|
||||
<div class="context-menu-item" data-action="copyname"><i class="fas fa-copy"></i> Copy Model Filename</div>
|
||||
<div class="context-menu-item" data-action="preview"><i class="fas fa-folder-open"></i> Open Examples Folder</div>
|
||||
<div class="context-menu-item" data-action="download-examples"><i class="fas fa-download"></i> Download Example Images</div>
|
||||
<div class="context-menu-item" data-action="replace-preview"><i class="fas fa-image"></i> Replace Preview</div>
|
||||
<div class="context-menu-item" data-action="set-nsfw"><i class="fas fa-exclamation-triangle"></i> Set Content Rating</div>
|
||||
<div class="context-menu-item" data-action="refresh-metadata"><i class="fas fa-sync"></i> {{ t('contextMenu.refreshMetadata') }}</div>
|
||||
<div class="context-menu-item" data-action="relink-civitai"><i class="fas fa-link"></i> {{ t('contextMenu.relinkCivitai') }}</div>
|
||||
<div class="context-menu-item" data-action="copyname"><i class="fas fa-copy"></i> {{ t('contextMenu.copyFilename') }}</div>
|
||||
<div class="context-menu-item" data-action="preview"><i class="fas fa-folder-open"></i> {{ t('contextMenu.openExamplesFolder') }}</div>
|
||||
<div class="context-menu-item" data-action="download-examples"><i class="fas fa-download"></i> {{ t('contextMenu.downloadExamples') }}</div>
|
||||
<div class="context-menu-item" data-action="replace-preview"><i class="fas fa-image"></i> {{ t('contextMenu.replacePreview') }}</div>
|
||||
<div class="context-menu-item" data-action="set-nsfw"><i class="fas fa-exclamation-triangle"></i> {{ t('contextMenu.setContentRating') }}</div>
|
||||
<div class="context-menu-separator"></div>
|
||||
<div class="context-menu-item" data-action="move"><i class="fas fa-folder-open"></i> Move to Folder</div>
|
||||
<div class="context-menu-item" data-action="exclude"><i class="fas fa-eye-slash"></i> Exclude Model</div>
|
||||
<div class="context-menu-item delete-item" data-action="delete"><i class="fas fa-trash"></i> Delete Model</div>
|
||||
<div class="context-menu-item" data-action="move"><i class="fas fa-folder-open"></i> {{ t('contextMenu.moveToFolder') }}</div>
|
||||
<div class="context-menu-item" data-action="exclude"><i class="fas fa-eye-slash"></i> {{ t('contextMenu.excludeModel') }}</div>
|
||||
<div class="context-menu-item delete-item" data-action="delete"><i class="fas fa-trash"></i> {{ t('contextMenu.deleteModel') }}</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -2,26 +2,26 @@
|
||||
<div id="duplicatesBanner" class="duplicates-banner" style="display: none;">
|
||||
<div class="banner-content">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span id="duplicatesCount">Found 0 duplicate groups</span>
|
||||
<i class="fas fa-question-circle help-icon" id="duplicatesHelp" aria-label="Help information"></i>
|
||||
<span id="duplicatesCount">{{ t('duplicates.found', count=0) }}</span>
|
||||
<i class="fas fa-question-circle help-icon" id="duplicatesHelp" aria-label="{{ t('common.actions.help') }}"></i>
|
||||
<div class="banner-actions">
|
||||
<div class="setting-contro" id="badgeToggleControl">
|
||||
<span>Show Duplicates Notification:</span>
|
||||
<span>{{ t('duplicates.showNotification') }}:</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="badgeToggleInput">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<button class="btn-delete-selected disabled" onclick="modelDuplicatesManager.deleteSelectedDuplicates()">
|
||||
Delete Selected (<span id="duplicatesSelectedCount">0</span>)
|
||||
{{ t('duplicates.deleteSelected') }} (<span id="duplicatesSelectedCount">0</span>)
|
||||
</button>
|
||||
<button class="btn-exit-mode" onclick="modelDuplicatesManager.exitDuplicateMode()">
|
||||
<i class="fas fa-times"></i> Exit Mode
|
||||
<i class="fas fa-times"></i> {{ t('duplicates.exitMode') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="help-tooltip" id="duplicatesHelpTooltip">
|
||||
<p>Identical hashes mean identical model files, even if they have different names or previews.</p>
|
||||
<p>Keep only one version (preferably with better metadata/previews) and safely delete the others.</p>
|
||||
<p>{{ t('duplicates.help.identicalHashes') }}</p>
|
||||
<p>{{ t('duplicates.help.keepOne') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<!-- Folder Navigation Sidebar -->
|
||||
<div class="folder-sidebar" id="folderSidebar">
|
||||
<div class="sidebar-header" id="sidebarHeader">
|
||||
<h3><i class="fas fa-home"></i> <span id="sidebarTitle">Model Root</span></h3>
|
||||
<h3><i class="fas fa-home"></i> <span id="sidebarTitle">{{ t('sidebar.modelRoot') }}</span></h3>
|
||||
<div class="sidebar-header-actions">
|
||||
<button class="sidebar-action-btn" id="sidebarCollapseAll" title="Collapse All Folders">
|
||||
<button class="sidebar-action-btn" id="sidebarCollapseAll" title="{{ t('sidebar.collapseAll') }}">
|
||||
<i class="fas fa-compress-alt"></i>
|
||||
</button>
|
||||
<button class="sidebar-action-btn" id="sidebarPinToggle" title="Pin/Unpin Sidebar">
|
||||
<button class="sidebar-action-btn" id="sidebarPinToggle" title="{{ t('sidebar.pinToggle') }}">
|
||||
<i class="fas fa-thumbtack"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -2,80 +2,79 @@
|
||||
<div class="initialization-container" id="initializationContainer">
|
||||
<div class="initialization-content">
|
||||
<div class="initialization-header">
|
||||
<h2 id="initTitle">{% block init_title %}Initializing{% endblock %}</h2>
|
||||
<p class="init-subtitle" id="initSubtitle">{% block init_message %}Preparing your workspace...{% endblock %}
|
||||
<h2 id="initTitle">{% block init_title %}{{ t('initialization.title') }}{% endblock %}</h2>
|
||||
<p class="init-subtitle" id="initSubtitle">{% block init_message %}{{ t('initialization.message') }}{% endblock %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="loading-content">
|
||||
<div class="loading-spinner"></div>
|
||||
<div class="loading-status" id="progressStatus">Initializing...</div>
|
||||
<div class="loading-status" id="progressStatus">{{ t('initialization.status') }}</div>
|
||||
<!-- Use initialization-specific classes for the progress bar -->
|
||||
<div class="init-progress-container">
|
||||
<div class="init-progress-bar" id="initProgressBar"></div>
|
||||
</div>
|
||||
<div class="progress-details">
|
||||
<span id="progressPercentage">0%</span>
|
||||
<span id="remainingTime">Estimating time...</span>
|
||||
<span id="remainingTime">{{ t('initialization.estimatingTime') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tips-container">
|
||||
<div class="tips-header">
|
||||
<i class="fas fa-lightbulb"></i>
|
||||
<h3>Tips & Tricks</h3>
|
||||
<h3>{{ t('initialization.tips.title') }}</h3>
|
||||
</div>
|
||||
<div class="tips-content">
|
||||
<div class="tip-carousel" id="tipCarousel">
|
||||
<div class="tip-item active">
|
||||
<div class="tip-image">
|
||||
<img src="/loras_static/images/tips/civitai-api.png" alt="Civitai API Setup"
|
||||
<img src="/loras_static/images/tips/civitai-api.png" alt="{{ t('initialization.tips.civitai.alt') }}"
|
||||
onerror="this.src='/loras_static/images/no-preview.png'">
|
||||
</div>
|
||||
<div class="tip-text">
|
||||
<h4>Civitai Integration</h4>
|
||||
<p>Connect your Civitai account: Visit Profile Avatar → Settings → API Keys → Add API Key,
|
||||
then paste it in Lora Manager settings.</p>
|
||||
<h4>{{ t('initialization.tips.civitai.title') }}</h4>
|
||||
<p>{{ t('initialization.tips.civitai.description') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<div class="tip-image">
|
||||
<img src="/loras_static/images/tips/civitai-download.png" alt="Civitai Download"
|
||||
<img src="/loras_static/images/tips/civitai-download.png" alt="{{ t('initialization.tips.download.alt') }}"
|
||||
onerror="this.src='/loras_static/images/no-preview.png'">
|
||||
</div>
|
||||
<div class="tip-text">
|
||||
<h4>Easy Download</h4>
|
||||
<p>Use Civitai URLs to quickly download and install new models.</p>
|
||||
<h4>{{ t('initialization.tips.download.title') }}</h4>
|
||||
<p>{{ t('initialization.tips.download.description') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<div class="tip-image">
|
||||
<img src="/loras_static/images/tips/recipes.png" alt="Recipes"
|
||||
<img src="/loras_static/images/tips/recipes.png" alt="{{ t('initialization.tips.recipes.alt') }}"
|
||||
onerror="this.src='/loras_static/images/no-preview.png'">
|
||||
</div>
|
||||
<div class="tip-text">
|
||||
<h4>Save Recipes</h4>
|
||||
<p>Create recipes to save your favorite model combinations for future use.</p>
|
||||
<h4>{{ t('initialization.tips.recipes.title') }}</h4>
|
||||
<p>{{ t('initialization.tips.recipes.description') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<div class="tip-image">
|
||||
<img src="/loras_static/images/tips/filter.png" alt="Filter Models"
|
||||
<img src="/loras_static/images/tips/filter.png" alt="{{ t('initialization.tips.filter.alt') }}"
|
||||
onerror="this.src='/loras_static/images/no-preview.png'">
|
||||
</div>
|
||||
<div class="tip-text">
|
||||
<h4>Fast Filtering</h4>
|
||||
<p>Filter models by tags or base model type using the filter button in the header.</p>
|
||||
<h4>{{ t('initialization.tips.filter.title') }}</h4>
|
||||
<p>{{ t('initialization.tips.filter.description') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-item">
|
||||
<div class="tip-image">
|
||||
<img src="/loras_static/images/tips/search.webp" alt="Quick Search"
|
||||
<img src="/loras_static/images/tips/search.webp" alt="{{ t('initialization.tips.search.alt') }}"
|
||||
onerror="this.src='/loras_static/images/no-preview.png'">
|
||||
</div>
|
||||
<div class="tip-text">
|
||||
<h4>Quick Search</h4>
|
||||
<p>Press Ctrl+F (Cmd+F on Mac) to quickly search within your current view.</p>
|
||||
<h4>{{ t('initialization.tips.search.title') }}</h4>
|
||||
<p>{{ t('initialization.tips.search.description') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button class="close" id="closeDownloadModal">×</button>
|
||||
<h2 id="downloadModalTitle">Download Model from URL</h2>
|
||||
<h2 id="downloadModalTitle">{{ t('modals.download.title') }}</h2>
|
||||
</div>
|
||||
|
||||
<!-- Step 1: URL Input -->
|
||||
<div class="download-step" id="urlStep">
|
||||
<div class="input-group">
|
||||
<label for="modelUrl" id="modelUrlLabel">Civitai URL:</label>
|
||||
<input type="text" id="modelUrl" placeholder="https://civitai.com/models/..." />
|
||||
<label for="modelUrl" id="modelUrlLabel">{{ t('modals.download.url') }}:</label>
|
||||
<input type="text" id="modelUrl" placeholder="{{ t('modals.download.placeholder') }}" />
|
||||
<div class="error-message" id="urlError"></div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="primary-btn" id="nextFromUrl">Next</button>
|
||||
<button class="primary-btn" id="nextFromUrl">{{ t('common.actions.next') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
<!-- Versions will be inserted here dynamically -->
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="secondary-btn" id="backToUrlBtn">Back</button>
|
||||
<button class="primary-btn" id="nextFromVersion">Next</button>
|
||||
<button class="secondary-btn" id="backToUrlBtn">{{ t('common.actions.back') }}</button>
|
||||
<button class="primary-btn" id="nextFromVersion">{{ t('common.actions.next') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
<!-- Path preview with inline toggle -->
|
||||
<div class="path-preview">
|
||||
<div class="path-preview-header">
|
||||
<label>Download Location Preview:</label>
|
||||
<div class="inline-toggle-container" title="When enabled, files are automatically organized using configured path templates">
|
||||
<span class="inline-toggle-label">Use Default Path</span>
|
||||
<label>{{ t('modals.download.locationPreview') }}:</label>
|
||||
<div class="inline-toggle-container" title="{{ t('modals.download.useDefaultPathTooltip') }}">
|
||||
<span class="inline-toggle-label">{{ t('modals.download.useDefaultPath') }}</span>
|
||||
<div class="toggle-switch">
|
||||
<input type="checkbox" id="useDefaultPath">
|
||||
<label for="useDefaultPath" class="toggle-slider"></label>
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="path-display" id="targetPathDisplay">
|
||||
<span class="path-text">Select a root directory</span>
|
||||
<span class="path-text">{{ t('modals.download.selectRootDirectory') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Embeddings Manager{% endblock %}
|
||||
{% block title %}{{ t('embeddings.title') }}{% endblock %}
|
||||
{% block page_id %}embeddings{% endblock %}
|
||||
|
||||
{% block preload %}
|
||||
<link rel="preload" href="/loras_static/js/embeddings.js" as="script" crossorigin="anonymous">
|
||||
{% endblock %}
|
||||
|
||||
{% block init_title %}Initializing Embeddings Manager{% endblock %}
|
||||
{% block init_message %}Scanning and building embeddings cache. This may take a few moments...{% endblock %}
|
||||
{% block init_title %}{{ t('initialization.embeddings.title') }}{% endblock %}
|
||||
{% block init_message %}{{ t('initialization.embeddings.message') }}{% endblock %}
|
||||
{% block init_check_url %}/api/embeddings/list?page=1&page_size=1{% endblock %}
|
||||
|
||||
{% block additional_components %}
|
||||
|
||||
<div id="embeddingContextMenu" class="context-menu" style="display: none;">
|
||||
<div class="context-menu-item" data-action="refresh-metadata"><i class="fas fa-sync"></i> Refresh Civitai Data</div>
|
||||
<div class="context-menu-item" data-action="relink-civitai"><i class="fas fa-link"></i> Re-link to Civitai</div>
|
||||
<div class="context-menu-item" data-action="copyname"><i class="fas fa-copy"></i> Copy Model Filename</div>
|
||||
<div class="context-menu-item" data-action="preview"><i class="fas fa-folder-open"></i> Open Examples Folder</div>
|
||||
<div class="context-menu-item" data-action="download-examples"><i class="fas fa-download"></i> Download Example Images</div>
|
||||
<div class="context-menu-item" data-action="replace-preview"><i class="fas fa-image"></i> Replace Preview</div>
|
||||
<div class="context-menu-item" data-action="set-nsfw"><i class="fas fa-exclamation-triangle"></i> Set Content Rating</div>
|
||||
<div class="context-menu-item" data-action="refresh-metadata"><i class="fas fa-sync"></i> {{ t('contextMenu.refreshMetadata') }}</div>
|
||||
<div class="context-menu-item" data-action="relink-civitai"><i class="fas fa-link"></i> {{ t('contextMenu.relinkCivitai') }}</div>
|
||||
<div class="context-menu-item" data-action="copyname"><i class="fas fa-copy"></i> {{ t('contextMenu.copyFilename') }}</div>
|
||||
<div class="context-menu-item" data-action="preview"><i class="fas fa-folder-open"></i> {{ t('contextMenu.openExamplesFolder') }}</div>
|
||||
<div class="context-menu-item" data-action="download-examples"><i class="fas fa-download"></i> {{ t('contextMenu.downloadExamples') }}</div>
|
||||
<div class="context-menu-item" data-action="replace-preview"><i class="fas fa-image"></i> {{ t('contextMenu.replacePreview') }}</div>
|
||||
<div class="context-menu-item" data-action="set-nsfw"><i class="fas fa-exclamation-triangle"></i> {{ t('contextMenu.setContentRating') }}</div>
|
||||
<div class="context-menu-separator"></div>
|
||||
<div class="context-menu-item" data-action="move"><i class="fas fa-folder-open"></i> Move to Folder</div>
|
||||
<div class="context-menu-item" data-action="exclude"><i class="fas fa-eye-slash"></i> Exclude Model</div>
|
||||
<div class="context-menu-item delete-item" data-action="delete"><i class="fas fa-trash"></i> Delete Model</div>
|
||||
<div class="context-menu-item" data-action="move"><i class="fas fa-folder-open"></i> {{ t('contextMenu.moveToFolder') }}</div>
|
||||
<div class="context-menu-item" data-action="exclude"><i class="fas fa-eye-slash"></i> {{ t('contextMenu.excludeModel') }}</div>
|
||||
<div class="context-menu-item delete-item" data-action="delete"><i class="fas fa-trash"></i> {{ t('contextMenu.deleteModel') }}</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}LoRA Recipes{% endblock %}
|
||||
{% block title %}{{ t('recipes.title') }}{% endblock %}
|
||||
{% block page_id %}recipes{% endblock %}
|
||||
|
||||
{% block page_css %}
|
||||
@@ -19,42 +19,42 @@
|
||||
|
||||
<div id="recipeContextMenu" class="context-menu" style="display: none;">
|
||||
<!-- <div class="context-menu-item" data-action="details"><i class="fas fa-info-circle"></i> View Details</div> -->
|
||||
<div class="context-menu-item" data-action="share"><i class="fas fa-share-alt"></i> Share Recipe</div>
|
||||
<div class="context-menu-item" data-action="copy"><i class="fas fa-copy"></i> Copy Recipe Syntax</div>
|
||||
<div class="context-menu-item" data-action="sendappend"><i class="fas fa-paper-plane"></i> Send to Workflow (Append)</div>
|
||||
<div class="context-menu-item" data-action="sendreplace"><i class="fas fa-exchange-alt"></i> Send to Workflow (Replace)</div>
|
||||
<div class="context-menu-item" data-action="viewloras"><i class="fas fa-layer-group"></i> View All LoRAs</div>
|
||||
<div class="context-menu-item download-missing-item" data-action="download-missing"><i class="fas fa-download"></i> Download Missing LoRAs</div>
|
||||
<div class="context-menu-item" data-action="share"><i class="fas fa-share-alt"></i> {{ t('contextMenu.shareRecipe') }}</div>
|
||||
<div class="context-menu-item" data-action="copy"><i class="fas fa-copy"></i> {{ t('contextMenu.copyRecipeSyntax') }}</div>
|
||||
<div class="context-menu-item" data-action="sendappend"><i class="fas fa-paper-plane"></i> {{ t('contextMenu.sendToWorkflowAppend') }}</div>
|
||||
<div class="context-menu-item" data-action="sendreplace"><i class="fas fa-exchange-alt"></i> {{ t('contextMenu.sendToWorkflowReplace') }}</div>
|
||||
<div class="context-menu-item" data-action="viewloras"><i class="fas fa-layer-group"></i> {{ t('contextMenu.viewAllLoras') }}</div>
|
||||
<div class="context-menu-item download-missing-item" data-action="download-missing"><i class="fas fa-download"></i> {{ t('contextMenu.downloadMissingLoras') }}</div>
|
||||
<div class="context-menu-item" data-action="set-nsfw">
|
||||
<i class="fas fa-exclamation-triangle"></i> Set Content Rating
|
||||
<i class="fas fa-exclamation-triangle"></i> {{ t('contextMenu.setContentRating') }}
|
||||
</div>
|
||||
<div class="context-menu-separator"></div>
|
||||
<div class="context-menu-item delete-item" data-action="delete"><i class="fas fa-trash"></i> Delete Recipe</div>
|
||||
<div class="context-menu-item delete-item" data-action="delete"><i class="fas fa-trash"></i> {{ t('contextMenu.deleteRecipe') }}</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block init_title %}Initializing Recipe Manager{% endblock %}
|
||||
{% block init_message %}Scanning and building recipe cache. This may take a few moments...{% endblock %}
|
||||
{% block init_title %}{{ t('initialization.recipes.title') }}{% endblock %}
|
||||
{% block init_message %}{{ t('initialization.recipes.message') }}{% endblock %}
|
||||
{% block init_check_url %}/api/recipes?page=1&page_size=1{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Recipe controls -->
|
||||
<div class="controls">
|
||||
<div class="action-buttons">
|
||||
<div title="Refresh recipe list" class="control-group">
|
||||
<button onclick="recipeManager.refreshRecipes()"><i class="fas fa-sync"></i> Refresh</button>
|
||||
<div title="{{ t('recipes.controls.refresh.title') }}" class="control-group">
|
||||
<button onclick="recipeManager.refreshRecipes()"><i class="fas fa-sync"></i> {{ t('common.actions.refresh') }}</button>
|
||||
</div>
|
||||
<div title="Import recipes" class="control-group">
|
||||
<button onclick="importManager.showImportModal()"><i class="fas fa-file-import"></i> Import</button>
|
||||
<div title="{{ t('recipes.controls.import.title') }}" class="control-group">
|
||||
<button onclick="importManager.showImportModal()"><i class="fas fa-file-import"></i> {{ t('recipes.controls.import') }}</button>
|
||||
</div>
|
||||
<!-- Add duplicate detection button -->
|
||||
<div title="Find duplicate recipes" class="control-group">
|
||||
<button onclick="recipeManager.findDuplicateRecipes()"><i class="fas fa-clone"></i> Duplicates</button>
|
||||
<div title="{{ t('recipes.controls.duplicates.title') }}" class="control-group">
|
||||
<button onclick="recipeManager.findDuplicateRecipes()"><i class="fas fa-clone"></i> {{ t('recipes.controls.duplicates') }}</button>
|
||||
</div>
|
||||
<!-- Custom filter indicator button (hidden by default) -->
|
||||
<div id="customFilterIndicator" class="control-group hidden">
|
||||
<div class="filter-active">
|
||||
<i class="fas fa-filter"></i> <span id="customFilterText">Filtered by LoRA</span>
|
||||
<i class="fas fa-filter"></i> <span id="customFilterText">{{ t('recipes.controls.filteredByLora') }}</span>
|
||||
<i class="fas fa-times-circle clear-filter"></i>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,13 +65,13 @@
|
||||
<div id="duplicatesBanner" class="duplicates-banner" style="display: none;">
|
||||
<div class="banner-content">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span id="duplicatesCount">Found 0 duplicate groups</span>
|
||||
<span id="duplicatesCount">{{ t('recipes.duplicates.found', count=0) }}</span>
|
||||
<div class="banner-actions">
|
||||
<button class="btn-select-latest" onclick="recipeManager.selectLatestDuplicates()">
|
||||
Keep Latest Versions
|
||||
{{ t('recipes.duplicates.keepLatest') }}
|
||||
</button>
|
||||
<button class="btn-delete-selected disabled" onclick="recipeManager.deleteSelectedDuplicates()">
|
||||
Delete Selected (<span id="duplicatesSelectedCount">0</span>)
|
||||
{{ t('recipes.duplicates.deleteSelected') }} (<span id="duplicatesSelectedCount">0</span>)
|
||||
</button>
|
||||
<button class="btn-exit" onclick="recipeManager.exitDuplicateMode()">
|
||||
<i class="fas fa-times"></i>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Statistics - LoRA Manager{% endblock %}
|
||||
{% block title %}{{ t('statistics.title') }} - {{ t('header.appTitle') }}{% endblock %}
|
||||
{% block page_id %}statistics{% endblock %}
|
||||
|
||||
{% block preload %}
|
||||
@@ -14,8 +14,8 @@
|
||||
<script src="/loras_static/vendor/chart.js/chart.umd.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block init_title %}Initializing Statistics{% endblock %}
|
||||
{% block init_message %}Loading model data and usage statistics. This may take a moment...{% endblock %}
|
||||
{% block init_title %}{{ t('initialization.statistics.title') }}{% endblock %}
|
||||
{% block init_message %}{{ t('initialization.statistics.message') }}{% endblock %}
|
||||
{% block init_check_url %}/api/stats/collection-overview{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -32,19 +32,19 @@
|
||||
<!-- Navigation Tabs -->
|
||||
<div class="dashboard-tabs">
|
||||
<button class="tab-button active" data-tab="overview">
|
||||
<i class="fas fa-chart-bar"></i> Overview
|
||||
<i class="fas fa-chart-bar"></i> {{ t('statistics.tabs.overview') }}
|
||||
</button>
|
||||
<button class="tab-button" data-tab="usage">
|
||||
<i class="fas fa-chart-line"></i> Usage Analysis
|
||||
<i class="fas fa-chart-line"></i> {{ t('statistics.tabs.usage') }}
|
||||
</button>
|
||||
<button class="tab-button" data-tab="collection">
|
||||
<i class="fas fa-layer-group"></i> Collection
|
||||
<i class="fas fa-layer-group"></i> {{ t('statistics.tabs.collection') }}
|
||||
</button>
|
||||
<button class="tab-button" data-tab="storage">
|
||||
<i class="fas fa-hdd"></i> Storage
|
||||
<i class="fas fa-hdd"></i> {{ t('statistics.tabs.storage') }}
|
||||
</button>
|
||||
<button class="tab-button" data-tab="insights">
|
||||
<i class="fas fa-lightbulb"></i> Insights
|
||||
<i class="fas fa-lightbulb"></i> {{ t('statistics.tabs.insights') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user