Signal updates
This commit is contained in:
parent
01c244aa07
commit
9b1179d99a
@ -8,7 +8,6 @@ export * from './lib/loading';
|
||||
export * from './lib/error';
|
||||
export * from './lib/search';
|
||||
export * from './lib/upload-file';
|
||||
export * from './lib/empty-state';
|
||||
export * from './lib/caching';
|
||||
export * from './lib/translations';
|
||||
export * from './lib/pipes';
|
||||
|
||||
1
src/lib/buttons/chevron-button/index.ts
Normal file
1
src/lib/buttons/chevron-button/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './chevron-button.component';
|
||||
@ -3,4 +3,3 @@ export * from './types/circle-button.type';
|
||||
|
||||
export * from './icon-button/icon-button.component';
|
||||
export * from './circle-button/circle-button.component';
|
||||
export * from './chevron-button/chevron-button.component';
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { booleanAttribute, Directive, Input } from '@angular/core';
|
||||
import { booleanAttribute, Directive, input } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[iqserDisableStopPropagation]',
|
||||
standalone: true,
|
||||
})
|
||||
export class DisableStopPropagationDirective {
|
||||
@Input({ transform: booleanAttribute }) iqserDisableStopPropagation = true;
|
||||
readonly iqserDisableStopPropagation = input(true, { transform: booleanAttribute });
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { booleanAttribute, Directive, HostListener, inject, Input } from '@angular/core';
|
||||
import { DisableStopPropagationDirective } from './disable-stop-propagation.directive';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { DisableStopPropagationDirective } from './disable-stop-propagation.directive';
|
||||
|
||||
@Directive({
|
||||
selector: '[iqserStopPropagation]',
|
||||
@ -13,7 +13,7 @@ export class StopPropagationDirective {
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
onClick($event: Event) {
|
||||
if (this.#disableStopPropagation?.iqserDisableStopPropagation) {
|
||||
if (this.#disableStopPropagation?.iqserDisableStopPropagation()) {
|
||||
this.#logger.info('[CLICK] iqserStopPropagation is disabled by iqserDisableStopPropagation');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,12 +1,5 @@
|
||||
<div
|
||||
[ngStyle]="{
|
||||
'padding-top': verticalPadding + 'px',
|
||||
'padding-left': horizontalPadding + 'px',
|
||||
'padding-right': horizontalPadding + 'px',
|
||||
}"
|
||||
class="empty-state"
|
||||
>
|
||||
@if (icon) {
|
||||
<div [ngStyle]="styles()" class="empty-state">
|
||||
@if (icon(); as icon) {
|
||||
<mat-icon [svgIcon]="icon"></mat-icon>
|
||||
}
|
||||
|
||||
@ -14,15 +7,15 @@
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
|
||||
<div [innerHTML]="text" class="heading-l"></div>
|
||||
<div [innerHTML]="text()" class="heading-l"></div>
|
||||
|
||||
@if (showButton) {
|
||||
@if (showButton() && this.action.observed) {
|
||||
<iqser-icon-button
|
||||
(action)="action.emit()"
|
||||
[buttonId]="buttonId"
|
||||
[icon]="buttonIcon"
|
||||
[attr.help-mode-key]="helpModeKey"
|
||||
[label]="buttonLabel"
|
||||
[buttonId]="buttonId()"
|
||||
[icon]="buttonIcon()"
|
||||
[attr.help-mode-key]="helpModeKey()"
|
||||
[label]="buttonLabel()"
|
||||
[type]="iconButtonTypes.primary"
|
||||
></iqser-icon-button>
|
||||
}
|
||||
|
||||
@ -1,32 +1,43 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { IconButtonComponent, IconButtonTypes } from '../buttons';
|
||||
import { randomString } from '../utils';
|
||||
import { NgStyle } from '@angular/common';
|
||||
import {
|
||||
booleanAttribute,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
EventEmitter,
|
||||
input,
|
||||
numberAttribute,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { IconButtonComponent } from '../buttons/icon-button/icon-button.component';
|
||||
import { IconButtonTypes } from '../buttons/types/icon-button.type';
|
||||
import { randomString } from '../utils/functions';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-empty-state [text]',
|
||||
selector: 'iqser-empty-state',
|
||||
templateUrl: './empty-state.component.html',
|
||||
styleUrls: ['./empty-state.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [NgStyle, MatIconModule, IconButtonComponent],
|
||||
})
|
||||
export class EmptyStateComponent implements OnInit {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
export class EmptyStateComponent {
|
||||
protected readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
@Input() text!: string;
|
||||
@Input() icon?: string;
|
||||
@Input() showButton = true;
|
||||
@Input() buttonIcon = 'iqser:plus';
|
||||
@Input() buttonLabel?: string;
|
||||
@Input() buttonId = `${randomString()}-icon-button`;
|
||||
@Input() horizontalPadding = 100;
|
||||
@Input() verticalPadding = 120;
|
||||
@Input() helpModeKey?: string;
|
||||
readonly text = input.required<string>();
|
||||
readonly icon = input<string>();
|
||||
readonly showButton = input(true, { transform: booleanAttribute });
|
||||
readonly buttonIcon = input('iqser:plus');
|
||||
readonly buttonLabel = input<string>();
|
||||
readonly buttonId = input(`${randomString()}-icon-button`);
|
||||
readonly horizontalPadding = input(100, { transform: numberAttribute });
|
||||
readonly verticalPadding = input(120, { transform: numberAttribute });
|
||||
protected readonly styles = computed(() => ({
|
||||
'padding-top': this.verticalPadding() + 'px',
|
||||
'padding-left': this.horizontalPadding() + 'px',
|
||||
'padding-right': this.horizontalPadding() + 'px',
|
||||
}));
|
||||
readonly helpModeKey = input<string>();
|
||||
@Output() readonly action = new EventEmitter();
|
||||
|
||||
ngOnInit(): void {
|
||||
this.showButton = this.showButton && this.action.observed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@if (errorService.connectionStatus$ | async; as status) {
|
||||
@if (connectionStatus(); as status) {
|
||||
<div [@animateOpenClose]="status" [ngClass]="status" class="indicator flex-align-items-center">
|
||||
<span [translate]="connectionStatusTranslations[status]"></span>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import { connectionStatusTranslations } from '../../translations';
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
import { connectionStatusTranslations } from '../../translations';
|
||||
import { ErrorService } from '../error.service';
|
||||
|
||||
@Component({
|
||||
@ -18,6 +19,6 @@ import { ErrorService } from '../error.service';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ConnectionStatusComponent {
|
||||
connectionStatusTranslations = connectionStatusTranslations;
|
||||
protected readonly errorService = inject(ErrorService);
|
||||
protected readonly connectionStatusTranslations = connectionStatusTranslations;
|
||||
protected readonly connectionStatus = toSignal(inject(ErrorService).connectionStatus$);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { IconButtonTypes } from '../../buttons';
|
||||
import { CustomError, ErrorService, ErrorType } from '../error.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-full-page-error',
|
||||
@ -10,9 +10,8 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FullPageErrorComponent {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
constructor(readonly errorService: ErrorService) {}
|
||||
protected readonly iconButtonTypes = IconButtonTypes;
|
||||
protected readonly errorService = inject(ErrorService);
|
||||
|
||||
errorTitle(error: ErrorType): string {
|
||||
return error instanceof CustomError ? error.label : _('error.title');
|
||||
|
||||
@ -9,7 +9,9 @@
|
||||
></iqser-input-with-action>
|
||||
</div>
|
||||
}
|
||||
|
||||
<ng-container *ngTemplateOutlet="filterHeader"></ng-container>
|
||||
|
||||
@if (primaryFilters$ | async; as filters) {
|
||||
<div class="filter-content">
|
||||
@for (filter of filters; track filter) {
|
||||
@ -24,11 +26,13 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (secondaryFilterGroup$ | async; as secondaryGroup) {
|
||||
<div class="filter-options">
|
||||
<div class="filter-menu-options">
|
||||
<div class="all-caps-label" translate="filter-menu.filter-options"></div>
|
||||
</div>
|
||||
|
||||
@for (filter of secondaryGroup.filters; track filter) {
|
||||
<ng-container
|
||||
[ngTemplateOutletContext]="{
|
||||
@ -51,7 +55,11 @@
|
||||
<ng-template #filterHeader>
|
||||
@if (primaryFilterGroup$ | async; as primaryGroup) {
|
||||
<div class="filter-menu-header">
|
||||
<div [translateParams]="{ count: primaryGroup.filters.length }" [translate]="primaryFiltersLabel" class="all-caps-label"></div>
|
||||
<div
|
||||
[translateParams]="{ count: primaryGroup.filters.length }"
|
||||
[translate]="primaryFiltersLabel()"
|
||||
class="all-caps-label"
|
||||
></div>
|
||||
<div class="actions">
|
||||
@if (!primaryGroup.singleSelect) {
|
||||
<div
|
||||
@ -61,6 +69,7 @@
|
||||
translate="actions.all"
|
||||
></div>
|
||||
}
|
||||
|
||||
<div
|
||||
(click)="deactivatePrimaryFilters()"
|
||||
class="all-caps-label primary pointer"
|
||||
@ -104,7 +113,7 @@
|
||||
></ng-container>
|
||||
</mat-checkbox>
|
||||
|
||||
<ng-container [ngTemplateOutletContext]="{ filter: filter }" [ngTemplateOutlet]="actionsTemplate"></ng-container>
|
||||
<ng-container [ngTemplateOutletContext]="{ filter: filter }" [ngTemplateOutlet]="actionsTemplate()"></ng-container>
|
||||
</div>
|
||||
|
||||
@if (filter.children?.length && filter.expanded) {
|
||||
@ -122,7 +131,7 @@
|
||||
[ngTemplateOutlet]="filterGroup.filterTemplate ?? defaultFilterLabelTemplate"
|
||||
></ng-container>
|
||||
</mat-checkbox>
|
||||
<ng-container [ngTemplateOutletContext]="{ filter: child }" [ngTemplateOutlet]="actionsTemplate"></ng-container>
|
||||
<ng-container [ngTemplateOutletContext]="{ filter: child }" [ngTemplateOutlet]="actionsTemplate()"></ng-container>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, Input, OnInit, TemplateRef } from '@angular/core';
|
||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, effect, ElementRef, inject, input, numberAttribute, OnInit, TemplateRef } from '@angular/core';
|
||||
import { MAT_CHECKBOX_DEFAULT_OPTIONS, MatCheckbox } from '@angular/material/checkbox';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
@ -23,7 +23,7 @@ const atLeastOneIsExpandable = pipe(
|
||||
);
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-filter-card [primaryFiltersSlug]',
|
||||
selector: 'iqser-filter-card',
|
||||
templateUrl: './filter-card.component.html',
|
||||
styleUrls: ['./filter-card.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
@ -38,38 +38,29 @@ const atLeastOneIsExpandable = pipe(
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
InputWithActionComponent,
|
||||
NgTemplateOutlet,
|
||||
TranslateModule,
|
||||
MatIcon,
|
||||
MatCheckbox,
|
||||
StopPropagationDirective,
|
||||
NgIf,
|
||||
NgForOf,
|
||||
],
|
||||
imports: [AsyncPipe, InputWithActionComponent, NgTemplateOutlet, TranslateModule, MatIcon, MatCheckbox, StopPropagationDirective],
|
||||
})
|
||||
export class FilterCardComponent implements OnInit {
|
||||
@Input() primaryFiltersSlug!: string;
|
||||
@Input() fileId?: string;
|
||||
@Input() actionsTemplate?: TemplateRef<unknown>;
|
||||
@Input() secondaryFiltersSlug = '';
|
||||
@Input() primaryFiltersLabel: string = _('filter-menu.filter-types');
|
||||
@Input() minWidth = 350;
|
||||
|
||||
readonly #filterService = inject(FilterService);
|
||||
readonly #elementRef = inject(ElementRef);
|
||||
protected readonly searchService = inject<SearchService<Filter>>(SearchService);
|
||||
readonly primaryFiltersSlug = input.required<string>();
|
||||
readonly fileId = input<string>();
|
||||
readonly actionsTemplate = input<TemplateRef<unknown>>();
|
||||
readonly secondaryFiltersSlug = input('');
|
||||
readonly primaryFiltersLabel = input<string>(_('filter-menu.filter-types'));
|
||||
readonly minWidth = input(350, { transform: numberAttribute });
|
||||
primaryFilterGroup$!: Observable<IFilterGroup | undefined>;
|
||||
secondaryFilterGroup$!: Observable<IFilterGroup | undefined>;
|
||||
primaryFilters$!: Observable<IFilter[] | undefined>;
|
||||
|
||||
atLeastOneFilterIsExpandable$?: Observable<boolean>;
|
||||
atLeastOneSecondaryFilterIsExpandable$?: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
readonly filterService: FilterService,
|
||||
readonly searchService: SearchService<Filter>,
|
||||
private readonly _elementRef: ElementRef,
|
||||
) {}
|
||||
constructor() {
|
||||
effect(() => {
|
||||
(this.#elementRef.nativeElement as HTMLElement).style.setProperty('--filter-card-min-width', `${this.minWidth()}px`);
|
||||
});
|
||||
}
|
||||
|
||||
private get _primaryFilters$(): Observable<IFilter[]> {
|
||||
return combineLatest([this.primaryFilterGroup$, this.searchService.valueChanges$]).pipe(
|
||||
@ -79,39 +70,37 @@ export class FilterCardComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.primaryFilterGroup$ = this.filterService.getGroup$(this.primaryFiltersSlug).pipe(shareLast());
|
||||
this.secondaryFilterGroup$ = this.filterService.getGroup$(this.secondaryFiltersSlug).pipe(shareLast());
|
||||
this.primaryFilterGroup$ = this.#filterService.getGroup$(this.primaryFiltersSlug()).pipe(shareLast());
|
||||
this.secondaryFilterGroup$ = this.#filterService.getGroup$(this.secondaryFiltersSlug()).pipe(shareLast());
|
||||
this.primaryFilters$ = this._primaryFilters$;
|
||||
|
||||
this.atLeastOneFilterIsExpandable$ = atLeastOneIsExpandable(this.primaryFilterGroup$);
|
||||
this.atLeastOneSecondaryFilterIsExpandable$ = atLeastOneIsExpandable(this.secondaryFilterGroup$);
|
||||
|
||||
(this._elementRef.nativeElement as HTMLElement).style.setProperty('--filter-card-min-width', `${this.minWidth}px`);
|
||||
}
|
||||
|
||||
filterCheckboxClicked(nestedFilter: INestedFilter, filterGroup: IFilterGroup, parent?: INestedFilter): void {
|
||||
this.filterService.filterCheckboxClicked({
|
||||
this.#filterService.filterCheckboxClicked({
|
||||
nestedFilter,
|
||||
filterGroup,
|
||||
parent,
|
||||
primaryFiltersSlug: this.primaryFiltersSlug,
|
||||
primaryFiltersSlug: this.primaryFiltersSlug(),
|
||||
});
|
||||
this.filterService.updateFiltersInLocalStorage(this.fileId);
|
||||
this.#filterService.updateFiltersInLocalStorage(this.fileId());
|
||||
}
|
||||
|
||||
deactivatePrimaryFilters() {
|
||||
this.filterService.deactivateFilters({ primaryFiltersSlug: this.primaryFiltersSlug });
|
||||
this.filterService.updateFiltersInLocalStorage(this.fileId);
|
||||
this.#filterService.deactivateFilters({ primaryFiltersSlug: this.primaryFiltersSlug() });
|
||||
this.#filterService.updateFiltersInLocalStorage(this.fileId());
|
||||
}
|
||||
|
||||
activatePrimaryFilters(): void {
|
||||
this.filterService.setFilters(this.primaryFiltersSlug, true);
|
||||
this.filterService.updateFiltersInLocalStorage(this.fileId);
|
||||
this.#filterService.setFilters(this.primaryFiltersSlug(), true);
|
||||
this.#filterService.updateFiltersInLocalStorage(this.fileId());
|
||||
}
|
||||
|
||||
toggleFilterExpanded(nestedFilter: INestedFilter): void {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
nestedFilter.expanded = !nestedFilter.expanded;
|
||||
this.filterService.refresh();
|
||||
this.#filterService.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
buttonId="{{ primaryGroup.slug }}"
|
||||
></iqser-icon-button>
|
||||
}
|
||||
|
||||
@if (!primaryGroup.icon) {
|
||||
<iqser-chevron-button
|
||||
[attr.aria-expanded]="expanded$ | async"
|
||||
@ -21,6 +22,7 @@
|
||||
[showDot]="hasActiveFilters$ | async"
|
||||
></iqser-chevron-button>
|
||||
}
|
||||
|
||||
<mat-menu
|
||||
#filterMenu="matMenu"
|
||||
(closed)="expanded.next(false)"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core';
|
||||
import { MatMenu, MatMenuContent, MatMenuTrigger } from '@angular/material/menu';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
@ -28,7 +28,6 @@ import { IFilterGroup } from '../models/filter-group.model';
|
||||
FilterCardComponent,
|
||||
StopPropagationDirective,
|
||||
MatMenuContent,
|
||||
NgIf,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
|
||||
@ -3,7 +3,8 @@ import { MatCheckbox } from '@angular/material/checkbox';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ChevronButtonComponent, CircleButtonComponent, IconButtonComponent } from '../../buttons';
|
||||
import { CircleButtonComponent, IconButtonComponent } from '../../buttons';
|
||||
import { ChevronButtonComponent } from '../../buttons/chevron-button/chevron-button.component';
|
||||
import { StopPropagationDirective } from '../../directives';
|
||||
import { InputWithActionComponent } from '../../inputs/input-with-action/input-with-action.component';
|
||||
import { SimpleFilterOption } from '../models/simple-filter-option';
|
||||
@ -22,7 +23,6 @@ import { SimpleFilterOption } from '../models/simple-filter-option';
|
||||
TranslateModule,
|
||||
MatCheckbox,
|
||||
IconButtonComponent,
|
||||
ChevronButtonComponent,
|
||||
CircleButtonComponent,
|
||||
],
|
||||
})
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { PruningTranslationLoader } from '../utils';
|
||||
import { getConfig, IqserConfigService } from '../services';
|
||||
import { inject } from '@angular/core';
|
||||
import { getConfig } from '../services';
|
||||
import { PruningTranslationLoader } from '../utils';
|
||||
|
||||
export function pruningTranslationLoaderFactory(pathPrefix: string): PruningTranslationLoader {
|
||||
const httpClient = inject(HttpClient);
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||
import { inject, InjectionToken, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { TranslateCompiler, TranslateLoader, TranslateModule, TranslateParser } from '@ngx-translate/core';
|
||||
import { MissingTranslationHandler, TranslateCompiler, TranslateLoader, TranslateModule, TranslateParser } from '@ngx-translate/core';
|
||||
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
|
||||
import { pruningTranslationLoaderFactory } from './http-loader-factory';
|
||||
import { IqserTranslateModuleOptions } from './iqser-translate-module-options';
|
||||
import { IqserTranslateParser } from './iqser-translate-parser.service';
|
||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||
import { IqserMissingTranslationHandler } from './missing-translations-handler';
|
||||
|
||||
const translateLoaderToken = new InjectionToken('translateLoader');
|
||||
|
||||
@ -46,6 +47,10 @@ export class IqserTranslateModule {
|
||||
provide: translateLoaderToken,
|
||||
useFactory: () => pruningTranslationLoaderFactory(pathPrefix),
|
||||
},
|
||||
{
|
||||
provide: MissingTranslationHandler,
|
||||
useClass: IqserMissingTranslationHandler,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
8
src/lib/translations/missing-translations-handler.ts
Normal file
8
src/lib/translations/missing-translations-handler.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { MissingTranslationHandler, MissingTranslationHandlerParams } from '@ngx-translate/core';
|
||||
|
||||
export class IqserMissingTranslationHandler implements MissingTranslationHandler {
|
||||
handle(params: MissingTranslationHandlerParams) {
|
||||
const missingKey = params.key;
|
||||
return `?${missingKey}?`;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user