From c9a80da7c3ea7fcf3848dfcd2832ca218c15ae66 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Thu, 13 Aug 2026 11:03:30 +0400 Subject: [PATCH] perf: memoize TranslatePipe instead of re-walking translations every CD cycle pure:false stays (needed so language switches propagate without touching every | translate template call site), but repeat calls with unchanged key/params/language now hit a Map lookup instead of re-splitting the key and re-walking the translation object tree. Co-Authored-By: Claude Sonnet 5 --- src/app/i18n/translate.pipe.ts | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/app/i18n/translate.pipe.ts b/src/app/i18n/translate.pipe.ts index 86c8b32..a35360e 100644 --- a/src/app/i18n/translate.pipe.ts +++ b/src/app/i18n/translate.pipe.ts @@ -1,14 +1,42 @@ import { Pipe, PipeTransform, inject } from '@angular/core'; import { TranslateService } from './translate.service'; +import { LanguageService } from '../services/language.service'; +/** + * Stays impure (must re-run every CD cycle so a live language switch + * updates every binding without touching hundreds of `| translate` + * template call sites to pass the language explicitly as a pure-pipe + * argument). Memoized per-instance instead: repeat calls with the same + * key/params/language - the overwhelming majority of CD cycles, since + * nothing actually changed - hit a Map lookup instead of re-walking the + * translation tree and re-running the interpolation regex. + */ @Pipe({ name: 'translate', pure: false, }) export class TranslatePipe implements PipeTransform { private translateService = inject(TranslateService); + private langService = inject(LanguageService); + + private lastLang = ''; + private readonly cache = new Map(); transform(key: string, params?: Record): string { - return this.translateService.t(key, params); + const lang = this.langService.currentLanguage(); + if (lang !== this.lastLang) { + this.lastLang = lang; + this.cache.clear(); + } + + const cacheKey = params ? `${key}::${JSON.stringify(params)}` : key; + const cached = this.cache.get(cacheKey); + if (cached !== undefined) { + return cached; + } + + const result = this.translateService.t(key, params); + this.cache.set(cacheKey, result); + return result; } }