diff --git a/projects/common/app.module.ts b/projects/common/app.module.ts index f708af2553efcb91ae8b8ad8a7e723a6a44a1d50..5cf5531e477dea27056124635ff5597e89e88873 100644 --- a/projects/common/app.module.ts +++ b/projects/common/app.module.ts @@ -32,8 +32,9 @@ import { ImageComponent } from './element-components/image.component'; import { VideoComponent } from './element-components/video.component'; import { AudioComponent } from './element-components/audio.component'; import { CorrectionComponent } from './element-components/compound-components/correction.component'; -import { SafeResourceUrlPipe } from './pipes/safe-resource-url.pipe'; +import { SafeResourceUrlPipe } from './element-components/pipes/safe-resource-url.pipe'; import { InputBackgroundColorDirective } from './element-components/directives/input-background-color.directive'; +import { ErrorTransformPipe } from './element-components/pipes/error-transform.pipe'; @NgModule({ imports: [ @@ -63,7 +64,8 @@ import { InputBackgroundColorDirective } from './element-components/directives/i DropdownComponent, CorrectionComponent, SafeResourceUrlPipe, - InputBackgroundColorDirective + InputBackgroundColorDirective, + ErrorTransformPipe ], exports: [ CommonModule, diff --git a/projects/common/assets/i18n/de.json b/projects/common/assets/i18n/de.json index 5b5eee08261da928c21658612418e78570465906..52227b0380884f964fbc62be1c8237e0dd50733c 100644 --- a/projects/common/assets/i18n/de.json +++ b/projects/common/assets/i18n/de.json @@ -1,4 +1,11 @@ { "pageIndication": "Seite {{index}}", - "close": "Schließen" + "close": "Schließen", + "validators": { + "inputRequired": "Eingabe erforderlich", + "inputRequiredTrue": "Ankreuzen erforderlich", + "inputTooShort": "Eingabe zu kurz", + "inputTooLong": "Eingabe zu lang", + "wrongPattern": "Eingabe enthält falsche Zeichen" + } } diff --git a/projects/common/element-components/checkbox.component.ts b/projects/common/element-components/checkbox.component.ts index ceae5c50446c6e31eb7fea9943c2a10738138fca..1c0b32fa913c745f09702a1956646d155f2cf052 100644 --- a/projects/common/element-components/checkbox.component.ts +++ b/projects/common/element-components/checkbox.component.ts @@ -1,25 +1,40 @@ import { Component } from '@angular/core'; +import { ValidatorFn, Validators } from '@angular/forms'; import { CheckboxElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @Component({ selector: 'app-checkbox', template: ` - <mat-checkbox #checkbox class="example-margin" - [formControl]="elementFormControl" - [style.width.%]="100" - [style.height.%]="100" - [style.background-color]="elementModel.backgroundColor" - [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''"> - <div [innerHTML]="elementModel.label"></div> - </mat-checkbox> + <div class="mat-form-field"> + <mat-checkbox #checkbox class="example-margin" + [formControl]="elementFormControl" + [style.width.%]="100" + [style.height.%]="100" + [style.background-color]="elementModel.backgroundColor" + [style.color]="elementModel.fontColor" + [style.font-family]="elementModel.font" + [style.font-size.px]="elementModel.fontSize" + [style.font-weight]="elementModel.bold ? 'bold' : ''" + [style.font-style]="elementModel.italic ? 'italic' : ''" + [style.text-decoration]="elementModel.underline ? 'underline' : ''"> + <div [innerHTML]="elementModel.label"></div> + </mat-checkbox> + <mat-error *ngIf="elementFormControl.errors && elementFormControl.touched" + [style.font-size.%]="75"> + {{elementFormControl.errors | errorTransform: elementModel}} + </mat-error> + </div> ` }) export class CheckboxComponent extends FormElementComponent { elementModel!: CheckboxElement; + + get validators(): ValidatorFn[] { + const validators: ValidatorFn[] = []; + if (this.elementModel.required) { + validators.push(Validators.requiredTrue); + } + return validators; + } } diff --git a/projects/common/element-components/compound-components/correction.component.ts b/projects/common/element-components/compound-components/correction.component.ts index 743d763237b8a0c12f66e33d02efd91d28fd8b44..459f5b0258f69494f159bad2482577719b082b5e 100644 --- a/projects/common/element-components/compound-components/correction.component.ts +++ b/projects/common/element-components/compound-components/correction.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { ValidatorFn, Validators } from '@angular/forms'; import { CompoundElementCorrection } from '../../unit'; import { FormElementComponent } from '../../form-element-component.directive'; @@ -32,4 +33,12 @@ import { FormElementComponent } from '../../form-element-component.directive'; }) export class CorrectionComponent extends FormElementComponent { elementModel!: CompoundElementCorrection; + + get validators(): ValidatorFn[] { + const validators: ValidatorFn[] = []; + if (this.elementModel.required) { + validators.push(Validators.required); + } + return validators; + } } diff --git a/projects/common/element-components/dropdown.component.ts b/projects/common/element-components/dropdown.component.ts index 0a7e2127e1addee5ab57dc74983515bc08a6f09d..50a0cfecbf3c3503d19e2da5fbe97f5bb214713a 100644 --- a/projects/common/element-components/dropdown.component.ts +++ b/projects/common/element-components/dropdown.component.ts @@ -1,31 +1,43 @@ import { Component } from '@angular/core'; +import { ValidatorFn, Validators } from '@angular/forms'; import { DropdownElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @Component({ selector: 'app-dropdown', template: ` - <mat-form-field appearance="fill" - [style.width.%]="100" - [style.height.%]="100" - [style.background-color]="elementModel.backgroundColor"> - <mat-label [style.color]="elementModel.fontColor" - [style.font-family]="elementModel.font" - [style.font-size.px]="elementModel.fontSize" - [style.font-weight]="elementModel.bold ? 'bold' : ''" - [style.font-style]="elementModel.italic ? 'italic' : ''" - [style.text-decoration]="elementModel.underline ? 'underline' : ''"> - {{$any(elementModel).label}} - </mat-label> - <mat-select [formControl]="elementFormControl"> - <mat-option *ngIf="elementModel.allowUnset" value=""></mat-option> - <mat-option *ngFor="let option of elementModel.options" [value]="option"> - {{option}} - </mat-option> - </mat-select> - </mat-form-field> + <mat-form-field appearance="fill" + [style.width.%]="100" + [style.height.%]="100" + appInputBackgroundColor [backgroundColor]="elementModel.backgroundColor"> + <mat-label [style.color]="elementModel.fontColor" + [style.font-family]="elementModel.font" + [style.font-size.px]="elementModel.fontSize" + [style.font-weight]="elementModel.bold ? 'bold' : ''" + [style.font-style]="elementModel.italic ? 'italic' : ''" + [style.text-decoration]="elementModel.underline ? 'underline' : ''"> + {{$any(elementModel).label}} + </mat-label> + <mat-select [formControl]="elementFormControl"> + <mat-option *ngIf="elementModel.allowUnset" value=""></mat-option> + <mat-option *ngFor="let option of elementModel.options" [value]="option"> + {{option}} + </mat-option> + </mat-select> + <mat-error *ngIf="elementFormControl.errors"> + {{elementFormControl.errors | errorTransform: elementModel}} + </mat-error> + </mat-form-field> ` }) export class DropdownComponent extends FormElementComponent { elementModel!: DropdownElement; + + get validators(): ValidatorFn[] { + const validators: ValidatorFn[] = []; + if (this.elementModel.required) { + validators.push(Validators.required); + } + return validators; + } } diff --git a/projects/common/element-components/pipes/error-transform.pipe.ts b/projects/common/element-components/pipes/error-transform.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..14bb4d29040c9f4bd3ef6ccc490451bd4c10a1e3 --- /dev/null +++ b/projects/common/element-components/pipes/error-transform.pipe.ts @@ -0,0 +1,46 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { ValidationErrors } from '@angular/forms'; +import { TranslateService } from '@ngx-translate/core'; +import { + CheckboxElement, InputUIElement, TextFieldElement, UnitUIElement +} from '../../unit'; + +@Pipe({ + name: 'errorTransform' +}) +export class ErrorTransformPipe implements PipeTransform { + constructor(private translateService: TranslateService) {} + + transform(validationErrors: ValidationErrors, elementModel: UnitUIElement): string { + const validationMessages = this.getValidationMessages(elementModel); + let returnMessage = ''; + + Object.keys(validationErrors).forEach(errorKey => { + if (returnMessage) { + returnMessage += '; '; + } + const messageKey = errorKey === 'required' && elementModel.type === 'checkbox' ? 'requiredTrue' : errorKey; + returnMessage += validationMessages[messageKey]; + }); + return returnMessage; + } + + private getValidationMessages(elementModel: UnitUIElement): Record<string, string> { + return { + required: (elementModel as InputUIElement).requiredWarnMessage || + this.translateService.instant('validators.inputRequired'), + + requiredTrue: (elementModel as CheckboxElement).requiredWarnMessage || + this.translateService.instant('validators.inputRequiredTrue'), + + minlength: (elementModel as TextFieldElement).minWarnMessage || + this.translateService.instant('validators.inputTooShort'), + + maxlength: (elementModel as TextFieldElement).maxWarnMessage || + this.translateService.instant('validators.inputTooLong'), + + pattern: (elementModel as TextFieldElement).patternWarnMessage || + this.translateService.instant('validators.wrongPattern') + }; + } +} diff --git a/projects/common/pipes/safe-resource-url.pipe.ts b/projects/common/element-components/pipes/safe-resource-url.pipe.ts similarity index 100% rename from projects/common/pipes/safe-resource-url.pipe.ts rename to projects/common/element-components/pipes/safe-resource-url.pipe.ts diff --git a/projects/common/element-components/radio-button-group.component.ts b/projects/common/element-components/radio-button-group.component.ts index 9531807c2659d9a53cd12adb0b88a2d9019d634a..01341c0d6ca3717d5e1c83204a349286fcb9f9e3 100644 --- a/projects/common/element-components/radio-button-group.component.ts +++ b/projects/common/element-components/radio-button-group.component.ts @@ -1,11 +1,13 @@ import { Component } from '@angular/core'; +import { ValidatorFn, Validators } from '@angular/forms'; import { RadioButtonGroupElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @Component({ selector: 'app-radio-button-group', template: ` - <div [style.width.%]="100" + <div class="mat-form-field" + [style.width.%]="100" [style.height.%]="100" [style.background-color]="elementModel.backgroundColor" [style.color]="elementModel.fontColor" @@ -22,10 +24,22 @@ import { FormElementComponent } from '../form-element-component.directive'; <mat-radio-button *ngFor="let option of elementModel.options" [value]="option"> {{option}} </mat-radio-button> + <mat-error *ngIf="elementFormControl.errors && elementFormControl.touched" + [style.font-size.%]="75"> + {{elementFormControl.errors | errorTransform: elementModel}} + </mat-error> </mat-radio-group> </div> ` }) export class RadioButtonGroupComponent extends FormElementComponent { elementModel!: RadioButtonGroupElement; + + get validators(): ValidatorFn[] { + const validators: ValidatorFn[] = []; + if (this.elementModel.required) { + validators.push(Validators.required); + } + return validators; + } } diff --git a/projects/common/element-components/text-area.component.ts b/projects/common/element-components/text-area.component.ts index feb6bb231a2cde082e2629656276e73c256a3c5a..f2360c6b3ef839c6a46a5565d4ee7783f9fa1b75 100644 --- a/projects/common/element-components/text-area.component.ts +++ b/projects/common/element-components/text-area.component.ts @@ -1,4 +1,5 @@ import { Component, Output, EventEmitter } from '@angular/core'; +import { ValidatorFn, Validators } from '@angular/forms'; import { TextAreaElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @@ -15,13 +16,16 @@ import { FormElementComponent } from '../form-element-component.directive'; [style.font-style]="elementModel.italic ? 'italic' : ''" [style.text-decoration]="elementModel.underline ? 'underline' : ''" [appearance]="$any(elementModel.appearance)"> - <textarea matInput [formControl]="elementFormControl" #input - (focus)="onFocus.emit(input)" - (blur)="onBlur.emit(input)" - placeholder="{{elementModel.label}}" - [style.min-width.%]="100" - [style.resize]="elementModel.resizeEnabled ? 'both' : 'none'"> - </textarea> + <textarea matInput [formControl]="elementFormControl" #input + (focus)="onFocus.emit(input)" + (blur)="onBlur.emit(input)" + placeholder="{{elementModel.label}}" + [style.min-width.%]="100" + [style.resize]="elementModel.resizeEnabled ? 'both' : 'none'"> + </textarea> + <mat-error *ngIf="elementFormControl.errors"> + {{elementFormControl.errors | errorTransform: elementModel}} + </mat-error> </mat-form-field> ` }) @@ -29,4 +33,12 @@ export class TextAreaComponent extends FormElementComponent { @Output() onFocus = new EventEmitter<HTMLElement>(); @Output() onBlur = new EventEmitter<HTMLElement>(); elementModel!: TextAreaElement; + + get validators(): ValidatorFn[] { + const validators: ValidatorFn[] = []; + if (this.elementModel.required) { + validators.push(Validators.required); + } + return validators; + } } diff --git a/projects/common/element-components/text-field.component.ts b/projects/common/element-components/text-field.component.ts index 9cc669da3850ead51f45dbb6dcfc92b5014aaf54..e2c95bf6eaa2ef11db0c38c9312a10dddaa8af4b 100644 --- a/projects/common/element-components/text-field.component.ts +++ b/projects/common/element-components/text-field.component.ts @@ -1,4 +1,5 @@ import { Component, EventEmitter, Output } from '@angular/core'; +import { ValidatorFn, Validators } from '@angular/forms'; import { TextFieldElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @@ -20,6 +21,9 @@ import { FormElementComponent } from '../form-element-component.directive'; (blur)="onBlur.emit(input)" [formControl]="elementFormControl" placeholder="{{elementModel.label}}"> + <mat-error *ngIf="elementFormControl.errors"> + {{elementFormControl.errors | errorTransform: elementModel}} + </mat-error> </mat-form-field> ` }) @@ -27,4 +31,21 @@ export class TextFieldComponent extends FormElementComponent { @Output() onFocus = new EventEmitter<HTMLElement>(); @Output() onBlur = new EventEmitter<HTMLElement>(); elementModel!: TextFieldElement; + + get validators(): ValidatorFn[] { + const validators: ValidatorFn[] = []; + if (this.elementModel.required) { + validators.push(Validators.required); + } + if (this.elementModel.minLength) { + validators.push(Validators.minLength(<number> this.elementModel.minLength)); + } + if (this.elementModel.maxLength) { + validators.push(Validators.maxLength(<number> this.elementModel.maxLength)); + } + if (this.elementModel.pattern) { + validators.push(Validators.pattern(<string> this.elementModel.pattern)); + } + return validators; + } } diff --git a/projects/common/form-element-component.directive.ts b/projects/common/form-element-component.directive.ts index 51318d0e39c4d8cda7d8faeb0d65792d82fc194f..f3933d8317770d536f9a220c6655eb5d277e0cf7 100644 --- a/projects/common/form-element-component.directive.ts +++ b/projects/common/form-element-component.directive.ts @@ -2,7 +2,7 @@ import { Directive, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; import { - FormControl, FormGroup + FormControl, FormGroup, ValidatorFn } from '@angular/forms'; import { Subject } from 'rxjs'; import { pairwise, startWith, takeUntil } from 'rxjs/operators'; @@ -17,6 +17,8 @@ export abstract class FormElementComponent extends ElementComponent implements O parentForm!: FormGroup; defaultValue!: string | number | boolean | undefined; elementFormControl!: FormControl; + abstract validators: ValidatorFn[]; + private ngUnsubscribe = new Subject<void>(); constructor(private formService: FormService) { @@ -31,6 +33,11 @@ export abstract class FormElementComponent extends ElementComponent implements O }); this.elementFormControl = this.formControl; this.updateFormValue((this.elementModel as InputUIElement).value); + this.formService.setValidators({ + id: this.elementModel.id, + validators: this.validators, + formGroup: this.parentForm + }); this.elementFormControl.valueChanges .pipe( startWith(this.elementModel.value), diff --git a/projects/common/form.service.ts b/projects/common/form.service.ts index d84d8584440629a9802328cdd18a266f406f7160..190adfa66d2423684eb6f215d55e450529d64a76 100644 --- a/projects/common/form.service.ts +++ b/projects/common/form.service.ts @@ -37,8 +37,8 @@ export class FormService { this._groupAdded.next(group); } - setValidators(validations: FormControlValidators): void { - this._validatorsAdded.next(validations); + setValidators(validators: FormControlValidators): void { + this._validatorsAdded.next(validators); } addPresentedPage(presentedPage: number): void { diff --git a/projects/player/src/app/app.module.ts b/projects/player/src/app/app.module.ts index e6f583b0b88f298166d98b5b1343aac76b060806..56a6f89b81a6073fae7ba2d68c05be4d39f72897 100644 --- a/projects/player/src/app/app.module.ts +++ b/projects/player/src/app/app.module.ts @@ -9,7 +9,6 @@ import { PageComponent } from './components/page/page.component'; import { SectionComponent } from './components/section/section.component'; import { SharedModule } from '../../../common/app.module'; import { ElementOverlayComponent } from './components/element-overlay/element-overlay.component'; -import { ValidationMessageComponent } from './components/validation-message/validation-message.component'; import { UnitStateComponent } from './components/unit-state/unit-state.component'; import { PlayerStateComponent } from './components/player-state/player-state.component'; import { PlayerTranslateLoader } from './classes/player-translate-loader'; @@ -28,7 +27,6 @@ import { ElementComponent } from './components/element/element.component'; PageComponent, SectionComponent, ElementOverlayComponent, - ValidationMessageComponent, UnitStateComponent, PlayerStateComponent, LayoutComponent, diff --git a/projects/player/src/app/components/element/element.component.html b/projects/player/src/app/components/element/element.component.html index 3970878d161e6ba74274690ecb7d2561e99e1c7b..56a216192018ec21baa64885ea8336fd19f116c3 100644 --- a/projects/player/src/app/components/element/element.component.html +++ b/projects/player/src/app/components/element/element.component.html @@ -22,8 +22,4 @@ </app-element-overlay> </ng-template> -<app-validation-message *ngIf="isInputElement" - [ngClass]="{'dynamic-validation-messages' : elementModel.dynamicPositioning}" - [parentForm]="elementForm" - [elementModel]="elementModel"> -</app-validation-message> + diff --git a/projects/player/src/app/components/validation-message/validation-message.component.css b/projects/player/src/app/components/validation-message/validation-message.component.css deleted file mode 100644 index 8352262b6bf47e4b2f0b0032275c6672d2007233..0000000000000000000000000000000000000000 --- a/projects/player/src/app/components/validation-message/validation-message.component.css +++ /dev/null @@ -1,9 +0,0 @@ -.dynamic-validation-message{ - display: contents; -} - -.dynamic-validation-message:not(:empty):not(:last-child):after { - content: ", "; -} - - diff --git a/projects/player/src/app/components/validation-message/validation-message.component.html b/projects/player/src/app/components/validation-message/validation-message.component.html deleted file mode 100644 index d953e911ad4d8234dd61a91a43c29c278fe8111e..0000000000000000000000000000000000000000 --- a/projects/player/src/app/components/validation-message/validation-message.component.html +++ /dev/null @@ -1,22 +0,0 @@ -<div *ngIf="formElementControl?.touched" class="mat-typography"> - <mat-error *ngIf="formElementControl.errors?.required && elementModel.type !== 'checkbox'" - [ngClass]="{'dynamic-validation-message' : elementModel.dynamicPositioning}" > - {{requiredMessage}} - </mat-error> - <mat-error *ngIf="formElementControl.errors?.required && elementModel.type === 'checkbox'" - [ngClass]="{'dynamic-validation-message' : elementModel.dynamicPositioning}" > - {{requiredTrueMessage}} - </mat-error> - <mat-error *ngIf="formElementControl.errors?.minlength" - [ngClass]="{'dynamic-validation-message' : elementModel.dynamicPositioning}" > - {{minLengthWarnMessage}} - </mat-error> - <mat-error *ngIf="formElementControl.errors?.maxlength" - [ngClass]="{'dynamic-validation-message' : elementModel.dynamicPositioning}" > - {{maxLengthWarnMessage}} - </mat-error> - <mat-error *ngIf="formElementControl.errors?.pattern" - [ngClass]="{'dynamic-validation-message' : elementModel.dynamicPositioning}" > - {{patternMessage}} - </mat-error> -</div> diff --git a/projects/player/src/app/components/validation-message/validation-message.component.ts b/projects/player/src/app/components/validation-message/validation-message.component.ts deleted file mode 100644 index 02e7337f164d899a2e5017a5bb6945c753f13004..0000000000000000000000000000000000000000 --- a/projects/player/src/app/components/validation-message/validation-message.component.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { - Component, Input, OnInit -} from '@angular/core'; -import { - FormControl, FormGroup, ValidatorFn, Validators -} from '@angular/forms'; -import { TranslateService } from '@ngx-translate/core'; -import { - CheckboxElement, - InputUIElement, TextFieldElement, UnitUIElement -} from '../../../../../common/unit'; -import { FormService } from '../../../../../common/form.service'; - -@Component({ - selector: 'app-validation-message', - templateUrl: './validation-message.component.html', - styleUrls: ['./validation-message.component.css'] -}) - -export class ValidationMessageComponent implements OnInit { - @Input() elementModel!: UnitUIElement; - @Input() parentForm!: FormGroup; - formElementControl!: FormControl; - requiredMessage!: string; - requiredTrueMessage!: string; - minLengthWarnMessage!: string; - maxLengthWarnMessage!: string; - patternMessage!: string; - - constructor(private formService: FormService, - private translateService: TranslateService) {} - - ngOnInit(): void { - this.setErrorMessages(); - this.formElementControl = this.parentForm.controls[this.elementModel.id] as FormControl; - this.formService.setValidators({ - id: this.elementModel.id, - validators: this.validators, - formGroup: this.parentForm - }); - } - - private get validators(): ValidatorFn[] { - const validators: ValidatorFn[] = []; - if (this.elementModel.required) { - if (this.elementModel.type === 'checkbox') { - validators.push(Validators.requiredTrue); - } else { - validators.push(Validators.required); - } - } - if (this.elementModel.minLength) { - validators.push(Validators.minLength(<number> this.elementModel.minLength)); - } - if (this.elementModel.maxLength) { - validators.push(Validators.maxLength(<number> this.elementModel.maxLength)); - } - if (this.elementModel.pattern) { - validators.push(Validators.pattern(<string> this.elementModel.pattern)); - } - return validators; - } - - private setErrorMessages() { - this.requiredMessage = (this.elementModel as InputUIElement).requiredWarnMessage || - this.translateService.instant('validators.inputRequired'); - - this.requiredTrueMessage = (this.elementModel as CheckboxElement).requiredWarnMessage || - this.translateService.instant('validators.inputRequiredTrue'); - - this.minLengthWarnMessage = (this.elementModel as TextFieldElement).minWarnMessage || - this.translateService.instant('validators.inputTooShort'); - - this.maxLengthWarnMessage = (this.elementModel as TextFieldElement).maxWarnMessage || - this.translateService.instant('validators.inputTooLong'); - - this.patternMessage = (this.elementModel as TextFieldElement).patternWarnMessage || - this.translateService.instant('validators.wrongPattern'); - } -} diff --git a/projects/player/src/assets/i18n/de.json b/projects/player/src/assets/i18n/de.json index 049ea0b40beaab0eb72d6f5c440d600ae9e25b00..0373373deb4cfd916f2908a115fc810884c496ec 100644 --- a/projects/player/src/assets/i18n/de.json +++ b/projects/player/src/assets/i18n/de.json @@ -3,13 +3,6 @@ "presentationIncomplete": "Bearbeitung unvollständig", "responsesIncomplete": "Antworten sind unvollständig", "noReason": "Navigation ohne Angabe von Gründen verweigert", - "validators": { - "inputRequired": "Eingabe erforderlich", - "inputRequiredTrue": "Ankreuzen erforderlich", - "inputTooShort": "Eingabe zu kurz", - "inputTooLong": "Eingabe zu lang", - "wrongPattern": "Eingabe enthält falsche Zeichen" - }, "dialogTitle": { "wrongUnitDefinitionType": "Falscher Unit-Definition-Type", "wrongUnitStateDataType": "Falscher Unit-State-Data-Type"