43c1f45e29
Two reader-hardening changes born from the park-buzi phantom-scan investigation
(empty pre-opening site, exit reader pushing sun-decoded garbage codes).
1. CHANNEL TAGGING — closes the printed-card-clone hole. The DT-008 push is
channel-blind (one opaque cardid from either engine) and SubscriptionFlow
matched by value only, so printing an RF card's UID (often written on the
card face, e.g. 86A158) as a barcode cloned the card. Now:
- Vendor tool sets output prefixes (QRCode "Q:", Card "K:"; server env
overrides READER_QR_PREFIX / READER_CARD_PREFIX).
- routes/qr-reader.ts strips the prefix and tags the read's confirmed
channel (DeviceReadEvent.channel optical|rf; kind qr|card). Enrollment
capture stores the BARE value. READ log lines carry ch=… (permanent
phantom attribution).
- SubscriptionFlow.match requires channel agreement: an optical decode may
not claim an rf credential (and vice versa) — refused + signed
sub.refused.channelMismatch anomaly (a clone attempt is a fraud signal).
- Unprefixed reads keep the legacy untagged shape and match as before, so
enforcement only bites where prefixes are deployed. Deploy server FIRST,
then set prefixes in the vendor tool.
2. STRUCTURAL FILTER — phantom decodes out of the signed feed (operator-
requested, reverses the earlier "record every probe" position — red
"who is exiting?" rows for NOBODY train the operator to ignore the feed).
read-dispatch.ts drops a no-match reader value that cannot possibly be a
credential we issue (no ticket Luhn shape, no SUB-/SUBSESS- prefix, not
confirmed-RF, not a plate) to UNSIGNED device_events telemetry
(unrecognizedRead:true). Deliberately WIDE plausibility: forged ticket
shapes, unknown physical cards, unknown SUB- codes all still sign the
normal refusal anomaly; enrolled credentials match before the filter and
can never be hidden. Works for legacy unprefixed reads too — the feed
cleans up on deploy, before any vendor-tool change.
Wiki: dingtian-dt008-reader.md records the clone hole + fix, the filter (as a
recorded position reversal), and the two device-side settings now part of the
credential contract (output prefixes + Card Input format, moving 6H→8H at the
next vendor-tool session; both live ON the device — re-apply after any
factory reset/swap).
Tests: qr-reader-channel.test.ts (prefix split, route tagging, bare-value
capture), subscription-channel.test.ts (channel agreement matrix + anomaly),
read-dispatch-filter.test.ts (filter boundary: phantoms dropped, probes kept,
enrolled never hidden). Suite 278 green.
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
1036 lines
45 KiB
TypeScript
1036 lines
45 KiB
TypeScript
// Albanian (sq) — the DEFAULT and fallback language. Customer/operator-facing copy.
|
||
// Keys are dot-namespaced by area (common, nav, booth, …). When adding a string,
|
||
// add it here first (the fallback), then mirror the key in en.ts.
|
||
// See wiki/concepts/i18n.md.
|
||
|
||
export const sq = {
|
||
common: {
|
||
loading: "Duke u ngarkuar…",
|
||
logout: "Dil",
|
||
cancel: "Anulo",
|
||
close: "Mbyll",
|
||
save: "Ruaj",
|
||
none: "—",
|
||
themeDark: "errët",
|
||
themeLight: "çelët",
|
||
theme: "Tema",
|
||
fontSmaller: "Zvogëlo tekstin",
|
||
fontLarger: "Rrit tekstin",
|
||
fontSize: "Madhësia e tekstit",
|
||
today: "Sot",
|
||
yesterday: "Dje",
|
||
// Month names (index 0 = January) — kept in the catalog because the appliance's
|
||
// browser ICU may lack Albanian locale data (Intl falls back to English).
|
||
months: [
|
||
"Janar",
|
||
"Shkurt",
|
||
"Mars",
|
||
"Prill",
|
||
"Maj",
|
||
"Qershor",
|
||
"Korrik",
|
||
"Gusht",
|
||
"Shtator",
|
||
"Tetor",
|
||
"Nëntor",
|
||
"Dhjetor",
|
||
],
|
||
},
|
||
auth: {
|
||
title: "Sistemi i Parkimit",
|
||
username: "Përdoruesi",
|
||
password: "Fjalëkalimi",
|
||
signIn: "Hyr",
|
||
signingIn: "Duke hyrë…",
|
||
},
|
||
update: {
|
||
available: "Përditësim i disponueshëm",
|
||
prompt: "Versioni {{version}} është i disponueshëm. Ta instaloj tani dhe ta rinis?",
|
||
},
|
||
nav: {
|
||
booth: "Kabina",
|
||
shift: "Turni",
|
||
setup: "Konfigurimi",
|
||
devices: "Pajisjet",
|
||
tariff: "Tarifa",
|
||
tariffLab: "Lab Tarife",
|
||
subscriptions: "Abonimet",
|
||
plans: "Planet",
|
||
site: "Park",
|
||
users: "Përdoruesit",
|
||
roles: "Rolet",
|
||
shifts: "Turnet",
|
||
drawer: "Arka",
|
||
reports: "Raportet",
|
||
recycleBin: "Koshi",
|
||
logs: "Loget",
|
||
backup: "Kopje rezervë",
|
||
profile: "Profili",
|
||
},
|
||
drawer: {
|
||
recordTitle: "Regjistro një lëvizje arke",
|
||
amount: "shuma",
|
||
reasonPlaceholder: "arsyeja (p.sh. pagesë furnitori, depozitë banke)",
|
||
recordHint: "Regjistrohet menjëherë në arkë. Një admin e shqyrton më pas.",
|
||
mandatArketimi: "Arkëtim (hyrje) +",
|
||
mandatPagese: "Pagesë (dalje) −",
|
||
enterPositive: "Fut një shumë pozitive.",
|
||
recorded: "{{no}} u regjistrua. Arka tani {{amount}}.",
|
||
myTitle: "Lëvizjet e mia të arkës",
|
||
allTitle: "Lëvizjet e arkës",
|
||
pendingCount: "{{count}} në pritje",
|
||
filterAll: "Të gjitha",
|
||
empty: "Asnjë lëvizje arke ende.",
|
||
colWhen: "Kur",
|
||
colType: "Lloji",
|
||
colAmount: "Shuma",
|
||
colReason: "Arsyeja",
|
||
colOperator: "Operatori",
|
||
colStatus: "Statusi",
|
||
status: {
|
||
pending: "në pritje",
|
||
authorized: "autorizuar",
|
||
denied: "refuzuar",
|
||
},
|
||
authorize: "Autorizo",
|
||
deny: "Refuzo",
|
||
denyNotePlaceholder: "arsyeja e refuzimit (opsionale)",
|
||
},
|
||
profile: {
|
||
title: "Profili im",
|
||
accountSection: "Llogaria",
|
||
fullName: "Emri i plotë",
|
||
fullNamePh: "Emri dhe mbiemri",
|
||
email: "Email",
|
||
emailPh: "ti@shembull.com",
|
||
username: "Përdoruesi",
|
||
role: "Roli",
|
||
saveProfile: "Ruaj profilin",
|
||
profileSaved: "Profili u ruajt.",
|
||
passwordSection: "Ndrysho fjalëkalimin",
|
||
currentPassword: "Fjalëkalimi aktual",
|
||
newPassword: "Fjalëkalimi i ri",
|
||
confirmPassword: "Konfirmo fjalëkalimin",
|
||
changePassword: "Ndrysho fjalëkalimin",
|
||
passwordChanged: "Fjalëkalimi u ndryshua.",
|
||
passwordsDontMatch: "Fjalëkalimet nuk përputhen.",
|
||
passwordTooShort: "Fjalëkalimi duhet të jetë të paktën {{min}} karaktere.",
|
||
},
|
||
status: {
|
||
live: "LIVE",
|
||
connecting: "DUKE U LIDHUR",
|
||
offline: "JASHTË LINJE",
|
||
},
|
||
devices: {
|
||
footerTitle: "Pajisjet",
|
||
none: "Asnjë pajisje e konfiguruar.",
|
||
catAccess: "Rele",
|
||
catReader: "Lexuesi",
|
||
catCamera: "Kamera",
|
||
catPrinter: "Printer",
|
||
catVision: "ANPR",
|
||
// Role/direction suffixes for the chip label (e.g. "Lexuesi hyrje").
|
||
role: {
|
||
entry: "hyrje",
|
||
exit: "dalje",
|
||
both: "hyrje/dalje",
|
||
mixed: "hyrje/dalje",
|
||
lane: "në korsi",
|
||
booth: "në kabinë",
|
||
},
|
||
state: {
|
||
ready: "gati",
|
||
degraded: "i dëmtuar",
|
||
offline: "jashtë linje",
|
||
},
|
||
allOk: "të gjitha gati",
|
||
issuesCount: "{{count}} me probleme",
|
||
issuesTitle: "Problemet e pajisjeve",
|
||
clickForIssues: "Kliko për detajet",
|
||
checkedAt: "kontrolluar {{time}}",
|
||
},
|
||
booth: {
|
||
processTicket: "Proceso biletën",
|
||
scanPlaceholder: "Skano ose shkruaj numrin e biletës…",
|
||
laneEntry: "Hyrje",
|
||
laneExit: "Dalje",
|
||
openTicket: "Lexo",
|
||
occupancy: "Prania",
|
||
occUnavailable: "zënia e padisponueshme",
|
||
inside: "brenda",
|
||
of: "nga",
|
||
uncapped: "pa kufi",
|
||
free: "Vende të lira",
|
||
lotFull: "● parkimi plot",
|
||
liveFeed: "Aktiviteti live",
|
||
events: "Evente",
|
||
noEventsYet: "Asnjë event ende — hyrjet dhe daljet do të shfaqen këtu.",
|
||
activeSessions: "Sesionet aktive",
|
||
insideCount: "brenda",
|
||
noActiveSessions: "Asnjë sesion aktiv.",
|
||
noMatch: "Asnjë rezultat për filtrin.",
|
||
// Kokat e kolonave të tabelës së sesioneve aktive.
|
||
colWho: "Biletë / abonent",
|
||
colPlate: "Targa",
|
||
colEntry: "Hyrja",
|
||
colElapsed: "Koha brenda",
|
||
badgeOverstay: "tej afatit",
|
||
badgeOverstayTitle:
|
||
"Sesion i paguar. Klienti nuk doli brënda afatit kohor. Ka filluar një periudhë e re tarifimi.",
|
||
plateTitle: "Targa e njohur nga ANPR",
|
||
// filtra
|
||
filterSearchSessions: "Kërko biletë / abonent / targë…",
|
||
filterSearchFeed: "Kërko event / identitet / targë…",
|
||
filterAll: "Të gjitha",
|
||
fKindTransient: "Kalimtarë",
|
||
fKindSubscription: "Abonentë",
|
||
fSrcBooth: "Kabinë",
|
||
fSrcReader: "Lexues",
|
||
fEvtEntry: "Hyrje",
|
||
fEvtExit: "Dalje",
|
||
fEvtPay: "Pagesë",
|
||
fEvtVoid: "Anulim",
|
||
fEvtAnomaly: "Anomali",
|
||
openPayExit: "Hap pagesën / daljen",
|
||
openReopenBarrier: "Hap — paguar, pret barrierën",
|
||
issueEntry: "Lësho biletë",
|
||
issueEntryTitle: "Lësho një biletë hyrjeje & hap barrierën (butoni fizik i prishur)",
|
||
issueEntryConfirm: "Një automjet është te hyrja. Të lëshohet një biletë hyrjeje dhe të hapet barriera?",
|
||
issueEntryOk: "Bileta e hyrjes {{ticket}} u lëshua.",
|
||
exitedGrace: "doli · në afat",
|
||
exitedGraceLeft: "doli · {{time}}",
|
||
exitedGraceTitle: "Paguar dhe dalur — barriera nuk u konfirmua; po pret afatin kohor.",
|
||
openBarrier: "Hap barrierën",
|
||
openBarrierTitle: "Hap barrierën manualisht",
|
||
barrierOpened: "barriera u hap",
|
||
openManually: "hape manualisht",
|
||
// session row badges
|
||
badgeExiting: "duke dalë",
|
||
badgePaid: "paguar",
|
||
badgeUnpaid: "papaguar",
|
||
badgeSubscription: "abonim",
|
||
// event types (live feed labels)
|
||
evtEntry: "HYRJE",
|
||
evtExit: "DALJE",
|
||
evtPay: "PAGESË",
|
||
evtVoid: "ANULIM",
|
||
evtOpenCmd: "HAP→",
|
||
evtOpenObserved: "HAP✓",
|
||
evtShiftOpen: "TURN+",
|
||
evtShiftZ: "TURN Z",
|
||
evtCashMovement: "ARKË",
|
||
evtCashIn: "ARKËTIM",
|
||
evtCashOut: "PAGESË",
|
||
evtCashReview: "SHQYRTIM",
|
||
evtConfigChange: "KONFIG",
|
||
decision: { authorize: "autorizuar", deny: "refuzuar" },
|
||
evtAnomaly: "ANOMALI",
|
||
evtRefused: "REFUZUAR",
|
||
// rreshti i detajeve të eventit live + etiketat e klasifikimit (nga payload)
|
||
evtNoReason: "pa arsye të regjistruar",
|
||
badgeEntryRefused: "hyrje e refuzuar",
|
||
badgeExitRefused: "dalje e refuzuar",
|
||
badgeLotFull: "parkimi plot",
|
||
badgeBarrierFailed: "barriera nuk u hap",
|
||
badgeManualOpen: "hapje manuale",
|
||
badgeSubRefused: "abonimi u refuzua",
|
||
badgeSubSale: "shitje abonimi",
|
||
badgeWindowCharge: "jashtë orarit — detyrim",
|
||
badgeNoTicket: "bileta nuk u printua",
|
||
feedSourceBooth: "kabinë",
|
||
feedSourceReader: "lexues",
|
||
// dritarja e detajeve të eventit
|
||
eventDetail: "Detajet e eventit",
|
||
edType: "Lloji",
|
||
edTime: "Ora",
|
||
edIndex: "Indeksi në regjistër",
|
||
edDirection: "Drejtimi",
|
||
edSource: "Burimi",
|
||
edIdentity: "Identiteti",
|
||
edReason: "Arsyeja",
|
||
edSnapshots: "Fotot",
|
||
edPayload: "Të dhënat e nënshkruara",
|
||
edChain: "Zinxhiri",
|
||
edSignature: "Nënshkrimi",
|
||
edKeyId: "Çelësi",
|
||
edPrevHash: "Hash-i i mëparshëm",
|
||
edNoPayload: "Ky event nuk ka të dhëna shtesë.",
|
||
edCopy: "Kopjo",
|
||
edCopied: "U kopjua",
|
||
edDetails: "Detajet",
|
||
edAuditData: "Të dhënat e auditimit (nënshkrimi & zinxhiri)",
|
||
edAmount: "Shuma",
|
||
edTender: "Mënyra e pagesës",
|
||
edSession: "Sesioni",
|
||
edPlate: "Targa",
|
||
edCategory: "Kategoria",
|
||
edOperator: "Operatori",
|
||
edDecision: "Vendimi i shqyrtimit",
|
||
edReviewedBy: "Shqyrtuar nga",
|
||
edReviewNote: "Shënim",
|
||
edReviewRef: "Ref. lëvizjes",
|
||
edTariffVersion: "Versioni i tarifës",
|
||
edRawPayload: "Të dhënat e papërpunuara të nënshkruara",
|
||
edOccurrence: "ID e hyrjes",
|
||
subscriber: "Abonent",
|
||
edVia: "Mënyra e hyrjes",
|
||
viaQr: "Kod QR",
|
||
viaCard: "Kartë/çip RFID",
|
||
viaPlate: "Targë",
|
||
},
|
||
// Mesazhet e përkthyera për REASON_CODES e nënshkruara (shih @parking/shared).
|
||
// Çelësat përputhen 1:1 me kodet; {{param}} mbushet nga reasonParams i eventit.
|
||
reason: {
|
||
"entry.refused.full": "Hyrja u refuzua — parkimi plot ({{count}}/{{capacity}})",
|
||
"entry.held.noTicket": "Hyrja u mbajt — bileta nuk u printua: {{detail}}",
|
||
"entry.operatorIssued": "Biletë hyrjeje e lëshuar nga operatori {{operator}} (butoni fizik i prishur)",
|
||
"entry.issue.noPresence": "Hyrja nga operatori u refuzua — asnjë automjet te hyrja",
|
||
"entry.duplicatePlate": "Hyrje e dyfishtë e mundshme — targa {{plate}} është tashmë brenda me biletën {{otherIdentity}}",
|
||
"exit.refused.closed": "Dalja u refuzua — sesioni është mbyllur tashmë",
|
||
"exit.refused.noSession": "Dalja u refuzua — biletë e panjohur",
|
||
"exit.refused.unpaid": "Dalja u refuzua — e papaguar (bëj pagesën në fillim)",
|
||
"exit.refused.graceExpired": "Dalja u refuzua — afati i daljes skadoi (kërkohet pagesë shtesë)",
|
||
"exit.open.noBarrier": "Dalja u regjistrua, por nuk ka barrierë daljeje të konfiguruar — hape manualisht",
|
||
"exit.open.unavailable": "Dalja u regjistrua, por barriera është e padisponueshme — hape manualisht",
|
||
"exit.open.failed": "Dalja u regjistrua, por barriera nuk u hap — hape manualisht",
|
||
"exit.freeGrace": "Periudhë pa pagesë në hyrje (pa tarifë)",
|
||
"exit.manualOpen": "Hapje manuale e barrierës (ndërhyrje njerëzore)",
|
||
"exit.plateSwapSuspected": "Mundësi ndërrimi biletash — targa {{plate}} është tashmë brenda me biletën {{otherIdentity}}",
|
||
"exit.plateSwapOverride": "Operatori {{operator}} lëshoi një dalje me dyshim ndërrimi biletash (targa {{plate}}, edhe e hapur me {{otherIdentity}})",
|
||
"sub.refused.notFound": "Abonimi u refuzua — nuk u gjet",
|
||
"sub.refused.outOfWindow": "Abonimi u refuzua — {{status}}/jashtë afatit",
|
||
"sub.refused.noSession": "Dalje me abonim pa sesion të hapur (tashmë jashtë / nuk ka hyrë kurrë)",
|
||
"sub.refused.atCapacity": "Abonimi u refuzua — në kapacitet ({{inUse}}/{{max}} makina brenda)",
|
||
"sub.refused.unpaidWindow": "Dalja u refuzua — detyrim jashtë orarit i papaguar ({{amount}} {{currency}}); paguaje në kabinë",
|
||
"sub.refused.channelMismatch": "Kredenciali u refuzua — kredencial {{credentialKind}} i paraqitur në kanalin {{channel}} (kredencial i mundshëm i klonuar)",
|
||
"void.ticketCancelled": "Bileta u anulua — {{reason}}",
|
||
"setup.relayTest": "Test releje — admini {{operator}} aktivizoi relenë {{relay}} te kontrolluesi {{controller}} nga Konfigurimi",
|
||
},
|
||
tariff: {
|
||
title: "Tarifa",
|
||
noRateCard: "Asnjë tarifë e publikuar — arka nuk mund të faturojë derisa të publikoni një.",
|
||
activeSince: "Aktive që nga {{date}} · {{count}} version(e) në histori. Publikimi krijon një version të ri; sesionet e kaluara ruajnë çmimin origjinal.",
|
||
currency: "Monedha",
|
||
freeEntryGrace: "Periudha pa pagesë në hyrje (min)",
|
||
billingIncrement: "Intervali i faturimit (min)",
|
||
dailyCap: "Kufiri ditor (bosh = pa kufi)",
|
||
dailyCapPh: "p.sh. 12.00",
|
||
lostTicketFee: "Tarifa për biletë të humbur",
|
||
exitGrace: "Periudha e kthimit në dalje (min)",
|
||
rateBlocks: "Blloqet tarifore",
|
||
rateBlocksHint: "Çdo brez zgjat një numër orësh dhe faturohet me çmimin e tij; brezat konsumohen me radhë (orët e para, pastaj orët në vijim). Brezi i fundit është \"më pas\" (i hapur) — çmimi i tij zbatohet pas mbarimit të shkallës. Çmimi është për interval faturimi.",
|
||
bandDuration: "Kohëzgjatja e brezit",
|
||
hoursUnit: "orë",
|
||
egHours: "p.sh. 2",
|
||
pricePerIncrement: "Çmimi / interval",
|
||
thereafter: "më pas (i hapur)",
|
||
remove: "Hiq",
|
||
addBlock: "+ Shto bllok",
|
||
publishNewVersion: "Publiko version të ri",
|
||
publishing: "Duke publikuar…",
|
||
publishedOk: "U publikua versioni i ri i tarifës — tani është tarifa aktive.",
|
||
defaultCard: "Tarifa bazë (gjithmonë aktive)",
|
||
defaultCardHint: "Çmimi bazë i zbatuar kur asnjë nivel kohor/sezonal nuk vlen. Kjo e vetme është mjaftueshëm për shumicën e parkimeve.",
|
||
modeLadder: "Shkallë orësh",
|
||
modeFlat: "Çmim fiks",
|
||
modeStepped: "Sipas kohëzgjatjes (deri-në)",
|
||
steppedHint:
|
||
"Vendos çmimin TOTAL për një qëndrim deri në një kohë të caktuar (p.sh. deri 3 orë = 500). Fiton rreshti i parë me kufi ≥ kohëzgjatjes (kufiri përfshihet). Totali i rreshtit të fundit përsëritet si çmim ditor për qëndrime më të gjata.",
|
||
stepUpTo: "Deri në",
|
||
stepTotal: "Çmimi total",
|
||
addStep: "+ Shto rresht",
|
||
steppedTiersConflict:
|
||
"⚠ Nivelet kohore/sezonale NUK zbatohen kur tarifa bazë është 'Sipas kohëzgjatjes (deri-në)' — motori i shpërfill plotësisht. Hiqi nivelet, ose ndrysho tarifën bazë në 'Shkallë orësh' a 'Çmim fiks'. Publikimi bllokohet derisa kjo të rregullohet.",
|
||
tiersAdvanced: "Të avancuara: nivele kohore & sezonale",
|
||
tiersHint: "Opsionale. Shto nivele tarifore që vlejnë vetëm në orë/ditë/data ose kategori të caktuara (p.sh. orë e lirë, tarifë nate, fundjavë, autobus). Pa nivele, publikohet vetëm tarifa bazë.",
|
||
tierName: "Emri",
|
||
tierPriority: "Përparësia",
|
||
tierCategory: "Kategoria",
|
||
tierCategoryPh: "p.sh. autobus",
|
||
tierDays: "Ditët",
|
||
tierHours: "Orët",
|
||
tierDates: "Datat",
|
||
tierOvernight: "(kalon mesnatën)",
|
||
addTier: "+ Shto nivel",
|
||
dow1: "Hën",
|
||
dow2: "Mar",
|
||
dow3: "Mër",
|
||
dow4: "Enj",
|
||
dow5: "Pre",
|
||
dow6: "Sht",
|
||
dow0: "Die",
|
||
},
|
||
setup: {
|
||
title: "Konfigurimi",
|
||
intro:
|
||
"Shto fillimisht kontrollerat e barrierave — Pastaj shto lexues (QR/RF), kamera, printera.",
|
||
// Category titles + the singular noun used in buttons/modal titles.
|
||
catControllers: "Kontrollerat (barrierat + butoni i hyrjes)",
|
||
catReaders: "Lexuesit (QR / RFID)",
|
||
catCameras: "Kamerat (foto + targë)",
|
||
catPrinters: "Printerat (bileta / vouchera)",
|
||
nounController: "kontroller",
|
||
nounReader: "lexues",
|
||
nounCamera: "kamerë",
|
||
nounPrinter: "printer",
|
||
add: "+ Shto {{noun}}",
|
||
addAnother: "+ Shto {{noun}}",
|
||
addTitle: "Shto {{noun}}",
|
||
editTitle: "Ndrysho {{noun}}",
|
||
needControllerFirst: "Shto fillimisht një kontroller — {{noun}} drejtohet te një prej releve të tij.",
|
||
failedToLoad: "Ngarkimi i konfigurimit dështoi: {{error}}",
|
||
loadingCatalog: "Duke ngarkuar katalogun e pajisjeve…",
|
||
// Direction labels (relay direction + inherited binding).
|
||
dirEntry: "Hyrje",
|
||
dirExit: "Dalje",
|
||
dirBoth: "Hyrje + dalje",
|
||
inherits: "trashëgon {{direction}}",
|
||
// Warnings panel.
|
||
warnTitle: "⚠ U ruajt, por nevojitet veprim:",
|
||
dismiss: "Mbyll",
|
||
// Assignment row.
|
||
disabled: "(çaktivizuar)",
|
||
edit: "Ndrysho",
|
||
remove: "Hiq",
|
||
removing: "Duke hequr…",
|
||
confirmRemove: "Të hiqet kjo pajisje {{driver}}?",
|
||
noRelaysSet: "asnjë rele e caktuar",
|
||
unbound: "e palidhur",
|
||
// Device form.
|
||
noDrivers: "Asnjë drejtues i regjistruar.",
|
||
chooseDevice: "Zgjidh një pajisje…",
|
||
scan: "Skano për kontroller",
|
||
scanning: "Duke skanuar…",
|
||
noControllersFound: "Asnjë kontroller në LAN.",
|
||
use: "Përdor",
|
||
test: "Testo lidhjen",
|
||
testing: "Duke testuar…",
|
||
saveConfigure: "Ruaj & konfiguro",
|
||
saveChanges: "Ruaj ndryshimet",
|
||
saving: "Duke ruajtur…",
|
||
cancel: "Anulo",
|
||
testFailed: "Testi dështoi: {{error}}",
|
||
saveFailed: "Ruajtja dështoi: {{error}}",
|
||
deviceLabel: "Pajisja:",
|
||
preconditionsOk: "● parakushtet OK",
|
||
autoFixedOnSave: "(rregullohet vetë në ruajtje)",
|
||
backendPushIp: "IP-ja e backend-it",
|
||
chooseAddress: "Zgjidh një adresë…",
|
||
onDeviceSubnet: "— në subnetin e pajisjes",
|
||
noNicOnSubnet: "⚠ asnjë NIC në subnetin e pajisjes — pajisja mund të mos arrijë backend-in",
|
||
backendIpHint: "Adresa te e cila kjo pajisje do të dërgojë eventet e hyrjes.",
|
||
// Relay editor.
|
||
relaysTitle: "Relet në këtë kontroller",
|
||
relaysHint:
|
||
"Çdo rele hap një barrierë. Cakto drejtimin e saj; për hyrje kalimtare, cakto në cilin terminal hyrës është lidhur butoni i hyrjes.",
|
||
outputsTitle: "Daljet — relet (barrierat + drita)",
|
||
outputsHint:
|
||
"Relet janë DALJE: secila hap një barrierë (ose ndez dritën e butonit). Cakto numrin e relesë dhe drejtimin. Terminalet hyrëse (butoni, sensori) janë te seksioni Hyrjet më poshtë.",
|
||
pulseOpenMs: "Kohëzgjatja e hapjes (ms)",
|
||
pulseOpenHint: "Sa kohë mbahet rele e barrierës e hapur (jog). Vlen për të gjitha relet e barrierave.",
|
||
inputsTitle: "Hyrjet — terminalet (buton, sensor)",
|
||
inputsHint:
|
||
"Hyrjet janë TERMINALE që hosti i LEXON: butoni i hyrjes dhe sensori i pranisë/radari. Secila i përket një barriere hyrëse — e gateron ose e nis atë rele.",
|
||
inputsIdleHigh: "Hyrjet në pushim HIGH",
|
||
inputsIdleHighHint: "Kjo pllakë i mban hyrjet HIGH në pushim (statusi 1111); një shtypje e ul në LOW.",
|
||
relay: "Rele",
|
||
// Generic input rows: terminal + role + the relay it serves.
|
||
inputTerminal: "Terminali",
|
||
inputServesRelay: "I shërben reles",
|
||
roleButton: "Butoni i hyrjes",
|
||
rolePresenceLoop: "Prania (lak induktiv)",
|
||
rolePresenceRadar: "Prania (radar)",
|
||
roleAlertTrigger: "Trigger alarmi",
|
||
addInput: "+ Shto hyrje",
|
||
entryCooldown: "Pritje pas biletës (sek)",
|
||
entryCooldownHint:
|
||
"Kur nuk ka sensor pranie: shtypjet e përsëritura të butonit shtypen për kaq sekonda pas një bilete. Zgjidhje rezervë (jo garanci) — një abuzues mund ta presë afatin.",
|
||
activeLow: "Aktiv-ulët",
|
||
activeLowHint:
|
||
"Shëno nëse sensori i pranisë (p.sh. radari) qëndron HIGH në pushim dhe shkon LOW kur detekton — e kundërta e butonit. Kjo përmbys leximin e atij terminali që 'prania' të lexohet saktë.",
|
||
eventRadarAlert: "Alarm radar (dritë)",
|
||
triggerInput: "Trigger input",
|
||
triggerInputHint:
|
||
"Terminali i hyrjes (radari) që nis pulsimin e kësaj rele. Pulson kur Trigger input është aktiv por kamera s'konfirmon makinë; ndizet fiks kur kamera konfirmon; përndryshe fiket.",
|
||
lockLane: "Bllokimi nga",
|
||
lockLaneHint:
|
||
"Cila kamerë e ndez dritën fiks: hyrja apo dalja. Një radar i daljes duhet të bllokohet nga kamera e DALJES.",
|
||
lockLaneEntry: "Kamera e hyrjes",
|
||
lockLaneExit: "Kamera e daljes",
|
||
blinkOnMs: "Pulsim ndezur (ms)",
|
||
blinkOffMs: "Pulsim fikur (ms)",
|
||
addRelay: "+ Shto rele",
|
||
// Camera ANPR opt-in.
|
||
anpr: "Njohja e targave (ANPR)",
|
||
anprHint:
|
||
"Lexo targat në këtë aparat: shërbimi i vizionit lexon targën nga çdo pamje dhe e regjistron (hyrje dhe dalje). Kërkon shërbimin e vizionit aktiv.",
|
||
anprAuto: "Hapje/mbyllje automatike me targën e abonentit",
|
||
anprAutoHint:
|
||
"Lejo që KY aparat të hapë vetë barrierën kur njeh targën e një abonenti. ÇAKTIVIZOJE te aparati i daljes në një korsi të përbashkët hyrje/dalje, që një makinë që HYN të mos DALË automatikisht nga targa e pasme (njohja vazhdon — fiket vetëm hapja automatike).",
|
||
testAnpr: "Testo ANPR",
|
||
anprTesting: "Duke testuar ANPR…",
|
||
testAnprHint:
|
||
"Merr një pamje të drejtpërdrejtë nga kjo kamerë dhe përpiqet të lexojë një targë, duke raportuar rezultatin dhe kohën e nevojshme. Vendos një targë para kamerës më parë.",
|
||
anprOk: "✓ Targa u lexua {{plate}} — {{confidence}}% besueshmëri, {{ms}} ms",
|
||
anprLowConfidence: "(besueshmëri e ulët — vetëm këshillues)",
|
||
anprTookMs: "{{ms}} ms",
|
||
"anprFail.vision-disabled": "Shërbimi i vizionit është çaktivizuar — aktivizoje (VISION_ENABLED) për ta testuar ANPR.",
|
||
"anprFail.snapshot-failed": "Nuk u mor dot pamje nga kamera (jashtë linje ose e paarritshme).",
|
||
"anprFail.no-plate": "Nuk u gjet asnjë targë në pamje.",
|
||
// Printer test slip — pushes a real slip so the admin can confirm it physically prints.
|
||
testPrint: "Printo provë",
|
||
printTesting: "Duke printuar…",
|
||
testPrintHint:
|
||
"Dërgon një fletë prove te printeri tani. ‘I lidhur’ vetëm hap lidhjen — kjo konfirmon se printeri vërtet nxjerr letër.",
|
||
printOk: "✓ Fleta e provës u dërgua ({{ms}} ms). Kontrollo printerin.",
|
||
"printFail.print-failed": "Printeri nuk pranoi punën (pa letër, kapaku hapur, ose lidhja ra).",
|
||
// Provë e releut — hap fizikisht barrierën (hapja regjistrohet në ledger).
|
||
testRelay: "Provo R{{relay}}",
|
||
relayTesting: "Duke hapur…",
|
||
testRelayTitle: "Puls releu {{relay}} — hap barrierën",
|
||
confirmRelayTest: "Ky veprim hap fizikisht barrierën dhe regjistrohet në ledger si provë.",
|
||
relayTestOk: "✓ R{{relay}} u pulsua — barriera u hap",
|
||
relayTestFailed: "✗ R{{relay}} dështoi: {{detail}}",
|
||
// Anashkalimi i portës së pranisë (radar/kamera me defekt) — admini heq një sinjal si kusht.
|
||
presenceGateTitle: "Porta e pranisë në hyrje",
|
||
presenceGateHint:
|
||
"Butoni i hyrjes normalisht kërkon edhe radarin/lakun edhe një zbulim nga kamera për të konfirmuar një automjet real. Nëse një pajisje ka defekt, anashkaloje që kalimtarët të mund të hyjnë derisa ta rregullojë ekipi i mbështetjes. Çdo ndryshim regjistrohet në ledger, dhe biletat e lëshuara gjatë anashkalimit shënohen.",
|
||
presenceBypassRadar: "Anashkalo radarin / lakun (sensor prania me defekt)",
|
||
presenceBypassCamera: "Anashkalo kamerën (zbulim automjeti me defekt)",
|
||
presenceBypassActive: "Anashkalimi i pranisë aktiv — porta e hyrjes është dobësuar. Fike sapo pajisja të rregullohet.",
|
||
// Reveal/hide toggle for a secret field (e.g. the device web password).
|
||
revealSecret: "Shfaq fjalëkalimin",
|
||
hideSecret: "Fshih fjalëkalimin",
|
||
// Alarm Server push settings — generated for the camera's Event → Alarm Server form.
|
||
alarmUrlTitle: "Cilësimet e Alarm Server (vendosi te kamera)",
|
||
alarmUrlHint:
|
||
"Vendosi këto te kamera: Configuration → Event → … → Alarm Settings (ose Notify Surveillance Center). Kamera do të dërgojë çdo ngjarje këtu — pa polling.",
|
||
alarmUrlCopy: "Kopjo të gjitha",
|
||
alarmUrlCopied: "U kopjua ✓",
|
||
alarmUrlSaveFirst:
|
||
"Ruaje kamerën më parë — adresa gjenerohet pasi pajisja të marrë një ID. Hape sërish për editim që ta shohësh.",
|
||
alarmUrlTestFirst:
|
||
"Kliko “Testo lidhjen” më parë — kështu përcaktohet IP-ja e këtij hosti në rrjetin e kamerës (që kamera ta thërrasë).",
|
||
alarmFieldHost: "Destination IP / Host",
|
||
alarmFieldUrl: "URL",
|
||
alarmFieldProtocol: "Protokolli",
|
||
alarmFieldPort: "Porta",
|
||
// Binding picker.
|
||
whichBarrier: "Cilën barrierë shërben kjo pajisje?",
|
||
controller: "Kontrolleri",
|
||
choose: "Zgjidh…",
|
||
relayLabel: "Rele {{relay}} ({{direction}})",
|
||
noRelaysConfigured: "Ky kontroller nuk ka rele të konfiguruar.",
|
||
},
|
||
lab: {
|
||
title: "Lab Tarife",
|
||
intro:
|
||
"Testo tarifat në kohë (dritare ditë/natë, kufi ditor, qëndrim tej afatit) në sekonda, pa pritur orë. Çmimi llogaritet me të njëjtën logjikë si kabina; nuk shkruhet asgjë në ledger.",
|
||
loadTicket: "Ngarko nga një biletë reale",
|
||
loadTicketPh: "Numri i biletës / identiteti",
|
||
load: "Ngarko",
|
||
loaded: "U ngarkua sesioni {{id}}",
|
||
tariffVersion: "Versioni i tarifës",
|
||
activeVersion: "Versioni aktiv (i tanishëm)",
|
||
entered: "Hyrja",
|
||
asOf: "Deri më (tani/dalja)",
|
||
now: "Tani",
|
||
category: "Kategoria",
|
||
categoryPh: "p.sh. bus (bosh = makinë)",
|
||
payment: "Pagesa",
|
||
paid: "u pagua",
|
||
graceMin: "afati (min)",
|
||
price: "Llogarit çmimin",
|
||
pricing: "Duke llogaritur…",
|
||
outcome: "Rezultati",
|
||
amountDue: "Shuma për pagesë",
|
||
billedPeriod: "Periudha e faturuar",
|
||
overstay: "tej afatit",
|
||
settled: "i shlyer",
|
||
periodStart: "Fillimi i periudhës",
|
||
graceExpires: "Afati skadon",
|
||
curve: "Kurba sipas kohëzgjatjes",
|
||
curveHint: "Tarifa nga hyrja për disa kohëzgjatje — shih ku rrafshohet kufiri ditor ose ndryshojnë dritaret.",
|
||
},
|
||
subs: {
|
||
title: "Abonimet",
|
||
unnamed: "(pa emër)",
|
||
unbound: "pa kufizim",
|
||
car_one: "{{count}} makinë",
|
||
car_other: "{{count}} makina",
|
||
cred: "kredencial",
|
||
plates: "{{count}} targë(a)",
|
||
noPrice: "pa çmim",
|
||
perDay: "ditë",
|
||
perWeek: "javë",
|
||
perMonth: "muaj",
|
||
plan: "Plani",
|
||
quantity: "Makina",
|
||
quantityHint: "makina të mbuluara nga ky abonim (çmimi ×N)",
|
||
count: "Sa",
|
||
planNone: "— pa pagesë / falas —",
|
||
planNoneAvail: "Asnjë plan i përcaktuar — admini duhet të krijojë një të parin.",
|
||
version: "Versioni",
|
||
versionCurrent: "aktual",
|
||
versionHint: "Zhvendos këtë abonent në një version tjetër të të njëjtit plan. Çmimi mbetet siç u faturua; ndryshon vetëm orari i lejuar nga këtu e tutje.",
|
||
versionOnlyOne: "vetëm një version i këtij plani",
|
||
everyDay: "çdo ditë",
|
||
allDay: "24/7 (pa orar)",
|
||
quoting: "duke llogaritur…",
|
||
quotePrompt: "zgjidh datën e mbarimit",
|
||
quoteLine: "{{periods}} × {{unit}} · {{amount}} {{currency}}",
|
||
tender: "Paguar me",
|
||
tenderCash: "Para në dorë",
|
||
tenderCard: "Kartë",
|
||
tenderHint: "Regjistrohet si pagesë e nënshkruar (aktiviteti, arka, raporti i turnit).",
|
||
saleRecorded: "Shitja u regjistrua: {{amount}} {{currency}} ({{tender}}).",
|
||
saleNoShift: "⚠ Asnjë turn i hapur — hapni një që arkëtimi të hyjë në një raport turni.",
|
||
edit: "Ndrysho",
|
||
revoke: "Anulo",
|
||
delete: "Fshij",
|
||
noneYet: "Asnjë abonim ende.",
|
||
add: "+ Shto abonim",
|
||
new: "Abonim i ri",
|
||
editTitle: "Ndrysho abonimin",
|
||
holderName: "Emri i mbajtësit",
|
||
contact: "Kontakti",
|
||
carLimit: "Kufiri i makinave",
|
||
limitCarsInAtOnce: "kufizo makinat brenda njëkohësisht",
|
||
validFrom: "Vlen nga",
|
||
validTo: "Vlen deri",
|
||
validToEnd: "Vlen deri (mbarimi)",
|
||
isoDateOptional: "Datë ISO (opsionale)",
|
||
boundPlates: "Targat e lidhura",
|
||
commaSeparatedOptional: "të ndara me presje (opsionale)",
|
||
credentials: "Kredencialet",
|
||
credentialsCardQr: "Kredencialet (kartë / QR)",
|
||
rfCardTag: "Kartë/Tag RF",
|
||
rfCardTagSoon: "Kartë/Tag RF (së shpejti)",
|
||
rfPlaceholder: "numri i kartës (ose lexo kartën)",
|
||
readCard: "Lexo kartën",
|
||
captureChooseReader: "Zgjidh lexuesin, pastaj afro kartën:",
|
||
captureNoReaders: "Asnjë lexues i konfiguruar.",
|
||
captureWaiting: "Afro kartën te lexuesi…",
|
||
captureTimeout: "Skadoi pa lexuar kartë. Provo sërish.",
|
||
captured: "Karta u lexua: {{value}}",
|
||
qr: "QR",
|
||
qrAutoGen: "kodi QR gjenerohet automatikisht në ruajtje",
|
||
credentialValue: "vlera e kredencialit",
|
||
addCredential: "+ kredencial",
|
||
needCredentialOrPlate: "Një abonim kërkon të paktën një kredencial OSE një targë të lidhur.",
|
||
save: "Ruaj",
|
||
cancel: "Anulo",
|
||
saved: "Abonimi u ruajt.",
|
||
savedPrinted: "Abonimi u ruajt — kodi QR u printua.",
|
||
savedPrintFailed: "Abonimi u ruajt, por printimi dështoi ({{error}}). Përdor \"Printo kodin\".",
|
||
printCode: "Printo kodin",
|
||
printedOn: "Kodi u printua te {{printer}}.",
|
||
confirmRevoke: "Të anulohet abonimi për {{name}}? Do të refuzohet te barriera.",
|
||
confirmDelete: "Të fshihet abonimi për {{name}}? (t e kaluara ruhen.)",
|
||
statusActive: "aktiv",
|
||
statusSuspended: "pezulluar",
|
||
statusRevoked: "anuluar",
|
||
},
|
||
plans: {
|
||
title: "Planet e abonimit",
|
||
intro: "Planet i përcakton admini; operatori vetëm shet prej tyre — çmimi merret automatikisht, nuk shkruhet. Ndryshimi i një plani publikon një version të ri; shitjet e mëparshme ruajnë çmimin e tyre.",
|
||
add: "+ Shto plan",
|
||
noneYet: "Asnjë plan ende. Shto një që kabina të shesë abonime.",
|
||
colName: "Emri",
|
||
colPrice: "Çmimi",
|
||
colHours: "Orari",
|
||
colUsedBy: "Përdorur nga",
|
||
colEffective: "Vlen nga",
|
||
allHours: "24/7",
|
||
usedByCount: "{{active}} aktive / {{total}}",
|
||
usedByNone: "asnjë",
|
||
usedByTitle: "Shfaq abonimet në këtë plan",
|
||
subscribers: "Abonentët",
|
||
inForce: "në fuqi",
|
||
retired: "i tërhequr",
|
||
versionCount: "{{count}} versione",
|
||
newVersion: "Version i ri",
|
||
retire: "Tërhiq",
|
||
reactivate: "Riaktivizo",
|
||
delete: "Fshij",
|
||
deleteTitle: "Fshij këtë plan përgjithmonë (vetëm kur asnjë abonim nuk e përdor)",
|
||
reactivated: "“{{name}}” është përsëri i shitshëm.",
|
||
confirmDelete: "Të fshihet plani “{{name}}” përgjithmonë? Kjo s'mund të kthehet.",
|
||
deleted: "Plani “{{name}}” u fshi.",
|
||
deleteInUse: "S'mund të fshihet — abonime ende e përdorin këtë plan. Tërhiqe në vend të kësaj.",
|
||
newTitle: "Plan i ri",
|
||
newVersionTitle: "Publiko version të ri",
|
||
newVersionHint: "Kjo publikon një version TË RI të planit — shitjet ekzistuese ruajnë çmimin origjinal.",
|
||
period: "Periudha",
|
||
pricePer: "Çmimi për periudhë",
|
||
namePlaceholder: "p.sh. Mujor standard, ose Mujor natën, ose Hotel ditor",
|
||
needName: "Emri i planit është i detyrueshëm.",
|
||
needPrice: "Shkruaj një çmim më të madh se zero.",
|
||
saved: "Plani u ruajt.",
|
||
confirmRetire: "Të tërhiqet plani “{{name}}”? Nuk do të jetë më i shitshëm (historiku ruhet).",
|
||
needWindow: "Shkruaj orare të vlefshme (HH:MM).",
|
||
needDays: "Zgjidh të paktën një ditë për intervalin.",
|
||
restrictTimes: "Kufizo oraret e parkimit (tarifë kalimtare jashtë intervalit)",
|
||
days: "Ditët",
|
||
window: "Intervali",
|
||
enterAfter: "hyrje pas",
|
||
exitBefore: "· dalje para",
|
||
grace: "Tolerancë",
|
||
graceHint: "minuta tolerancë rreth kufijve të intervalit",
|
||
timeframesHint: "Një skanim jashtë intervalit të lejuar tarifohet me tarifën normale kalimtare për minutat jashtë intervalit (hyrja e hershme shtyhet në dalje; dalja e vonuar bllokohet derisa paguhet).",
|
||
},
|
||
site: {
|
||
occupancy: "Prania:",
|
||
noCapacitySet: "(pa kapacitet të caktuar)",
|
||
free: "lirë",
|
||
full: "PLOT",
|
||
capacityLabel: "Kapaciteti (bosh = pa kufi):",
|
||
capacityPlaceholder: "p.sh. 120",
|
||
printExitDefault: "Printo biletën e daljes si parazgjedhje",
|
||
printExitHint: "(klienti skanon biletën në dalje)",
|
||
reserveSubs: "Rezervo vendet e abonentëve",
|
||
reserveSubsHint: "Mban një vend për makinat e çdo abonenti aktiv edhe kur nuk janë të parkuar — kalimtarët e shohin 'plot' më shpejt. Joaktiv: numërohen vetëm makinat brenda (mbingarkesa menaxhohet me parkim manual).",
|
||
anprEntry: "Hapje automatike për targat e abonentëve (ANPR)",
|
||
anprEntryHint: "Kur është aktiv, targa e një abonenti e lexuar nga kamera e korsisë hap barrierën përmes portës normale të abonimit. Joaktiv: abonentët duhet të përdorin kartën/QR-në. Fotot e targave regjistrohen gjithsesi.",
|
||
parkDetails: "Të dhënat e parkimit (opsionale — shfaqen në bileta/fatura)",
|
||
save: "Ruaj",
|
||
saved: "U ruajt.",
|
||
fieldParkName: "Emri i parkimit",
|
||
fieldParkNamePh: "p.sh. Parking Aeroport",
|
||
fieldOperator: "Operatori (emri ligjor)",
|
||
fieldOperatorPh: "kompania operuese",
|
||
fieldNius: "NIUS",
|
||
fieldNiusPh: "p.sh. L01234567A",
|
||
fieldAddress: "Adresa",
|
||
fieldPhone: "Telefoni",
|
||
fieldEmail: "Email",
|
||
},
|
||
users: {
|
||
title: "Përdoruesit",
|
||
add: "+ Shto përdorues",
|
||
new: "Përdorues i ri",
|
||
none: "Asnjë përdorues.",
|
||
username: "Përdoruesi",
|
||
password: "Fjalëkalimi",
|
||
passwordHint: "Të paktën 8 karaktere.",
|
||
newPassword: "fjalëkalim i ri",
|
||
role: "Roli",
|
||
resetPassword: "Rivendos fjalëkalimin",
|
||
edit: "Ndrysho",
|
||
editTitle: "Ndrysho përdoruesin",
|
||
save: "Ruaj",
|
||
delete: "Fshi",
|
||
confirmDelete: "Të fshihet përdoruesi \"{{name}}\"?",
|
||
// Optional profile metadata.
|
||
detailsSection: "Të dhënat (opsionale)",
|
||
fullName: "Emri i plotë",
|
||
phone: "Telefoni",
|
||
email: "Email",
|
||
address: "Adresa",
|
||
},
|
||
roles: {
|
||
title: "Rolet",
|
||
add: "+ Shto rol",
|
||
new: "Rol i ri",
|
||
editTitle: "Ndrysho rolin",
|
||
name: "Emri",
|
||
permissions: "Lejet",
|
||
builtin: "i integruar",
|
||
edit: "Ndrysho",
|
||
delete: "Fshi",
|
||
confirmDelete: "Të fshihet roli \"{{name}}\"?",
|
||
permCount_one: "{{count}} leje",
|
||
permCount_other: "{{count}} leje",
|
||
userCount_one: "{{count}} përdorues",
|
||
userCount_other: "{{count}} përdorues",
|
||
},
|
||
shift: {
|
||
label: "Turni:",
|
||
open: "hapur",
|
||
notStarted: "i panisur",
|
||
since: "që nga",
|
||
startShift: "Fillo turnin",
|
||
starting: "Duke filluar…",
|
||
endShift: "Mbyll turnin",
|
||
ending: "Duke mbyllur…",
|
||
endConfirm: "",
|
||
drawer: "Arka:",
|
||
openingFloatInherited: "(bilanci fillestar i trashëguar nga turni i mëparshëm)",
|
||
drawerCashAdmin: "Para në arkë (admin) — shto ose hiq bilancin",
|
||
drawerVoucher: "Mandat arke — operatori e hap, admini e autorizon",
|
||
amount: "shuma",
|
||
reasonPlaceholder: "arsyeja (p.sh. bilanci fillestar)",
|
||
load: "Shto +",
|
||
remove: "Hiq −",
|
||
authName: "përdoruesi i adminit",
|
||
authPassword: "fjalëkalimi i adminit",
|
||
authRequired: "Një admin duhet ta autorizojë: shkruaj përdoruesin dhe fjalëkalimin e tij.",
|
||
mandatArketimi: "Arkëtim (hyrje) +",
|
||
mandatPagese: "Pagesë (dalje) −",
|
||
voucherHint: "Mandat Arkëtimi shton para; Mandat Pagese heq para. Arka lëviz vetëm me autorizimin e një admini.",
|
||
voucherRecorded: "Mandati {{no}} u regjistrua. Arka tani {{amount}}.",
|
||
enterPositive: "Shkruaj një shumë pozitive.",
|
||
drawerNow: "Arka tani {{amount}}.",
|
||
zReport: "MBYLLJA E TURNIT",
|
||
viewTakings: "Arkëtimet deri tani",
|
||
xReport: "ARKËTIMET DERI TANI",
|
||
asOf: "deri më",
|
||
xReportHint: "Vetëm për shikim — asgjë nuk regjistrohet. Këto shifra nënshkruhen kur mbyllet turni.",
|
||
payments: "Pagesa:",
|
||
cash: "Para:",
|
||
card: "Kartë:",
|
||
srcTickets: "Bileta:",
|
||
srcSubscriptions: "Abonime:",
|
||
srcSubWindow: "jashtë orarit",
|
||
drawerSection: "— Arka —",
|
||
openingFloat: "Arka fillestare:",
|
||
cashTaken: "Xhiro ditore:",
|
||
cashAdded: "Arkëtime:",
|
||
cashRemoved: "Pagesa:",
|
||
expectedDrawer: "Gjëndje Arke:",
|
||
printedToReceipt: "Printuar te printeri i kabinës.",
|
||
recordedNoPrinter: "Regjistruar (pa printer për të printuar).",
|
||
// Header shift control + the booth shift gate.
|
||
headerNoShift: "Asnjë turn",
|
||
headerOpen: "Hap turnin",
|
||
headerClose: "Mbyll turnin",
|
||
headerHeldBy: "Turn i hapur nga {{operator}}",
|
||
headerHeldByShort: "Turni: {{operator}}",
|
||
gateTitle: "Hap një turn për të proceduar biletat",
|
||
gateBody:
|
||
"Asnjë turn nuk është i hapur. Hap turnin tënd që pagesat dhe daljet të regjistrohen te ky turn.",
|
||
gateOtherTitle: "Turni i hapur i përket një operatori tjetër",
|
||
gateOtherBody:
|
||
"{{operator}} ka një turn të hapur. Vetëm një turn mund të jetë i hapur njëkohësisht — ai duhet të mbyllë turnin para se ti të hapësh tëndin.",
|
||
openNow: "Hap turnin tani",
|
||
opening: "Duke hapur…",
|
||
},
|
||
shifts: {
|
||
title: "Historiku i turneve",
|
||
myTitle: "Turnet e mia",
|
||
none: "Asnjë turn i mbyllur.",
|
||
operator: "Operatori",
|
||
started: "Filloi",
|
||
ended: "Mbaroi",
|
||
payments: "Pagesa",
|
||
cash: "Para",
|
||
card: "Kartë",
|
||
srcTickets: "Bileta",
|
||
srcSubscriptions: "Abonime",
|
||
srcSubWindow: "jashtë orarit",
|
||
expectedDrawer: "Gjëndje arke",
|
||
// Filter (admin only).
|
||
filterFrom: "Nga",
|
||
filterTo: "Deri",
|
||
allOperators: "Të gjithë operatorët",
|
||
apply: "Apliko",
|
||
clear: "Pastro",
|
||
timeframe: "Periudha",
|
||
preset_yesterday: "Dje",
|
||
preset_week: "Javën e fundit",
|
||
preset_month: "Muajin e fundit",
|
||
preset_all: "Të gjitha",
|
||
preset_custom: "Zgjidh periudhë",
|
||
selectAShift: "Zgjidh një turn për të parë aktivitetin e tij.",
|
||
noActivity: "Asnjë aktivitet në këtë turn.",
|
||
current: "aktual",
|
||
// Expanded drawer detail.
|
||
drawerSection: "Arka",
|
||
openingFloat: "Arka fillestare",
|
||
cashTaken: "Xhiro ditore",
|
||
cashAdded: "Arkëtime",
|
||
cashRemoved: "Pagesa",
|
||
loadFailed: "Ngarkimi i turneve dështoi.",
|
||
},
|
||
reports: {
|
||
title: "Raportet",
|
||
groupBy: "Grupo sipas",
|
||
exportCsv: "Eksporto CSV",
|
||
loadFailed: "Raporti nuk u ngarkua dot: {{error}}",
|
||
noData: "Nuk ka të dhëna në këtë interval.",
|
||
footnote: "Numërimet dhe paratë mblidhen nga regjistri i nënshkruar. Oraret në {{tz}}.",
|
||
preset: { today: "Sot", "7d": "7 ditë", "30d": "30 ditë", "90d": "90 ditë" },
|
||
bucket: { hour: "Orë", day: "Ditë", month: "Muaj" },
|
||
kpi: {
|
||
entries: "Hyrje",
|
||
exits: "Dalje",
|
||
revenue: "Të ardhura",
|
||
payments: "Pagesa",
|
||
avgStay: "Qëndrim mes.",
|
||
subscribers: "Abonentë",
|
||
},
|
||
chart: {
|
||
flow: "Hyrjet & daljet me kalimin e kohës",
|
||
revenue: "Të ardhurat ({{currency}})",
|
||
mix: "Përbërja e të ardhurave",
|
||
peakHours: "Hyrjet sipas orës së ditës",
|
||
breakdown: "Ndarja",
|
||
},
|
||
mix: { ticket: "Tranzit", subSales: "Abonime", subWindow: "Jashtë orarit" },
|
||
row: {
|
||
cash: "Para në dorë",
|
||
card: "Kartë",
|
||
closed: "Sesione të mbyllura",
|
||
medianStay: "Qëndrim mesatar (median)",
|
||
subActive: "Abonime aktive",
|
||
subCars: "Makina të mbuluara",
|
||
},
|
||
},
|
||
recycleBin: {
|
||
title: "Koshi",
|
||
retentionNote: "Artikujt e fshirë mbahen për {{days}} ditë, pastaj hiqen përgjithmonë.",
|
||
empty: "Asgjë e fshirë. Artikujt që fshini shfaqen këtu, të rikuperueshëm derisa të skadojnë.",
|
||
col: { type: "Lloji", item: "Artikulli", deleted: "Fshirë", actions: "" },
|
||
kind: {
|
||
user: "Përdorues",
|
||
role: "Rol",
|
||
subscription: "Abonim",
|
||
plan: "Plan",
|
||
tariff: "Tarifë",
|
||
},
|
||
restore: "Rikthe",
|
||
purge: "Fshi përfundimisht",
|
||
purgeConfirmTitle: "Të fshihet përfundimisht?",
|
||
purgeConfirmBody: "Të fshihet përgjithmonë “{{label}}”? Nuk mund të rikthehet pas kësaj.",
|
||
purgeIrreversible: "Ky veprim është i pakthyeshëm.",
|
||
},
|
||
logs: {
|
||
title: "Loget e sistemit",
|
||
refresh: "Rifresko",
|
||
level: "Niveli",
|
||
source: "Burimi",
|
||
since: "Që nga",
|
||
apply: "Apliko",
|
||
clear: "Pastro",
|
||
allLevels: "Të gjitha nivelet",
|
||
allSources: "Të gjitha burimet",
|
||
frontend: "Ndërfaqja",
|
||
backend: "Serveri",
|
||
time: "Koha",
|
||
message: "Mesazhi",
|
||
status: "Statusi",
|
||
path: "Rruga",
|
||
empty: "Asnjë regjistër.",
|
||
},
|
||
backup: {
|
||
title: "Kopje rezervë",
|
||
intro:
|
||
"Kopje e enkriptuar e bazës së të dhënave (regjistri i nënshkruar) në një disk të jashtëm. Bëhet automatikisht çdo ditë dhe me butonin më poshtë.",
|
||
statusTitle: "Gjendja",
|
||
configured: "Aktive",
|
||
notConfigured: "E pakonfiguruar",
|
||
notConfiguredHint:
|
||
"Cakto BACKUP_TARGET_DIR dhe BACKUP_KEY në server që të aktivizohet kopja rezervë.",
|
||
running: "Duke u kryer…",
|
||
idle: "Në pritje",
|
||
lastSuccess: "Kopja e fundit e suksesshme",
|
||
lastError: "Gabimi i fundit",
|
||
never: "Asnjëherë",
|
||
lastFile: "Skedari",
|
||
size: "Madhësia",
|
||
pruned: "Të hequra",
|
||
runNow: "Bëj kopje tani",
|
||
runSuccess: "Kopja rezervë u krye.",
|
||
runFailed: "Kopja rezervë dështoi.",
|
||
notConfiguredError: "Kopja rezervë nuk është e konfiguruar.",
|
||
restoreNote:
|
||
"Rikthimi nuk bëhet nga këtu — është veprim i jashtëm gjatë instalimit të një aparati të ri (kërkon skedarin e kopjes + çelësat e ruajtur jashtë).",
|
||
targetLabel: "Vendndodhja e kopjes",
|
||
targetPlaceholder: "p.sh. /mnt/backup ose /media/usb",
|
||
targetHint: "Rrugë absolute drejt një disku të lidhur (USB/SATA) ose një ndarjeje rrjeti (SMB/NFS).",
|
||
save: "Ruaj",
|
||
saved: "U ruajt.",
|
||
test: "Testo vendndodhjen",
|
||
testOk: "Vendndodhja është e shkruajtshme.",
|
||
testEmpty: "Shkruaj një rrugë.",
|
||
testMissing: "Vendndodhja nuk ekziston.",
|
||
testNotDir: "Rruga nuk është një dosje.",
|
||
testNotWritable: "Dosja nuk është e shkruajtshme.",
|
||
keyMissing: "Çelësi i enkriptimit (BACKUP_KEY) mungon në server — caktoje që kopja të aktivizohet.",
|
||
keepLastLabel: "Mbaj kopjet e fundit",
|
||
keepLastHint: "Numri i kopjeve më të reja që mbahen gjithmonë.",
|
||
keepDailyLabel: "Mbaj ditore (ditë)",
|
||
keepDailyHint: "Përtej atyre, mbaj një kopje për ditë për kaq ditë.",
|
||
},
|
||
pay: {
|
||
ticket: "Bileta",
|
||
entry: "Hyrja",
|
||
now: "Tani",
|
||
exit: "Dalja",
|
||
duration: "Kohëzgjatja",
|
||
statusLabel: "Statusi",
|
||
paid: "PAGUAR",
|
||
unpaid: "PAPAGUAR",
|
||
overstay: "TEJ AFATIT",
|
||
overstayHint: "Sesion i mëparshëm i paguar. Klienti nuk doli brënda afatit kohor. Kërkohet pagesë për periudhën e re. Totali më poshtë është tarifa e periudhës së re.",
|
||
closedWithinGrace: "Paguar",
|
||
closedWithinGraceHint: "Pagesa dhe dalja u regjistruan — barriera nuk u konfirmua ende. Makina mbetet në listë derisa të mbarojë afati. Hapni barrierën manualisht nëse pret ende.",
|
||
topUp: "Periudha e re për pagesë",
|
||
total: "Totali",
|
||
paidAmount: "Paguar",
|
||
noTariff: "pa tarifë",
|
||
tender: "Mënyra",
|
||
cash: "Para",
|
||
card: "Kartë",
|
||
printExitVoucher: "Printo biletë dalje",
|
||
selfExitHint: "(klienti del duke skanuar biletën)",
|
||
payAndOpen: "Paguaj + hap barrierën",
|
||
payAndVoucher: "Paguaj + printo biletën",
|
||
openBarrier: "Hap barrierën",
|
||
printVoucher: "Printo biletën",
|
||
takingPayment: "Duke marrë pagesën…",
|
||
printingVoucher: "Duke printuar biletën…",
|
||
opening: "Duke hapur…",
|
||
noSessionFound: "Nuk u gjet asnjë sesion për këtë biletë.",
|
||
alreadyClosed: "Ky sesion është mbyllur tashmë (doli {{time}}).",
|
||
lookingUp: "Duke kërkuar…",
|
||
paidBarrierOpened: "Paguar — barriera u hap. Automjeti mund të dalë.",
|
||
paidExitRecorded: "Paguar dhe dalja u regjistrua, por barriera nuk u hap: {{reason}}.",
|
||
swapTitle: "Mundësi ndërrimi biletash",
|
||
swapBody: "Targa {{plate}} është tashmë brenda me biletën {{other}} (hyri {{when}}). Ky automjet mund të jetë duke dalë me një biletë tjetër nga ajo me të cilën hyri.",
|
||
swapHint: "Verifiko automjetin para se ta lëshosh. Anashkalimi regjistrohet në emrin tënd.",
|
||
swapOverride: "Anashkalo & lësho",
|
||
subscription: "ABONIM",
|
||
plan: "Plani",
|
||
prepaid: "I PARAPAGUAR",
|
||
subAssistHint: "Abonim i parapaguar. Hap barrierën për të ndihmuar daljen (lexues me defekt / kartë e munguar). S'ka pagesë.",
|
||
assistOpenReveal: "Ndihmë për hapje (lexues me defekt / kartë e humbur)…",
|
||
payWindowCharge: "Merr pagesën",
|
||
windowPaidHint: "Pagesa jashtë orarit u krye. Hap barrierën që abonenti të dalë.",
|
||
windowCharge: "JASHTË ORARIT",
|
||
windowChargeHint: "Ky abonent parkoi jashtë orarit të lejuar të planit. Detyrohet të paguajë tarifën kalimtare për kohën jashtë orarit — merr pagesën, pastaj hap barrierën.",
|
||
subBarrierOpened: "Barriera u hap për abonentin (ndërhyrje e regjistruar).",
|
||
voucherPrinted: "Bileta e daljes u printua në {{printer}}. Klienti del duke skanuar biletën.",
|
||
// payment receipt (transparency slip)
|
||
receiptPrintFailed: "(fatura nuk u printua — provoni \"Riprinto faturën\".)",
|
||
receiptReprinted: "Fatura u riprintua në {{printer}}.",
|
||
reprintReceipt: "Riprinto faturën",
|
||
reprinting: "duke printuar…",
|
||
cancelTicket: "Anulo biletën",
|
||
cancelTicketTitle: "Anulo këtë biletë",
|
||
cancelTicketHint: "Anulon një biletë të printuar gabimisht. Ruhet një gjurmë e nënshkruar (operatori + arsyeja); hyrja origjinale nuk fshihet kurrë.",
|
||
cancelReason: {
|
||
misprint: "Printim i gabuar",
|
||
test: "Test",
|
||
wrongVehicle: "Automjet i gabuar",
|
||
},
|
||
cancelReasonPlaceholder: "Arsyeja e anulimit (e detyrueshme)…",
|
||
confirmCancelTicket: "Konfirmo anulimin",
|
||
cancelling: "duke anuluar…",
|
||
ticketCancelled: "Bileta u anulua.",
|
||
// snapshots
|
||
noSnapshots: "asnjë foto",
|
||
loadingSnapshots: "duke ngarkuar fotot…",
|
||
snapEntry: "hyrje",
|
||
snapExit: "dalje",
|
||
snapFailed: "kamera e paarritshme",
|
||
plate: "Targa",
|
||
},
|
||
};
|
||
|
||
// The catalog SHAPE (keys + nesting), with string-typed values — so en.ts must
|
||
// supply every key but may differ in value. (Not `typeof sq` with `as const`, which
|
||
// would pin en.ts to the Albanian literals.)
|
||
type Stringify<T> = { [K in keyof T]: T[K] extends object ? Stringify<T[K]> : string };
|
||
export type Catalog = Stringify<typeof sq>;
|