mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-09 09:52:56 +00:00
feat: add formatting pipes basted on Intl
This commit is contained in:
@@ -13,10 +13,10 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<unknown>();
|
||||
|
||||
transform<T>(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) => {
|
||||
if (this.onLangChange?.closed === true) {
|
||||
this.onLangChange = this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
|
||||
this.locale = event.lang;
|
||||
this.updateValue(value, digitsInfo);
|
||||
},
|
||||
);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user