TTN — Text to Number
Utilitar Vue 3 + TypeScript care convertește în ambele sensuri între numere întregi și forme textuale românești, cu normalizare a diacriticelor, validare deterministă, interfață responsive și suport PWA offline.

Stack principal
Provocarea
Provocarea a fost modelarea numerelor românești fără un serviciu extern: normalizarea variantelor cu și fără diacritice, interpretarea zecilor și multiplicatorilor, compunerea inversă pe grupuri de milioane/mii/sute și oferirea unui comportament predictibil pentru input invalid, într-un utilitar care să rămână complet client-side și instalabil ca PWA.
Soluția
Soluția separă logica de conversie într-un modul TypeScript pur și păstrează UI-ul Vue subțire. normalizeText standardizează inputul, textToNumber tokenizează și acumulează valori pe baza dicționarelor și multiplicatorilor, iar numberToText descompune întregul pe grupuri și reconstruiește expresia. Vitest documentează o parte din cazurile dorite, iar Vite PWA/Workbox adaugă instalare și cache offline. Snapshot-ul actual demonstrează direcția arhitecturală, dar necesită corectarea multiplicatorilor compuși, gramaticii pentru unele grupuri mari și validării parseInt înainte de a putea fi prezentat ca parser lingvistic complet.
Complexitate notabilă
TTN — Text to Number este un proiect personal construit ca utilitar client-side pentru conversia bidirecțională dintre numere întregi și exprimări textuale în limba română. Aplicația nu folosește backend, bază de date sau servicii externe pentru conversie: logica rulează local în browser, ceea ce face fluxul rapid, ușor de distribuit și compatibil cu utilizarea offline prin PWA.
Interfața Vue oferă două moduri explicite — Text → Număr și Număr → Text — comutate din același ecran. Inputul poate fi trimis prin buton sau Enter, rezultatul și erorile sunt afișate în aceeași carte centrală, iar schimbarea modului resetează inputul și starea rezultatelor. UI-ul este realizat cu Tailwind CSS și stiluri scoped: fundal gradient animat, card alb semi-transparent, stări de focus, micro-animații pentru rezultat și etichete ARIA pentru controalele principale.
Pentru Text → Număr, parserul normalizează mai întâi diacriticele românești, transformă cratimele în spații, compactează whitespace-ul și trece textul în lowercase. Conversia folosește tabele explicite pentru unități, 10–19, zeci și multiplicatori (sute, mii, milioane), apoi procesează tokenurile cu acumulatoare pentru grupul curent și total. Conectorul «și» este permis doar după o valoare de zeci între 20 și 99, iar tokenurile necunoscute, multiplicatorii repetați sau anumite ordini invalide întorc null în loc să producă un rezultat aproximativ.
Pentru Număr → Text, formatterul acceptă doar întregi între 0 și 999.999.999 și descompune valoarea în grupuri de milioane, mii și unități. Fiecare grup este formatat din sute, zeci și unități, cu forme dedicate pentru «o/două» și pentru 11–19. Implementarea este deterministă și nu depinde de locale sau de un API extern, dar nu acoperă complet gramatica românească pentru toate combinațiile mari.
Repository-ul include Vitest pentru normalizeText și textToNumber: sunt acoperite diacriticele, lowercase, spațiile/cratimele, numerele 0–19, zecile, zecile cu unități, sute, mii, milioane, exemple compuse și input invalid. Totuși, starea actuală a parserului are o problemă structurală: lastMultiplier este coborât la 100 atunci când apare o sută în interiorul unui grup, astfel că un multiplicator ulterior de 1.000 este respins. De aceea exemple valide precum «trei milioane cinci sute de mii» sau «un milion două sute treizeci și patru de mii…», deși apar ca așteptări în teste, nu sunt compatibile cu logica actuală. Testele nu acoperă numberToText.
Formatterul are și limite gramaticale verificabile în snapshot: 1.000 este compus prin grupul «mie» fără ramura specială pentru feminin și rezultă «unu mie», iar regula pentru «de» după grupuri mari nu tratează corect toate sutele de mii/milioane. În sens invers, parserul ignoră tokenul «de» indiferent de poziție și acceptă unele secvențe de unități prin simplă adunare, deci validarea sintactică este intenționată, dar nu constituie un parser complet al gramaticii numerale românești.
Validarea din UI pentru modul Număr → Text folosește parseInt. Asta înseamnă că șiruri precum «123abc», «12.7» sau «1e3» pot fi trunchiate și interpretate ca întregi în loc să fie respinse integral. Intervalul final este totuși verificat în numberToText, iar valorile negative, peste 999.999.999 sau neîntregi primite direct de funcție întorc null. O versiune de producție ar trebui să valideze strict întregul input înainte de conversie.
Aplicația este configurată ca PWA cu vite-plugin-pwa și Workbox. Manifestul definește nume, short name, theme color, mod standalone, iconuri pentru Android/iOS/Windows, screenshots desktop/mobile, shortcut și scope /ttn/. Service worker-ul folosește autoUpdate și strategii CacheFirst pentru JS/CSS, imagini și fonturi, respectiv NetworkFirst pentru HTML. Există și o regulă generică pentru API-uri, deși aplicația actuală nu face request-uri către un API.
Configurația PWA declară și protocol handler-ul web+ttn cu un query parameter text, însă App.vue nu citește acel parametru, deci această integrare este doar configurată, nu funcțională end-to-end. Vue Router este instalat și are o singură rută Home către App.vue, dar App.vue este oricum componenta rădăcină și nu conține router-view; în forma actuală routerul nu furnizează o suprafață de navigare reală. Base path-ul Vite este /ttn/, în timp ce createWebHistory este inițializat fără base explicit.
Din perspectivă de securitate, suprafața este redusă: nu există autentificare, secrete, formulare persistate, uploaduri sau date personale, iar rezultatele sunt randate prin interpolarea Vue, nu prin HTML injectat. Repository-ul nu conține un fișier .env în arborele analizat; .gitignore exclude *.local, dar nu declară explicit un pattern pentru .env. Principalul hardening relevant este mai degrabă de UX și validare strictă decât de control al accesului.
Deployment-ul nu este automatizat în repository: nu există .github/workflows, Docker, scripturi de deploy sau health checks. Configurația /ttn/ și artefactele PWA indică o țintă de hosting subpath/static, dar repository-ul nu demonstrează prin CI/CD cum este publicată aplicația. Singurul commit disponibil este «Initial commit» din 12 iulie 2026, așa că se poate verifica snapshot-ul produsului, nu o cronologie de refactorizări sau bugfixuri.
Rezultate cheie
- Conversie Text → Număr implementată local în TypeScript pentru vocabular românesc până la nivel de milioane
- Conversie Număr → Text implementată pentru întregi validați programatic între 0 și 999.999.999
- Normalizarea diacriticelor ș/ț/ă/î/â, a literelor mari, cratimelor și spațiilor multiple
- Tratament explicit pentru unități, 10–19, zeci, sute, mii și milioane
- Validare deterministă prin null pentru tokenuri necunoscute și mai multe combinații invalide
- Interfață unică cu mod comutabil Text → Număr / Număr → Text
- Conversie declanșabilă atât prin buton, cât și prin tasta Enter
- Mesaje de eroare separate de rezultatele numerice și textuale
- Suită Vitest pentru normalizare și direcția Text → Număr, inclusiv cazuri de sute, mii, milioane și input invalid
- Manifest PWA cu instalare standalone, iconuri multi-platformă, screenshots și shortcut
- Service worker Workbox cu auto-update și politici de cache pentru resurse statice, HTML, imagini și fonturi
- UI responsive pe un singur ecran, realizat cu Vue 3 și Tailwind CSS
Vrei ceva similar?
Începe cu wizard-ul de estimare — răspunzi la câteva întrebări și primești un range de preț + timeline realist.