fix: resolve Auto-Trim canvas CORS block with webSecurity, implement dynamic multi-language localization (EN, TR, DE, RU, AR) with English base
This commit is contained in:
+46
-36
@@ -41,6 +41,16 @@
|
||||
<span class="badge">Trunçgil AI</span>
|
||||
</div>
|
||||
<div class="titlebar-controls">
|
||||
<!-- Language Switcher Selector -->
|
||||
<div class="select-wrapper language-select-wrapper" style="width: 76px; height: 26px; margin-right: 8px; -webkit-app-region: no-drag;">
|
||||
<select id="lang-select" style="padding: 2px 20px 2px 8px; font-size: 11px; height: 100%; border-radius: 6px; background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,0.08); font-weight: 600;">
|
||||
<option value="en">EN</option>
|
||||
<option value="tr">TR</option>
|
||||
<option value="de">DE</option>
|
||||
<option value="ru">RU</option>
|
||||
<option value="ar">AR</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="win-btn info-btn" id="btn-show-credits" title="Credits & Info">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>
|
||||
</button>
|
||||
@@ -77,27 +87,27 @@
|
||||
<circle cx="12" cy="12" r="4" fill="url(#neon-grad)" opacity="0.3" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1>Initializing AI Engine</h1>
|
||||
<p class="subtitle">Dekupai requires a local Python environment to run the BiRefNet neural network models.</p>
|
||||
<h1 data-i18n="initWizardTitle">Initializing AI Engine</h1>
|
||||
<p class="subtitle" data-i18n="initWizardSubtitle">Dekupai requires a local Python environment to run the BiRefNet neural network models.</p>
|
||||
</div>
|
||||
|
||||
<div class="setup-progress-box glass-panel-inner">
|
||||
<div class="setup-steps">
|
||||
<div class="step-item" id="step-venv">
|
||||
<span class="step-dot"></span>
|
||||
<span class="step-text">Creating isolated virtual environment (.venv)</span>
|
||||
<span class="step-text" data-i18n="stepVenv">Creating isolated virtual environment (.venv)</span>
|
||||
</div>
|
||||
<div class="step-item" id="step-pip">
|
||||
<span class="step-dot"></span>
|
||||
<span class="step-text">Upgrading Python package installer (pip)</span>
|
||||
<span class="step-text" data-i18n="stepPip">Upgrading Python package installer (pip)</span>
|
||||
</div>
|
||||
<div class="step-item" id="step-deps">
|
||||
<span class="step-dot"></span>
|
||||
<span class="step-text">Installing PyTorch AI Engine (CPU version)</span>
|
||||
<span class="step-text" data-i18n="stepDeps">Installing PyTorch AI Engine (CPU version)</span>
|
||||
</div>
|
||||
<div class="step-item" id="step-libs">
|
||||
<span class="step-dot"></span>
|
||||
<span class="step-text">Installing HuggingFace Transformers & PIL library</span>
|
||||
<span class="step-text" data-i18n="stepLibs">Installing HuggingFace Transformers & PIL library</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +119,7 @@
|
||||
|
||||
<div class="wizard-actions">
|
||||
<button class="btn btn-primary" id="btn-start-setup">
|
||||
<span>Configure Engine (Automatic)</span>
|
||||
<span data-i18n="configureEngine">Configure Engine (Automatic)</span>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
@@ -134,11 +144,11 @@
|
||||
<polyline points="21 15 16 10 5 21"></polyline>
|
||||
</svg>
|
||||
</div>
|
||||
<h2>Drag & Drop Image Here</h2>
|
||||
<p class="dropzone-sub">Supports PNG, JPG, JPEG, or WebP formats</p>
|
||||
<div class="or-separator"><span>OR</span></div>
|
||||
<h2 data-i18n="dragDropText">Drag & Drop Image Here</h2>
|
||||
<p class="dropzone-sub" data-i18n="dragDropSub">Supports PNG, JPG, JPEG, or WebP formats</p>
|
||||
<div class="or-separator"><span data-i18n="orText">OR</span></div>
|
||||
<button class="btn btn-glass" id="btn-browse">
|
||||
<span>Browse Local Files</span>
|
||||
<span data-i18n="browseFiles">Browse Local Files</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -215,7 +225,7 @@
|
||||
<path d="M4 3h16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z"></path>
|
||||
<path d="M8 8h8v8H8z"></path>
|
||||
</svg>
|
||||
<span>Auto-Trim</span>
|
||||
<span data-i18n="autoTrim">Auto-Trim</span>
|
||||
</button>
|
||||
|
||||
<button class="ctrl-btn btn-danger-icon" id="ctrl-reset" title="Reset Image State">
|
||||
@@ -234,27 +244,27 @@
|
||||
<section class="tower-group" id="sec-file-info">
|
||||
<div class="tower-heading">
|
||||
<span class="step-badge">1</span>
|
||||
<h3>Source File</h3>
|
||||
<h3 data-i18n="sourceFile">Source File</h3>
|
||||
</div>
|
||||
<div class="info-card glass-panel-inner" id="info-card-empty">
|
||||
<p class="text-muted text-center py-2">No image loaded</p>
|
||||
<p class="text-muted text-center py-2" data-i18n="noImage">No image loaded</p>
|
||||
</div>
|
||||
<div class="info-card glass-panel-inner hidden" id="info-card-loaded">
|
||||
<div class="info-row">
|
||||
<span class="label">Name</span>
|
||||
<span class="label" data-i18n="fileName">Name</span>
|
||||
<span class="val truncate" id="info-filename">-</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Resolution</span>
|
||||
<span class="label" data-i18n="fileResolution">Resolution</span>
|
||||
<span class="val" id="info-resolution">-</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Size</span>
|
||||
<span class="label" data-i18n="fileSize">Size</span>
|
||||
<span class="val" id="info-size">-</span>
|
||||
</div>
|
||||
<button class="btn btn-secondary btn-sm w-full" id="btn-change-image" style="margin-top: 10px; border-color: rgba(255, 122, 0, 0.2) !important;">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>
|
||||
<span style="font-size: 11px;">Yeni Görsel Yükle</span>
|
||||
<span style="font-size: 11px;" data-i18n="newImage">Import New Image</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
@@ -263,7 +273,7 @@
|
||||
<section class="tower-group" id="sec-ai-process">
|
||||
<div class="tower-heading">
|
||||
<span class="step-badge">2</span>
|
||||
<h3>Background Removal</h3>
|
||||
<h3 data-i18n="bgRemoval">Background Removal</h3>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary w-full" id="btn-remove-bg" disabled>
|
||||
@@ -271,7 +281,7 @@
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 16V8a2 2 0 0 0-2-2h-5m-9 0h5M3 8v8a2 2 0 0 0 2 2h8m9 0h-5"></path>
|
||||
</svg>
|
||||
<span>Extract Subject</span>
|
||||
<span data-i18n="extractSubject">Extract Subject</span>
|
||||
</button>
|
||||
|
||||
<!-- Loader panel inside -->
|
||||
@@ -282,8 +292,8 @@
|
||||
<circle cx="25" cy="25" r="20" fill="none" stroke-width="4"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="loader-text" id="loader-text">Initializing AI Model...</div>
|
||||
<div class="loader-subtext" id="loader-subtext">First launch downloads model (~200MB)</div>
|
||||
<div class="loader-text" id="loader-text" data-i18n="initAI">Initializing AI Model...</div>
|
||||
<div class="loader-subtext" id="loader-subtext" data-i18n="loadingWeights">First launch downloads model (~200MB)</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -291,24 +301,24 @@
|
||||
<section class="tower-group disabled-group" id="sec-canvas-bg">
|
||||
<div class="tower-heading">
|
||||
<span class="step-badge">3</span>
|
||||
<h3>Background Settings</h3>
|
||||
<h3 data-i18n="bgSettings">Background Settings</h3>
|
||||
</div>
|
||||
|
||||
<div class="bg-mode-tabs glass-panel-inner">
|
||||
<button class="bg-tab active" data-mode="transparent" id="tab-bg-trans">
|
||||
<span>Transparent</span>
|
||||
<span data-i18n="transparent">Transparent</span>
|
||||
</button>
|
||||
<button class="bg-tab" data-mode="solid" id="tab-bg-solid">
|
||||
<span>Solid Color</span>
|
||||
<span data-i18n="solidColor">Solid Color</span>
|
||||
</button>
|
||||
<button class="bg-tab" data-mode="gradient" id="tab-bg-grad">
|
||||
<span>Gradient</span>
|
||||
<span data-i18n="gradient">Gradient</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Solid Colors Panel -->
|
||||
<div class="bg-settings-subpanel hidden" id="subpanel-solid">
|
||||
<label class="panel-sublabel">Select Solid Fill</label>
|
||||
<label class="panel-sublabel" data-i18n="selectSolid">Select Solid Fill</label>
|
||||
<div class="color-swatches-grid">
|
||||
<button class="swatch white active" data-color="#ffffff"></button>
|
||||
<button class="swatch black" data-color="#000000"></button>
|
||||
@@ -328,7 +338,7 @@
|
||||
|
||||
<!-- Gradients Panel -->
|
||||
<div class="bg-settings-subpanel hidden" id="subpanel-gradient">
|
||||
<label class="panel-sublabel">Select High-End Gradient</label>
|
||||
<label class="panel-sublabel" data-i18n="selectGrad">Select High-End Gradient</label>
|
||||
<div class="gradient-swatches-grid">
|
||||
<button class="grad-swatch grad-1 active" data-gradient="linear-gradient(135deg, #a78bfa, #06b6d4)"
|
||||
title="Violet Cyan Glow"></button>
|
||||
@@ -350,12 +360,12 @@
|
||||
<section class="tower-group disabled-group" id="sec-export">
|
||||
<div class="tower-heading">
|
||||
<span class="step-badge">4</span>
|
||||
<h3>Export Studio</h3>
|
||||
<h3 data-i18n="exportStudio">Export Studio</h3>
|
||||
</div>
|
||||
|
||||
<div class="export-settings-box glass-panel-inner">
|
||||
<div class="settings-row">
|
||||
<label for="export-format">Format</label>
|
||||
<label for="export-format" data-i18n="format">Format</label>
|
||||
<div class="select-wrapper">
|
||||
<select id="export-format">
|
||||
<option value="png">PNG (Lossless)</option>
|
||||
@@ -367,7 +377,7 @@
|
||||
|
||||
<div class="settings-row hidden" id="row-quality-slider">
|
||||
<div class="slider-labels">
|
||||
<label for="export-quality">Quality</label>
|
||||
<label for="export-quality" data-i18n="quality">Quality</label>
|
||||
<span class="slider-val" id="export-quality-val">90%</span>
|
||||
</div>
|
||||
<input type="range" id="export-quality" min="10" max="100" value="90">
|
||||
@@ -381,7 +391,7 @@
|
||||
<polyline points="7 10 12 15 17 10"></polyline>
|
||||
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||
</svg>
|
||||
<span>Export Masterpiece</span>
|
||||
<span data-i18n="exportMasterpiece">Export Masterpiece</span>
|
||||
</button>
|
||||
</section>
|
||||
</aside>
|
||||
@@ -412,20 +422,20 @@
|
||||
<div style="font-size: 11px; font-weight: 700; color: #ff7a00; letter-spacing: 1.5px; margin-bottom: 12px; text-transform: uppercase;">Version 1.0.0</div>
|
||||
|
||||
<div class="glass-panel-inner" style="margin-top: 14px; text-align: center; display: flex; flex-direction: column; gap: 10px; padding: 20px !important;">
|
||||
<p style="font-size: 13px; color: var(--text-muted); font-weight: 500;">Developed under the vision of</p>
|
||||
<p style="font-size: 13px; color: var(--text-muted); font-weight: 500;" data-i18n="creditsVision">Developed under the vision of</p>
|
||||
<h2 style="font-family: var(--font-heading); font-size: 22px; font-weight: 800; color: #ff7a00; text-shadow: 0 0 12px rgba(255, 122, 0, 0.35);">Trunçgil Teknoloji</h2>
|
||||
<p style="font-size: 12px; color: var(--text-muted-dark); line-height: 1.4;">by the engineering expertise of</p>
|
||||
<p style="font-size: 12px; color: var(--text-muted-dark); line-height: 1.4;" data-i18n="creditsExpertise">by the engineering expertise of</p>
|
||||
<h3 style="font-family: var(--font-heading); font-size: 19px; font-weight: 700; color: #fff;">Ümit Tunç</h3>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 16px; font-size: 12px; color: var(--text-muted-dark); line-height: 1.5; padding: 0 10px;">
|
||||
<div style="margin-top: 16px; font-size: 12px; color: var(--text-muted-dark); line-height: 1.5; padding: 0 10px;" data-i18n="creditsDesc">
|
||||
Dekupai is an advanced deep-learning desktop workspace that provides local, high-precision background removal using BiRefNet neural segmentation networks.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-actions" style="margin-top: 10px; width: 100%;">
|
||||
<button class="btn btn-secondary w-full" id="btn-close-credits">
|
||||
<span>Close Credits</span>
|
||||
<span data-i18n="closeCredits">Close Credits</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,8 @@ function createWindow() {
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false
|
||||
nodeIntegration: false,
|
||||
webSecurity: false // Disabled to allow canvas pixel reading on local file:// assets for Auto-Trim
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+358
-19
@@ -33,6 +33,7 @@ const elements = {
|
||||
btnShowCredits: document.getElementById('btn-show-credits'),
|
||||
creditsOverlay: document.getElementById('credits-overlay'),
|
||||
btnCloseCredits: document.getElementById('btn-close-credits'),
|
||||
langSelect: document.getElementById('lang-select'),
|
||||
|
||||
// Setup Wizard
|
||||
setupOverlay: document.getElementById('setup-overlay'),
|
||||
@@ -106,6 +107,7 @@ const elements = {
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
setupTitlebarListeners();
|
||||
setupToastListeners();
|
||||
initLanguage(); // Initialize translations immediately on load
|
||||
|
||||
// Check if Python virtual environment exists
|
||||
const { hasVenv } = await window.api.checkPythonSetup();
|
||||
@@ -424,18 +426,25 @@ function setupToolbarListeners() {
|
||||
function autoTrimTransparent() {
|
||||
if (!cropper || !processedTempPath) return;
|
||||
|
||||
// We request canvas size matching the full uncropped image dimension
|
||||
const canvas = cropper.getCroppedCanvas({
|
||||
width: cropper.getImageData().naturalWidth,
|
||||
height: cropper.getImageData().naturalHeight
|
||||
});
|
||||
// Create a temporary hidden canvas to read pixels directly from the original image element
|
||||
// This bypasses any cropper canvas restrictions or CORS issues when webSecurity is false
|
||||
const canvas = document.createElement('canvas');
|
||||
const img = elements.imageElement;
|
||||
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
if (!canvas) {
|
||||
showToast("Trim Warning", "Could not analyze transparent boundaries.", "error");
|
||||
try {
|
||||
ctx.drawImage(img, 0, 0);
|
||||
} catch (err) {
|
||||
const title = getTrans('toastTrimFailed');
|
||||
const msg = getTrans('toastTrimFailedMsg') + ": " + err.message;
|
||||
showToast(title, msg, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const data = imgData.data;
|
||||
|
||||
@@ -445,11 +454,11 @@ function autoTrimTransparent() {
|
||||
let maxY = 0;
|
||||
let foundAlpha = false;
|
||||
|
||||
// Loop through pixels in grid to find bounding box of non-transparent values
|
||||
// Scan alpha channel (index + 3) to locate non-empty boundaries
|
||||
for (let y = 0; y < canvas.height; y++) {
|
||||
for (let x = 0; x < canvas.width; x++) {
|
||||
const alphaIndex = (y * canvas.width + x) * 4 + 3;
|
||||
if (data[alphaIndex] > 8) { // Alpha transparency cut-off
|
||||
if (data[alphaIndex] > 8) { // transparency threshold
|
||||
if (x < minX) minX = x;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y < minY) minY = y;
|
||||
@@ -460,16 +469,21 @@ function autoTrimTransparent() {
|
||||
}
|
||||
|
||||
if (foundAlpha) {
|
||||
// Add small padding to avoid clipping exactly
|
||||
// Add small padding to avoid clipping edge pixels exactly
|
||||
const pad = 10;
|
||||
minX = Math.max(0, minX - pad);
|
||||
minY = Math.max(0, minY - pad);
|
||||
maxX = Math.min(canvas.width, maxX + pad);
|
||||
maxY = Math.min(canvas.height, maxY + pad);
|
||||
|
||||
// Turn on Crop selection mode visual indicators
|
||||
cropper.setDragMode('crop');
|
||||
elements.ctrlCropDrag.classList.remove('active');
|
||||
elements.ctrlCropBox.classList.add('active');
|
||||
|
||||
// Convert pixel coordinates to Cropper canvas boundaries
|
||||
const canvasData = cropper.getCanvasData();
|
||||
const scale = canvasData.width / cropper.getImageData().naturalWidth;
|
||||
const scale = canvasData.width / img.naturalWidth;
|
||||
|
||||
// Set crop boundaries
|
||||
cropper.setCropBoxData({
|
||||
@@ -479,17 +493,342 @@ function autoTrimTransparent() {
|
||||
height: (maxY - minY) * scale
|
||||
});
|
||||
|
||||
// Switch to crop selection mode visual indicator
|
||||
cropper.setDragMode('crop');
|
||||
elements.ctrlCropDrag.classList.remove('active');
|
||||
elements.ctrlCropBox.classList.add('active');
|
||||
|
||||
showToast("Auto-Trim Complete", "Crop boundaries adjusted securely around subject.", "success");
|
||||
showToast(getTrans('toastTrimComplete'), getTrans('toastTrimCompleteMsg'), "success");
|
||||
} else {
|
||||
showToast("Trim Info", "No transparent border boundaries identified.", "info");
|
||||
showToast(getTrans('toastTitleInfo'), getTrans('toastTrimFailedMsg'), "info");
|
||||
}
|
||||
}
|
||||
|
||||
// --- LOCALIZATION ENGINE (i18n) ---
|
||||
const TRANSLATIONS = {
|
||||
en: {
|
||||
title: "Dekupai - Trunçgil AI Decoupage",
|
||||
sourceFile: "Source File",
|
||||
noImage: "No image loaded",
|
||||
fileName: "Name",
|
||||
fileResolution: "Resolution",
|
||||
fileSize: "Size",
|
||||
newImage: "Import New Image",
|
||||
bgRemoval: "Background Removal",
|
||||
extractSubject: "Extract Subject",
|
||||
initAI: "Initializing AI Model...",
|
||||
loadingWeights: "First launch downloads model (~200MB)",
|
||||
bgSettings: "Background Settings",
|
||||
transparent: "Transparent",
|
||||
solidColor: "Solid Color",
|
||||
gradient: "Gradient",
|
||||
selectSolid: "Select Solid Fill",
|
||||
selectGrad: "Select High-End Gradient",
|
||||
exportStudio: "Export Studio",
|
||||
format: "Format",
|
||||
quality: "Quality",
|
||||
exportMasterpiece: "Export Masterpiece",
|
||||
toastTitleInfo: "Info",
|
||||
toastTitleSuccess: "Success",
|
||||
toastTitleError: "Error",
|
||||
toastImageChanged: "Image Changed",
|
||||
toastImageChangedMsg: "Workspace cleared. Ready for a new image.",
|
||||
toastTrimComplete: "Auto-Trim Complete",
|
||||
toastTrimCompleteMsg: "Crop boundaries adjusted securely.",
|
||||
toastTrimFailed: "Trim Warning",
|
||||
toastTrimFailedMsg: "Could not analyze transparent boundaries.",
|
||||
toastSetupSuccess: "Setup Success",
|
||||
toastSetupSuccessMsg: "Python environment is fully configured.",
|
||||
toastSetupError: "Setup Error",
|
||||
toastSetupErrorMsg: "Failed to configure Python environment.",
|
||||
initWizardTitle: "Initializing AI Engine",
|
||||
initWizardSubtitle: "Dekupai requires a local Python environment to run the BiRefNet neural network models.",
|
||||
configureEngine: "Configure Engine (Automatic)",
|
||||
stepVenv: "Creating isolated virtual environment (.venv)",
|
||||
stepPip: "Upgrading Python package installer (pip)",
|
||||
stepDeps: "Installing PyTorch AI Engine (CPU version)",
|
||||
stepLibs: "Installing HuggingFace Transformers & PIL library",
|
||||
creditsVision: "Developed under the vision of",
|
||||
creditsExpertise: "by the engineering expertise of",
|
||||
creditsDesc: "Dekupai is an advanced deep-learning desktop workspace that provides local, high-precision background removal using BiRefNet neural segmentation networks.",
|
||||
closeCredits: "Close Credits",
|
||||
dragDropText: "Drag & Drop Image Here",
|
||||
dragDropSub: "Supports PNG, JPG, JPEG, or WebP formats",
|
||||
orText: "OR",
|
||||
browseFiles: "Browse Local Files",
|
||||
autoTrim: "Auto-Trim"
|
||||
},
|
||||
tr: {
|
||||
title: "Dekupai - Trunçgil AI Dekupaj",
|
||||
sourceFile: "Kaynak Dosya",
|
||||
noImage: "Görsel yüklenmedi",
|
||||
fileName: "Dosya Adı",
|
||||
fileResolution: "Çözünürlük",
|
||||
fileSize: "Boyut",
|
||||
newImage: "Yeni Görsel Yükle",
|
||||
bgRemoval: "Arka Plan Temizleme",
|
||||
extractSubject: "Özneyi Dekupe Et",
|
||||
initAI: "AI Modeli Başlatılıyor...",
|
||||
loadingWeights: "İlk çalıştırmada model indirilir (~200MB)",
|
||||
bgSettings: "Arka Plan Ayarları",
|
||||
transparent: "Şeffaf",
|
||||
solidColor: "Tek Renk",
|
||||
gradient: "Degrade",
|
||||
selectSolid: "Düz Renk Seçin",
|
||||
selectGrad: "Premium Degrade Seçin",
|
||||
exportStudio: "Dışa Aktarma Stüdyosu",
|
||||
format: "Format",
|
||||
quality: "Kalite",
|
||||
exportMasterpiece: "Çalışmayı Dışa Aktar",
|
||||
toastTitleInfo: "Bilgi",
|
||||
toastTitleSuccess: "Başarılı",
|
||||
toastTitleError: "Hata",
|
||||
toastImageChanged: "Görsel Değiştirildi",
|
||||
toastImageChangedMsg: "Çalışma alanı temizlendi. Yeni görsel için hazır.",
|
||||
toastTrimComplete: "Otomatik Kırpma Tamamlandı",
|
||||
toastTrimCompleteMsg: "Kırpma sınırları güvenli bir şekilde ayarlandı.",
|
||||
toastTrimFailed: "Kırpma Uyarısı",
|
||||
toastTrimFailedMsg: "Şeffaf sınırlar analiz edilemedi.",
|
||||
toastSetupSuccess: "Kurulum Başarılı",
|
||||
toastSetupSuccessMsg: "Python ortamı tamamen yapılandırıldı.",
|
||||
toastSetupError: "Kurulum Hatası",
|
||||
toastSetupErrorMsg: "Python ortamı yapılandırılamadı.",
|
||||
initWizardTitle: "AI Motoru Başlatılıyor",
|
||||
initWizardSubtitle: "Dekupai, BiRefNet yapay zeka modelini çalıştırmak için yerel bir Python ortamına ihtiyaç duyar.",
|
||||
configureEngine: "Motoru Yapılandır (Otomatik)",
|
||||
stepVenv: "İzole sanal ortam oluşturuluyor (.venv)",
|
||||
stepPip: "Python paket yöneticisi güncelleniyor (pip)",
|
||||
stepDeps: "PyTorch AI motoru kuruluyor (CPU versiyonu)",
|
||||
stepLibs: "HuggingFace Transformers ve PIL kuruluyor",
|
||||
creditsVision: "Vizyon ve liderlik",
|
||||
creditsExpertise: "yazılım geliştirme ve mühendislik",
|
||||
creditsDesc: "Dekupai, BiRefNet yapay sinir ağı segmentasyon modellerini kullanarak yerel ve yüksek hassasiyetli arka plan temizleme sağlayan gelişmiş bir derin öğrenme masaüstü uygulamasıdır.",
|
||||
closeCredits: "Kapat",
|
||||
dragDropText: "Görseli Buraya Sürükleyip Bırakın",
|
||||
dragDropSub: "PNG, JPG, JPEG veya WebP formatlarını destekler",
|
||||
orText: "VEYA",
|
||||
browseFiles: "Yerel Dosyalara Göz Atın",
|
||||
autoTrim: "Oto-Kırp"
|
||||
},
|
||||
de: {
|
||||
title: "Dekupai - Trunçgil AI Dekupage",
|
||||
sourceFile: "Quelldatei",
|
||||
noImage: "Kein Bild geladen",
|
||||
fileName: "Dateiname",
|
||||
fileResolution: "Auflösung",
|
||||
fileSize: "Größe",
|
||||
newImage: "Neues Bild Laden",
|
||||
bgRemoval: "Hintergrundentfernung",
|
||||
extractSubject: "Motiv Freistellen",
|
||||
initAI: "AI-Modell wird initialisiert...",
|
||||
loadingWeights: "Erster Start lädt Modell herunter (~200MB)",
|
||||
bgSettings: "Hintergrundeinstellungen",
|
||||
transparent: "Transparent",
|
||||
solidColor: "Vollfarbe",
|
||||
gradient: "Verlauf",
|
||||
selectSolid: "Volltonfarbe wählen",
|
||||
selectGrad: "Premium-Verlauf wählen",
|
||||
exportStudio: "Export Studio",
|
||||
format: "Format",
|
||||
quality: "Qualität",
|
||||
exportMasterpiece: "Meisterwerk Exportieren",
|
||||
toastTitleInfo: "Info",
|
||||
toastTitleSuccess: "Erfolg",
|
||||
toastTitleError: "Fehler",
|
||||
toastImageChanged: "Bild Geändert",
|
||||
toastImageChangedMsg: "Arbeitsbereich geleert. Bereit für neues Bild.",
|
||||
toastTrimComplete: "Auto-Zuschneiden Fertig",
|
||||
toastTrimCompleteMsg: "Zuschnittsgrenzen sicher angepasst.",
|
||||
toastTrimFailed: "Zuschnitt Warnung",
|
||||
toastTrimFailedMsg: "Transparente Grenzen konnten nicht analysiert werden.",
|
||||
toastSetupSuccess: "Setup erfolgreich",
|
||||
toastSetupSuccessMsg: "Python-Umgebung ist vollständig konfiguriert.",
|
||||
toastSetupError: "Setup-Fehler",
|
||||
toastSetupErrorMsg: "Konfiguration der Python-Umgebung fehlgeschlagen.",
|
||||
initWizardTitle: "AI-Engine wird initialisiert",
|
||||
initWizardSubtitle: "Dekupai erfordert eine lokale Python-Umgebung, um die BiRefNet-Modelle auszuführen.",
|
||||
configureEngine: "Engine konfigurieren (Automatisch)",
|
||||
stepVenv: "Erstellen einer isolierten virtuellen Umgebung (.venv)",
|
||||
stepPip: "Upgrade des Python-Paketinstallers (pip)",
|
||||
stepDeps: "Installation der PyTorch AI-Engine (CPU-Version)",
|
||||
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.",
|
||||
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"
|
||||
},
|
||||
ru: {
|
||||
title: "Dekupai - Trunçgil AI Декупаж",
|
||||
sourceFile: "Исходный файл",
|
||||
noImage: "Изображение не загружено",
|
||||
fileName: "Имя",
|
||||
fileResolution: "Разрешение",
|
||||
fileSize: "Размер",
|
||||
newImage: "Загрузить новое изображение",
|
||||
bgRemoval: "Удаление фона",
|
||||
extractSubject: "Вырезать объект",
|
||||
initAI: "Инициализация модели ИИ...",
|
||||
loadingWeights: "Первый запуск загружает модель (~200 МБ)",
|
||||
bgSettings: "Настройки фона",
|
||||
transparent: "Прозрачный",
|
||||
solidColor: "Сплошной цвет",
|
||||
gradient: "Градиент",
|
||||
selectSolid: "Выберите сплошной цвет",
|
||||
selectGrad: "Выберите премиум градиент",
|
||||
exportStudio: "Студия экспорта",
|
||||
format: "Формат",
|
||||
quality: "Качество",
|
||||
exportMasterpiece: "Экспортировать шедевр",
|
||||
toastTitleInfo: "Информация",
|
||||
toastTitleSuccess: "Успех",
|
||||
toastTitleError: "Ошибка",
|
||||
toastImageChanged: "Изображение изменено",
|
||||
toastImageChangedMsg: "Рабочая область очищена. Готово к новому изображению.",
|
||||
toastTrimComplete: "Автообрезка завершена",
|
||||
toastTrimCompleteMsg: "Границы обрезки успешно скорректированы.",
|
||||
toastTrimFailed: "Предупреждение об обрезке",
|
||||
toastTrimFailedMsg: "Не удалось проанализировать прозрачные границы.",
|
||||
toastSetupSuccess: "Установка успешна",
|
||||
toastSetupSuccessMsg: "Среда Python полностью настроена.",
|
||||
toastSetupError: "Ошибка установки",
|
||||
toastSetupErrorMsg: "Не удалось настроить среду Python.",
|
||||
initWizardTitle: "Инициализация движка ИИ",
|
||||
initWizardSubtitle: "Для работы Dekupai требуется локальная среда Python для запуска нейросетевых моделей BiRefNet.",
|
||||
configureEngine: "Настроить движок (Автоматически)",
|
||||
stepVenv: "Создание изолированной виртуальной среды (.venv)",
|
||||
stepPip: "Обновление установщика пакетов Python (pip)",
|
||||
stepDeps: "Установка движка ИИ PyTorch (версия для CPU)",
|
||||
stepLibs: "Установка библиотек HuggingFace Transformers и PIL",
|
||||
creditsVision: "Разработано под руководством",
|
||||
creditsExpertise: "программная инженерия и разработка",
|
||||
creditsDesc: "Dekupai — это продвинутое настольное приложение для глубокого обучения, обеспечивающее локальное высокоточное удаление фона с использованием моделей сегментации BiRefNet.",
|
||||
closeCredits: "Закрыть",
|
||||
dragDropText: "Перетащите изображение сюда",
|
||||
dragDropSub: "Поддерживает форматы PNG, JPG, JPEG или WebP",
|
||||
orText: "ИЛИ",
|
||||
browseFiles: "Обзор локальных файлов",
|
||||
autoTrim: "Автообрезка"
|
||||
},
|
||||
ar: {
|
||||
title: "Dekupai - Trunçgil AI إزالة الخلفية",
|
||||
sourceFile: "الملف المصدر",
|
||||
noImage: "لم يتم تحميل أي صورة",
|
||||
fileName: "الاسم",
|
||||
fileResolution: "الدقة",
|
||||
fileSize: "الحجم",
|
||||
newImage: "تحميل صورة جديدة",
|
||||
bgRemoval: "إزالة الخلفية",
|
||||
extractSubject: "استخراج العنصر",
|
||||
initAI: "تهيئة نموذج الذكاء الاصطناعي...",
|
||||
loadingWeights: "التشغيل الأول يقوم بتحميل النموذج (~200 ميجابايت)",
|
||||
bgSettings: "إعدادات الخلفية",
|
||||
transparent: "شفاف",
|
||||
solidColor: "لون موحد",
|
||||
gradient: "تدرج لوني",
|
||||
selectSolid: "اختر لوناً موحداً",
|
||||
selectGrad: "اختر تدرجاً لونيًا فاخرًا",
|
||||
exportStudio: "استوديو التصدير",
|
||||
format: "الصيغة",
|
||||
quality: "الجودة",
|
||||
exportMasterpiece: "تصدير العمل الفني",
|
||||
toastTitleInfo: "معلومات",
|
||||
toastTitleSuccess: "نجاح",
|
||||
toastTitleError: "خطأ",
|
||||
toastImageChanged: "تم تغيير الصورة",
|
||||
toastImageChangedMsg: "تم مسح مساحة العمل. جاهز لصورة جديدة.",
|
||||
toastTrimComplete: "اكتمل القص التلقائي",
|
||||
toastTrimCompleteMsg: "تم ضبط حدود القص بأمان حول العنصر.",
|
||||
toastTrimFailed: "تحذير القص",
|
||||
toastTrimFailedMsg: "تعذر تحليل الحدود الشفافة.",
|
||||
toastSetupSuccess: "نجاح التهيئة",
|
||||
toastSetupSuccessMsg: "تم تكوين بيئة بايثون بنجاح.",
|
||||
toastSetupError: "خطأ في التهيئة",
|
||||
toastSetupErrorMsg: "فشل تكوين بيئة بايثون.",
|
||||
initWizardTitle: "تهيئة محرك الذكاء الاصطناعي",
|
||||
initWizardSubtitle: "يتطلب Dekupai بيئة بايثون محلية لتشغيل نماذج الشبكة العصبية BiRefNet.",
|
||||
configureEngine: "تكوين المحرك (تلقائي)",
|
||||
stepVenv: "إنشاء بيئة افتراضية معزولة (.venv)",
|
||||
stepPip: "ترقية مثبت حزم بايثون (pip)",
|
||||
stepDeps: "تثبيت محرك الذكاء الاصطناعي PyTorch (نسخة المعالج CPU)",
|
||||
stepLibs: "تثبيت مكتبة HuggingFace Transformers و PIL",
|
||||
creditsVision: "تم التطوير تحت رؤية",
|
||||
creditsExpertise: "بواسطة الخبرة البرمجية والهندسية لـ",
|
||||
creditsDesc: "Dekupai هو مساحة عمل متقدمة للتعلم العميق توفر إزالة محلية ودقيقة للغاية للخلفيات باستخدام نماذج BiRefNet.",
|
||||
closeCredits: "إغلاق",
|
||||
dragDropText: "اسحب وأسقط الصورة هنا",
|
||||
dragDropSub: "يدعم صيغ PNG أو JPG أو JPEG أو WebP",
|
||||
orText: "أو",
|
||||
browseFiles: "تصفح الملفات المحلية",
|
||||
autoTrim: "قص تلقائي"
|
||||
}
|
||||
};
|
||||
|
||||
let currentLang = 'en'; // default English base language
|
||||
|
||||
function changeLanguage(lang) {
|
||||
currentLang = lang;
|
||||
localStorage.setItem('dekupai_lang', lang);
|
||||
|
||||
if (elements.langSelect) {
|
||||
elements.langSelect.value = lang;
|
||||
}
|
||||
|
||||
// Update HTML elements marked with data-i18n
|
||||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||||
const key = el.getAttribute('data-i18n');
|
||||
if (TRANSLATIONS[lang] && TRANSLATIONS[lang][key]) {
|
||||
// If element contains an inner span for icon text
|
||||
const span = el.querySelector('span');
|
||||
if (span) {
|
||||
span.innerText = TRANSLATIONS[lang][key];
|
||||
} else if (el.tagName === 'OPTION') {
|
||||
el.innerText = TRANSLATIONS[lang][key];
|
||||
} else {
|
||||
// Preserving SVG structure inside tags
|
||||
const svg = el.querySelector('svg');
|
||||
if (svg) {
|
||||
// If it has SVG, clear other text and append text node safely
|
||||
const textNodes = Array.from(el.childNodes).filter(node => node.nodeType === Node.TEXT_NODE);
|
||||
if (textNodes.length > 0) {
|
||||
textNodes[textNodes.length - 1].nodeValue = " " + TRANSLATIONS[lang][key];
|
||||
} else {
|
||||
el.appendChild(document.createTextNode(" " + TRANSLATIONS[lang][key]));
|
||||
}
|
||||
} else {
|
||||
el.innerText = TRANSLATIONS[lang][key];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle RTL for Arabic
|
||||
if (lang === 'ar') {
|
||||
document.body.dir = 'rtl';
|
||||
} else {
|
||||
document.body.dir = 'ltr';
|
||||
}
|
||||
|
||||
// Update original title
|
||||
document.title = TRANSLATIONS[lang].title;
|
||||
}
|
||||
|
||||
function getTrans(key) {
|
||||
return (TRANSLATIONS[currentLang] && TRANSLATIONS[currentLang][key]) || TRANSLATIONS['en'][key] || key;
|
||||
}
|
||||
|
||||
function initLanguage() {
|
||||
const savedLang = localStorage.getItem('dekupai_lang') || 'en';
|
||||
|
||||
if (elements.langSelect) {
|
||||
elements.langSelect.value = savedLang;
|
||||
elements.langSelect.addEventListener('change', (e) => {
|
||||
changeLanguage(e.target.value);
|
||||
});
|
||||
}
|
||||
|
||||
changeLanguage(savedLang);
|
||||
}
|
||||
|
||||
// --- CONTROL TOWER CONTROLLER ---
|
||||
function setupControlTowerListeners() {
|
||||
// Remove Background click
|
||||
|
||||
Reference in New Issue
Block a user