feat(i18n): internationalize statistics page strings across all locales

This commit is contained in:
Will Miao
2026-06-19 13:37:01 +08:00
parent ab6bb25d46
commit 16e5dcf7b2
12 changed files with 476 additions and 67 deletions

View File

@@ -1016,6 +1016,18 @@
"storage": "Speicher",
"insights": "Erkenntnisse"
},
"metrics": {
"totalModels": "Modelle gesamt",
"totalStorage": "Speicher gesamt",
"totalGenerations": "Generationen gesamt",
"usageRate": "Nutzungsrate",
"loras": "LoRAs",
"checkpoints": "Checkpoints",
"embeddings": "Embeddings",
"uniqueTags": "Einzigartige Tags",
"unusedModels": "Ungenutzte Modelle",
"avgUsesPerModel": "Ø Nutzungen/Modell"
},
"usage": {
"mostUsedLoras": "Meistgenutzte LoRAs",
"mostUsedCheckpoints": "Meistgenutzte Checkpoints",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "Intelligente Erkenntnisse",
"recommendations": "Empfehlungen"
"recommendations": "Empfehlungen",
"noInsights": "Keine Erkenntnisse verfügbar"
},
"charts": {
"collectionOverview": "Sammlungsübersicht",
"baseModelDistribution": "Basis-Modell-Verteilung",
"usageTrends": "Nutzungstrends (Letzte 30 Tage)",
"usageDistribution": "Nutzungsverteilung"
"usageDistribution": "Nutzungsverteilung",
"date": "Datum",
"usageCount": "Nutzungsanzahl",
"fileSizeBytes": "Dateigröße (Bytes)",
"models": "Modelle",
"loraUsage": "LoRA-Nutzung",
"checkpointUsage": "Checkpoint-Nutzung",
"embeddingUsage": "Embedding-Nutzung"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Checkpoint",
"diffusion_model": "Diffusionsmodell",
"embedding": "Embeddings"
},
"placeholders": {
"loading": "Lädt...",
"noModels": "Keine Modelle gefunden",
"errorLoading": "Fehler beim Laden der Daten",
"noStorageData": "Keine Speicherdaten verfügbar",
"rootFolder": "Root",
"chartLibraryMissing": "Diagramm benötigt Chart.js-Bibliothek"
},
"tooltips": {
"tagCount": "{tag}: {count} Modelle",
"chartUsage": "{name}: {size}, {count} Nutzungen",
"chartPercentage": "{label}: {value} ({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "Storage",
"insights": "Insights"
},
"metrics": {
"totalModels": "Total Models",
"totalStorage": "Total Storage",
"totalGenerations": "Total Generations",
"usageRate": "Usage Rate",
"loras": "LoRAs",
"checkpoints": "Checkpoints",
"embeddings": "Embeddings",
"uniqueTags": "Unique Tags",
"unusedModels": "Unused Models",
"avgUsesPerModel": "Avg. Uses/Model"
},
"usage": {
"mostUsedLoras": "Most Used LoRAs",
"mostUsedCheckpoints": "Most Used Checkpoints",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "Smart Insights",
"recommendations": "Recommendations"
"recommendations": "Recommendations",
"noInsights": "No insights available"
},
"charts": {
"collectionOverview": "Collection Overview",
"baseModelDistribution": "Base Model Distribution",
"usageTrends": "Usage Trends (Last 30 Days)",
"usageDistribution": "Usage Distribution"
"usageDistribution": "Usage Distribution",
"date": "Date",
"usageCount": "Usage Count",
"fileSizeBytes": "File Size (bytes)",
"models": "Models",
"loraUsage": "LoRA Usage",
"checkpointUsage": "Checkpoint Usage",
"embeddingUsage": "Embedding Usage"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Checkpoint",
"diffusion_model": "Diffusion Model",
"embedding": "Embeddings"
},
"placeholders": {
"loading": "Loading...",
"noModels": "No models found",
"errorLoading": "Error loading data",
"noStorageData": "No storage data available",
"rootFolder": "Root",
"chartLibraryMissing": "Chart requires Chart.js library"
},
"tooltips": {
"tagCount": "{tag}: {count} models",
"chartUsage": "{name}: {size}, {count} uses",
"chartPercentage": "{label}: {value} ({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "Almacenamiento",
"insights": "Perspectivas"
},
"metrics": {
"totalModels": "Total de modelos",
"totalStorage": "Almacenamiento total",
"totalGenerations": "Generaciones totales",
"usageRate": "Tasa de uso",
"loras": "LoRAs",
"checkpoints": "Puntos de control",
"embeddings": "Embeddings",
"uniqueTags": "Etiquetas únicas",
"unusedModels": "Modelos no usados",
"avgUsesPerModel": "Prom. usos/modelo"
},
"usage": {
"mostUsedLoras": "LoRAs más utilizados",
"mostUsedCheckpoints": "Checkpoints más utilizados",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "Perspectivas inteligentes",
"recommendations": "Recomendaciones"
"recommendations": "Recomendaciones",
"noInsights": "No hay información disponible"
},
"charts": {
"collectionOverview": "Resumen de colección",
"baseModelDistribution": "Distribución de modelo base",
"usageTrends": "Tendencias de uso (Últimos 30 días)",
"usageDistribution": "Distribución de uso"
"usageDistribution": "Distribución de uso",
"date": "Fecha",
"usageCount": "Conteo de uso",
"fileSizeBytes": "Tamaño del archivo (bytes)",
"models": "Modelos",
"loraUsage": "Uso de LoRA",
"checkpointUsage": "Uso de Checkpoint",
"embeddingUsage": "Uso de Embedding"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Punto de control",
"diffusion_model": "Modelo de difusión",
"embedding": "Embeddings"
},
"placeholders": {
"loading": "Cargando...",
"noModels": "No se encontraron modelos",
"errorLoading": "Error al cargar datos",
"noStorageData": "No hay datos de almacenamiento disponibles",
"rootFolder": "Raíz",
"chartLibraryMissing": "El gráfico requiere la librería Chart.js"
},
"tooltips": {
"tagCount": "{tag}: {count} modelos",
"chartUsage": "{name}: {size}, {count} usos",
"chartPercentage": "{label}: {value} ({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "Stockage",
"insights": "Aperçus"
},
"metrics": {
"totalModels": "Total des modèles",
"totalStorage": "Stockage total",
"totalGenerations": "Générations totales",
"usageRate": "Taux d'utilisation",
"loras": "LoRAs",
"checkpoints": "Points de contrôle",
"embeddings": "Embeddings",
"uniqueTags": "Tags uniques",
"unusedModels": "Modèles inutilisés",
"avgUsesPerModel": "Moy. utilisations/modèle"
},
"usage": {
"mostUsedLoras": "LoRAs les plus utilisés",
"mostUsedCheckpoints": "Checkpoints les plus utilisés",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "Aperçus intelligents",
"recommendations": "Recommandations"
"recommendations": "Recommandations",
"noInsights": "Aucun aperçu disponible"
},
"charts": {
"collectionOverview": "Aperçu de la collection",
"baseModelDistribution": "Distribution des modèles de base",
"usageTrends": "Tendances d'utilisation (30 derniers jours)",
"usageDistribution": "Distribution de l'utilisation"
"usageDistribution": "Distribution de l'utilisation",
"date": "Date",
"usageCount": "Nombre d'utilisations",
"fileSizeBytes": "Taille du fichier (octets)",
"models": "Modèles",
"loraUsage": "Utilisation LoRA",
"checkpointUsage": "Utilisation Checkpoint",
"embeddingUsage": "Utilisation Embedding"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Point de contrôle",
"diffusion_model": "Modèle de diffusion",
"embedding": "Embeddings"
},
"placeholders": {
"loading": "Chargement...",
"noModels": "Aucun modèle trouvé",
"errorLoading": "Erreur de chargement des données",
"noStorageData": "Aucune donnée de stockage disponible",
"rootFolder": "Racine",
"chartLibraryMissing": "Le graphique nécessite la bibliothèque Chart.js"
},
"tooltips": {
"tagCount": "{tag}: {count} modèles",
"chartUsage": "{name}: {size}, {count} utilisations",
"chartPercentage": "{label}: {value} ({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "אחסון",
"insights": "תובנות"
},
"metrics": {
"totalModels": "סה\"כ דגמים",
"totalStorage": "סה\"כ אחסון",
"totalGenerations": "סה\"כ יצירות",
"usageRate": "שיעור שימוש",
"loras": "LoRA",
"checkpoints": "נקודות ביקורת",
"embeddings": "הטמעות",
"uniqueTags": "תגיות ייחודיות",
"unusedModels": "דגמים שאינם בשימוש",
"avgUsesPerModel": "ממוצע שימושים/דגם"
},
"usage": {
"mostUsedLoras": "LoRAs הנפוצים ביותר",
"mostUsedCheckpoints": "Checkpoints הנפוצים ביותר",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "תובנות חכמות",
"recommendations": "המלצות"
"recommendations": "המלצות",
"noInsights": "אין תובנות זמינות"
},
"charts": {
"collectionOverview": "סקירת אוסף",
"baseModelDistribution": "התפלגות מודלי בסיס",
"usageTrends": "מגמות שימוש (30 יום אחרונים)",
"usageDistribution": "התפלגות שימוש"
"usageDistribution": "התפלגות שימוש",
"date": "תאריך",
"usageCount": "מספר שימושים",
"fileSizeBytes": "גודל קובץ (בתים)",
"models": "דגמים",
"loraUsage": "שימוש ב-LoRA",
"checkpointUsage": "שימוש ב-Checkpoint",
"embeddingUsage": "שימוש ב-Embedding"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "נקודת ביקורת",
"diffusion_model": "מודל דיפוזיה",
"embedding": "הטמעות"
},
"placeholders": {
"loading": "טוען...",
"noModels": "לא נמצאו דגמים",
"errorLoading": "שגיאה בטעינת נתונים",
"noStorageData": "אין נתוני אחסון זמינים",
"rootFolder": "שורש",
"chartLibraryMissing": "הגרף דורש את ספריית Chart.js"
},
"tooltips": {
"tagCount": "{tag}: {count} דגמים",
"chartUsage": "{name}: {size}, {count} שימושים",
"chartPercentage": "{label}: {value} ({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "ストレージ",
"insights": "インサイト"
},
"metrics": {
"totalModels": "モデル総数",
"totalStorage": "ストレージ合計",
"totalGenerations": "生成回数合計",
"usageRate": "使用率",
"loras": "LoRA",
"checkpoints": "Checkpoint",
"embeddings": "Embedding",
"uniqueTags": "ユニークタグ",
"unusedModels": "未使用モデル",
"avgUsesPerModel": "平均使用回数/モデル"
},
"usage": {
"mostUsedLoras": "最も使用されているLoRA",
"mostUsedCheckpoints": "最も使用されているCheckpoint",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "スマートインサイト",
"recommendations": "推奨事項"
"recommendations": "推奨事項",
"noInsights": "インサイトはありません"
},
"charts": {
"collectionOverview": "コレクション概要",
"baseModelDistribution": "ベースモデル分布",
"usageTrends": "使用傾向過去30日",
"usageDistribution": "使用分布"
"usageDistribution": "使用分布",
"date": "日付",
"usageCount": "使用回数",
"fileSizeBytes": "ファイルサイズ(バイト)",
"models": "モデル",
"loraUsage": "LoRA 使用量",
"checkpointUsage": "Checkpoint 使用量",
"embeddingUsage": "Embedding 使用量"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Checkpoint",
"diffusion_model": "拡散モデル",
"embedding": "Embedding"
},
"placeholders": {
"loading": "読み込み中...",
"noModels": "モデルが見つかりません",
"errorLoading": "データ読み込みエラー",
"noStorageData": "ストレージデータがありません",
"rootFolder": "ルート",
"chartLibraryMissing": "Chart.js ライブラリが必要です"
},
"tooltips": {
"tagCount": "{tag}: {count} モデル",
"chartUsage": "{name}: {size}, {count} 回使用",
"chartPercentage": "{label}: {value} ({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "저장소",
"insights": "인사이트"
},
"metrics": {
"totalModels": "모델 총계",
"totalStorage": "총 저장 공간",
"totalGenerations": "총 생성 횟수",
"usageRate": "사용률",
"loras": "LoRA",
"checkpoints": "Checkpoint",
"embeddings": "Embedding",
"uniqueTags": "고유 태그",
"unusedModels": "미사용 모델",
"avgUsesPerModel": "모델당 평균 사용"
},
"usage": {
"mostUsedLoras": "가장 많이 사용된 LoRA",
"mostUsedCheckpoints": "가장 많이 사용된 Checkpoint",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "스마트 인사이트",
"recommendations": "추천"
"recommendations": "추천",
"noInsights": "인사이트 없음"
},
"charts": {
"collectionOverview": "컬렉션 개요",
"baseModelDistribution": "베이스 모델 분포",
"usageTrends": "사용량 트렌드 (최근 30일)",
"usageDistribution": "사용량 분포"
"usageDistribution": "사용량 분포",
"date": "날짜",
"usageCount": "사용 횟수",
"fileSizeBytes": "파일 크기(바이트)",
"models": "모델",
"loraUsage": "LoRA 사용량",
"checkpointUsage": "Checkpoint 사용량",
"embeddingUsage": "Embedding 사용량"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Checkpoint",
"diffusion_model": "확산 모델",
"embedding": "Embedding"
},
"placeholders": {
"loading": "로딩 중...",
"noModels": "모델을 찾을 수 없음",
"errorLoading": "데이터 로딩 오류",
"noStorageData": "저장 데이터 없음",
"rootFolder": "루트",
"chartLibraryMissing": "Chart.js 라이브러리가 필요합니다"
},
"tooltips": {
"tagCount": "{tag}: {count}개 모델",
"chartUsage": "{name}: {size}, {count}회 사용",
"chartPercentage": "{label}: {value}({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "Хранение",
"insights": "Аналитика"
},
"metrics": {
"totalModels": "Всего моделей",
"totalStorage": "Всего хранилища",
"totalGenerations": "Всего генераций",
"usageRate": "Коэффициент использования",
"loras": "LoRA",
"checkpoints": "Контрольные точки",
"embeddings": "Эмбеддинги",
"uniqueTags": "Уникальные теги",
"unusedModels": "Неиспользуемые модели",
"avgUsesPerModel": "Сред. использований/модель"
},
"usage": {
"mostUsedLoras": "Наиболее используемые LoRAs",
"mostUsedCheckpoints": "Наиболее используемые Checkpoints",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "Умная аналитика",
"recommendations": "Рекомендации"
"recommendations": "Рекомендации",
"noInsights": "Нет доступных данных"
},
"charts": {
"collectionOverview": "Обзор коллекции",
"baseModelDistribution": "Распределение базовых моделей",
"usageTrends": "Тенденции использования (за последние 30 дней)",
"usageDistribution": "Распределение использования"
"usageDistribution": "Распределение использования",
"date": "Дата",
"usageCount": "Количество использований",
"fileSizeBytes": "Размер файла (байты)",
"models": "Модели",
"loraUsage": "Использование LoRA",
"checkpointUsage": "Использование Checkpoint",
"embeddingUsage": "Использование Embedding"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Контрольная точка",
"diffusion_model": "Диффузионная модель",
"embedding": "Эмбеддинги"
},
"placeholders": {
"loading": "Загрузка...",
"noModels": "Модели не найдены",
"errorLoading": "Ошибка загрузки данных",
"noStorageData": "Нет данных о хранилище",
"rootFolder": "Корень",
"chartLibraryMissing": "Для графика требуется библиотека Chart.js"
},
"tooltips": {
"tagCount": "{tag}: {count} моделей",
"chartUsage": "{name}: {size}, {count} использований",
"chartPercentage": "{label}: {value} ({pct}%)"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "存储",
"insights": "洞察"
},
"metrics": {
"totalModels": "模型总数",
"totalStorage": "总存储空间",
"totalGenerations": "总生成次数",
"usageRate": "使用率",
"loras": "LoRA",
"checkpoints": "Checkpoint",
"embeddings": "Embedding",
"uniqueTags": "唯一标签",
"unusedModels": "未使用模型",
"avgUsesPerModel": "平均使用次数/模型"
},
"usage": {
"mostUsedLoras": "最常用 LoRA",
"mostUsedCheckpoints": "最常用 Checkpoint",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "智能洞察",
"recommendations": "推荐"
"recommendations": "推荐",
"noInsights": "暂无可用洞察"
},
"charts": {
"collectionOverview": "收藏概览",
"baseModelDistribution": "基础模型分布",
"usageTrends": "使用趋势最近30天",
"usageDistribution": "使用分布"
"usageDistribution": "使用分布",
"date": "日期",
"usageCount": "使用次数",
"fileSizeBytes": "文件大小(字节)",
"models": "模型",
"loraUsage": "LoRA 使用量",
"checkpointUsage": "Checkpoint 使用量",
"embeddingUsage": "Embedding 使用量"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Checkpoint",
"diffusion_model": "扩散模型",
"embedding": "Embedding"
},
"placeholders": {
"loading": "加载中...",
"noModels": "未找到模型",
"errorLoading": "数据加载失败",
"noStorageData": "暂无存储数据",
"rootFolder": "根目录",
"chartLibraryMissing": "需要 Chart.js 库来显示图表"
},
"tooltips": {
"tagCount": "{tag}{count} 个模型",
"chartUsage": "{name}{size}{count} 次使用",
"chartPercentage": "{label}{value}{pct}%"
}
},
"modals": {

View File

@@ -1016,6 +1016,18 @@
"storage": "儲存空間",
"insights": "洞察"
},
"metrics": {
"totalModels": "模型總數",
"totalStorage": "總儲存空間",
"totalGenerations": "總生成次數",
"usageRate": "使用率",
"loras": "LoRA",
"checkpoints": "Checkpoint",
"embeddings": "Embedding",
"uniqueTags": "唯一標籤",
"unusedModels": "未使用模型",
"avgUsesPerModel": "平均使用次數/模型"
},
"usage": {
"mostUsedLoras": "最常用的 LoRA",
"mostUsedCheckpoints": "最常用的 Checkpoint",
@@ -1033,13 +1045,42 @@
},
"insights": {
"smartInsights": "智慧洞察",
"recommendations": "推薦"
"recommendations": "推薦",
"noInsights": "暫無可用洞察"
},
"charts": {
"collectionOverview": "收藏總覽",
"baseModelDistribution": "基礎模型分布",
"usageTrends": "使用趨勢(最近 30 天)",
"usageDistribution": "使用分布"
"usageDistribution": "使用分布",
"date": "日期",
"usageCount": "使用次數",
"fileSizeBytes": "檔案大小(位元組)",
"models": "模型",
"loraUsage": "LoRA 使用量",
"checkpointUsage": "Checkpoint 使用量",
"embeddingUsage": "Embedding 使用量"
},
"modelTypes": {
"lora": "LoRA",
"locon": "LyCORIS",
"dora": "DoRA",
"checkpoint": "Checkpoint",
"diffusion_model": "擴散模型",
"embedding": "Embedding"
},
"placeholders": {
"loading": "載入中...",
"noModels": "找不到模型",
"errorLoading": "資料載入失敗",
"noStorageData": "暫無儲存資料",
"rootFolder": "根目錄",
"chartLibraryMissing": "需要 Chart.js 函式庫來顯示圖表"
},
"tooltips": {
"tagCount": "{tag}{count} 個模型",
"chartUsage": "{name}{size}{count} 次使用",
"chartPercentage": "{label}{value}{pct}%"
}
},
"modals": {

View File

@@ -1,6 +1,8 @@
// Statistics page functionality
import { appCore } from './core.js';
import { showToast } from './utils/uiHelpers.js';
import { translate } from './utils/i18nHelpers.js';
import { i18n } from './i18n/index.js';
// Chart.js import (assuming it's available globally or via CDN)
// If Chart.js isn't available, we'll need to add it to the project
@@ -124,43 +126,43 @@ export class StatisticsManager {
{
icon: 'fas fa-magic',
value: this.data.collection.total_models,
label: 'Total Models',
label: translate('statistics.metrics.totalModels'),
format: 'number'
},
{
icon: 'fas fa-database',
value: this.data.collection.total_size,
label: 'Total Storage',
label: translate('statistics.metrics.totalStorage'),
format: 'size'
},
{
icon: 'fas fa-play-circle',
value: this.data.collection.total_generations,
label: 'Total Generations',
label: translate('statistics.metrics.totalGenerations'),
format: 'number'
},
{
icon: 'fas fa-chart-line',
value: this.calculateUsageRate(),
label: 'Usage Rate',
label: translate('statistics.metrics.usageRate'),
format: 'percentage'
},
{
icon: 'fas fa-layer-group',
value: this.data.collection.lora_count,
label: 'LoRAs',
label: translate('statistics.metrics.loras'),
format: 'number'
},
{
icon: 'fas fa-check-circle',
value: this.data.collection.checkpoint_count,
label: 'Checkpoints',
label: translate('statistics.metrics.checkpoints'),
format: 'number'
},
{
icon: 'fas fa-code',
value: this.data.collection.embedding_count,
label: 'Embeddings',
label: translate('statistics.metrics.embeddings'),
format: 'number'
}
];
@@ -196,11 +198,7 @@ export class StatisticsManager {
}
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
return i18n.formatFileSize(bytes);
}
calculateUsageRate() {
@@ -250,7 +248,7 @@ export class StatisticsManager {
if (!ctx || !this.data.collection) return;
const data = {
labels: ['LoRAs', 'Checkpoints', 'Embeddings'],
labels: [translate('statistics.metrics.loras'), translate('statistics.metrics.checkpoints'), translate('statistics.metrics.embeddings')],
datasets: [{
data: [
this.data.collection.lora_count,
@@ -300,17 +298,17 @@ export class StatisticsManager {
labels: Array.from(allModels),
datasets: [
{
label: 'LoRAs',
label: translate('statistics.metrics.loras'),
data: Array.from(allModels).map(model => loraData[model] || 0),
backgroundColor: 'oklch(68% 0.28 256 / 0.7)'
},
{
label: 'Checkpoints',
label: translate('statistics.metrics.checkpoints'),
data: Array.from(allModels).map(model => checkpointData[model] || 0),
backgroundColor: 'oklch(68% 0.28 200 / 0.7)'
},
{
label: 'Embeddings',
label: translate('statistics.metrics.embeddings'),
data: Array.from(allModels).map(model => embeddingData[model] || 0),
backgroundColor: 'oklch(68% 0.28 120 / 0.7)'
}
@@ -345,21 +343,21 @@ export class StatisticsManager {
labels: timeline.map(item => new Date(item.date).toLocaleDateString()),
datasets: [
{
label: 'LoRA Usage',
label: translate('statistics.charts.loraUsage'),
data: timeline.map(item => item.lora_usage),
borderColor: 'oklch(68% 0.28 256)',
backgroundColor: 'oklch(68% 0.28 256 / 0.1)',
fill: true
},
{
label: 'Checkpoint Usage',
label: translate('statistics.charts.checkpointUsage'),
data: timeline.map(item => item.checkpoint_usage),
borderColor: 'oklch(68% 0.28 200)',
backgroundColor: 'oklch(68% 0.28 200 / 0.1)',
fill: true
},
{
label: 'Embedding Usage',
label: translate('statistics.charts.embeddingUsage'),
data: timeline.map(item => item.embedding_usage),
borderColor: 'oklch(68% 0.28 120)',
backgroundColor: 'oklch(68% 0.28 120 / 0.1)',
@@ -383,14 +381,14 @@ export class StatisticsManager {
display: true,
title: {
display: true,
text: 'Date'
text: translate('statistics.charts.date')
}
},
y: {
display: true,
title: {
display: true,
text: 'Usage Count'
text: translate('statistics.charts.usageCount')
}
}
}
@@ -416,7 +414,7 @@ export class StatisticsManager {
const data = {
labels: allModels.map(model => model.name),
datasets: [{
label: 'Usage Count',
label: translate('statistics.charts.usageCount'),
data: allModels.map(model => model.usage_count),
backgroundColor: allModels.map(model => {
switch(model.type) {
@@ -450,7 +448,7 @@ export class StatisticsManager {
if (!ctx || !this.data.collection) return;
const data = {
labels: ['LoRAs', 'Checkpoints', 'Embeddings'],
labels: [translate('statistics.metrics.loras'), translate('statistics.metrics.checkpoints'), translate('statistics.metrics.embeddings')],
datasets: [{
data: [
this.data.collection.lora_size,
@@ -504,7 +502,7 @@ export class StatisticsManager {
const data = {
datasets: [{
label: 'Models',
label: translate('statistics.charts.models'),
data: allData.map(item => ({
x: item.size,
y: item.usage_count,
@@ -532,14 +530,14 @@ export class StatisticsManager {
x: {
title: {
display: true,
text: 'File Size (bytes)'
text: translate('statistics.charts.fileSizeBytes')
},
type: 'logarithmic'
},
y: {
title: {
display: true,
text: 'Usage Count'
text: translate('statistics.charts.usageCount')
}
}
},
@@ -548,7 +546,7 @@ export class StatisticsManager {
callbacks: {
label: (context) => {
const point = context.raw;
return `${point.name}: ${this.formatFileSize(point.x)}, ${point.y} uses`;
return translate('statistics.tooltips.chartUsage', { name: point.name, size: this.formatFileSize(point.x), count: point.y });
}
}
}
@@ -563,12 +561,12 @@ export class StatisticsManager {
const distribution = this.data.collection.model_types_distribution;
const typeDisplayNames = {
lora: 'LoRA',
locon: 'LyCORIS',
dora: 'DoRA',
checkpoint: 'Checkpoint',
diffusion_model: 'Diffusion Model',
embedding: 'Embeddings'
lora: translate('statistics.modelTypes.lora'),
locon: translate('statistics.modelTypes.locon'),
dora: translate('statistics.modelTypes.dora'),
checkpoint: translate('statistics.modelTypes.checkpoint'),
diffusion_model: translate('statistics.modelTypes.diffusion_model'),
embedding: translate('statistics.modelTypes.embedding')
};
const colorPalette = {
@@ -610,7 +608,7 @@ export class StatisticsManager {
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const value = context.parsed;
const pct = ((value / total) * 100).toFixed(1);
return ` ${context.label}: ${value} (${pct}%)`;
return translate('statistics.tooltips.chartPercentage', { label: context.label, value, pct });
}
}
}
@@ -654,7 +652,7 @@ export class StatisticsManager {
// Show loading indicator on initial load
if (state.offset === 0) {
container.innerHTML = '<div class="loading-placeholder"><i class="fas fa-spinner fa-spin"></i> Loading...</div>';
container.innerHTML = '<div class="loading-placeholder"><i class="fas fa-spinner fa-spin"></i> ' + translate('statistics.placeholders.loading') + '</div>';
}
try {
@@ -670,7 +668,7 @@ export class StatisticsManager {
}
if (items.length === 0 && state.offset === 0) {
container.innerHTML = '<div class="loading-placeholder">No models found</div>';
container.innerHTML = '<div class="loading-placeholder">' + translate('statistics.placeholders.noModels') + '</div>';
state.hasMore = false;
} else if (items.length < state.limit) {
state.hasMore = false;
@@ -683,7 +681,7 @@ export class StatisticsManager {
onerror="this.src='/loras_static/images/no-preview.png'">
<div class="model-info">
<div class="model-name" title="${model.name}">${model.name}</div>
<div class="model-meta">${model.base_model}${model.folder || 'Root'}</div>
<div class="model-meta">${model.base_model}${model.folder || translate('statistics.placeholders.rootFolder')}</div>
</div>
<div class="model-usage">${model.usage_count}</div>
</div>
@@ -695,7 +693,7 @@ export class StatisticsManager {
} catch (error) {
console.error(`Error loading ${type} list:`, error);
if (state.offset === 0) {
container.innerHTML = '<div class="loading-placeholder">Error loading data</div>';
container.innerHTML = '<div class="loading-placeholder">' + translate('statistics.placeholders.errorLoading') + '</div>';
}
} finally {
state.isLoading = false;
@@ -718,7 +716,7 @@ export class StatisticsManager {
].sort((a, b) => b.size - a.size).slice(0, 10);
if (allModels.length === 0) {
container.innerHTML = '<div class="loading-placeholder">No storage data available</div>';
container.innerHTML = '<div class="loading-placeholder">' + translate('statistics.placeholders.noStorageData') + '</div>';
return;
}
@@ -726,7 +724,7 @@ export class StatisticsManager {
<div class="model-item">
<div class="model-info">
<div class="model-name" title="${model.name}">${model.name}</div>
<div class="model-meta">${model.type}${model.base_model}</div>
<div class="model-meta">${translate('statistics.modelTypes.' + model.type.toLowerCase())}${model.base_model}</div>
</div>
<div class="model-usage">${this.formatFileSize(model.size)}</div>
</div>
@@ -744,7 +742,7 @@ export class StatisticsManager {
const size = Math.ceil((tagData.count / maxCount) * 5);
return `
<span class="tag-cloud-item size-${size}"
title="${tagData.tag}: ${tagData.count} models">
title="${translate('statistics.tooltips.tagCount', { tag: tagData.tag, count: tagData.count })}">
${tagData.tag}
</span>
`;
@@ -758,7 +756,7 @@ export class StatisticsManager {
const insights = this.data.insights.insights;
if (insights.length === 0) {
container.innerHTML = '<div class="loading-placeholder">No insights available</div>';
container.innerHTML = '<div class="loading-placeholder">' + translate('statistics.insights.noInsights') + '</div>';
return;
}
@@ -782,25 +780,25 @@ export class StatisticsManager {
{
icon: 'fas fa-percentage',
value: this.calculateUsageRate(),
label: 'Usage Rate',
label: translate('statistics.metrics.usageRate'),
format: 'percentage'
},
{
icon: 'fas fa-tags',
value: this.data.tags?.total_unique_tags || 0,
label: 'Unique Tags',
label: translate('statistics.metrics.uniqueTags'),
format: 'number'
},
{
icon: 'fas fa-clock',
value: this.data.collection.unused_loras + this.data.collection.unused_checkpoints,
label: 'Unused Models',
label: translate('statistics.metrics.unusedModels'),
format: 'number'
},
{
icon: 'fas fa-chart-line',
value: this.calculateAverageUsage(),
label: 'Avg. Uses/Model',
label: translate('statistics.metrics.avgUsesPerModel'),
format: 'decimal'
}
];
@@ -829,7 +827,7 @@ export class StatisticsManager {
const chartCanvases = document.querySelectorAll('canvas');
chartCanvases.forEach(canvas => {
const container = canvas.parentElement;
container.innerHTML = '<div class="loading-placeholder"><i class="fas fa-chart-bar"></i> Chart requires Chart.js library</div>';
container.innerHTML = '<div class="loading-placeholder"><i class="fas fa-chart-bar"></i> ' + translate('statistics.placeholders.chartLibraryMissing') + '</div>';
});
}

View File

@@ -80,6 +80,7 @@ FALSE_POSITIVES = {
"array",
"object",
"non.existent.key",
"statistics.modelTypes.",
}
SPECIAL_UI_HELPER_KEYS = {