Skip to content

Commit

Permalink
Perf: make pure convert function to avoid change detection
Browse files Browse the repository at this point in the history
  • Loading branch information
robisim74 committed Nov 10, 2021
1 parent 78bb497 commit b625cf6
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 42 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"analyze": "ng build angular-l10n-app --stats-json && webpack-bundle-analyzer dist/angular-l10n-app/stats.json",
"dev:ssr": "ng run angular-l10n-app-ssr:serve-ssr",
"serve:ssr": "node dist/angular-l10n-app-ssr/server/main.js",
"build:ssr": "ng build && ng run angular-l10n-app-ssr:server:production",
"build:ssr": "ng build angular-l10n-app-ssr && ng run angular-l10n-app-ssr:server",
"prerender": "concurrently \"npx http-server ./dist/angular-l10n-app-ssr/browser -p 5000 \" \"ng run angular-l10n-app-ssr:prerender\"",
"prepare": "husky install"
},
Expand Down
34 changes: 16 additions & 18 deletions projects/angular-l10n-app/src/app/conversions.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
export const convertCurrency = (currency: string) => {
return (value: number) => {
switch (currency) {
case "USD":
return value * 1.16;
default:
return value;
}
};
import { L10nLocale } from "angular-l10n";

export const convertCurrency = (value: number, locale: L10nLocale, rate: number) => {
switch (locale.currency) {
case "USD":
return value * rate;
default:
return value;
}
};

export const convertLength = (to: string) => {
return (value: number) => {
switch (to) {
case "mile":
return value * 0.621371;
default:
return value;
}
};
export const convertLength = (value: number, locale: L10nLocale) => {
switch (locale.units['length']) {
case "mile":
return value * 0.621371;
default:
return value;
}
};
5 changes: 3 additions & 2 deletions projects/angular-l10n-app/src/app/home/api/api.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ export class ApiComponent implements OnInit, OnChanges {
{ digits: '1.2-2', style: 'currency' },
undefined,
undefined,
convertCurrency(this.translation.getLocale().currency)
convertCurrency,
{ rate: 1.16 }
);
this.formattedLength = this.intl.formatNumber(
1,
{ digits: '1.0-2', style: 'unit', unit: this.translation.getLocale().units['length'] },
undefined,
undefined,
convertLength(this.translation.getLocale().units['length'])
convertLength
);
this.formattedOnePlural = this.intl.plural(1, 'home', { type: 'cardinal' });
this.formattedOtherPlural = this.intl.plural(2, 'home', { type: 'cardinal' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ <h3>Directives</h3>
<p [options]="{ dateStyle: 'full', timeStyle: 'short' }" l10nDate>{{ today }}</p>
<p [options]="{ numeric:'always', style:'long' }" unit="second" l10nTimeAgo>{{ timeAgo }}</p>
<br>
<p [options]="{ digits: '1.2-2', style: 'currency' }" [convert]="convertCurrency(locale.currency)" l10nNumber>{{ value }}</p>
<p [options]="{ digits: '1.0-2', style: 'unit', unit: locale.units['length'] }" [convert]="convertLength(locale.units['length'])" l10nNumber>1</p>
<p [options]="{ digits: '1.2-2', style: 'currency' }" [convert]="convertCurrency" [convertParams]="{ rate: 1.16 }" l10nNumber>{{ value }}</p>
<p [options]="{ digits: '1.0-2', style: 'unit', unit: locale.units['length'] }" [convert]="convertLength" l10nNumber>1</p>
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ <h3>Pure Pipes</h3>
<p>{{ today | l10nDate:locale.language:{ dateStyle: 'full', timeStyle: 'short' } }}</p>
<p>{{ timeAgo | l10nTimeAgo:locale.language:'second':{ numeric:'always', style:'long' } }}</p>
<br>
<p>{{ value | l10nNumber:locale.language:{ digits: '1.2-2', style: 'currency' }:undefined:convertCurrency(locale.currency) }}</p>
<p>{{ 1 | l10nNumber:locale.language:{ digits: '1.0-2', style: 'unit', unit: locale.units['length'] }:undefined:convertLength(locale.units['length']) }}</p>
<p>{{ value | l10nNumber:locale.language:{ digits: '1.2-2', style: 'currency' }:locale.currency:convertCurrency:{ rate: 1.16 } }}</p>
<p>{{ 1 | l10nNumber:locale.language:{ digits: '1.0-2', style: 'unit', unit: locale.units['length'] }:undefined:convertLength }}</p>
<br>
<p>1 {{ 1 | l10nPlural:locale.language:'home':{ type: 'cardinal' } }}</p>
<p>2 {{ 2 | l10nPlural:locale.language:'home':{ type: 'cardinal' } }}</p>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Directive, Input, ElementRef, Renderer2 } from '@angular/core';

import { L10nNumberFormatOptions } from '../models/types';
import { L10nLocale, L10nNumberFormatOptions } from '../models/types';
import { L10nDirective } from '../models/l10n-directive';
import { L10nTranslationService } from '../services/l10n-translation.service';
import { L10nIntlService } from '../services/l10n-intl.service';
Expand All @@ -18,7 +18,8 @@ export class L10nNumberDirective extends L10nDirective {

@Input() public currency?: string;

@Input() public convert?: (...args: any) => number;
@Input() public convert?: (value: number, locale: L10nLocale, params: any) => number;
@Input() public convertParams?: any;

constructor(
protected override el: ElementRef,
Expand All @@ -30,7 +31,7 @@ export class L10nNumberDirective extends L10nDirective {
}

protected getValue(text: string): string {
return this.intl.formatNumber(text, this.options, this.language, this.currency, this.convert);
return this.intl.formatNumber(text, this.options, this.language, this.currency, this.convert, this.convertParams);
}

}
12 changes: 7 additions & 5 deletions projects/angular-l10n/src/lib/pipes/l10n-number.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Pipe, PipeTransform, ChangeDetectorRef } from '@angular/core';

import { L10nNumberFormatOptions } from '../models/types';
import { L10nLocale, L10nNumberFormatOptions } from '../models/types';
import { L10nAsyncPipe } from '../models/l10n-async-pipe';
import { L10nIntlService } from '../services/l10n-intl.service';
import { L10nTranslationService } from '../services/l10n-translation.service';
Expand All @@ -18,11 +18,12 @@ export class L10nNumberPipe implements PipeTransform {
language: string,
options?: L10nNumberFormatOptions,
currency?: string,
convert?: (...args: any) => number
convert?: (value: number, locale: L10nLocale, params: any) => number,
convertParams?: any
): string | null {
if (value == null || value === '') return null;

return this.intl.formatNumber(value, options, language, currency, convert);
return this.intl.formatNumber(value, options, language, currency, convert, convertParams);
}

}
Expand All @@ -46,11 +47,12 @@ export class L10nNumberAsyncPipe extends L10nAsyncPipe implements PipeTransform
options?: L10nNumberFormatOptions,
language?: string,
currency?: string,
convert?: (...args: any) => number
convert?: (value: number, locale: L10nLocale, params: any) => number,
convertParams?: any
): string | null {
if (value == null || value === '') return null;

return this.intl.formatNumber(value, options, language, currency, convert);
return this.intl.formatNumber(value, options, language, currency, convert, convertParams);
}

}
12 changes: 7 additions & 5 deletions projects/angular-l10n/src/lib/services/l10n-intl.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,29 +70,31 @@ import { L10nTranslationService } from './l10n-translation.service';
* @param options A L10n or Intl NumberFormatOptions object
* @param language The current language
* @param currency The current currency
* @param convert An optional function to convert the value, that returns an arrow function with value in the signature.
* @param convert An optional function to convert the value, with value and locale in the signature.
* For example:
* ```
* const convert = (factor: number) => { return (value: number) => value * factor; };
* const convert = (value: number, locale: L10nLocale) => { return ... };
* ```
* @param convertParams Optional parameters for the convert function
*/
public formatNumber(
value: any,
options?: L10nNumberFormatOptions,
language = this.locale.numberLanguage || this.locale.language,
currency = this.locale.currency,
convert?: (...args: any) => number
convert?: (value: number, locale: L10nLocale, params: any) => number,
convertParams?: any
): string {
if (!hasNumberFormat() && options && options.style === 'currency') return `${value} ${currency}`;
if (options && options.style === 'unit' && !options.unit) return value;
if (!hasNumberFormat() && options && options.style === 'unit') return `${value} ${options.unit}`;
if (!hasNumberFormat() || language == null || language === '') return value;
if (options && options.style === 'unit' && !options.unit) return value;

value = toNumber(value);

// Optional conversion.
if (typeof convert === 'function') {
value = convert(value);
value = convert(value, this.locale, Object.values(convertParams || {})); // Destructures params
}

let numberFormatOptions: Intl.NumberFormatOptions = {};
Expand Down
15 changes: 11 additions & 4 deletions projects/angular-l10n/src/tests/l10n-intl.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing';

import { L10nLoader, L10nIntlService, L10nTranslationService, L10nConfig, L10nTranslationModule, L10nIntlModule } from '../public-api';
import { L10nLoader, L10nIntlService, L10nTranslationService, L10nConfig, L10nTranslationModule, L10nIntlModule, L10nLocale } from '../public-api';

describe('L10nIntlService', () => {
let loader: L10nLoader;
Expand Down Expand Up @@ -63,10 +63,17 @@ describe('L10nIntlService', () => {
});
it('should format and convert numbers', () => {
const value = 1234.5;
const convert = (factor: number) => {
return (value: number) => value * factor;
const convert = (value: number, locale: L10nLocale) => {
return value * 2;
};
expect(intl.formatNumber(value, { digits: '1.2-2' }, undefined, undefined, convert(2))).toEqual('2,469.00');
expect(intl.formatNumber(value, { digits: '1.2-2' }, undefined, undefined, convert)).toEqual('2,469.00');
});
it('should format and convert numbers with parameters', () => {
const value = 1234.5;
const convert = (value: number, locale: L10nLocale, rate: number) => {
return value * rate;
};
expect(intl.formatNumber(value, { digits: '1.2-2' }, undefined, undefined, convert, { rate: 2 })).toEqual('2,469.00');
});
it('should format relative times', () => {
expect(intl.formatRelativeTime(-1, 'day')).toEqual('1 day ago');
Expand Down

0 comments on commit b625cf6

Please sign in to comment.