AngularAtlased. 22.2

Cap. 14Reactivitate avansată62 / 75

RxJS avansat: operatori de ordin superior

switchMap, mergeMap, concatMap și exhaustMap pe o diagramă live, plus retry cu backoff, shareReplay și cum eviți scurgerile.

arhitectură ~0 min de citit Documentația oficială

Semnalele au preluat starea, dar evenimentele în timp rămân teritoriul RxJS: tastări, click-uri, request-uri care se suprapun, reîncercări, websocket-uri. Partea cea mai importantă, și cea mai des greșită, sunt operatorii de ordin superior. Fiecare valoare pornește un nou Observable, de obicei un request HTTP. Întrebarea reală e: ce faci când vine valoarea următoare, iar request-ul de dinainte încă rulează?

Există patru răspunsuri: anulezi, rulezi în paralel, pui la coadă sau ignori. Fiecare are un operator. Dacă alegi greșit, rezultatul e un bug de tip race condition: rezultate vechi care le suprascriu pe cele noi, comenzi duble, salvări în altă ordine.

De ce contează
„Căutarea arată uneori rezultate pentru textul de dinainte” sau „comanda a fost trimisă de două ori” sunt aproape mereu un mergeMap pus acolo unde trebuia switchMap sau exhaustMap. Diferența nu se vede în teste rapide, doar pe o rețea lentă. Poți reproduce exact asta în demo-ul de mai jos.

Problema: Observable de Observable

Un map care întoarce un request produce un Observable<Observable<T>>: un stream de request-uri la care nu s-a abonat nimeni. Operatorii *Map se abonează ei la fluxurile interioare și le „aplatizează” într-un singur stream de rezultate. Diferența dintre ei e doar politica de suprapunere.

// „Pentru fiecare valoare, pornește un Observable” — problema e ce faci când vine valoarea următoare
// iar cea de dinainte încă rulează.
clicks$.pipe(map((id) => http.get(`/api/items/${id}`)));       // ✗ Observable<Observable<Item>>
clicks$.pipe(switchMap((id) => http.get(`/api/items/${id}`))); // ✓ Observable<Item> — plus o politică

Cei patru operatori

OperatorVine o valoare nouă cât rulează cea vecheExemplu tipic
switchMapo anulează pe cea veche (dezabonare → HttpClient anulează request-ul)typeahead, parametri de rută
mergeMaple rulează în paralel; ordinea rezultatelor nu e garantatăupload-uri independente
concatMapo pune la coadă; rulează pe rând, în ordineautosave, comenzi ordonate
exhaustMapo ignoră până se termină cea curentăsubmit, login
// Typeahead: doar ultimul request contează; cele vechi sunt ANULATE (HttpClient anulează și XHR/fetch-ul)
readonly results = toSignal(
  this.query$.pipe(
    debounceTime(300),
    distinctUntilChanged(),
    switchMap((q) => this.api.search(q).pipe(catchError(() => of([])))),
  ),
  { initialValue: [] },
);
LiveDiagramă marble live (operatori RxJS reali)

switchMap: un click nou ANULEAZĂ request-ul în curs. Ideal pentru căutare (typeahead) și parametri de rută.

click-uri (outer)
request-uri (inner)
rezultat (output)
emise: 0livrate: 0anulate: 0
Alege un operator și apasă „Emite” de mai multe ori, mai repede decât durata request-ului. switchMap taie barele vechi (✕), mergeMap le suprapune, concatMap le pune una după alta, exhaustMap le ignoră pe cele din timpul unui request.

Unde pui catchError

O eroare completează stream-ul în care apare. Dacă catchError stă după switchMap, primul request eșuat închide tot fluxul: căutarea nu mai răspunde, fără nicio eroare în consolă. Pune-l în proiecția interioară. Atunci doar acel request e înlocuit cu o valoare de rezervă, iar stream-ul exterior continuă.

// ✗ catchError DUPĂ switchMap: prima eroare completează stream-ul exterior — căutarea „moare”
query$.pipe(
  switchMap((q) => api.search(q)),
  catchError(() => of([])),
);

// ✓ catchError ÎN interiorul proiecției: doar request-ul acela eșuează, stream-ul rămâne viu
query$.pipe(
  switchMap((q) => api.search(q).pipe(catchError(() => of([])))),
);

