diff --git a/apps/web/src/lib/i18n/en.ts b/apps/web/src/lib/i18n/en.ts index dd93c80..f2a626a 100644 --- a/apps/web/src/lib/i18n/en.ts +++ b/apps/web/src/lib/i18n/en.ts @@ -599,7 +599,7 @@ export const en: Catalog = { save: "Save", saved: "Saved.", fieldParkName: "Park name", - fieldParkNamePh: "e.g. Acme Parking", + fieldParkNamePh: "e.g. Airport Parking", fieldOperator: "Operator (legal name)", fieldOperatorPh: "operating company", fieldNius: "NIUS", diff --git a/apps/web/src/lib/i18n/sq.ts b/apps/web/src/lib/i18n/sq.ts index 5fb9936..09fe6f7 100644 --- a/apps/web/src/lib/i18n/sq.ts +++ b/apps/web/src/lib/i18n/sq.ts @@ -308,13 +308,13 @@ export const sq = { setup: { title: "Konfigurimi", intro: - "Shto fillimisht kontrolluesit e barrierave — cakto cili rele është hyrje/dalje dhe në cilin terminal është lidhur butoni i hyrjes. Pastaj shto lexues, kamera dhe printera dhe drejto secilin te barriera që shërben.", + "Shto fillimisht kontrollerat e barrierave — cakto cili rele është hyrje/dalje dhe në cilin terminal është lidhur butoni i hyrjes. Pastaj shto lexues, kamera dhe printera dhe drejto secilin te barriera që shërben.", // Category titles + the singular noun used in buttons/modal titles. - catControllers: "Kontrolluesit (barrierat + butoni i hyrjes)", + catControllers: "Kontrollerat (barrierat + butoni i hyrjes)", catReaders: "Lexuesit (QR / RFID)", catCameras: "Kamerat (foto + targë)", catPrinters: "Printerat (bileta / vouchera)", - nounController: "kontrollues", + nounController: "kontroller", nounReader: "lexues", nounCamera: "kamerë", nounPrinter: "printer", @@ -322,7 +322,7 @@ export const sq = { addAnother: "+ Shto edhe një {{noun}}", addTitle: "Shto {{noun}}", editTitle: "Ndrysho {{noun}}", - needControllerFirst: "Shto fillimisht një kontrollues — {{noun}} drejtohet te një prej releve të tij.", + 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). @@ -344,9 +344,9 @@ export const sq = { // Device form. noDrivers: "Asnjë drejtues i regjistruar.", chooseDevice: "Zgjidh një pajisje…", - scan: "Skano për kontrollues", + scan: "Skano për kontroller", scanning: "Duke skanuar…", - noControllersFound: "Asnjë kontrollues në LAN.", + noControllersFound: "Asnjë kontroller në LAN.", use: "Përdor", test: "Testo lidhjen", testing: "Duke testuar…", @@ -365,7 +365,7 @@ export const sq = { 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ë kontrollues", + 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)", @@ -432,10 +432,10 @@ export const sq = { alarmFieldPort: "Porta", // Binding picker. whichBarrier: "Cilën barrierë shërben kjo pajisje?", - controller: "Kontrolluesi", + controller: "Kontrolleri", choose: "Zgjidh…", relayLabel: "Rele {{relay}} ({{direction}})", - noRelaysConfigured: "Ky kontrollues nuk ka rele të konfiguruar.", + noRelaysConfigured: "Ky kontroller nuk ka rele të konfiguruar.", }, lab: { title: "Lab Tarife", @@ -611,7 +611,7 @@ export const sq = { save: "Ruaj", saved: "U ruajt.", fieldParkName: "Emri i parkimit", - fieldParkNamePh: "p.sh. Acme Parking", + fieldParkNamePh: "p.sh. Parking Aeroport", fieldOperator: "Operatori (emri ligjor)", fieldOperatorPh: "kompania operuese", fieldNius: "NIUS", diff --git a/i18n-review.md b/i18n-review.md new file mode 100644 index 0000000..75e011d --- /dev/null +++ b/i18n-review.md @@ -0,0 +1,238 @@ +# i18n long-sentence review — EN vs SQ + +Generated 2026-06-24. Source: `apps/web/src/lib/i18n/en.ts` + `sq.ts`. Threshold: strings ≥ 80 chars in either language (35 keys). + +Review each pair for MEANING (does SQ say the same as EN?). Mark your decision in the **Verdict** line: `OK` / `FIX: ` / `?`. + +Keys with an automated note are tagged **⚑ NOTE**. + +--- + +## 1. `badgeOverstayTitle` ⚑ + +- **EN** (en.ts:138, 86 ch): Paid session. The customer failed to exit during the grace period. A new period began. +- **SQ** (sq.ts:140, 93 ch): Sesion i paguar. Klienti nuk doli brenda afatit kohor. Ka filluar një periudhë e re tarifimi. +- **⚑ NOTE:** Spelling: "brënda" → standard is "brenda" (no ë). +- **Verdict:** + +## 2. `activeSince` + +- **EN** (en.ts:254, 133 ch): Active since {{date}} · {{count}} version(s) in history. Publishing creates a new version; past sessions keep their original pricing. +- **SQ** (sq.ts:257, 137 ch): Aktive që nga {{date}} · {{count}} version(e) në histori. Publikimi krijon një version të ri; sesionet e kaluara ruajnë çmimin origjinal. +- **Verdict:** + +## 3. `rateBlocksHint` + +- **EN** (en.ts:263, 256 ch): Each band lasts a number of hours and bills at its own price; bands are consumed in order (the first hours, then the next hours). The last band is \"thereafter\" (open-ended) — its price applies once the ladder is exhausted. Price is per billing increment. +- **SQ** (sq.ts:266, 251 ch): Ç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. +- **Verdict:** + +## 4. `defaultCardHint` + +- **EN** (en.ts:275, 98 ch): The base rate applied when no time/seasonal tier matches. This alone is enough for most car parks. +- **SQ** (sq.ts:278, 116 ch): Çmimi bazë i zbatuar kur asnjë nivel kohor/sezonal nuk vlen. Kjo e vetme është mjaftueshëm për shumicën e parkimeve. +- **Verdict:** + +## 5. `steppedHint` + +- **EN** (en.ts:280, 210 ch): Set the TOTAL price for a stay up to a given time (e.g. up to 3h = 500). The first row whose limit ≥ the duration wins (the limit is inclusive). The last row's total repeats as a per-day price for longer stays. +- **SQ** (sq.ts:283, 233 ch): 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. +- **Verdict:** + +## 6. `steppedTiersConflict` + +- **EN** (en.ts:285, 235 ch): ⚠ Time/seasonal tiers do NOT apply when the base rate is 'By duration (up-to)' — the engine ignores them entirely. Remove the tiers, or switch the base rate to 'Hourly ladder' or 'Flat price'. Publishing is blocked until this is fixed. +- **SQ** (sq.ts:288, 244 ch): ⚠ 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. +- **Verdict:** + +## 7. `tiersHint` + +- **EN** (en.ts:287, 174 ch): Optional. Add tiers that apply only at certain hours/days/dates or for a category (e.g. happy hour, night rate, weekend, bus). With no tiers, just the base rate is published. +- **SQ** (sq.ts:290, 182 ch): 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ë. +- **Verdict:** + +## 8. `intro` + +- **EN** (en.ts:526, 160 ch): Admin-defined plans the operator sells from — the price is looked up, never typed. Editing a plan publishes a new version; past sales keep their recorded price. +- **SQ** (sq.ts:537, 193 ch): 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. +- **Verdict:** + +## 9. `relaysHint` + +- **EN** (en.ts:361, 124 ch): Each relay opens one barrier. Set its direction; for transient entry, set which input terminal the entry button is wired to. +- **SQ** (sq.ts:370, 130 ch): Çdo rele hap një barrierë. Cakto drejtimin e saj; për hyrje kalimtare, cakto në cilin terminal hyrës është lidhur butoni i hyrjes. +- **Verdict:** + +## 10. `outputsHint` + +- **EN** (en.ts:364, 175 ch): Relays are OUTPUTS: each opens a barrier (or drives the button lamp). Set the relay number and direction. The input terminals (button, sensor) are in the Inputs section below. +- **SQ** (sq.ts:373, 178 ch): 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ë. +- **Verdict:** + +## 11. `pulseOpenHint` + +- **EN** (en.ts:366, 75 ch): How long a barrier relay is held open (jog). Applies to all barrier relays. +- **SQ** (sq.ts:375, 85 ch): Sa kohë mbahet rele e barrierës e hapur (jog). Vlen për të gjitha relet e barrierave. +- **Verdict:** + +## 12. `inputsHint` ⚑ + +- **EN** (en.ts:369, 152 ch): Inputs are TERMINALS the host READS: the entry button and the presence/radar sensor. Each belongs to an entry barrier — it triggers or gates that relay. +- **SQ** (sq.ts:378, 153 ch): 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. +- **⚑ NOTE:** "e gateron" is an anglicism ("gates it"). Native: "e kushtëzon" / "e lejon". +- **Verdict:** + +## 13. `inputsIdleHighHint` + +- **EN** (en.ts:371, 62 ch): This board idles inputs HIGH (status 1111); a press pulls LOW. +- **SQ** (sq.ts:380, 80 ch): Kjo pllakë i mban hyrjet HIGH në pushim (statusi 1111); një shtypje e ul në LOW. +- **Verdict:** + +## 14. `inputsNoEntryRelay` + +- **EN** (en.ts:373, 87 ch): No entry relay — add an 'Entry' or 'Entry + exit' relay in Outputs to assign terminals. +- **SQ** (sq.ts:382, 97 ch): Asnjë rele hyrëse — shto një rele 'Hyrje' ose 'Hyrje + dalje' te Daljet që të caktosh terminalet. +- **Verdict:** + +## 15. `presenceInputHint` ⚑ + +- **EN** (en.ts:378, 290 ch): Input terminal the vehicle-presence sensor (induction loop or radar) is wired to. When set, exactly ONE ticket issues per car: the button prints only while a car is present, and no second ticket issues until the sensor clears (the car drove in) and a new car re-occupies it. Preferred mode. +- **SQ** (sq.ts:387, 275 ch): Terminali hyrës ku është lidhur sensori/laku i pranisë së automjetit. Kur vendoset, lëshohet vetëm NJË biletë për automjet: butoni printon vetëm kur ka makinë, dhe nuk lëshon biletë të dytë derisa laku të lirohet (makina hyri) dhe një makinë e re ta zërë. Mënyra e preferuar. +- **⚑ NOTE:** EN names "induction loop OR radar"; SQ "sensori/laku i pranisë" omits radar explicitly. +- **Verdict:** + +## 16. `entryCooldownHint` + +- **EN** (en.ts:381, 175 ch): When there's no presence sensor: repeat button presses are suppressed for this many seconds after a ticket. A fallback (not a guarantee) — a determined abuser can wait it out. +- **SQ** (sq.ts:390, 165 ch): 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. +- **Verdict:** + +## 17. `presenceActiveLowHint` + +- **EN** (en.ts:387, 178 ch): Tick if the presence sensor (e.g. a radar) idles HIGH and goes LOW on detection — the opposite of the button. This inverts that terminal's reading so 'present' is read correctly. +- **SQ** (sq.ts:396, 184 ch): 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ë. +- **Verdict:** + +## 18. `buttonLightHint` + +- **EN** (en.ts:391, 152 ch): The button's 12 V light on a spare relay. Blinks when the radar detects but the camera doesn't confirm a car; solid on when both confirm; off otherwise. +- **SQ** (sq.ts:400, 160 ch): Drita 12V e butonit e lidhur në një rele rezervë. Pulson kur radari detekton por kamera s'konfirmon makinë; ndizet fiks kur të dy konfirmojnë; përndryshe fiket. +- **Verdict:** + +## 19. `anprHint` ⚑ + +- **EN** (en.ts:398, 203 ch): Enable to scan plates on this camera: the vision service reads the plate from a snapshot and feeds it as a read (advisory only — it never opens a barrier on its own). Requires the vision service running. +- **SQ** (sq.ts:408, 185 ch): Aktivizo që ky aparat të skanojë targat: shërbimi i vizionit lexon targën nga pamja dhe e dërgon si lexim (vetëm këshillues — nuk hap vetë barrierën). Kërkon shërbimin e vizionit aktiv. +- **⚑ NOTE:** SQ uses "aparat" for camera; elsewhere camera = "kamerë" (see testAnprHint). Inconsistent. +- **Verdict:** + +## 20. `testAnprHint` + +- **EN** (en.ts:402, 143 ch): Takes a live snapshot from this camera and tries to read a plate, reporting the result and the time it took. Point a plate at the camera first. +- **SQ** (sq.ts:412, 169 ch): 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ë. +- **Verdict:** + +## 21. `curveHint` + +- **EN** (en.ts:443, 88 ch): Fee from entry at several durations — see where the daily cap flattens or windows shift. +- **SQ** (sq.ts:454, 96 ch): Tarifa nga hyrja për disa kohëzgjatje — shih ku rrafshohet kufiri ditor ose ndryshojnë dritaret. +- **Verdict:** + +## 22. `versionHint` + +- **EN** (en.ts:465, 128 ch): Move this subscriber to another version of the same plan. The price stays as billed; only the access hours change going forward. +- **SQ** (sq.ts:476, 139 ch): 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. +- **Verdict:** + +## 23. `deleteInUse` + +- **EN** (en.ts:550, 68 ch): Can't delete — subscriptions still use this plan. Retire it instead. +- **SQ** (sq.ts:561, 80 ch): S'mund të fshihet — abonime ende e përdorin këtë plan. Tërhiqe në vend të kësaj. +- **Verdict:** + +## 24. `newVersionHint` + +- **EN** (en.ts:553, 84 ch): This publishes a NEW version of the plan — existing sales keep their original price. +- **SQ** (sq.ts:564, 86 ch): Kjo publikon një version TË RI të planit — shitjet ekzistuese ruajnë çmimin origjinal. +- **Verdict:** + +## 25. `timeframesHint` + +- **EN** (en.ts:570, 168 ch): A scan outside the allowed window is charged the normal transient tariff for the out-of-window minutes (early entry is deferred to exit; late exit is gated until paid). +- **SQ** (sq.ts:581, 184 ch): 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). +- **Verdict:** + +## 26. `reserveSubsHint` ⚑ + +- **EN** (en.ts:582, 164 ch): Hold a spot for each active subscriber's car(s) even when they're not parked — transients see 'full' sooner. Off: only cars inside count (handle overflow by valet). +- **SQ** (sq.ts:593, 198 ch): 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). +- **⚑ NOTE:** EN "handle overflow by valet" → SQ "parkim manual" (manual parking) — meaning shift; valet ≠ manual parking. +- **Verdict:** + +## 27. `anprEntryHint` + +- **EN** (en.ts:584, 195 ch): When on, a subscriber's plate read by a lane camera opens the barrier through the normal subscription gate. Off: subscribers must use their card/QR. Plate snapshots are still recorded either way. +- **SQ** (sq.ts:595, 207 ch): 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. +- **Verdict:** + +## 28. `voucherHint` + +- **EN** (en.ts:659, 128 ch): A receipt (Mandat Arkëtimi) adds cash; a disbursement (Mandat Pagese) removes it. The float only moves with an admin's sign-off. +- **SQ** (sq.ts:671, 97 ch): Mandat Arkëtimi shton para; Mandat Pagese heq para. Arka lëviz vetëm me autorizimin e një admini. +- **Verdict:** + +## 29. `xReportHint` + +- **EN** (en.ts:667, 83 ch): View only — nothing is recorded. These figures are signed when the shift is closed. +- **SQ** (sq.ts:679, 85 ch): Vetëm për shikim — asgjë nuk regjistrohet. Këto shifra nënshkruhen kur mbyllet turni. +- **Verdict:** + +## 30. `gateBody` + +- **EN** (en.ts:691, 80 ch): No shift is open. Open your shift so payments and exits are recorded against it. +- **SQ** (sq.ts:703, 95 ch): Asnjë turn nuk është i hapur. Hap turnin tënd që pagesat dhe daljet të regjistrohen te ky turn. +- **Verdict:** + +## 31. `gateOtherBody` + +- **EN** (en.ts:694, 120 ch): {{operator}} has an open shift. Only one shift may be open at a time — they must close theirs before you can open yours. +- **SQ** (sq.ts:706, 140 ch): {{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. +- **Verdict:** + +## 32. `overstayHint` ⚑ + +- **EN** (en.ts:813, 155 ch): Earlier session paid. The customer failed to exit during the grace period. Payment for the new period is required. The total below is the new period's fee. +- **SQ** (sq.ts:827, 151 ch): 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. +- **⚑ NOTE:** Spelling: "brënda" → standard is "brenda" (no ë). +- **Verdict:** + +## 33. `subAssistHint` + +- **EN** (en.ts:837, 101 ch): Prepaid subscription. Open the barrier to assist the exit (faulty reader / missing card). No payment. +- **SQ** (sq.ts:851, 108 ch): Abonim i parapaguar. Hap barrierën për të ndihmuar daljen (lexues me defekt / kartë e munguar). S'ka pagesë. +- **Verdict:** + +## 34. `windowChargeHint` + +- **EN** (en.ts:842, 154 ch): This subscriber parked outside their plan's allowed hours. They owe the transient tariff for the out-of-window time — take payment, then open the barrier. +- **SQ** (sq.ts:856, 153 ch): 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. +- **Verdict:** + +## 35. `cancelTicketHint` + +- **EN** (en.ts:852, 115 ch): Cancels a wrongly-printed ticket. A signed record is kept (operator + reason); the original entry is never deleted. +- **SQ** (sq.ts:866, 129 ch): Anulon një biletë të printuar gabimisht. Ruhet një gjurmë e nënshkruar (operatori + arsyeja); hyrja origjinale nuk fshihet kurrë. +- **Verdict:** + +--- + +## Summary of flagged items + +- `badgeOverstayTitle` — Spelling: "brënda" → standard is "brenda" (no ë). +- `inputsHint` — "e gateron" is an anglicism ("gates it"). Native: "e kushtëzon" / "e lejon". +- `presenceInputHint` — EN names "induction loop OR radar"; SQ "sensori/laku i pranisë" omits radar explicitly. +- `anprHint` — SQ uses "aparat" for camera; elsewhere camera = "kamerë" (see testAnprHint). Inconsistent. +- `reserveSubsHint` — EN "handle overflow by valet" → SQ "parkim manual" (manual parking) — meaning shift; valet ≠ manual parking. +- `overstayHint` — Spelling: "brënda" → standard is "brenda" (no ë). + +_All other pairs: meaning judged faithful in automated review; confirm during your read._