fix(parcel-sync): replace Unicode escapes with actual Romanian diacritics

The \u0103, \u00ee etc. escape sequences were rendering literally in JSX
text nodes instead of displaying ă, î, ț, ș characters.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-24 15:24:11 +02:00
parent d48a2bbf5d
commit 2b8d144924
8 changed files with 167 additions and 167 deletions
@@ -244,7 +244,7 @@ export function ExportTab({
phase: "Finalizat",
downloaded: prev.total ?? 100,
total: prev.total ?? 100,
message: `Desc\u0103rcare complet\u0103 \u2014 ${filename}`,
message: `Descărcare completă — ${filename}`,
note: undefined,
}
: null,
@@ -365,7 +365,7 @@ export function ExportTab({
err instanceof DOMException && err.name === "AbortError";
if (isTimeout) {
console.warn(
"[no-geom-scan] Timeout after 2 min \u2014 server eTerra lent",
"[no-geom-scan] Timeout after 2 min server eTerra lent",
);
}
setNoGeomScan({
@@ -469,7 +469,7 @@ export function ExportTab({
} else if (data.status === "done") {
setBgJobId(saved.jobId);
setBgProgress(data);
if (data.phase) setBgPhaseTrail(["Sincronizare complet\u0103"]);
if (data.phase) setBgPhaseTrail(["Sincronizare completă"]);
localStorage.removeItem("parcel-sync:bg-job");
} else {
localStorage.removeItem("parcel-sync:bg-job");
@@ -532,7 +532,7 @@ export function ExportTab({
}
startBgPolling(jid);
} catch (error) {
const msg = error instanceof Error ? error.message : "Eroare re\u021bea";
const msg = error instanceof Error ? error.message : "Eroare rețea";
console.warn("[sync-background]", msg);
}
},
@@ -573,7 +573,7 @@ export function ExportTab({
URL.revokeObjectURL(url);
} catch (error) {
const msg =
error instanceof Error ? error.message : "Eroare desc\u0103rcare";
error instanceof Error ? error.message : "Eroare descărcare";
console.warn("[download-from-db]", msg);
}
setDownloadingFromDb(false);
@@ -597,7 +597,7 @@ export function ExportTab({
<span className="font-medium text-foreground">
{dbTotalFeatures.toLocaleString("ro-RO")}
</span>{" "}
entit\u0103\u021bi \u00een DB din{" "}
entități în DB din{" "}
<span className="font-medium text-foreground">
{dbLayersSummary.length}
</span>{" "}
@@ -664,10 +664,10 @@ export function ExportTab({
)}
<div className="text-left">
<div className="font-semibold">
Descarc\u0103 Terenuri \u0219i Cl\u0103diri
Descarcă Terenuri și Clădiri
</div>
<div className="text-xs opacity-70 font-normal">
Sync + GPKG (din cache dac\u0103 e proasp\u0103t)
Sync + GPKG (din cache dacă e proaspăt)
</div>
</div>
</Button>
@@ -686,7 +686,7 @@ export function ExportTab({
<div className="text-left">
<div className="font-semibold">Magic</div>
<div className="text-xs opacity-70 font-normal">
Sync + \u00eembog\u0103\u021bire (CF, proprietari, adres\u0103) + GPKG + CSV
Sync + îmbogățire (CF, proprietari, adresă) + GPKG + CSV
</div>
</div>
</Button>
@@ -697,12 +697,12 @@ export function ExportTab({
{!session.connected ? (
<>
<Wifi className="h-10 w-10 mx-auto mb-3 opacity-30" />
<p>Conecteaz\u0103-te la eTerra pentru a activa exportul.</p>
<p>Conectează-te la eTerra pentru a activa exportul.</p>
</>
) : (
<>
<MapPin className="h-10 w-10 mx-auto mb-3 opacity-30" />
<p>Selecteaz\u0103 un UAT pentru a activa exportul.</p>
<p>Selectează un UAT pentru a activa exportul.</p>
</>
)}
</CardContent>
@@ -730,10 +730,10 @@ export function ExportTab({
<CardContent className="py-3 px-4">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Loader2 className="h-4 w-4 animate-spin text-amber-500" />
Se scaneaz\u0103 lista de imobile din eTerra\u2026 (max 2 min)
Se scanează lista de imobile din eTerra (max 2 min)
</div>
<p className="text-[11px] text-muted-foreground mt-1 ml-6">
Po\u021bi folosi butoanele de mai jos f\u0103r\u0103 s\u0103 a\u0219tep\u021bi scanarea.
Poți folosi butoanele de mai jos fără aștepți scanarea.
</p>
</CardContent>
</Card>
@@ -746,10 +746,10 @@ export function ExportTab({
<CardContent className="py-3 px-4">
<div className="flex items-center gap-2 text-sm text-amber-600 dark:text-amber-400">
<Clock className="h-4 w-4 shrink-0" />
Scanarea a dep\u0103\u0219it 2 minute \u2014 serverul eTerra e lent.
Scanarea a depășit 2 minute serverul eTerra e lent.
</div>
<p className="text-[11px] text-muted-foreground mt-1 ml-6">
Po\u021bi lansa sincronizarea fundal f\u0103r\u0103 rezultate de scanare.
Poți lansa sincronizarea fundal fără rezultate de scanare.
Include no-geom nu va fi disponibil.
</p>
<Button
@@ -759,7 +759,7 @@ export function ExportTab({
onClick={() => void handleNoGeomScan()}
>
<RefreshCw className="h-3 w-3 mr-1" />
Re\u00eencearc\u0103 scanarea
Reîncearcă scanarea
</Button>
</CardContent>
</Card>
@@ -779,7 +779,7 @@ export function ExportTab({
<div className="flex items-center gap-1.5 flex-wrap text-[11px] text-muted-foreground">
<Database className="h-3 w-3 shrink-0" />
<span>
Baza de date local\u0103:{" "}
Baza de date locală:{" "}
<span className="font-medium text-foreground">
{noGeomScan.localDbWithGeom.toLocaleString("ro-RO")}
</span>{" "}
@@ -790,16 +790,16 @@ export function ExportTab({
<span className="font-medium text-amber-600 dark:text-amber-400">
{noGeomScan.localDbNoGeom.toLocaleString("ro-RO")}
</span>{" "}
f\u0103r\u0103 geometrie
fără geometrie
</>
)}
{noGeomScan.localDbEnriched > 0 && (
<>
{" \u00b7 "}
{" · "}
<span className="font-medium text-teal-600 dark:text-teal-400">
{noGeomScan.localDbEnriched.toLocaleString("ro-RO")}
</span>{" "}
\u00eembog\u0103\u021bite
îmbogățite
{staleEnrichment && (
<span className="text-orange-600 dark:text-orange-400">
{" "}
@@ -810,7 +810,7 @@ export function ExportTab({
)}
{noGeomScan.localSyncFresh && (
<span className="text-emerald-600 dark:text-emerald-400 ml-1">
(proasp\u0103t)
(proaspăt)
</span>
)}
</span>
@@ -819,9 +819,9 @@ export function ExportTab({
<div className="flex items-center gap-1.5 text-[11px] text-orange-600 dark:text-orange-400 ml-[18px]">
<AlertTriangle className="h-3 w-3 shrink-0" />
<span>
{staleCount.toLocaleString("ro-RO")} parcele au \u00eembog\u0103\u021bire
veche (lips\u0103 PROPRIETARI_VECHI). Vor fi re-\u00eembog\u0103\u021bite la
urm\u0103torul export Magic.
{staleCount.toLocaleString("ro-RO")} parcele au îmbogățire
veche (lipsă PROPRIETARI_VECHI). Vor fi re-îmbogățite la
următorul export Magic.
</span>
</div>
)}
@@ -832,11 +832,11 @@ export function ExportTab({
const workflowPreview = scanDone && (
<div className="mt-2 ml-7 space-y-0.5">
<p className="text-[11px] font-medium text-muted-foreground">
La ap\u0103sarea Magic, pa\u0219ii vor fi:
La apăsarea Magic, pașii vor fi:
</p>
<ol className="text-[11px] text-muted-foreground list-decimal ml-4 space-y-px">
<li>
{"Sync GIS \u2014 "}
{"Sync GIS "}
<span
className={cn(
"font-medium",
@@ -848,16 +848,16 @@ export function ExportTab({
>
{noGeomScan.localSyncFresh &&
noGeomScan.localDbWithGeom > 0
? "skip (date proaspete \u00een DB)"
: `descarc\u0103 ${noGeomScan.remoteGisCount.toLocaleString("ro-RO")} terenuri` +
? "skip (date proaspete în DB)"
: `descarcă ${noGeomScan.remoteGisCount.toLocaleString("ro-RO")} terenuri` +
(noGeomScan.remoteCladiriCount > 0
? ` + ${noGeomScan.remoteCladiriCount.toLocaleString("ro-RO")} cl\u0103diri`
? ` + ${noGeomScan.remoteCladiriCount.toLocaleString("ro-RO")} clădiri`
: "")}
</span>
</li>
{includeNoGeom && (
<li>
Import parcele f\u0103r\u0103 geometrie \u2014{" "}
Import parcele fără geometrie {" "}
<span className="font-medium text-amber-600 dark:text-amber-400">
{(() => {
const usefulNoGeom =
@@ -878,7 +878,7 @@ export function ExportTab({
</li>
)}
<li>
\u00cembog\u0103\u021bire CF, proprietari, adrese \u2014{" "}
\u00cembogățire CF, proprietari, adrese {" "}
<span className="font-medium text-teal-600 dark:text-teal-400">
{(() => {
// What will be in DB after sync + optional no-geom import:
@@ -900,12 +900,12 @@ export function ExportTab({
totalAfter - noGeomScan.localDbEnrichedComplete;
return remaining > 0
? `~${remaining.toLocaleString("ro-RO")} de procesat (~${Math.ceil((remaining * 0.25) / 60)} min)`
: "deja \u00eembog\u0103\u021bite";
: "deja îmbogățite";
})()}
</span>
</li>
<li>Generare GPKG + CSV</li>
<li>Comprimare ZIP + desc\u0103rcare</li>
<li>Comprimare ZIP + descărcare</li>
</ol>
</div>
);
@@ -939,10 +939,10 @@ export function ExportTab({
"ro-RO",
)}
</span>{" "}
cl\u0103diri
clădiri
</>
)}
{" \u00b7 "}
{" · "}
Lista imobile:{" "}
<span className="font-semibold">
{noGeomScan.totalImmovables.toLocaleString("ro-RO")}
@@ -956,11 +956,11 @@ export function ExportTab({
noGeomScan.remoteGisCount,
).toLocaleString("ro-RO")}
</span>
{" f\u0103r\u0103 geometrie)"}
{" fără geometrie)"}
</p>
<p className="text-[11px] text-muted-foreground mt-0.5">
Cele f\u0103r\u0103 geometrie exist\u0103 \u00een baza de date eTerra dar
nu au contur desenat \u00een layerul GIS.
Cele fără geometrie există în baza de date eTerra dar
nu au contur desenat în layerul GIS.
</p>
{localDbLine}
</div>
@@ -984,7 +984,7 @@ export function ExportTab({
className="h-4 w-4 rounded border-muted-foreground/30 accent-amber-600"
/>
<span className="text-sm font-medium">
Include \u0219i parcelele f\u0103r\u0103 geometrie la export
Include și parcelele fără geometrie la export
</span>
</label>
{/* Quality breakdown of no-geom items */}
@@ -992,7 +992,7 @@ export function ExportTab({
<div className="ml-7 p-2 rounded-md bg-muted/40 space-y-1">
<p className="text-[11px] font-medium text-muted-foreground">
Calitate date (din{" "}
{noGeomScan.noGeomCount.toLocaleString("ro-RO")} f\u0103r\u0103
{noGeomScan.noGeomCount.toLocaleString("ro-RO")} fără
geometrie):
</p>
<div className="grid grid-cols-2 gap-x-4 gap-y-0.5 text-[11px] text-muted-foreground">
@@ -1013,7 +1013,7 @@ export function ExportTab({
</span>
</span>
<span>
Cu nr. cad. pe h\u00e2rtie:{" "}
Cu nr. cad. pe hârtie:{" "}
<span className="font-medium text-foreground">
{noGeomScan.qualityBreakdown.withPaperCad.toLocaleString(
"ro-RO",
@@ -1021,7 +1021,7 @@ export function ExportTab({
</span>
</span>
<span>
Cu suprafa\u021b\u0103:{" "}
Cu suprafață:{" "}
<span className="font-medium text-foreground">
{noGeomScan.qualityBreakdown.withArea.toLocaleString(
"ro-RO",
@@ -1037,7 +1037,7 @@ export function ExportTab({
</span>
</span>
<span>
Cu carte funciar\u0103:{" "}
Cu carte funciară:{" "}
<span className="font-medium text-foreground">
{noGeomScan.qualityBreakdown.withLandbook.toLocaleString(
"ro-RO",
@@ -1056,7 +1056,7 @@ export function ExportTab({
</span>
{noGeomScan.qualityBreakdown.empty > 0 && (
<span>
Filtrate (f\u0103r\u0103 CF/inactive/f\u0103r\u0103 date):{" "}
Filtrate (fără CF/inactive/fără date):{" "}
<span className="font-semibold text-rose-600 dark:text-rose-400">
{noGeomScan.qualityBreakdown.empty.toLocaleString(
"ro-RO",
@@ -1070,9 +1070,9 @@ export function ExportTab({
{includeNoGeom && (
<p className="text-[11px] text-muted-foreground ml-7">
{noGeomScan.qualityBreakdown.empty > 0
? `Din ${noGeomScan.noGeomCount.toLocaleString("ro-RO")} f\u0103r\u0103 geometrie, ~${noGeomScan.qualityBreakdown.useful.toLocaleString("ro-RO")} vor fi importate (imobile electronice cu CF). ${noGeomScan.qualityBreakdown.empty.toLocaleString("ro-RO")} vor fi filtrate (f\u0103r\u0103 carte funciar\u0103, inactive sau f\u0103r\u0103 date).`
: "Vor fi importate \u00een DB \u0219i incluse \u00een CSV + Magic GPKG (coloana HAS_GEOMETRY=0/1)."}{" "}
\u00cen GPKG de baz\u0103 apar doar cele cu geometrie.
? `Din ${noGeomScan.noGeomCount.toLocaleString("ro-RO")} fără geometrie, ~${noGeomScan.qualityBreakdown.useful.toLocaleString("ro-RO")} vor fi importate (imobile electronice cu CF). ${noGeomScan.qualityBreakdown.empty.toLocaleString("ro-RO")} vor fi filtrate (fără carte funciară, inactive sau fără date).`
: "Vor fi importate în DB și incluse în CSV + Magic GPKG (coloana HAS_GEOMETRY=0/1)."}{" "}
\u00cen GPKG de bază apar doar cele cu geometrie.
</p>
)}
{workflowPreview}
@@ -1091,14 +1091,14 @@ export function ExportTab({
<CheckCircle2 className="h-3.5 w-3.5 text-emerald-500" />
Toate cele{" "}
{noGeomScan.totalImmovables.toLocaleString("ro-RO")}{" "}
imobile din eTerra au geometrie \u2014 nimic de importat
imobile din eTerra au geometrie nimic de importat
suplimentar.
{noGeomScan.localDbTotal > 0 && (
<span className="ml-1">
({noGeomScan.localDbTotal.toLocaleString("ro-RO")}{" "}
\u00een DB local
în DB local
{noGeomScan.localDbEnriched > 0 &&
`, ${noGeomScan.localDbEnriched.toLocaleString("ro-RO")} \u00eembog\u0103\u021bite`}
`, ${noGeomScan.localDbEnriched.toLocaleString("ro-RO")} îmbogățite`}
{noGeomScan.localDbEnriched > 0 &&
noGeomScan.localDbEnrichedComplete <
noGeomScan.localDbEnriched && (
@@ -1106,15 +1106,15 @@ export function ExportTab({
{` (${(noGeomScan.localDbEnriched - noGeomScan.localDbEnrichedComplete).toLocaleString("ro-RO")} incomplete)`}
</span>
)}
{noGeomScan.localSyncFresh && ", proasp\u0103t"})
{noGeomScan.localSyncFresh && ", proaspăt"})
</span>
)}
</>
) : (
<>
<AlertTriangle className="h-3.5 w-3.5 text-muted-foreground" />
Nu s-au g\u0103sit imobile \u00een lista eTerra pentru acest
UAT. Verific\u0103 sesiunea eTerra.
Nu s-au găsit imobile în lista eTerra pentru acest
UAT. Verifică sesiunea eTerra.
</>
)}
</div>
@@ -1133,10 +1133,10 @@ export function ExportTab({
<div className="flex items-center gap-2">
<HardDrive className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium">
Procesare fundal &amp; desc\u0103rcare din DB
Procesare fundal &amp; descărcare din DB
</span>
<span className="text-[10px] text-muted-foreground">
\u2014 porne\u0219te sincronizarea, \u00eenchide pagina, descarc\u0103 mai t\u00e2rziu
pornește sincronizarea, închide pagina, descarcă mai târziu
</span>
</div>
@@ -1154,11 +1154,11 @@ export function ExportTab({
className="h-4 w-4 rounded border-muted-foreground/30 accent-amber-600"
/>
<span className="text-xs">
Include \u0219i parcelele f\u0103r\u0103 geometrie
Include și parcelele fără geometrie
</span>
{noGeomScanning && (
<span className="text-[10px] text-muted-foreground">
(scanare \u00een curs\u2026)
(scanare în curs)
</span>
)}
</label>
@@ -1179,17 +1179,17 @@ export function ExportTab({
>
{bgJobId &&
bgProgress?.status === "running" &&
!bgPhaseTrail.some((p) => p.includes("\u00cembog\u0103\u021bire")) ? (
!bgPhaseTrail.some((p) => p.includes("\u00cembogățire")) ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
<ArrowDownToLine className="mr-2 h-4 w-4" />
)}
<div className="text-left">
<div className="text-xs font-semibold">
Sync fundal \u2014 Baz\u0103
Sync fundal Bază
</div>
<div className="text-[10px] opacity-60 font-normal">
Terenuri + cl\u0103diri \u2192 salveaz\u0103 \u00een DB
Terenuri + clădiri \u2192 salvează în DB
</div>
</div>
</Button>
@@ -1205,17 +1205,17 @@ export function ExportTab({
>
{bgJobId &&
bgProgress?.status === "running" &&
bgPhaseTrail.some((p) => p.includes("\u00cembog\u0103\u021bire")) ? (
bgPhaseTrail.some((p) => p.includes("\u00cembogățire")) ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin text-teal-600" />
) : (
<Sparkles className="mr-2 h-4 w-4 text-teal-600" />
)}
<div className="text-left">
<div className="text-xs font-semibold">
Sync fundal \u2014 Magic
Sync fundal Magic
</div>
<div className="text-[10px] opacity-60 font-normal">
Sync + \u00eembog\u0103\u021bire \u2192 salveaz\u0103 \u00een DB
Sync + îmbogățire \u2192 salvează în DB
</div>
</div>
</Button>
@@ -1239,10 +1239,10 @@ export function ExportTab({
)}
<div className="text-left">
<div className="text-xs font-semibold">
Descarc\u0103 din DB \u2014 Baz\u0103
Descarcă din DB Bază
</div>
<div className="text-[10px] opacity-60 font-normal">
GPKG terenuri + cl\u0103diri (instant, f\u0103r\u0103 eTerra)
GPKG terenuri + clădiri (instant, fără eTerra)
</div>
</div>
</Button>
@@ -1260,7 +1260,7 @@ export function ExportTab({
)}
<div className="text-left">
<div className="text-xs font-semibold">
Descarc\u0103 din DB \u2014 Magic
Descarcă din DB Magic
</div>
<div className="text-[10px] opacity-60 font-normal">
GPKG + CSV + raport calitate (instant)
@@ -1272,8 +1272,8 @@ export function ExportTab({
{!session.connected && dbTotalFeatures === 0 && (
<p className="text-xs text-muted-foreground ml-6">
Conecteaz\u0103-te la eTerra pentru a porni sincronizarea fundal,
sau sincronizeaz\u0103 mai \u00eent\u00e2i date \u00een baza local\u0103.
Conectează-te la eTerra pentru a porni sincronizarea fundal,
sau sincronizează mai întâi date în baza locală.
</p>
)}
</CardContent>
@@ -1302,7 +1302,7 @@ export function ExportTab({
</span>
{bgProgress.status === "running" && (
<span className="text-muted-foreground">
(po\u021bi \u00eenchide pagina)
(poți închide pagina)
</span>
)}
</div>
@@ -1396,7 +1396,7 @@ export function ExportTab({
) : (
<Database className="mr-1.5 h-3 w-3" />
)}
Descarc\u0103 din DB (Magic)
Descarcă din DB (Magic)
</Button>
<Button
variant="ghost"
@@ -1466,7 +1466,7 @@ export function ExportTab({
{exportProgress.phase}
{exportProgress.phaseCurrent != null &&
exportProgress.phaseTotal
? ` \u2014 ${exportProgress.phaseCurrent} / ${exportProgress.phaseTotal}`
? ` ${exportProgress.phaseCurrent} / ${exportProgress.phaseTotal}`
: ""}
</p>
{exportProgress.note && (