Retry cu backoff exponențial

retry({ count, delay }) se reabonează la sursă după o eroare. Funcția delay primește eroarea și numărul reîncercării și întoarce un Observable care spune când se reîncearcă. Dublarea pauzei la fiecare pas (300, 600, 1200 ms…) nu mai lovește în server cât timp acesta are probleme. Aruncă eroarea mai departe pentru coduri care nu se vor rezolva singure (401, 404). Pentru HTTP, retry-ul stă de obicei într-un interceptor (vezi HttpClient & interceptori). Pentru o conexiune care trebuie să supraviețuiască restartărilor serverului — cu jitter, ca o mie de clienți să nu revină în aceeași secundă — vezi WebSockets.

import { retry, timer } from 'rxjs';

http.get('/api/report').pipe(
  retry({
    count: 4,                                                // maximum 4 reîncercări
    delay: (error, retryCount) => {
      if (error.status === 401 || error.status === 404) throw error; // nu reîncerca erorile „definitive”
      return timer(300 * 2 ** (retryCount - 1));              // 300, 600, 1200, 2400 ms
    },
    resetOnSuccess: true,
  }),
);
Liveretry cu backoff, pe o sursă care pică
  1. Apasă butonul.
Setează câte eșecuri are serverul și câte reîncercări permiți. Jurnalul arată pauzele crescătoare. Dacă eșecurile depășesc count, primești eroarea finală.

share și shareReplay

Un Observable „rece”, cum e http.get, se execută la fiecare subscribe. Trei abonați înseamnă trei request-uri. share() face ca abonații simultani să împartă o singură execuție. shareReplay păstrează și ultima valoare pentru cei care vin mai târziu, deci funcționează ca un cache. Capcana e la shareReplay(1) simplu: are refCount: false, deci nu se dezabonează niciodată de la sursă. Pe un stream care nu se termină (websocket, interval), sursa rulează și după ce toți abonații au plecat.

Un detaliu fin la refCount: true: cache-ul se păstrează doar dacă sursa a apucat să se termine. Dacă toți abonații pleacă înainte de complete (de exemplu firstValueFrom, take(1) sau o componentă distrusă în timpul request-ului), shareReplay se dezabonează de la sursă și o ia de la capăt la următorul abonat.

// Fără partajare: fiecare subscribe = încă o execuție (încă un request)
const user$ = http.get<User>('/api/me');
user$.subscribe(); user$.subscribe();                 // 2 request-uri

// share(): abonații SIMULTANI împart o execuție; după complete se resetează
const shared$ = http.get<User>('/api/me').pipe(share());

// shareReplay: păstrează ultima valoare pentru abonații TÂRZII (cache)
const cached$ = http.get<User>('/api/me').pipe(shareReplay({ bufferSize: 1, refCount: true }));
// refCount: true → când pleacă ultimul abonat, se dezabonează și de la sursă.
// shareReplay(1) (refCount: false) pe o sursă care nu se termină = sursa rulează la nesfârșit.
LiveCâte execuții? Și cine rămâne abonat?
3 abonați simultan + 1 abonat târziu la un „request” de 400 ms; apoi un stream infinit, din care toți se dezabonează.
Variantă Execuții ale request-ului Abonatul târziu Stream infinit după dezabonare
Apasă „Rulează scenariul” (durează ~2 s).
Scenariul rulează cu RxJS real: aceiași 3 abonați simultani și 1 târziu, apoi un stream infinit din care toți se dezabonează. Doar shareReplay(1) lasă sursa pornită. Sursele demonstrative sunt oprite la final.

Combinarea fluxurilor

combineLatest emite ori de câte ori se schimbă oricare sursă, după ce fiecare a emis o dată. E potrivit pentru filtre combinate. withLatestFrom emite doar la sursa principală și ia valoarea curentă din celelalte („la click, salvează formularul curent”). forkJoin așteaptă să se termine toate și emite o singură dată: e un Promise.all pentru request-uri.

// combineLatest: emite la fiecare schimbare, după ce TOATE au emis o dată — filtre combinate
combineLatest([category$, sort$]).pipe(switchMap(([c, s]) => api.list(c, s)));

