diff --git a/renderer.js b/renderer.js
index d578809..4d268d7 100644
--- a/renderer.js
+++ b/renderer.js
@@ -182,7 +182,7 @@ function resetWorkspaceToEmpty() {
// Clear background customizations
resetBgSettings();
- showToast("Image Changed", "Workspace cleared. You can now load a new image.", "info");
+ showToast(getTrans('toastImageChanged'), getTrans('toastImageChangedMsg'), "info");
}
// --- PYTHON VENV INSTALLER ENGINE ---
@@ -208,40 +208,55 @@ elements.btnStartSetup.addEventListener('click', async () => {
};
setStepActive(elements.stepVenv);
+ elements.setupStatusText.innerText = getTrans('setupCreatingVenv');
// Listen for pipeline setup output logs
window.api.onSetupProgress((progressText) => {
- elements.setupStatusText.innerText = progressText;
-
- // Parse step state
+ // Translate setup output progress text
if (progressText.includes("Creating Python virtual environment")) {
+ elements.setupStatusText.innerText = getTrans('setupCreatingVenv');
setStepActive(elements.stepVenv);
elements.setupProgressBar.style.width = '15%';
- } else if (progressText.includes("Virtual environment successfully created") || progressText.includes("Virtual environment already exists")) {
+ } else if (progressText.includes("Virtual environment successfully created")) {
+ elements.setupStatusText.innerText = getTrans('setupVenvCreated');
+ setStepDone(elements.stepVenv);
+ setStepActive(elements.stepPip);
+ elements.setupProgressBar.style.width = '30%';
+ } else if (progressText.includes("Virtual environment already exists")) {
+ elements.setupStatusText.innerText = getTrans('setupVenvExists');
setStepDone(elements.stepVenv);
setStepActive(elements.stepPip);
elements.setupProgressBar.style.width = '30%';
} else if (progressText.includes("Upgrading pip")) {
+ elements.setupStatusText.innerText = getTrans('setupUpgradingPip');
setStepActive(elements.stepPip);
elements.setupProgressBar.style.width = '45%';
} else if (progressText.includes("Installing PyTorch")) {
+ elements.setupStatusText.innerText = getTrans('setupInstallingTorch');
setStepDone(elements.stepPip);
setStepActive(elements.stepDeps);
elements.setupProgressBar.style.width = '60%';
- } else if (progressText.includes("Downloading torch") || progressText.includes("Installing collected packages")) {
+ } else if (progressText.includes("Downloading torch")) {
+ elements.setupStatusText.innerText = getTrans('setupDownloadingTorch');
elements.setupProgressBar.style.width = '75%';
+ } else if (progressText.includes("Installing collected packages")) {
+ elements.setupStatusText.innerText = getTrans('setupInstallingDeps');
+ elements.setupProgressBar.style.width = '85%';
} else if (progressText.includes("Setup completed successfully")) {
+ elements.setupStatusText.innerText = getTrans('setupCompleted');
setStepDone(elements.stepDeps);
setStepDone(elements.stepLibs);
elements.setupProgressBar.style.width = '100%';
+ } else {
+ elements.setupStatusText.innerText = progressText;
}
});
try {
const result = await window.api.runPythonSetup();
if (result.code === 0) {
- elements.setupStatusText.innerText = "Configuration Complete! Enjoy background removal.";
- showToast("Setup Success", "Python environment is fully configured.", "success");
+ elements.setupStatusText.innerText = getTrans('setupCompleted');
+ showToast(getTrans('toastSetupSuccess'), getTrans('toastSetupSuccessMsg'), "success");
setTimeout(() => {
elements.setupOverlay.classList.add('hidden');
@@ -249,14 +264,14 @@ elements.btnStartSetup.addEventListener('click', async () => {
}, 1500);
} else {
setStepFailed(elements.stepDeps);
- elements.setupStatusText.innerText = "Setup failed. Check system dependencies.";
+ elements.setupStatusText.innerText = getTrans('setupFailed');
elements.btnStartSetup.disabled = false;
- showToast("Setup Error", "Failed to build Python environment.", "error");
+ showToast(getTrans('toastSetupError'), getTrans('toastSetupErrorMsg'), "error");
}
} catch (err) {
- elements.setupStatusText.innerText = `Error: ${err.message}`;
+ elements.setupStatusText.innerText = `${getTrans('toastSetupError')}: ${err.message}`;
elements.btnStartSetup.disabled = false;
- showToast("Setup Error", err.message, "error");
+ showToast(getTrans('toastSetupError'), err.message, "error");
}
});
@@ -551,7 +566,39 @@ const TRANSLATIONS = {
dragDropSub: "Supports PNG, JPG, JPEG, or WebP formats",
orText: "OR",
browseFiles: "Browse Local Files",
- autoTrim: "Auto-Trim"
+ autoTrim: "Auto-Trim",
+ statusInit: "Initializing AI model...",
+ statusWeights: "Loading neural weights into memory...",
+ statusImporting: "Importing libraries...",
+ statusDetecting: "Detecting device...",
+ statusUsingDevice: "Using device: ",
+ statusLoadingModel: "Loading BiRefNet model...",
+ statusPreprocessing: "Loading and preprocessing image...",
+ statusInference: "Running background removal inference...",
+ statusGeneratingMask: "Generating transparency mask...",
+ statusSaving: "Saving output transparent image...",
+ statusDone: "Completed!",
+ subFirstRun: "This downloads ~200MB of weights on first run.",
+ subInference: "Extracting details and soft matting alpha...",
+ subSaving: "Assembling high-res RGBA container...",
+ subDefault: "Please wait while the AI model processes...",
+ setupReady: "Ready to configure environment.",
+ setupCreatingVenv: "Creating Python virtual environment...",
+ setupVenvCreated: "Virtual environment successfully created.",
+ setupVenvExists: "Virtual environment already exists.",
+ setupUpgradingPip: "Upgrading Python package installer (pip)...",
+ setupInstallingTorch: "Installing PyTorch AI Engine (CPU version)...",
+ setupDownloadingTorch: "Downloading torch and dependencies...",
+ setupInstallingDeps: "Installing collected packages...",
+ setupCompleted: "Configuration Complete! Enjoy background removal.",
+ setupFailed: "Setup failed. Check system dependencies.",
+ exportingMasterpiece: "Exporting masterpiece...",
+ toastExportSuccess: "Export Successful",
+ toastExportSuccessMsg: "Saved file correctly: ",
+ toastExportFailed: "Export Failed",
+ toastExportFailedMsg: "Save operation failed.",
+ toastExportError: "Export Error",
+ showInExplorer: "Show in File Explorer"
},
tr: {
title: "Dekupai - Trunçgil AI Dekupaj",
@@ -603,7 +650,39 @@ const TRANSLATIONS = {
dragDropSub: "PNG, JPG, JPEG veya WebP formatlarını destekler",
orText: "VEYA",
browseFiles: "Yerel Dosyalara Göz Atın",
- autoTrim: "Oto-Kırp"
+ autoTrim: "Oto-Kırp",
+ statusInit: "AI modeli başlatılıyor...",
+ statusWeights: "Yapay sinir ağları belleğe yükleniyor...",
+ statusImporting: "Kütüphaneler içe aktarılıyor...",
+ statusDetecting: "Donanım tespit ediliyor...",
+ statusUsingDevice: "Kullanılan donanım: ",
+ statusLoadingModel: "BiRefNet modeli yükleniyor...",
+ statusPreprocessing: "Görsel yükleniyor ve ön işleme yapılıyor...",
+ statusInference: "Arka plan temizleme algoritması çalıştırılıyor...",
+ statusGeneratingMask: "Şeffaflık maskesi oluşturuluyor...",
+ statusSaving: "Şeffaf görsel kaydediliyor...",
+ statusDone: "Tamamlandı!",
+ subFirstRun: "İlk çalıştırmada ~200MB ağırlık dosyası indirilir.",
+ subInference: "Detaylar ve yumuşak matlaştırma katmanı çıkarılıyor...",
+ subSaving: "Yüksek çözünürlüklü RGBA görsel birleştiriliyor...",
+ subDefault: "Yapay zeka modeli işleme yaparken lütfen bekleyin...",
+ setupReady: "Ortamı yapılandırmaya hazır.",
+ setupCreatingVenv: "Python sanal ortamı oluşturuluyor...",
+ setupVenvCreated: "Sanal ortam başarıyla oluşturuldu.",
+ setupVenvExists: "Sanal ortam zaten mevcut.",
+ setupUpgradingPip: "Python paket yükleyici (pip) güncelleniyor...",
+ setupInstallingTorch: "PyTorch AI motoru kuruluyor (CPU versiyonu)...",
+ setupDownloadingTorch: "Torch ve bağımlılıklar indiriliyor...",
+ setupInstallingDeps: "Toplanan paketler kuruluyor...",
+ setupCompleted: "Yapılandırma Tamamlandı! Arka plan temizlemenin keyfini çıkarın.",
+ setupFailed: "Kurulum başarısız oldu. Sistem bağımlılıklarını kontrol edin.",
+ exportingMasterpiece: "Çalışma dışa aktarılıyor...",
+ toastExportSuccess: "Dışa Aktarma Başarılı",
+ toastExportSuccessMsg: "Dosya başarıyla kaydedildi: ",
+ toastExportFailed: "Dışa Aktarma Başarısız",
+ toastExportFailedMsg: "Kaydetme işlemi başarısız oldu.",
+ toastExportError: "Dışa Aktarma Hatası",
+ showInExplorer: "Dosya Gezgininde Göster"
},
de: {
title: "Dekupai - Trunçgil AI Dekupage",
@@ -649,13 +728,45 @@ const TRANSLATIONS = {
stepLibs: "Installation der HuggingFace Transformers & PIL Bibliothek",
creditsVision: "Entwickelt unter der Vision von",
creditsExpertise: "durch die Software-Expertise von",
- creditsDesc: "Dekupai ist ein fortschrittlicher Deep-Learning-Desktop-Arbeitsbereich, der eine lokale, hochpräzise Hintergrundentfernung mithilfe von BiRefNet-Segmentierungsnetzwerken bietet.",
+ creditsDesc: "Dekupai is ein fortschrittlicher Deep-Learning-Desktop-Arbeitsbereich, der eine lokale, hochpräzise Hintergrundentfernung mithilfe von BiRefNet-Segmentierungsnetzwerken bietet.",
closeCredits: "Schließen",
dragDropText: "Bild hierher ziehen und ablegen",
dragDropSub: "Unterstützt PNG-, JPG-, JPEG- oder WebP-Formate",
orText: "ODER",
browseFiles: "Lokale Dateien durchsuchen",
- autoTrim: "Auto-Trim"
+ autoTrim: "Auto-Trim",
+ statusInit: "AI-Modell wird initialisiert...",
+ statusWeights: "Neuronale Gewichte werden geladen...",
+ statusImporting: "Bibliotheken werden importiert...",
+ statusDetecting: "Hardware wird erkannt...",
+ statusUsingDevice: "Verwendetes Gerät: ",
+ statusLoadingModel: "BiRefNet-Modell wird geladen...",
+ statusPreprocessing: "Bild wird geladen und vorverarbeitet...",
+ statusInference: "Hintergrundentfernungs-Inferenz wird ausgeführt...",
+ statusGeneratingMask: "Transparenzmaske wird generiert...",
+ statusSaving: "Transparentes Ausgabebild wird gespeichert...",
+ statusDone: "Abgeschlossen!",
+ subFirstRun: "Erster Start lädt Modell herunter (~200MB)",
+ subInference: "Details und weiche Maske werden extrahiert...",
+ subSaving: "Hochauflösender RGBA-Container wird zusammengestellt...",
+ subDefault: "Bitte warten Sie, während das AI-Modell verarbeitet...",
+ setupReady: "Bereit zum Konfigurieren der Umgebung.",
+ setupCreatingVenv: "Isolierte virtuelle Umgebung (.venv) wird erstellt...",
+ setupVenvCreated: "Virtuelle Umgebung erfolgreich erstellt.",
+ setupVenvExists: "Virtuelle Umgebung existiert bereits.",
+ setupUpgradingPip: "Python-Paketinstallateur (pip) wird aktualisiert...",
+ setupInstallingTorch: "PyTorch AI-Engine (CPU-Version) wird installiert...",
+ setupDownloadingTorch: "Torch und Abhängigkeiten werden heruntergeladen...",
+ setupInstallingDeps: "Gesammelte Pakete werden installiert...",
+ setupCompleted: "Konfiguration abgeschlossen! Viel Spaß mit der Hintergrundentfernung.",
+ setupFailed: "Setup fehlgeschlagen. Systemabhängigkeiten prüfen.",
+ exportingMasterpiece: "Meisterwerk wird exportiert...",
+ toastExportSuccess: "Export erfolgreich",
+ toastExportSuccessMsg: "Datei erfolgreich gespeichert: ",
+ toastExportFailed: "Export fehlgeschlagen",
+ toastExportFailedMsg: "Speichervorgang fehlgeschlagen.",
+ toastExportError: "Exportfehler",
+ showInExplorer: "Im Datei-Explorer anzeigen"
},
ru: {
title: "Dekupai - Trunçgil AI Декупаж",
@@ -707,7 +818,39 @@ const TRANSLATIONS = {
dragDropSub: "Поддерживает форматы PNG, JPG, JPEG или WebP",
orText: "ИЛИ",
browseFiles: "Обзор локальных файлов",
- autoTrim: "Автообрезка"
+ autoTrim: "Автообрезка",
+ statusInit: "Инициализация модели ИИ...",
+ statusWeights: "Загрузка весов нейросети в память...",
+ statusImporting: "Импорт библиотек...",
+ statusDetecting: "Обнаружение устройства...",
+ statusUsingDevice: "Используемое устройство: ",
+ statusLoadingModel: "Загрузка модели BiRefNet...",
+ statusPreprocessing: "Загрузка и предобработка изображения...",
+ statusInference: "Выполнение удаления фона...",
+ statusGeneratingMask: "Генерация маски прозрачности...",
+ statusSaving: "Сохранение выходного прозрачного изображения...",
+ statusDone: "Готово!",
+ subFirstRun: "Первый запуск загружает модель (~200 МБ)",
+ subInference: "Извлечение деталей и мягкой маски альфа...",
+ subSaving: "Сборка RGBA-контейнера высокого разрешения...",
+ subDefault: "Пожалуйста, подождите, пока модель ИИ обрабатывает...",
+ setupReady: "Готов к настройке среды.",
+ setupCreatingVenv: "Создание изолированной виртуальной среды (.venv)...",
+ setupVenvCreated: "Виртуальная среда успешно создана.",
+ setupVenvExists: "Виртуальная среда уже существует.",
+ setupUpgradingPip: "Обновление установщика пакетов Python (pip)...",
+ setupInstallingTorch: "Установка движка ИИ PyTorch (версия CPU)...",
+ setupDownloadingTorch: "Скачивание torch и зависимостей...",
+ setupInstallingDeps: "Установка собранных пакетов...",
+ setupCompleted: "Настройка завершена! Наслаждайтесь удалением фона.",
+ setupFailed: "Ошибка настройки. Проверьте системные зависимости.",
+ exportingMasterpiece: "Экспорт шедевра...",
+ toastExportSuccess: "Экспорт успешен",
+ toastExportSuccessMsg: "Файл успешно сохранен: ",
+ toastExportFailed: "Ошибка экспорта",
+ toastExportFailedMsg: "Операция сохранения не удалась.",
+ toastExportError: "Ошибка экспорта",
+ showInExplorer: "Показать в проводнике"
},
ar: {
title: "Dekupai - Trunçgil AI إزالة الخلفية",
@@ -759,7 +902,39 @@ const TRANSLATIONS = {
dragDropSub: "يدعم صيغ PNG أو JPG أو JPEG أو WebP",
orText: "أو",
browseFiles: "تصفح الملفات المحلية",
- autoTrim: "قص تلقائي"
+ autoTrim: "قص تلقائي",
+ statusInit: "تهيئة نموذج الذكاء الاصطناعي...",
+ statusWeights: "تحميل أوزان الشبكة العصبية في الذاكرة...",
+ statusImporting: "استيراد المكتبات...",
+ statusDetecting: "الكشف عن الجهاز...",
+ statusUsingDevice: "الجهاز المستخدم: ",
+ statusLoadingModel: "تحميل نموذج BiRefNet...",
+ statusPreprocessing: "تحميل ومعالجة الصورة مسبقاً...",
+ statusInference: "تشغيل خوارزمية إزالة الخلفية...",
+ statusGeneratingMask: "إنشاء قناع الشفافية...",
+ statusSaving: "حفظ الصورة الشفافة الناتجة...",
+ statusDone: "اكتمل!",
+ subFirstRun: "التشغيل الأول يقوم بتنزيل النموذج (~200 ميجابايت)",
+ subInference: "استخراج التفاصيل والشفافية الناعمة...",
+ subSaving: "تجميع حاوية RGBA عالية الدقة...",
+ subDefault: "يرجى الانتظار أثناء معالجة نموذج الذكاء الاصطناعي...",
+ setupReady: "جاهز لتكوين البيئة.",
+ setupCreatingVenv: "إنشاء بيئة افتراضية معزولة (.venv)...",
+ setupVenvCreated: "تم إنشاء البيئة الافتراضية بنجاح.",
+ setupVenvExists: "البيئة الافتراضية موجودة بالفعل.",
+ setupUpgradingPip: "ترقية مثبت حزم بايثون (pip)...",
+ setupInstallingTorch: "تثبيت محرك الذكاء الاصطناعي PyTorch (نسخة CPU)...",
+ setupDownloadingTorch: "تنزيل torch والاعتمادات...",
+ setupInstallingDeps: "تثبيت الحزم التي تم جمعها...",
+ setupCompleted: "اكتمل التكوين! استمتع بإزالة الخلفية.",
+ setupFailed: "فشل الإعداد. تحقق من تبعيات النظام.",
+ exportingMasterpiece: "تصدير العمل الفني...",
+ toastExportSuccess: "تم التصدير بنجاح",
+ toastExportSuccessMsg: "تم حفظ الملف بنجاح: ",
+ toastExportFailed: "فشل التصدير",
+ toastExportFailedMsg: "فشلت عملية الحفظ.",
+ toastExportError: "خطأ في التصدير",
+ showInExplorer: "عرض في مستكشف الملفات"
}
};
@@ -862,8 +1037,8 @@ async function executeBackgroundRemoval() {
elements.btnRemoveBg.classList.add('hidden');
elements.loaderBox.classList.remove('hidden');
- elements.loaderText.innerText = "Initializing AI model...";
- elements.loaderSubtext.innerText = "Loading neural weights into memory...";
+ elements.loaderText.innerText = getTrans('statusInit');
+ elements.loaderSubtext.innerText = getTrans('statusWeights');
// Get unique temporary output file path
const tempOut = await window.api.getTempPath('transparent_result.png');
@@ -871,15 +1046,40 @@ async function executeBackgroundRemoval() {
// Listen to execution progress
window.api.onProcessProgress((progress) => {
if (progress.includes("[STATUS]")) {
- const statusText = progress.replace("[STATUS] ", "");
- elements.loaderText.innerText = statusText;
+ const statusText = progress.replace("[STATUS] ", "").trim();
- if (statusText.includes("Hugging Face")) {
- elements.loaderSubtext.innerText = "This downloads ~200MB of weights on first run.";
- } else if (statusText.includes("inference")) {
- elements.loaderSubtext.innerText = "Extracting details and soft matting alpha...";
- } else if (statusText.includes("Saving")) {
- elements.loaderSubtext.innerText = "Assembling high-res RGBA container...";
+ // Let's map statusText to localized keys
+ if (statusText.includes("Importing libraries")) {
+ elements.loaderText.innerText = getTrans('statusImporting');
+ elements.loaderSubtext.innerText = getTrans('subDefault');
+ } else if (statusText.includes("Detecting device")) {
+ elements.loaderText.innerText = getTrans('statusDetecting');
+ elements.loaderSubtext.innerText = getTrans('subDefault');
+ } else if (statusText.startsWith("Using device:")) {
+ const device = statusText.replace("Using device:", "").trim();
+ elements.loaderText.innerText = getTrans('statusUsingDevice') + device;
+ elements.loaderSubtext.innerText = getTrans('subDefault');
+ } else if (statusText.includes("Loading BiRefNet model")) {
+ elements.loaderText.innerText = getTrans('statusLoadingModel');
+ elements.loaderSubtext.innerText = getTrans('subFirstRun');
+ } else if (statusText.includes("Loading and preprocessing image")) {
+ elements.loaderText.innerText = getTrans('statusPreprocessing');
+ elements.loaderSubtext.innerText = getTrans('subDefault');
+ } else if (statusText.includes("Running background removal inference")) {
+ elements.loaderText.innerText = getTrans('statusInference');
+ elements.loaderSubtext.innerText = getTrans('subInference');
+ } else if (statusText.includes("Generating transparency mask")) {
+ elements.loaderText.innerText = getTrans('statusGeneratingMask');
+ elements.loaderSubtext.innerText = getTrans('subInference');
+ } else if (statusText.includes("Saving output transparent image")) {
+ elements.loaderText.innerText = getTrans('statusSaving');
+ elements.loaderSubtext.innerText = getTrans('subSaving');
+ } else if (statusText.includes("DONE")) {
+ elements.loaderText.innerText = getTrans('statusDone');
+ elements.loaderSubtext.innerText = "";
+ } else {
+ // Fallback for any other status logs
+ elements.loaderText.innerText = statusText;
}
}
});
@@ -889,7 +1089,7 @@ async function executeBackgroundRemoval() {
if (result.success) {
processedTempPath = result.outputPath;
- showToast("AI Success", "Image background removed successfully!", "success");
+ showToast(getTrans('toastTitleSuccess'), getTrans('toastTrimCompleteMsg'), "success");
// Update workspace preview image source to output transparent PNG
// Add timestamp to bypass browser cache refreshing
@@ -909,10 +1109,10 @@ async function executeBackgroundRemoval() {
}, 300);
} else {
- showToast("Inference Error", result.error || "Execution terminated unexpectedly.", "error");
+ showToast(getTrans('toastTitleError'), result.error || getTrans('toastSetupErrorMsg'), "error");
}
} catch (err) {
- showToast("AI Fatal Error", err.message, "error");
+ showToast(getTrans('toastTitleError'), err.message, "error");
} finally {
elements.loaderBox.classList.add('hidden');
elements.btnRemoveBg.classList.remove('hidden');
@@ -1006,7 +1206,7 @@ async function executeExport() {
elements.btnExport.disabled = true;
elements.btnExport.innerHTML = `
- Exporting masterpiece...
+ ${getTrans('exportingMasterpiece')}
`;
setTimeout(async () => {
@@ -1069,22 +1269,22 @@ async function executeExport() {
if (result.success) {
showToastWithAction(
- "Export Successful",
- `Saved file correctly: ${result.filePath.split(/[\\/]/).pop()}`,
+ getTrans('toastExportSuccess'),
+ `${getTrans('toastExportSuccessMsg')}${result.filePath.split(/[\\/]/).pop()}`,
"success",
result.filePath
);
} else if (!result.canceled) {
- showToast("Export Failed", result.error || "Save operation failed.", "error");
+ showToast(getTrans('toastExportFailed'), result.error || getTrans('toastExportFailedMsg'), "error");
}
} catch (err) {
- showToast("Export Error", err.message, "error");
+ showToast(getTrans('toastExportError'), err.message, "error");
} finally {
// Re-enable button
elements.btnExport.disabled = false;
elements.btnExport.innerHTML = `
- Export Masterpiece
+ ${getTrans('exportMasterpiece')}
`;
}
}, 100);
@@ -1118,7 +1318,7 @@ function showToastWithAction(title, message, type = 'success', filePath) {
hideToast();
elements.toastTitle.innerText = title;
- elements.toastMessage.innerHTML = `${message}
`;
+ elements.toastMessage.innerHTML = `${message}
`;
elements.toastBanner.className = 'toast-notification glass-panel-inner';
if (type === 'success') elements.toastBanner.classList.add('success');
diff --git a/styles.css b/styles.css
index 22854a6..9c86eb3 100644
--- a/styles.css
+++ b/styles.css
@@ -348,13 +348,17 @@ body {
left: 0;
right: 0;
bottom: 0;
- z-index: 1;
+ z-index: 1 !important;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
}
/* CropperJS Custom Visual Styling overrides */
+.cropper-container {
+ z-index: 2 !important;
+}
+
.cropper-view-box {
outline: 2px solid var(--accent-purple);
outline-color: var(--accent-purple);