diff --git a/src/app/translation/common-string-pipes.ts b/src/app/translation/common-string-pipes.ts index e1177ee0..1787b362 100644 --- a/src/app/translation/common-string-pipes.ts +++ b/src/app/translation/common-string-pipes.ts @@ -13,10 +13,10 @@ * this program. If not, see . */ -import {DecimalPipe} from '@angular/common'; import {Injectable, OnDestroy, Pipe, PipeTransform} from '@angular/core'; import {LangChangeEvent, TranslateService} from '@ngx-translate/core'; import {Subscription} from 'rxjs'; +import {logger} from '../_helpers/ts-logger'; @Injectable() @Pipe({ @@ -26,7 +26,7 @@ import {Subscription} from 'rxjs'; export class ArrayJoinPipe implements PipeTransform { value = ''; - transform(anArray: unknown[], separator: string | unknown): unknown { + transform(anArray: unknown[] | unknown, separator: string | unknown): string { if (typeof separator !== 'string' || separator.length <= 0) { return this.value; } @@ -43,6 +43,27 @@ export class ArrayJoinPipe implements PipeTransform { } } +@Injectable() +@Pipe({ + name: 'sentencecase', + pure: false, // required to update the value when the promise is resolved +}) +export class SentenceCasePipe implements PipeTransform { + value = ''; + + transform(aString: string | unknown): string { + + if (typeof aString !== 'string'){ + throw new SyntaxError(`Wrong parameter in StringSplitPipe. Expected a valid String, received: ${aString}`); + } + + this.value = aString.substr(0,1) + .toUpperCase() + aString.substr(1); + + return this.value; + } +} + @Injectable() @Pipe({ name: 'split', @@ -51,7 +72,7 @@ export class ArrayJoinPipe implements PipeTransform { export class StringSplitPipe implements PipeTransform { value = new Array(); - transform(aString: string | T, splitter: string | T): T { + transform(aString: string | unknown, splitter: string | unknown): unknown[] { if (typeof splitter !== 'string' || splitter.length <= 0) { return this.value as never; } @@ -74,21 +95,16 @@ export class StringSplitPipe implements PipeTransform { pure: false, // required to update the value when the promise is resolved }) export class NumberLocalizedPipe implements PipeTransform, OnDestroy { - decimalPipe: DecimalPipe; - locale: string; - - onLangChange: Subscription; - - value: unknown; + onLangChange?: Subscription; + value: string; constructor(private readonly translate: TranslateService) { - this.decimalPipe = new DecimalPipe('de-DE'); this.locale = translate.currentLang; } private _dispose(): void { - if (this.onLangChange?.closed) { + if (this.onLangChange?.closed === false) { this.onLangChange?.unsubscribe(); } } @@ -98,33 +114,97 @@ export class NumberLocalizedPipe implements PipeTransform, OnDestroy { } /** - * @param value The number to be formatted. - * @param digitsInfo Decimal representation options, specified by a string - * in the following format: {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits} - * - `minIntegerDigits`: The minimum number of integer digits before the decimal point. - * Default is `1`. - * - `minFractionDigits`: The minimum number of digits after the decimal point. - * Default is `0`. - * - `maxFractionDigits`: The maximum number of digits after the decimal point. - * Default is `3`. + * @param value The number to be formatted + * @param formatOptions Formatting options to include. + * As specified by Intl.NumberFormatOptions as comma seperated key:value pairs. */ - transform(value: unknown, digitsInfo?: string | undefined): unknown { - this.updateValue(value, digitsInfo); + transform(value: string | number | unknown, formatOptions?: string): string { + this.updateValue(value, formatOptions); this._dispose(); - if (typeof this.onLangChange === 'undefined' || this.onLangChange.closed) { - this.onLangChange = this.translate.onLangChange.subscribe( - (event: LangChangeEvent) => { - this.locale = event.lang; - this.updateValue(value, digitsInfo); - }, - ); + if (this.onLangChange?.closed === true) { + this.onLangChange = this.translate.onLangChange.subscribe((event: LangChangeEvent) => { + this.locale = event.lang; + this.updateValue(value, formatOptions); + }); } return this.value; } - updateValue(value: unknown, digitsInfo?: string | undefined): void { - // this.value = this.locale; - this.value = this.decimalPipe.transform(value, digitsInfo, this.locale); + updateValue(value: string | number | unknown, formatOptions?: string): void { + if (typeof value !== 'string' && typeof value !== 'number') { + logger.warn(`numberLocalized pipe unable to parse input: ${value}`); + + return; + } + const options = formatOptions?.split(',') + .map((element) => element.split(':')) + .reduce((acc, [key, val]) => ({...acc, [key.trim()]: val.trim()}),{}) as Intl.NumberFormatOptions; + const float = typeof value === 'string' ? Number.parseFloat(value) : value as number; + this.value = new Intl.NumberFormat(this.locale, options).format(float); + } +} + +@Injectable() +@Pipe({ + name: 'dateFormat', + pure: false, // required to update the value when the promise is resolved +}) +export class DateLocalizedFormatPipe implements PipeTransform, OnDestroy { + locale: string; + onLangChange?: Subscription; + value: string; + + constructor(private readonly translate: TranslateService) { + this.locale = translate.currentLang; + } + + private _dispose(): void { + if (this.onLangChange?.closed === false) { + this.onLangChange?.unsubscribe(); + } + } + + ngOnDestroy(): void { + this._dispose(); + } + + /** + * @param value The date to be formatted + * @param formatOptions Dateformat options to include. + * As specified by Intl.DateTimeFormatOptions as comma seperated key:value pairs + * Default is year,month,day,hour and minute in numeric representation e.g. (en-US) "8/6/2021, 10:35" + */ + transform(value: string | unknown, formatOptions?: string): string { + this.updateValue(value, formatOptions); + this._dispose(); + if (this.onLangChange?.closed === true) { + this.onLangChange = this.translate.onLangChange.subscribe((event: LangChangeEvent) => { + this.locale = event.lang; + this.updateValue(value, formatOptions); + }); + } + + return this.value; + } + + updateValue(value: string | Date | unknown, formatOptions?: string): void { + if (typeof value !== 'string' && Object.prototype.toString.call(value) !== '[object Date]') { + logger.warn(`dateFormat pipe unable to parse input: ${value}`); + + return; + } + const options = formatOptions?.split(',') + .map((element) => element.split(':')) + .reduce((acc, [key, val]) => ({...acc, [key.trim()]: val.trim()}),{}) as Intl.DateTimeFormatOptions; + const date = typeof value === 'string' ? Date.parse(value) : value as Date; + this.value = new Intl.DateTimeFormat(this.locale, options ?? { + day: 'numeric', + month: 'numeric', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + }) + .format(date); } } diff --git a/src/app/translation/thing-translate.module.ts b/src/app/translation/thing-translate.module.ts index e411c771..3434fe47 100644 --- a/src/app/translation/thing-translate.module.ts +++ b/src/app/translation/thing-translate.module.ts @@ -14,19 +14,9 @@ */ import {ModuleWithProviders, NgModule, Provider} from '@angular/core'; -import { - ArrayJoinPipe, - NumberLocalizedPipe, - StringSplitPipe, -} from './common-string-pipes'; -import { - ThingTranslateDefaultParser, - ThingTranslateParser, -} from './thing-translate.parser'; -import { - ThingPropertyNameTranslatePipe, - ThingTranslatePipe, -} from './thing-translate.pipe'; +import {ArrayJoinPipe, DateLocalizedFormatPipe, NumberLocalizedPipe, SentenceCasePipe, StringSplitPipe} from './common-string-pipes'; +import {ThingTranslateDefaultParser, ThingTranslateParser} from './thing-translate.parser'; +import {ThingPropertyNameTranslatePipe, ThingTranslatePipe} from './thing-translate.pipe'; import {ThingTranslateService} from './thing-translate.service'; export interface ThingTranslateModuleConfig { @@ -40,6 +30,8 @@ export interface ThingTranslateModuleConfig { StringSplitPipe, ThingPropertyNameTranslatePipe, ThingTranslatePipe, + DateLocalizedFormatPipe, + SentenceCasePipe, ], exports: [ ArrayJoinPipe, @@ -47,6 +39,8 @@ export interface ThingTranslateModuleConfig { StringSplitPipe, ThingPropertyNameTranslatePipe, ThingTranslatePipe, + DateLocalizedFormatPipe, + SentenceCasePipe, ], }) export class ThingTranslateModule {