// withLatestFrom: emite doar la sursa principală, luând ultima valoare din celelalte
save$.pipe(withLatestFrom(form$), concatMap(([, value]) => api.save(value)));

// forkJoin: așteaptă ca TOATE să se termine, o singură emisie — request-uri paralele independente
forkJoin({ user: api.me(), settings: api.settings() });

// zip: împerechează a n-a valoare din fiecare — rar util în UI

Fără subscribe-uri uitate

Orice subscribe manual într-o componentă trebuie închis. takeUntilDestroyed() o face automat la distrugerea componentei. Pentru valori afișate în template, toSignal() e și mai simplu: se abonează și se dezabonează singur (vezi Signals ↔ RxJS).

import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

export class Live {
  constructor() {
    interval(1000)
      .pipe(takeUntilDestroyed()) // în context de injecție; altfel: takeUntilDestroyed(this.destroyRef)
      .subscribe((n) => this.tick.set(n));
  }
}
// Pentru stare afișată în template, toSignal(obs$) se dezabonează singur (vezi pagina Signals ↔ RxJS).

Când DA, când NU

RxJS e unealta potrivită
  • Evenimente în timp: debounce, throttle, ferestre de timp, combinarea mai multor surse.
  • Request-uri care se pot suprapune și au nevoie de o politică: anulare, coadă, ignorare.
  • Reîncercări, timeout-uri, polling, websocket-uri, server-sent events.
  • Fluxuri de comenzi ordonate (autosave, cozi offline).
Ajung semnalele / resource
  • Stare afișată în UI: signal / computed (vezi Signals).
  • Un request care depinde de parametri: httpResource / rxResource anulează singure ce e vechi (vezi resource).
  • Un singur request la un click, fără suprapuneri posibile: un subscribe simplu sau o metodă async.
  • „Ca să fie reactiv”: un BehaviorSubject pentru o valoare simplă e acum un signal().

Capcane frecvente

  • mergeMap pentru căutare. Răspunsurile vin în orice ordine, iar unul vechi îl poate suprascrie pe cel nou. Folosește switchMap.
  • switchMap pentru salvări. Un save anulat la jumătate poate fi deja procesat pe server, sau poate nu. Pentru scrieri, concatMap sau exhaustMap. Mai multe despre scrieri care sosesc în altă ordine la actualizări optimiste.
  • Subscribe în subscribe. Pierzi anularea și gestiunea erorilor. Orice „subscribe, apoi în callback alt subscribe” e un operator *Map.
  • catchError la nivelul exterior într-un stream care trebuie să trăiască: oprește totul la prima eroare.
  • shareReplay(1) pe surse infinite: scurgere de memorie și conexiuni. Folosește { bufferSize: 1, refCount: true }. Cum le găsești afli pe pagina despre memory leaks.
  • Retry pe 4xx: reîncerci la nesfârșit un request care nu va reuși niciodată. Filtrează după status.

Fișă rapidă

OPERATOR      LA O VALOARE NOUĂ CÂT CEA VECHE RULEAZĂ        FOLOSEȘTE PENTRU
switchMap     anulează-o pe cea veche                       căutare, parametri de rută, „ultimul câștigă”
mergeMap      rulează-le în paralel (opțional: concurrency) operații independente, upload-uri
concatMap     pune-o la coadă, în ordine                     salvări ordonate, cozi de comenzi
exhaustMap    ignor-o                                        submit, login, refresh manual

catchError    ÎN proiecția interioară, ca stream-ul exterior să rămână viu
retry         { count, delay: (err, n) => timer(base * 2 ** (n - 1)) } — nu reîncerca 4xx
share()       abonați simultani împart execuția
shareReplay   { bufferSize: 1, refCount: true } — cache + dezabonare corectă
combineLatest filtre combinate · withLatestFrom „la click, ia valoarea curentă” · forkJoin „toate, o dată”
takeUntilDestroyed() / toSignal()   fără subscribe-uri uitate

Cap. 14 · 0 din 4 terminate

Ai terminat lecția?

Marcheaz-o și apare pe harta ta: în cuprins și pe prima pagină.

Se marchează singură după ce citești toată lecția.

  1. Semnalele pe dinăuntru
  2. RxJS avansat: operatori de ordin superior
  3. NgRx SignalStore
  4. Mașini de stări cu signals
Vezi toată harta ta

