diff --git a/js/i18n.js b/js/i18n.js
index 76ce246..83ddbbf 100644
--- a/js/i18n.js
+++ b/js/i18n.js
@@ -10,6 +10,7 @@ export const TRANSLATIONS = {
fr: { 'lang.name': 'Français' },
ja: { 'lang.name': '日本語 (beta)' },
ko: { 'lang.name': '한국어' },
+ ro: { 'lang.name': 'Română'}
};
// ── Module state ──────────────────────────────────────────────────────────────
diff --git a/js/i18n/ro.js b/js/i18n/ro.js
new file mode 100644
index 0000000..49b29bf
--- /dev/null
+++ b/js/i18n/ro.js
@@ -0,0 +1,167 @@
+export default {
+ "theme.dark": "Temă Întunecată",
+ "theme.light": "Temă Luminoasă",
+ "theme.toggleTitle": "Comută mod luminos/întunecat",
+ "theme.toggleAriaLabel": "Comută mod luminos/întunecat",
+ "dropHint.text": "Trage un fișier .stl, .obj sau un fișier .3mf aici ori ",
+ "ui.wireframe": "Schelet",
+ "ui.perspective": "Vedere din perspectivă",
+ "ui.controlsHint": "Trage în stânga: rotire · Trage în dreapta: deplasare · Scroll: zoom",
+ "ui.meshInfo": "{n} triunghiuri · {mb} MB · {sx} × {sy} × {sz} mm",
+ "ui.loadStl": "Încarcă modelul…",
+ "ui.localProcessingNote": "Toată procesarea este locală pe browser - nimic nu este încărcat online.",
+ "sections.displacementMap": "Hartă de deplasare",
+ "ui.uploadCustomMap": "Încarcă o hartă personalizată",
+ "ui.noMapSelected": "Nicio hartă selectată",
+ "ui.loadingTextures": "Se incarcă texturile…",
+ "sections.projection": "Proiecție",
+ "labels.mode": "Mod",
+ "projection.triplanar": "Triplanar",
+ "projection.cubic": "Cubic (Cutie)",
+ "projection.cylindrical": "Cilindric",
+ "projection.spherical": "Sferic",
+ "projection.planarXY": "Planar XY",
+ "projection.planarXZ": "Planar XZ",
+ "projection.planarYZ": "Planar YZ",
+ "sections.transform": "Transformare",
+ "labels.scaleU": "Scară U",
+ "labels.scaleV": "Scară V",
+ "labels.offsetU": "Decalaj U",
+ "labels.offsetV": "Decalaj V",
+ "labels.rotation": "Rotație",
+ "tooltips.proportionalScaling": "Scalare proporțională (U = V)",
+ "tooltips.proportionalScalingAria": "Scalare proporțională (U = V)",
+ "sections.displacement": "Adâncime textură",
+ "labels.amplitude": "Amplitudine (mm)",
+ "labels.seamBlend": "Îmbinare cusătură ⓘ",
+ "tooltips.seamBlend": "Netezește îmbinarea aspră de la punctul de întâlnire al fațetelor proeminente. Eficient pentru modurile cubic și cilindric.",
+ "labels.transitionSmoothing": "Netezire tranziție ⓘ",
+ "tooltips.transitionSmoothing": "Lățimea zonei de estompare în apropierea marginilor îmbinării. Valorile mai mici mențin tranzițiile strânse lângă îmbinare; valorile mai mari estompează o bandă mai largă.",
+ "labels.textureSmoothing": "Netezire textură ⓘ",
+ "tooltips.textureSmoothing": "Aplică un efect de estompare gaussiană hărții de deplasare. Valorile mai mari generează detalii ale suprafeței mai fine și mai treptate. 0 = dezactivat.",
+ "labels.capAngle": "Unghi capac ⓘ",
+ "tooltips.capAngle": "Unghiul (în grade) față de verticală la care începe proiecția capacului superior/inferior. Valorile mai mici limitează proiecția capacului la suprafețe aproape plane.",
+ "sections.masking": "Mascare",
+ "sections.maskAngles": "După unghi ⓘ",
+ "tooltips.maskAngles": "0° = fără mascare. Suprafețele aflate în acest unghi față de orizontală nu vor fi texturate.",
+ "labels.bottomFaces": "Fețe inferioare",
+ "tooltips.bottomFaces": "Se elimină textura de pe suprafețele orientate în jos aflate în acest unghi față de orizontală",
+ "labels.topFaces": "Fețe superioare",
+ "tooltips.topFaces": "Se elimină textura de pe suprafețele orientate în sus în cadrul acestui unghi față de orizontală",
+ "sections.surfaceMasking": "După suprafața ⓘ",
+ "sections.surfaceSelection": "Selecție suprafețe",
+ "tooltips.surfaceMasking": "Mască suprafețele pentru a controla zonele care vor fi deplasate.",
+ "tooltips.surfaceSelection": "Suprafețele selectate sunt afișate în verde și vor fi singurele care vor fi deplasate în timpul exportului.",
+ "excl.modeExclude": "Exclude",
+ "excl.modeExcludeTitle": "Modul de excludere: suprafețele vopsite nu vor fi afectate de deplasarea texturii",
+ "excl.modeIncludeOnly": "Include Only",
+ "excl.modeIncludeOnlyTitle": "Modul „Include Only”: doar suprafețele vopsite vor beneficia de deplasarea texturii",
+ "excl.toolBrush": "Pensulă",
+ "excl.toolBrushTitle": "Pensulă: pictează triunghiuri pentru a exclude",
+ "excl.toolFill": "Umplere",
+ "excl.toolFillTitle": "Umplere: umplere completă a suprafeței până la un unghi limită",
+ "excl.shiftHint": "Apasă Shift pentru a sterge",
+ "labels.type": "Tip",
+ "brushType.single": "Singur",
+ "brushType.circle": "Cerc",
+ "labels.size": "Marime",
+ "labels.maxAngle": "Unghi maxim",
+ "tooltips.maxAngle": "Unghiul diedru maxim dintre triunghiurile adiacente pe care umplerea trebuie să îl traverseze",
+ "ui.clearAll": "Șterge tot",
+ "excl.initExcluded": "0 fețe mascate",
+ "excl.faceExcluded": "{n} față mascată",
+ "excl.facesExcluded": "{n} fețe mascate",
+ "excl.faceSelected": "{n} față selectată",
+ "excl.facesSelected": "{n} fețe selectate",
+ "excl.hintExclude": "Suprafețele mascate apar în culoarea portocaliu și nu vor fi afectate de deplasare la export.",
+ "excl.hintInclude": "Suprafețele selectate sunt afișate în verde și vor fi singurele care vor fi deplasate în timpul exportului.",
+ "precision.label": "Precizie (Beta) ⓘ",
+ "precision.labelTitle": "Împărțiți rețeaua din fundal astfel încât pensula să selecteze cu o granularitate mai fină",
+ "precision.outdated": "⚠ Învechit",
+ "precision.refreshTitle": "Reîmpărțește rețeaua pentru a se potrivi cu dimensiunea actuală a pensulei",
+ "precision.triCount": "{n} △",
+ "precision.refining": "Se rafinează…",
+ "precision.warningBody": "Se estimează ~{n} triunghiuri. Acest lucru ar putea încetini browserul. Continuați?",
+ "labels.boundaryFalloff": "Mască netedă ⓘ",
+ "tooltips.boundaryFalloff": "Reduce treptat deplasarea la zero în apropierea marginilor mascate, împiedicând suprapunerea triunghiurilor la intersecția dintre zonele texturate și cele netexturate.",
+ "labels.symmetricDisplacement": "Deplasare simetrică ⓘ",
+ "tooltips.symmetricDisplacement": "Când este activată, griul la 50% = fără deplasare; albul împinge spre exterior, negrul împinge spre interior. Volumul piesei rămâne aproximativ constant.",
+ "labels.displacementPreview": "Previzualizare 3D ⓘ",
+ "tooltips.displacementPreview": "Împarte rețeaua și deplasează vârfurile în timp real, pentru a putea evalua adâncimea reală. Solicită intens procesorul grafic în cazul modelelor complexe.",
+ "ui.placeOnFace": "Asează pe față",
+ "ui.placeOnFaceTitle": "Faceți clic pe o față pentru a o orienta cu partea de jos spre patul de imprimare",
+ "progress.subdividingPreview": "Se pregătește previzualizarea...",
+ "warnings.amplitudeOverlap": "⚠ Amplitudinea depășește 10% din cea mai mică dimensiune a modelului — pot apărea suprapuneri geometrice în fișierul STL exportat.",
+ "sections.export": "Export ⓘ",
+ "tooltips.export": "O lungime mai mică a laturii = detalii mai fine ale deplasării. Rezultatul este apoi redus la numărul maxim de triunghiuri.",
+ "labels.resolution": "Rezoluție (mm)",
+ "tooltips.resolution": "Marginile mai lungi decât această valoare vor fi împărțite în timpul exportului",
+ "warnings.resolutionTooCoarse": "⚠ Rezoluția este mai mică decât 1/100 din diagonala cadrului de delimitare al modelului — detaliile fine se vor pierde. Reduceți valoarea pentru a obține rezultate mai detaliate.",
+ "labels.outputTriangles": "Triunghiuri de ieșire",
+ "tooltips.outputTriangles": "Mai întâi, rețeaua este subdivizată complet, apoi este redusă la acest număr",
+ "warnings.safetyCapHit": "⚠ Limita de siguranță de 20M pentru triunghi a fost atinsă în timpul subdivizării — rezultatul poate fi totuși mai grosier decât lungimea dorită a muchiei.",
+ "ui.exportStl": "Exportă STL",
+ "ui.export3mf": "Exportă 3MF",
+ "tooltips.exportStl": "Compatibil cu o gamă largă de programe de slicing",
+ "tooltips.export3mf": "Dimensiune mai mică a fișierului — este posibil să nu fie acceptată de toate programele de slicing",
+ "progress.writing3mf": "Scriere 3MF…",
+ "progress.subdividing": "Subdivizarea rețelei…",
+ "progress.refining": "Rafinare: {cur} triunghiuri, latura cea mai lungă {edge}",
+ "progress.applyingDisplacement": "Aplicarea deplasării la {n} triunghiuri…",
+ "progress.displacingVertices": "Deplasarea vârfurilor…",
+ "progress.decimatingTo": "Simplificarea triunghiurilor {from} → {to}…",
+ "progress.decimating": "Simplificare: {cur} → {to} triunghiuri",
+ "progress.writingStl": "Scriere STL…",
+ "progress.done": "Gata!",
+ "progress.processing": "Se procesează…",
+ "license.btn": "Licență & Condiții",
+ "license.title": "Licență & Condiții",
+ "license.item1": "Gratuit de utilizat în orice scop, inclusiv lucrări comerciale (ex: texturarea STL-urilor pentru clienți sau produse).",
+ "license.item2": "Atribuirea este apreciată, dar nu este obligatorie atunci când utilizezi acest instrument ca atare.",
+ "license.item3": "Susții acest instrument? Cumpără de pe CNCKitchen.STORE sau donează pe PayPal / Ko-fi.",
+ "license.item4": "Acest instrument este furnizat ca atare, fără nicio garanție de orice fel. Folosește-l pe propriul risc.",
+ "license.item5": "Nu se oferă suport. Autorul nu are nicio obligație să repare bug-uri, să răspundă la întrebări sau să actualizeze acest instrument. Acestea fiind spuse, raportările de bug-uri și sugestiile de funcționalități sunt mereu binevenite la texturizer@cnckitchen.com.",
+ "license.item6": "Autorul nu va fi tras la răspundere pentru daune, pierderi de date sau probleme apărute în urma utilizării acestui instrument.",
+ "license.item7": "Dorești să licențiezi sau să integrezi acest instrument pentru propria afacere sau website? Contactează-ne la contact@cnckitchen.com.",
+ "license.item8": "Codul sursă este disponibil pe GitHub.",
+ "imprint.btn": "Informații Legale & Confidențialitate",
+ "imprint.title": "Informații Legale & Politica de Confidențialitate",
+ "imprint.sectionImprint": "Informații Legale (Impressum)",
+ "imprint.info": "CNC Kitchen Stefan Hermann Bahnhofstr. 2 88145 Hergatz Germania",
+ "imprint.contact": "Email: contact@cnckitchen.com Telefon: +49 175 2011824 Numărul de telefon este strict pentru cereri legale/de afaceri — nu pentru suport tehnic.",
+ "imprint.odr": "Platforma UE de Soluționare Online a Litigiilor: https://ec.europa.eu/consumers/odr",
+ "imprint.sectionPrivacy": "Politica de Confidențialitate (Datenschutzerklärung)",
+ "imprint.privacyIntro": "Partea responsabilă (Verantwortlicher gem. Art. 4 Abs. 7 DSGVO): Stefan Hermann, Bahnhofstr. 2, 88145 Hergatz, Germania.",
+ "imprint.privacyHosting": "Acest website este găzduit pe GitHub Pages (GitHub Inc. / Microsoft Corp., 88 Colin P Kelly Jr St, San Francisco, CA 94107, SUA). Când vizitezi acest site, GitHub îți poate procesa adresa IP în jurnalele de server. Baza legală: Art. 6(1)(f) DSGVO (interes legitim în furnizarea website-ului). Vezi Declarația de Confidențialitate GitHub.",
+ "imprint.privacyLocal": "Acest instrument stochează preferințele utilizatorului (limba, tema) în localStorage-ul browserului tău. Aceste date nu părăsesc niciodată dispozitivul tău și nu sunt transmise către niciun server.",
+ "imprint.privacyNoCookies": "Acest website nu folosește cookie-uri, analytics sau alte tehnologii de urmărire.",
+ "imprint.privacyExternal": "Acest site conține linkuri către site-uri externe (ex: CNCKitchen.STORE, PayPal, Ko-fi). Aceste site-uri au propriile politici de confidențialitate, asupra cărora nu avem niciun control.",
+ "imprint.privacyRights": "Conform GDPR, ai dreptul la acces, rectificare, ștergere, restricționarea prelucrării, portabilitatea datelor, precum și dreptul de a depune o plângere la o autoritate de supraveghere.",
+ "sponsor.title": "Îți mulțumim că folosești BumpMesh de CNC Kitchen!",
+ "sponsor.body": "Acest instrument este oferit complet gratuit de CNC Kitchen. Cât timp se procesează STL-ul tău, de ce să nu arunci o privire pe magazinul care ne ajută să continuăm să facem lucruri faine pentru tine?",
+ "sponsor.visitStore": "🛒 Vizitează CNCKitchen.STORE",
+ "sponsor.donate": "💙 Donează prin PayPal",
+ "sponsor.donateKofi": "☕ Susține-ne pe Ko-fi",
+ "sponsor.dontShow": "Nu mai arăta asta",
+ "sponsor.closeAndContinue": "Închide & Continuă",
+ "cta.store": "Susții acest instrument? Cumpără de pe CNCKitchen.STORE sau donează pe PayPal / Ko-fi",
+ "cta.storeDismiss": "Închide",
+ "alerts.loadFailed": "Nu s-a putut incărca modelul: {msg}",
+ "alerts.exportFailed": "Exportul a eșuat: {msg}",
+ "alerts.exportOOM": "Exportul a eșuat: modelul a epuizat memoria în timpul subdivizării.\n\nAceasta se întâmplă atunci când rețeaua necesită prea multe triunghiuri la rezoluția solicitată.\n\nCum se remediază:\n\u2022 Măriți valoarea rezoluției (mm) pentru a genera mai puține triunghiuri",
+ "alerts.fileTooLarge": "Fișierul este prea mare ({size} MB). Limită maximă: {max} MB.",
+ "alerts.degenerateTrianglesRemoved": "{n} triunghiuri nevalide (coordonate NaN sau arie zero) au fost eliminate din rețea în momentul încărcării. Modelul va funcționa în continuare corect.",
+ "diag.runAdvanced": "Efectuați verificări avansate",
+ "diag.runAdvancedTitle": "Verificați dacă există triunghiuri care se intersectează sau se suprapun (poate dura câteva secunde în cazul rețelelor de dimensiuni mari)",
+ "diag.running": "Se verifică\u2026",
+ "diag.meshOk": "\u2714 Rețeaua arată bine",
+ "diag.openEdges": "{n} muchii deschise \u2014 rețeaua nu este etanșă",
+ "diag.nonManifoldEdges": "{n} muchie (muchii) care nu aparține (aparțin) unei varietăți",
+ "diag.multipleShells": "{n} carcasă (carcase) deconectată (deconectate)",
+ "diag.intersectingTris": "{n} perechi de triunghiuri care se intersectează",
+ "diag.overlappingTris": "{n} triunghiuri suprapuse/duplicate",
+ "diag.advancedOk": "\u2714 Nu s-au găsit intersecții sau suprapuneri",
+ "diag.recommendFix": "Remediați aceste probleme în programul CAD, în programul de slicing sau online înainte de a aplica textura.",
+ "diag.show": "Afișează",
+ "diag.hide": "Ascunde"
+};