Skip to content

Commit 48a651b

Browse files
committed
fix(#632): locale pipes optimizations unit tests
1 parent 8eb567e commit 48a651b

9 files changed

+396
-284
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,64 @@
1-
import {
2-
ChangeDetectorRef,
3-
inject,
4-
Injectable,
5-
OnDestroy,
6-
} from '@angular/core';
7-
import { Subscription } from 'rxjs';
8-
9-
import { Locale } from '../../lib/transloco-locale.types';
10-
import { TranslocoLocaleService } from '../transloco-locale.service';
11-
12-
type Deps = [TranslocoLocaleService, ChangeDetectorRef];
13-
@Injectable()
14-
export abstract class BaseLocalePipe<VALUE = unknown, ARGS extends unknown[] = []> implements OnDestroy {
15-
protected localeService = inject(TranslocoLocaleService);
16-
protected cdr = inject(ChangeDetectorRef);
17-
18-
private localeChangeSub: Subscription | null =
19-
this.localeService.localeChanges$.subscribe(() => this.invalidate());
20-
21-
protected lastValue?: VALUE;
22-
protected lastArgs?: string;
23-
24-
protected lastResult = '';
25-
26-
protected getLocale(locale?: Locale): Locale {
27-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
28-
return locale || this.localeService.getLocale()!;
29-
}
30-
31-
transform(value: VALUE, ...args: ARGS): string {
32-
if (this.isSameValue(value) && this.isSameArgs(...args)) {
33-
return this.lastResult;
34-
}
35-
this.lastResult = this.doTransform(value, ...args);
36-
this.lastValue = value;
37-
this.lastArgs = JSON.stringify(args);
38-
return this.lastResult;
39-
}
40-
41-
protected abstract doTransform(value: VALUE, ...args: ARGS): string;
42-
43-
protected isSameValue(value: VALUE): boolean {
44-
return this.lastValue === value;
45-
}
46-
47-
protected isSameArgs(...args: ARGS): boolean {
48-
return JSON.stringify(args) === this.lastArgs;
49-
}
50-
51-
invalidate() {
52-
this.lastValue = undefined;
53-
this.lastArgs = undefined;
54-
this.lastResult = '';
55-
this.cdr.markForCheck();
56-
}
57-
58-
ngOnDestroy(): void {
59-
this.localeChangeSub?.unsubscribe();
60-
// Caretaker note: it's important to clean up references to subscriptions since they save the `next`
61-
// callback within its `destination` property, preventing classes from being GC'd.
62-
this.localeChangeSub = null;
63-
}
64-
}
1+
import {
2+
ChangeDetectorRef,
3+
inject,
4+
Injectable,
5+
OnDestroy,
6+
} from '@angular/core';
7+
import { Subscription } from 'rxjs';
8+
9+
import { Locale } from '../../lib/transloco-locale.types';
10+
import { TranslocoLocaleService } from '../transloco-locale.service';
11+
12+
type Deps = [TranslocoLocaleService, ChangeDetectorRef];
13+
@Injectable()
14+
export abstract class BaseLocalePipe<VALUE = unknown, ARGS extends unknown[] = []> implements OnDestroy {
15+
protected localeService = inject(TranslocoLocaleService);
16+
protected cdr = inject(ChangeDetectorRef);
17+
18+
private localeChangeSub: Subscription | null =
19+
this.localeService.localeChanges$.subscribe(() => this.invalidate());
20+
21+
protected lastValue?: VALUE;
22+
protected lastArgs?: string;
23+
24+
protected lastResult = '';
25+
26+
protected getLocale(locale?: Locale): Locale {
27+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
28+
return locale || this.localeService.getLocale()!;
29+
}
30+
31+
transform(value: VALUE, ...args: ARGS): string {
32+
if (this.isSameValue(value) && this.isSameArgs(...args)) {
33+
return this.lastResult;
34+
}
35+
this.lastResult = this.doTransform(value, ...args);
36+
this.lastValue = value;
37+
this.lastArgs = JSON.stringify(args);
38+
return this.lastResult;
39+
}
40+
41+
protected abstract doTransform(value: VALUE, ...args: ARGS): string;
42+
43+
protected isSameValue(value: VALUE): boolean {
44+
return this.lastValue === value;
45+
}
46+
47+
protected isSameArgs(...args: ARGS): boolean {
48+
return JSON.stringify(args) === this.lastArgs;
49+
}
50+
51+
invalidate() {
52+
this.lastValue = undefined;
53+
this.lastArgs = undefined;
54+
this.lastResult = '';
55+
this.cdr.markForCheck();
56+
}
57+
58+
ngOnDestroy(): void {
59+
this.localeChangeSub?.unsubscribe();
60+
// Caretaker note: it's important to clean up references to subscriptions since they save the `next`
61+
// callback within its `destination` property, preventing classes from being GC'd.
62+
this.localeChangeSub = null;
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,66 @@
1-
import { inject, Pipe, PipeTransform } from '@angular/core';
2-
import { isNil } from '@ngneat/transloco';
3-
4-
import { getDefaultOptions } from '../shared';
5-
import { TRANSLOCO_LOCALE_CONFIG } from '../transloco-locale.config';
6-
import {
7-
Currency,
8-
Locale,
9-
LocaleConfig,
10-
NumberFormatOptions,
11-
} from '../transloco-locale.types';
12-
13-
import { BaseLocalePipe } from './base-locale.pipe';
14-
15-
@Pipe({
16-
name: 'translocoCurrency',
17-
pure: false,
18-
standalone: true,
19-
})
20-
export class TranslocoCurrencyPipe
21-
extends BaseLocalePipe<number | string, [
22-
display?: 'code' | 'symbol' | 'name',
23-
numberFormatOptions?: NumberFormatOptions,
24-
currencyCode?: Currency,
25-
locale?: Locale]>
26-
implements PipeTransform
27-
{
28-
private localeConfig: LocaleConfig = inject(TRANSLOCO_LOCALE_CONFIG);
29-
30-
/**
31-
* Transform a given number into the locale's currency format.
32-
*
33-
* @example
34-
*
35-
* 1000000 | translocoCurrency: 'symbol' : {} : USD // $1,000,000.00
36-
* 1000000 | translocoCurrency: 'name' : {} : USD // 1,000,000.00 US dollars
37-
* 1000000 | translocoCurrency: 'symbol' : {minimumFractionDigits: 0 } : USD // $1,000,000
38-
* 1000000 | translocoCurrency: 'symbol' : {minimumFractionDigits: 0 } : CAD // CA$1,000,000
39-
* 1000000 | translocoCurrency: 'narrowSymbol' : {minimumFractionDigits: 0 } : CAD // $1,000,000
40-
*
41-
*/
42-
protected override doTransform(
43-
value: number | string,
44-
display: 'code' | 'symbol' | 'narrowSymbol' | 'name' = 'symbol',
45-
numberFormatOptions: NumberFormatOptions = {},
46-
currencyCode?: Currency,
47-
locale?: Locale
48-
): string {
49-
if (isNil(value)) return '';
50-
locale = this.getLocale(locale);
51-
52-
const options = {
53-
...getDefaultOptions(locale, 'currency', this.localeConfig),
54-
...numberFormatOptions,
55-
currencyDisplay: display,
56-
currency: currencyCode || this.localeService._resolveCurrencyCode(),
57-
};
58-
59-
return this.localeService.localizeNumber(
60-
value,
61-
'currency',
62-
locale,
63-
options
64-
);
65-
}
66-
}
1+
import { inject, Pipe, PipeTransform } from '@angular/core';
2+
import { isNil } from '@ngneat/transloco';
3+
4+
import { getDefaultOptions } from '../shared';
5+
import { TRANSLOCO_LOCALE_CONFIG } from '../transloco-locale.config';
6+
import {
7+
Currency,
8+
Locale,
9+
LocaleConfig,
10+
NumberFormatOptions,
11+
} from '../transloco-locale.types';
12+
13+
import { BaseLocalePipe } from './base-locale.pipe';
14+
15+
@Pipe({
16+
name: 'translocoCurrency',
17+
pure: false,
18+
standalone: true,
19+
})
20+
export class TranslocoCurrencyPipe
21+
extends BaseLocalePipe<number | string, [
22+
display?: 'code' | 'symbol' | 'name',
23+
numberFormatOptions?: NumberFormatOptions,
24+
currencyCode?: Currency,
25+
locale?: Locale]>
26+
implements PipeTransform
27+
{
28+
private localeConfig: LocaleConfig = inject(TRANSLOCO_LOCALE_CONFIG);
29+
30+
/**
31+
* Transform a given number into the locale's currency format.
32+
*
33+
* @example
34+
*
35+
* 1000000 | translocoCurrency: 'symbol' : {} : USD // $1,000,000.00
36+
* 1000000 | translocoCurrency: 'name' : {} : USD // 1,000,000.00 US dollars
37+
* 1000000 | translocoCurrency: 'symbol' : {minimumFractionDigits: 0 } : USD // $1,000,000
38+
* 1000000 | translocoCurrency: 'symbol' : {minimumFractionDigits: 0 } : CAD // CA$1,000,000
39+
* 1000000 | translocoCurrency: 'narrowSymbol' : {minimumFractionDigits: 0 } : CAD // $1,000,000
40+
*
41+
*/
42+
protected override doTransform(
43+
value: number | string,
44+
display: 'code' | 'symbol' | 'narrowSymbol' | 'name' = 'symbol',
45+
numberFormatOptions: NumberFormatOptions = {},
46+
currencyCode?: Currency,
47+
locale?: Locale
48+
): string {
49+
if (isNil(value)) return '';
50+
locale = this.getLocale(locale);
51+
52+
const options = {
53+
...getDefaultOptions(locale, 'currency', this.localeConfig),
54+
...numberFormatOptions,
55+
currencyDisplay: display,
56+
currency: currencyCode || this.localeService._resolveCurrencyCode(),
57+
};
58+
59+
return this.localeService.localizeNumber(
60+
value,
61+
'currency',
62+
locale,
63+
options
64+
);
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,57 @@
1-
import { inject, Pipe, PipeTransform } from '@angular/core';
2-
import { isNil } from '@ngneat/transloco';
3-
4-
import { getDefaultOptions } from '../shared';
5-
import { TRANSLOCO_LOCALE_CONFIG } from '../transloco-locale.config';
6-
import {
7-
DateFormatOptions,
8-
Locale,
9-
LocaleConfig,
10-
ValidDate,
11-
} from '../transloco-locale.types';
12-
13-
import { BaseLocalePipe } from './base-locale.pipe';
14-
15-
@Pipe({
16-
name: 'translocoDate',
17-
pure: false,
18-
standalone: true,
19-
})
20-
export class TranslocoDatePipe
21-
extends BaseLocalePipe<ValidDate, [options?: DateFormatOptions, locale?: Locale]>
22-
implements PipeTransform {
23-
private localeConfig: LocaleConfig = inject(TRANSLOCO_LOCALE_CONFIG);
24-
25-
/**
26-
* Transform a date into the locale's date format.
27-
*
28-
* The date expression: a `Date` object, a number
29-
* (milliseconds since UTC epoch), or an ISO string (https://www.w3.org/TR/NOTE-datetime).
30-
*
31-
* @example
32-
*
33-
* date | translocoDate: {} : en-US // 9/10/2019
34-
* date | translocoDate: { dateStyle: 'medium', timeStyle: 'medium' } : en-US // Sep 10, 2019, 10:46:12 PM
35-
* date | translocoDate: { timeZone: 'UTC', timeStyle: 'full' } : en-US // 7:40:32 PM Coordinated Universal Time
36-
* 1 | translocoDate: { dateStyle: 'medium' } // Jan 1, 1970
37-
* '2019-02-08' | translocoDate: { dateStyle: 'medium' } // Feb 8, 2019
38-
*/
39-
protected override doTransform(date: ValidDate, options: DateFormatOptions = {}, locale?: Locale) {
40-
if (isNil(date)) return '';
41-
locale = this.getLocale(locale);
42-
43-
return this.localeService.localizeDate(date, locale, {
44-
...getDefaultOptions(locale, 'date', this.localeConfig),
45-
...options,
46-
});
47-
}
48-
49-
protected override isSameValue(value?: ValidDate) {
50-
return this.getComparableDate(this.lastValue) === this.getComparableDate(value);
51-
}
52-
53-
private getComparableDate(value?: any) {
54-
return value?.getTime ? value.getTime() : value;
55-
}
56-
}
1+
import { inject, Pipe, PipeTransform } from '@angular/core';
2+
import { isNil } from '@ngneat/transloco';
3+
4+
import { isDate } from '../helpers';
5+
import { getDefaultOptions } from '../shared';
6+
import { TRANSLOCO_LOCALE_CONFIG } from '../transloco-locale.config';
7+
import {
8+
DateFormatOptions,
9+
Locale,
10+
LocaleConfig,
11+
ValidDate,
12+
} from '../transloco-locale.types';
13+
14+
import { BaseLocalePipe } from './base-locale.pipe';
15+
16+
@Pipe({
17+
name: 'translocoDate',
18+
pure: false,
19+
standalone: true,
20+
})
21+
export class TranslocoDatePipe
22+
extends BaseLocalePipe<ValidDate, [options?: DateFormatOptions, locale?: Locale]>
23+
implements PipeTransform {
24+
private localeConfig: LocaleConfig = inject(TRANSLOCO_LOCALE_CONFIG);
25+
26+
/**
27+
* Transform a date into the locale's date format.
28+
*
29+
* The date expression: a `Date` object, a number
30+
* (milliseconds since UTC epoch), or an ISO string (https://www.w3.org/TR/NOTE-datetime).
31+
*
32+
* @example
33+
*
34+
* date | translocoDate: {} : en-US // 9/10/2019
35+
* date | translocoDate: { dateStyle: 'medium', timeStyle: 'medium' } : en-US // Sep 10, 2019, 10:46:12 PM
36+
* date | translocoDate: { timeZone: 'UTC', timeStyle: 'full' } : en-US // 7:40:32 PM Coordinated Universal Time
37+
* 1 | translocoDate: { dateStyle: 'medium' } // Jan 1, 1970
38+
* '2019-02-08' | translocoDate: { dateStyle: 'medium' } // Feb 8, 2019
39+
*/
40+
protected override doTransform(date: ValidDate, options: DateFormatOptions = {}, locale?: Locale) {
41+
if (isNil(date)) return '';
42+
locale = this.getLocale(locale);
43+
44+
return this.localeService.localizeDate(date, locale, {
45+
...getDefaultOptions(locale, 'date', this.localeConfig),
46+
...options,
47+
});
48+
}
49+
50+
protected override isSameValue(value?: ValidDate) {
51+
return this.getComparableDate(this.lastValue) === this.getComparableDate(value);
52+
}
53+
54+
private getComparableDate(value?: any) {
55+
return isDate(value) ? value.getTime() : value;
56+
}
57+
}

0 commit comments

Comments
 (0)