Toate cele 75 de pagini · scrie ca să filtrezi

  • 01Ce e nou în Angular 21 & 22Toate schimbările importante din v21 și v22, pe scurt, cu link către pagina care le explică.Start
  • 01Prima ta aplicație, pas cu pasO listă de lecturi construită de la o componentă goală la o aplicație terminată — signals, @for, input-uri și output-uri, un serviciu și un formular, pas cu pas.Start
  • 01Decizii rapide„Unde pun asta?”, „Signal sau Observable?”, „Shared sau feature?” — răspunsuri scurte la întrebările de zi cu zi.Start
  • 01Întrebări de interviu Angular60 de întrebări reale de interviu pentru junior, mid și senior, cu răspunsul de dat, întrebarea care urmează și greșelile de evitat. Plus o simulare de interviu.Start
  • 02Standalone & bootstrapCum pornește o aplicație fără NgModule: bootstrapApplication, app.config.ts, imports în componentă.Fundamente moderne
  • 02Data binding și evenimenteInterpolare, binding pe proprietăți și pe atribute, evenimente cu $event și filtre de taste și cum e construit [( )] — ce intră în DOM și ce se întoarce.Fundamente moderne
  • 02Control flow: @if, @for, @switchSintaxa de blocuri care înlocuiește *ngIf/*ngFor/ngSwitch, cu track, @empty și verificare exhaustivă.Fundamente moderne
  • 02@let și expresiile noi din templateVariabile locale cu @let, arrow functions, spread, regex, instanceof, comentarii în tag-uri.Fundamente moderne
  • 02@defer — lazy loading în templateÎncarci componente grele doar când e nevoie: triggere, prefetch, placeholder, loading, error.Fundamente moderne
  • 02Class & style bindingsDe ce [class.x] și [style.x] au înlocuit ngClass și ngStyle (cu migrare automată din v21).Fundamente moderne
  • 02Stilurile componentelor și încapsularea:host, cele trei moduri de încapsulare, teme cu variabile CSS și de ce ::ng-deep e ultima soluție.Fundamente moderne
  • 02Pipes: când și cumPipe pur vs impur, pipe custom și cum alegi între pipe, computed() și o metodă.Fundamente moderne
  • 03signal() și computed()Primitivele reactive: stare scriibilă, stare derivată, egalitate, untracked și reguli de imutabilitate.Signals & reactivitate
  • 03effect() — când DA, când NUEfecte secundare sincronizate cu semnale: localStorage, logging, API-uri imperative. Și capcanele lor.Signals & reactivitate
  • 03linkedSignal() — stare derivată editabilăUn semnal care se resetează când se schimbă sursa, dar pe care îl poți și seta manual.Signals & reactivitate
  • 03resource, rxResource, httpResourceDate asincrone ca semnale: status, value, error, reload, anulare automată. Stabile din v22.Signals & reactivitate
  • 03debounced() — semnale cu întârziereVarianta „debounce” a unui semnal, fără RxJS. Perfect pentru căutare.Signals & reactivitate
  • 03Liste: căutare, filtrare, sortare, paginareUn lanț de computed-uri care recalculează doar ce s-a schimbat, cu filtrele ținute în URL, ca un link să redeschidă aceeași vedere.Signals & reactivitate
  • 03Observables de la zeroCe e un Observable, subscribe și unsubscribe, operatorii pe care îi folosești în fiecare săptămână, cold vs hot — și când ajunge un signal.Signals & reactivitate
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — și când RxJS rămâne alegerea bună.Signals & reactivitate
  • 04input() și output()Inputuri ca semnale (required, transform, alias) și outputuri tipizate. Data down, events up.Componente: comunicare
  • 04model() — two-way bindingBanana-in-a-box [( )] cu un singur API. Când îl folosești și când e mai bine input + output.Componente: comunicare
  • 04viewChild & contentChildInterogări ca semnale: viewChild, viewChildren, contentChild, contentChildren, opțiunea read.Componente: comunicare
  • 04Lifecycle & DestroyRefCe hook-uri mai contează în era signals, afterNextRender, DestroyRef și ngOnChanges tipizat.Componente: comunicare
  • 04Content projectionng-content cu select, sloturi multiple, conținut implicit și capcana proiecției condiționale.Componente: comunicare
  • 04ng-template & ngTemplateOutletTemplate-uri ca valori: render props în Angular, context tipizat și personalizare de componente.Componente: comunicare
  • 05Smart vs DumbContainer vs presentational: cine ține starea, cine doar afișează, și cum le împarți corect.Design de componente
  • 05Componente generice <T>Un DataTable<T> sau Select<T> tipizat corect, cu template-uri pentru celule.Design de componente
  • 05Componente dinamiceNgComponentOutlet, createComponent cu inputBinding/outputBinding și un dashboard construit din config.Design de componente
  • 05Directive & host compositionDirective atribut, metadata host: {} și Directive Composition API (hostDirectives).Design de componente
  • 05Controale custom de formularFormValueControl (Signal Forms) vs ControlValueAccessor: un rating cu stele, în ambele variante.Design de componente
  • 05Change detectionOnPush e implicit din v22, zone.js lipsește din v21. Ce declanșează randarea și cum să nu te arzi.Design de componente
  • 06inject() & @Service()Noul decorator @Service() din v22, inject() vs constructor și contextul de injecție.Dependency Injection
  • 06Providers & ierarhia de injectoriRoot vs rută vs componentă, useClass/useValue/useFactory/useExisting și modificatorii optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Configurare tipizată, funcții provideFeature(), makeEnvironmentProviders și inițializatori.Dependency Injection
  • 06injectAsync() — servicii lazyÎncarci un serviciu greu abia când ai nevoie de el, cu prefetch la idle.Dependency Injection
  • 07Structura de folderecore / shared / features, ce intră în fiecare și cum arată un feature pe dinăuntru.Arhitectura aplicației
  • 07Shared vs featureCând muți o componentă în shared și (mai ales) când NU. Checklist concret.Arhitectura aplicației
  • 07Interfețe & modeleInterfață inline sau fișier separat? DTO vs model de domeniu, type vs interface, unde le pui.Arhitectura aplicației
  • 07State management cu signalsStore-uri simple pe semnale, facade, stare locală vs globală și când îți trebuie NgRx.Arhitectura aplicației
  • 07Style guide & namingConvențiile oficiale actuale: nume de fișiere fără sufixe, protected, readonly, ordinea membrilor.Arhitectura aplicației
  • 07Barrels, aliasuri & granițeindex.ts, path aliases, API public pe feature și reguli de dependență care se pot verifica automat.Arhitectura aplicației
  • 07Erori: @boundary & ErrorHandlerNoul bloc @boundary din v22.2, ErrorHandler global, erori HTTP și erori din resource.Arhitectura aplicației
  • 08Routing modern & lazy loadingloadComponent, rute copil, parametri ca input-uri și moștenirea parametrilor (default nou în v22).Routing
  • 08Guards & resolverscanActivate, canMatch, canDeactivate și resolve ca funcții, cu redirect prin UrlTree / RedirectCommand.Routing
  • 09Signal Forms — bazeleFormulare construite pe semnale: form(), [formField], validare prin schemă. Stabile din v22.Formulare
  • 09Signal Forms — avansatValidare custom și cross-field, async/HTTP cu debounce, liste dinamice, disabled/hidden, scheme reutilizabile.Formulare
  • 09Reactive Forms tipizateFormGroup tipizat, nonNullable, FormArray — și cum conviețuiesc cu Signal Forms.Formulare
  • 10HttpClient, interceptors & API layerHttpClient fără setup (v21), Fetch implicit (v22), interceptori funcționali și stratul de API cu mapare DTO.HTTP & date
  • 11Performanță — checklistCe chiar contează: OnPush + signals, track, @defer, lazy routes, imagini, bundle și hidratare.Calitate & performanță
  • 11Testare cu VitestVitest e runner-ul implicit din v21. TestBed, componente cu semnale, servicii, HTTP și harness-uri.Calitate & performanță
  • 11DevTools: cum te uiți în aplicațieChrome DevTools și Angular DevTools pas cu pas: ce arată fiecare panou, cu exerciții care merg chiar pe site-ul ăsta.Calitate & performanță
  • 11Angular AriaComponente headless, accesibile, pe care le stilizezi cum vrei: tabs, accordion, menu, listbox...Calitate & performanță
  • 12SSR, prerender & render modesCând randezi pe server, când la build și când doar în browser: RenderMode pe rută, app.routes.server.ts și costurile reale.SSR & hidratare
  • 12Hidratare: event replay & incrementalCum preia browserul HTML-ul de pe server fără să-l refacă: hidratare completă, event replay, @defer (hydrate on …) și erorile de nepotrivire.SSR & hidratare
  • 12Cod compatibil cu serverulwindow nu există pe server: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, cache-ul HTTP și PendingTasks.SSR & hidratare
  • 13Micro frontendsCând merită să spargi o aplicație în mai multe deploy-uri și când e doar complexitate: Native Federation, Module Federation, iframes, Web Components.Arhitectură la scară
  • 13Web Components cu Angular ElementscreateCustomElement: o componentă Angular folosită ca tag HTML oriunde, plus comunicarea între aplicații prin evenimente și BroadcastChannel.Arhitectură la scară
  • 13Monorepo, librării & granițeUn workspace cu mai multe aplicații și librării: ng generate library, Nx, entry points secundare, publicare și reguli de dependență.Arhitectură la scară
  • 13Arhitectură hexagonală (ports & adapters)Domeniul fără Angular, porturi ca clase abstracte și adaptoare interschimbabile: HTTP, localStorage sau in-memory, fără să atingi UI-ul.Arhitectură la scară
  • 14Semnalele pe dinăuntruGraful reactiv: producători și consumatori, push-pull, de ce computed e lazy și glitch-free, problema diamantului și când rulează efectele.Reactivitate avansată
  • 14RxJS avansat: operatori de ordin superiorswitchMap, mergeMap, concatMap și exhaustMap pe o diagramă live, plus retry cu backoff, shareReplay și cum eviți scurgerile.Reactivitate avansată
  • 14NgRx SignalStoreState management la scară pe semnale: withState, withComputed, withMethods, rxMethod, entități și hooks — și când un store simplu e suficient.Reactivitate avansată
  • 14Mașini de stări cu signalsFără stări imposibile: o mașină tipizată pe signals, cu tranziții, guards și diagrama stărilor, live.Reactivitate avansată
  • 15WebSockets: timp real care rezistă rețeleiUn socket tipizat ca signals: reconectare cu backoff și jitter, heartbeat, coadă de mesaje cât ești offline și siguranță la SSR.Timp real și offline
  • 15Actualizări optimiste și rollbackInterfață instantanee, dar onestă: snapshot și rollback, răspunsuri sosite în altă ordine, chei de idempotență.Timp real și offline
  • 15Offline-first: Service Worker și cacheService Worker-ul Angular: strategii de cache, anunțarea versiunilor noi și o coadă pentru modificările făcute offline.Timp real și offline
  • 16Web WorkersCalcule grele fără să blochezi interfața: un worker real în pagină, comunicare prin mesaje și când nu merită.UI & performanță avansată
  • 16Liste uriașe: virtual scroll100.000 de rânduri fără lag: CDK virtual scroll, itemSize, trackBy și alternativele (paginare, infinite scroll).UI & performanță avansată
  • 16Animații moderne & View Transitionsanimate.enter și animate.leave în locul @angular/animations (depreciat), tranziții CSS și View Transitions la navigare.UI & performanță avansată
  • 16Memory leaks: cum le găsești și le repariSubscripții, timere și listeneri care trăiesc mai mult decât componenta lor — cum îi vezi în DevTools și cum îi închizi.UI & performanță avansată
  • 17Securitate: XSS, sanitizare & CSPCe face Angular automat împotriva XSS, când devine periculos bypassSecurityTrust, plus CSP cu nonce, Trusted Types și XSRF.Securitate & globalizare
  • 17Autentificare: token-uri & refreshUn interceptor care atașează token-ul, reîmprospătează o singură dată la 401 și reia cererile din coadă — plus unde ții token-ul.Securitate & globalizare
  • 17OAuth 2.1 și OpenID Connect cu PKCEFluxul authorization code cu PKCE, pas cu pas: verifier și challenge, state și nonce, ID token-ul și de ce un BFF e mai sigur.Securitate & globalizare
  • 17Internaționalizare (i18n)$localize, atributul i18n, ICU plural/select, build per limbă vs. traduceri la runtime și formatarea după locale.Securitate & globalizare