Merge pull request #2384 from alberto-art3ch/fix/user_change_password_validations

Change password view enhancement to support and display password vali…
This commit is contained in:
Jose Alberto Hernandez
2025-04-06 12:29:30 -05:00
committed by GitHub
24 changed files with 352 additions and 102 deletions
+35
View File
@@ -0,0 +1,35 @@
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import { environment } from 'environments/environment';
export function passwordValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const value = control.value;
if (!value) return null; // No validation if the field is empty
const errors: ValidationErrors = {};
if (value.length < environment.minPasswordLength) {
errors['minLength'] = 'Password must be at least ' + environment.minPasswordLength + ' characters long';
}
if (value.length > 50) {
errors['maxLength'] = 'Password must be maximum 50 characters long';
}
if (!/[A-Z]/.test(value)) {
errors['uppercase'] = 'Password must contain at least one uppercase letter';
}
if (!/[a-z]/.test(value)) {
errors['lowercase'] = 'Password must contain at least one lowercase letter';
}
if (!/\d/.test(value)) {
errors['number'] = 'Password must contain at least one number';
}
if (!/^(?:(.)(?!\1))+$/.test(value)) {
errors['repeated'] = 'Password must have not consecutive repeating characters';
}
if (!/[@$!%*?&]/.test(value)) {
errors['specialChar'] = 'Password must contain at least one special character (@$!%*?&)';
}
return Object.keys(errors).length > 0 ? errors : null;
};
}
+10 -4
View File
@@ -1,21 +1,27 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
import { environment } from 'environments/environment';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { passwordValidator } from './password.validator';
import { environment } from 'environments/environment';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class PasswordsUtility { export class PasswordsUtility {
minPasswordLength: number = environment.minPasswordLength | 12;
// password regex pattern // password regex pattern
public static PASSWORD_REGEX = '^(?!.*(.)\\1{1,})(?!.*\\s)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^\\w\\s]).{12,50}$'; public static PASSWORD_REGEX =
'^(?!.*(.)\\1{1,})(?!.*\\s)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^\\w\\s]).{' +
(environment.minPasswordLength | 12) +
',50}$';
public getPasswordValidators(): ValidatorFn[] { public getPasswordValidators(): ValidatorFn[] {
return [ return [
Validators.required, Validators.required,
Validators.pattern(PasswordsUtility.PASSWORD_REGEX), Validators.minLength(this.minPasswordLength),
Validators.maxLength(50), Validators.maxLength(50),
Validators.minLength(environment.minPasswordLength)]; passwordValidator()
];
} }
/** /**
@@ -3,68 +3,40 @@
<div mat-dialog-content> <div mat-dialog-content>
<form [formGroup]="changePasswordForm"> <form [formGroup]="changePasswordForm">
<div fxLayout="column"> <div fxLayout="column">
<mat-form-field> <mifosx-input-password
<mat-label>{{ 'labels.inputs.Password' | translate }}</mat-label> #password
<input matInput formControlName="password" type="{{ passwordInputType[0] }}" /> formControlName="password"
<button label="{{ 'Password' | translateKey: 'inputs' }}"
type="button" ></mifosx-input-password>
mat-button <div class="error">
matSuffix <p *ngIf="changePasswordForm.get('password').errors?.['uppercase']">
mat-icon-button {{ changePasswordForm.get('password').errors?.['uppercase'] | translateKey: 'inputs' }}
(mousedown)="togglePasswordVisibility(0)" </p>
(mouseup)="togglePasswordVisibility(0)" <p *ngIf="changePasswordForm.get('password').errors?.['number']">
> {{ changePasswordForm.get('password').errors?.['number'] | translateKey: 'inputs' }}
<fa-icon *ngIf="passwordInputType[0] === 'password'" icon="eye"></fa-icon> </p>
<fa-icon *ngIf="passwordInputType[0] === 'text'" icon="eye-slash"></fa-icon> <p *ngIf="changePasswordForm.get('password').errors?.['repeated']">
</button> {{ changePasswordForm.get('password').errors?.['repeated'] | translateKey: 'inputs' }}
<mat-error *ngIf="changePasswordForm.controls.password.hasError('required')"> </p>
{{ 'labels.inputs.Password' | translate }} <strong>{{ 'labels.commons.is required' | translate }}</strong> <p *ngIf="changePasswordForm.get('password').errors?.['specialChar']">
</mat-error> {{ changePasswordForm.get('password').errors?.['specialChar'] | translateKey: 'inputs' }}
<mat-error *ngIf="changePasswordForm.controls.password.hasError('minlength')"> </p>
{{ 'labels.commons.Password should be at least' | translate }} <p *ngIf="changePasswordForm.get('password').errors?.['minlength']">
<strong>{{ 'labels.commons.12 characters long' | translate }}</strong> {{ 'Password minimun length must be' | translateKey: 'inputs' }} {{ minPasswordLength }}
</mat-error> </p>
<mat-error *ngIf="changePasswordForm.controls.password.hasError('maxlength')"> </div>
{{ 'labels.commons.Password should not be more than' | translate }}
<strong>{{ 'labels.commons.50 characters long' | translate }}</strong>
</mat-error>
<mat-error
*ngIf="
changePasswordForm.controls.password.hasError('pattern') &&
!(
changePasswordForm.controls.password.hasError('minlength') ||
changePasswordForm.controls.password.hasError('maxlength')
)
"
>
{{ 'labels.commons.Password should include a' | translate }}
<strong>{{ 'labels.commons.numeral' | translate }}</strong> {{ 'labels.commons.and at' | translate }}
<strong>{{ 'labels.commons.least one uppercase' | translate }}</strong
>, <strong>{{ 'labels.commons.lowercase and special character' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field> <mifosx-input-password
<mat-label>{{ 'labels.inputs.Repeat Password' | translate }}</mat-label> #repeatPassword
<input matInput formControlName="repeatPassword" type="{{ passwordInputType[1] }}" /> formControlName="repeatPassword"
<button label="{{ 'Confirm Password' | translateKey: 'inputs' }}"
type="button" ></mifosx-input-password>
mat-button </div>
matSuffix
mat-icon-button <div class="error">
(mousedown)="togglePasswordVisibility(1)" <p *ngIf="changePasswordForm.get('repeatPassword').errors?.['notequal']">
(mouseup)="togglePasswordVisibility(1)" {{ 'Passwords do not match' | translateKey: 'inputs' }}
> </p>
<fa-icon *ngIf="passwordInputType[1] === 'password'" icon="eye"></fa-icon>
<fa-icon *ngIf="passwordInputType[1] === 'text'" icon="eye-slash"></fa-icon>
</button>
<mat-error *ngIf="changePasswordForm.controls.repeatPassword.hasError('required')">
{{ 'labels.inputs.Password' | translate }} <strong>{{ 'labels.commons.required' | translate }}</strong>
</mat-error>
<mat-error *ngIf="changePasswordForm.controls.repeatPassword.hasError('notequal')">
{{ 'labels.inputs.Password' | translate }} <strong>{{ 'labels.commons.does not match' | translate }}</strong>
</mat-error>
</mat-form-field>
</div> </div>
</form> </form>
</div> </div>
@@ -0,0 +1,8 @@
.error {
color: red;
}
mat-dialog-content {
min-width: 240px;
width: 240px;
}
@@ -4,6 +4,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { UntypedFormBuilder, Validators, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms'; import { UntypedFormBuilder, Validators, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { PasswordsUtility } from 'app/core/utils/passwords-utility'; import { PasswordsUtility } from 'app/core/utils/passwords-utility';
import { environment } from 'environments/environment';
/** /**
* Change Password Dialog component. * Change Password Dialog component.
@@ -14,6 +15,8 @@ import { PasswordsUtility } from 'app/core/utils/passwords-utility';
styleUrls: ['./change-password-dialog.component.scss'] styleUrls: ['./change-password-dialog.component.scss']
}) })
export class ChangePasswordDialogComponent implements OnInit { export class ChangePasswordDialogComponent implements OnInit {
minPasswordLength: number = environment.minPasswordLength | 12;
/** Change Password Form */ /** Change Password Form */
changePasswordForm: any; changePasswordForm: any;
/** Password input field type. */ /** Password input field type. */
@@ -37,15 +40,6 @@ export class ChangePasswordDialogComponent implements OnInit {
this.createChangePasswordForm(); this.createChangePasswordForm();
} }
/**
* Toggles the visibility of the password input field.
*
* Changes the input type between 'password' and 'text'.
*/
togglePasswordVisibility(index: number) {
this.passwordInputType[index] = this.passwordInputType[index] === 'password' ? 'text' : 'password';
}
/** Change Password form */ /** Change Password form */
createChangePasswordForm() { createChangePasswordForm() {
this.changePasswordForm = this.formBuilder.group({ this.changePasswordForm = this.formBuilder.group({
@@ -0,0 +1,16 @@
<mat-form-field>
<mat-label>{{ label }}</mat-label>
<input
matInput
[disabled]="disabled"
[errorStateMatcher]="matcher"
(focusout)="onFocusOut()"
(input)="onInput($event)"
[required]="required"
[type]="type"
[value]="value"
/>
<mat-icon matSuffix (click)="onVisibilityClick($event)">{{ icon }}</mat-icon>
<mat-error *ngIf="ngControl.hasError('required')">{{ label }} is a required field.</mat-error>
<mat-error *ngIf="ngControl.hasError(customErrorName)">{{ customErrorMessage }}</mat-error>
</mat-form-field>
@@ -0,0 +1,11 @@
:host {
width: 100%;
mat-icon {
font-size: 16px;
}
.mat-form-field {
width: 100%;
}
}
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { InputPasswordComponent } from './input-password.component';
describe('InputPasswordComponent', () => {
let component: InputPasswordComponent;
let fixture: ComponentFixture<InputPasswordComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [InputPasswordComponent]
}).compileComponents();
fixture = TestBed.createComponent(InputPasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,114 @@
import { Component, Input, Optional, Self, ViewChild } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
FormGroupDirective,
NgControl,
NgForm,
Validators
} from '@angular/forms';
import { MatInput } from '@angular/material/input';
import { ErrorStateMatcher } from '@angular/material/core';
@Component({
selector: 'mifosx-input-password',
templateUrl: './input-password.component.html',
styleUrls: ['./input-password.component.scss']
})
export class InputPasswordComponent implements ControlValueAccessor, ErrorStateMatcher {
disabled = false;
icon = 'visibility_off';
@Input()
label: string = null;
@Input()
customErrorMessage: string = null;
@Input()
customErrorName: string = null;
get matcher() {
return this;
}
@ViewChild(MatInput)
matInput: MatInput;
get required(): boolean {
return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;
}
@Input()
set required(value: boolean) {
this._required = value;
}
touched = false;
type = 'password';
value: string = null;
private _required: boolean = null;
private _visible = false;
constructor(@Optional() @Self() public ngControl: NgControl) {
if (ngControl !== null) {
ngControl.valueAccessor = this;
}
}
isErrorState(control: AbstractControl | null, form: FormGroupDirective | NgForm | null): boolean {
return this.touched && (this.ngControl?.control?.invalid ?? false);
}
onChange = (value: any) => {};
onFocusOut(): void {
this.touched = true;
this.onTouched();
this.matInput.updateErrorState();
}
onInput($event: any): void {
this.value = $event.currentTarget.value;
this.touched = true;
this.onChange(this.value);
}
onTouched = () => {};
onVisibilityClick($event: Event): void {
if (this._visible) {
this.icon = 'visibility_off';
this.type = 'password';
} else {
this.icon = 'visibility';
this.type = 'text';
}
// Invert the value.
this._visible = !this._visible;
$event.stopPropagation();
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean) {
this.disabled = isDisabled;
}
writeValue(obj: any): void {
this.value = obj;
}
}
+3 -1
View File
@@ -50,6 +50,7 @@ import { ThemeToggleComponent } from './theme-toggle/theme-toggle.component';
import { LongTextComponent } from './long-text/long-text.component'; import { LongTextComponent } from './long-text/long-text.component';
import { DropdownComponent } from './dropdown/dropdown.component'; import { DropdownComponent } from './dropdown/dropdown.component';
import { InputAmountComponent } from './input-amount/input-amount.component'; import { InputAmountComponent } from './input-amount/input-amount.component';
import { InputPasswordComponent } from './input-password/input-password.component';
/** /**
* Shared Module * Shared Module
@@ -106,7 +107,8 @@ import { InputAmountComponent } from './input-amount/input-amount.component';
ThemeToggleComponent, ThemeToggleComponent,
LongTextComponent, LongTextComponent,
DropdownComponent, DropdownComponent,
InputAmountComponent InputAmountComponent,
InputPasswordComponent
], ],
exports: [ exports: [
FileUploadComponent, FileUploadComponent,
+6 -14
View File
@@ -2,18 +2,18 @@
window["env"] = window["env"] || {}; window["env"] = window["env"] || {};
// BackEnd Environment variables // BackEnd Environment variables
window['env']['fineractApiUrls'] = ''; window["env"]["fineractApiUrls"] = '';
window['env']['fineractApiUrl'] = ''; window["env"]["fineractApiUrl"] = '';
window['env']['apiProvider'] = ''; window["env"]["apiProvider"] = '';
window['env']['apiVersion'] = ''; window["env"]["apiVersion"] = '';
window["env"]["fineractPlatformTenantId"] = ''; window["env"]["fineractPlatformTenantId"] = '';
window["env"]["fineractPlatformTenantIds"] = ''; window["env"]["fineractPlatformTenantIds"] = '';
// Language Environment variables // Language Environment variables
window['env']['defaultLanguage'] = ''; window["env"]["defaultLanguage"] = '';
window['env']['supportedLanguages'] = ''; window["env"]["supportedLanguages"] = '';
window['env']['preloadClients'] = ''; window['env']['preloadClients'] = '';
@@ -44,12 +44,4 @@
// OAuth Client Id // OAuth Client Id
window['env']['oauthAppId'] = ''; window['env']['oauthAppId'] = '';
// Min Password length
window['env']['minPasswordLength'] = '12';
window["env"]["vNextApiUrl"] = '';
window["env"]["vNextApiProvider"] = '';
window["env"]["vNextApiVersion"] = '';
window["env"]["interbankTransfers"] = "false";
})(this); })(this);
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "VRÁCENÍ ÚROKU", "INTEREST REFUND": "VRÁCENÍ ÚROKU",
"Supported Interest Refund Types": "Unterstützte Zinsrückerstattungsarten", "Supported Interest Refund Types": "Unterstützte Zinsrückerstattungsarten",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Podporované typy vrácení úroků", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Podporované typy vrácení úroků",
"Charge-off reason": "Důvod vyúčtování" "Charge-off reason": "Důvod vyúčtování",
"Password must contain at least one uppercase letter": "Heslo musí obsahovat alespoň jedno velké písmeno",
"Password must contain at least one number": "Heslo musí obsahovat alespoň jedno číslo",
"Password must have not consecutive repeating characters": "Heslo nesmí obsahovat po sobě jdoucí opakující se znaky",
"Password must contain at least one special character (@$!%*?&)": "Heslo musí obsahovat alespoň jeden speciální znak (@$!%*?&)",
"Password minimun length must be": "Minimální délka hesla musí být",
"Passwords do not match": "Hesla se neshodují"
}, },
"links": { "links": {
"Community": "Společenství", "Community": "Společenství",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "ZINSRÜCKERSTATTUNG", "INTEREST REFUND": "ZINSRÜCKERSTATTUNG",
"Supported Interest Refund Types": "Unterstützte Zinsrückerstattungsarten", "Supported Interest Refund Types": "Unterstützte Zinsrückerstattungsarten",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Unterstützte Zinsrückerstattungsarten", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Unterstützte Zinsrückerstattungsarten",
"Charge-off reason": "Abschreibungsgrund" "Charge-off reason": "Abschreibungsgrund",
"Password must contain at least one uppercase letter": "Das Passwort muss mindestens einen Großbuchstaben enthalten",
"Password must contain at least one number": "Das Passwort muss mindestens eine Zahl enthalten",
"Password must have not consecutive repeating characters": "Das Passwort darf keine aufeinanderfolgenden, sich wiederholenden Zeichen enthalten",
"Password must contain at least one special character (@$!%*?&)": "Das Passwort muss mindestens ein Sonderzeichen enthalten (@$!%*?&)",
"Password minimun length must be": "Die Mindestlänge des Passworts muss betragen",
"Passwords do not match": "Passwörter stimmen nicht überein"
}, },
"links": { "links": {
"Community": "Gemeinschaft", "Community": "Gemeinschaft",
+7 -1
View File
@@ -2457,7 +2457,13 @@
"INTEREST REFUND": "INTEREST REFUND", "INTEREST REFUND": "INTEREST REFUND",
"Supported Interest Refund Types": "Supported Interest Refund Types", "Supported Interest Refund Types": "Supported Interest Refund Types",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Supported interest refund types", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Supported interest refund types",
"Charge-off reason": "Charge-off reason" "Charge-off reason": "Charge-off reason",
"Password must contain at least one uppercase letter": "Password must contain at least one uppercase letter",
"Password must contain at least one number": "Password must contain at least one number",
"Password must have not consecutive repeating characters": "Password must have not consecutive repeating characters",
"Password must contain at least one special character (@$!%*?&)": "Password must contain at least one special character (@$!%*?&)",
"Password minimun length must be": "Password minimun length must be",
"Passwords do not match": "Passwords do not match"
}, },
"links": { "links": {
"Community": "Community", "Community": "Community",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "REEMBOLSO DE INTERESES", "INTEREST REFUND": "REEMBOLSO DE INTERESES",
"Supported Interest Refund Types": "Tipos de reembolso de intereses admitidos", "Supported Interest Refund Types": "Tipos de reembolso de intereses admitidos",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipos de reembolso de intereses admitidos", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipos de reembolso de intereses admitidos",
"Charge-off reason": "Motivo de la cancelación" "Charge-off reason": "Motivo de la cancelación",
"Password must contain at least one uppercase letter": "La contraseña debe contener al menos una letra mayúscula",
"Password must contain at least one number": "La contraseña debe contener al menos un número",
"Password must have not consecutive repeating characters": "La contraseña no debe tener caracteres repetidos consecutivos.",
"Password must contain at least one special character (@$!%*?&)": "La contraseña debe contener al menos un carácter especial (@$!%*?&)",
"Password minimun length must be": "La longitud mínima de la contraseña debe ser",
"Passwords do not match": "Las contraseñas no coinciden"
}, },
"links": { "links": {
"Community": "Comunidad", "Community": "Comunidad",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "REEMBOLSO DE INTERESES", "INTEREST REFUND": "REEMBOLSO DE INTERESES",
"Supported Interest Refund Types": "Tipos de reembolso de intereses admitidos", "Supported Interest Refund Types": "Tipos de reembolso de intereses admitidos",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipos de reembolso de intereses admitidos", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipos de reembolso de intereses admitidos",
"Charge-off reason": "Motivo de la cancelación" "Charge-off reason": "Motivo de la cancelación",
"Password must contain at least one uppercase letter": "La contraseña debe contener al menos una letra mayúscula",
"Password must contain at least one number": "La contraseña debe contener al menos un número",
"Password must have not consecutive repeating characters": "La contraseña no debe tener caracteres repetidos consecutivos.",
"Password must contain at least one special character (@$!%*?&)": "La contraseña debe contener al menos un carácter especial (@$!%*?&)",
"Password minimun length must be": "La longitud mínima de la contraseña debe ser",
"Passwords do not match": "Las contraseñas no coinciden"
}, },
"links": { "links": {
"Community": "Comunidad", "Community": "Comunidad",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "REMBOURSEMENT DES INTÉRÊTS", "INTEREST REFUND": "REMBOURSEMENT DES INTÉRÊTS",
"Supported Interest Refund Types": "Types de remboursement d'intérêts pris en charge", "Supported Interest Refund Types": "Types de remboursement d'intérêts pris en charge",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Types de remboursement d'intérêts pris en charge", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Types de remboursement d'intérêts pris en charge",
"Charge-off reason": "Motif de la radiation" "Charge-off reason": "Motif de la radiation",
"Password must contain at least one uppercase letter": "Le mot de passe doit contenir au moins une lettre majuscule",
"Password must contain at least one number": "Le mot de passe doit contenir au moins un chiffre",
"Password must have not consecutive repeating characters": "Le mot de passe ne doit pas contenir de caractères répétitifs consécutifs",
"Password must contain at least one special character (@$!%*?&)": "Le mot de passe doit contenir au moins un caractère spécial (@$!%*?&)",
"Password minimun length must be": "La longueur minimale du mot de passe doit être",
"Passwords do not match": "Les mots de passe ne correspondent pas"
}, },
"links": { "links": {
"Community": "Communauté", "Community": "Communauté",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "RIMBORSO DEGLI INTERESSI", "INTEREST REFUND": "RIMBORSO DEGLI INTERESSI",
"Supported Interest Refund Types": "Tipi di rimborso degli interessi supportati", "Supported Interest Refund Types": "Tipi di rimborso degli interessi supportati",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipi di rimborso degli interessi supportati", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipi di rimborso degli interessi supportati",
"Charge-off reason": "Motivo dell'addebito" "Charge-off reason": "Motivo dell'addebito",
"Password must contain at least one uppercase letter": "La password deve contenere almeno una lettera maiuscola",
"Password must contain at least one number": "La password deve contenere almeno un numero",
"Password must have not consecutive repeating characters": "La password non deve contenere caratteri ripetuti consecutivi",
"Password must contain at least one special character (@$!%*?&)": "La password deve contenere almeno un carattere speciale (@$!%*?&)",
"Password minimun length must be": "La lunghezza minima della password deve essere",
"Passwords do not match": "Le password non corrispondono"
}, },
"links": { "links": {
"Community": "Comunità", "Community": "Comunità",
+7 -1
View File
@@ -2451,7 +2451,13 @@
"INTEREST REFUND": "이자환급", "INTEREST REFUND": "이자환급",
"Supported Interest Refund Types": "지원되는 이자 환불 유형", "Supported Interest Refund Types": "지원되는 이자 환불 유형",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "지원되는 이자 환불 유형", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "지원되는 이자 환불 유형",
"Charge-off reason": "청구 취소 사유" "Charge-off reason": "청구 취소 사유",
"Password must contain at least one uppercase letter": "비밀번호에는 대문자가 하나 이상 포함되어야 합니다.",
"Password must contain at least one number": "비밀번호에는 숫자가 하나 이상 포함되어야 합니다.",
"Password must have not consecutive repeating characters": "비밀번호에는 연속된 반복 문자가 없어야 합니다.",
"Password must contain at least one special character (@$!%*?&)": "비밀번호에는 특수 문자가 하나 이상 포함되어야 합니다. (@$!%*?&)",
"Password minimun length must be": "비밀번호의 최소 길이는 다음과 같아야 합니다.",
"Passwords do not match": "비밀번호가 일치하지 않습니다."
}, },
"links": { "links": {
"Community": "지역 사회", "Community": "지역 사회",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "PALŪKANŲ GRĄŽINIMAS", "INTEREST REFUND": "PALŪKANŲ GRĄŽINIMAS",
"Supported Interest Refund Types": "Palaikomi palūkanų grąžinimo tipai", "Supported Interest Refund Types": "Palaikomi palūkanų grąžinimo tipai",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Palaikomi palūkanų grąžinimo tipai", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Palaikomi palūkanų grąžinimo tipai",
"Charge-off reason": "Apmokestinimo priežastis" "Charge-off reason": "Apmokestinimo priežastis",
"Password must contain at least one uppercase letter": "Slaptažodyje turi būti bent viena didžioji raidė",
"Password must contain at least one number": "Slaptažodyje turi būti bent vienas skaičius",
"Password must have not consecutive repeating characters": "Slaptažodyje neturi būti iš eilės besikartojančių simbolių",
"Password must contain at least one special character (@$!%*?&)": "Slaptažodyje turi būti bent vienas specialusis simbolis (@$!%*?&)",
"Password minimun length must be": "Minimalus slaptažodžio ilgis turi būti",
"Passwords do not match": "Slaptažodžiai nesutampa"
}, },
"links": { "links": {
"Community": "bendruomenė", "Community": "bendruomenė",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "PROCENTU ATMAKSĀŠANA", "INTEREST REFUND": "PROCENTU ATMAKSĀŠANA",
"Supported Interest Refund Types": "Atbalstītie procentu atmaksas veidi", "Supported Interest Refund Types": "Atbalstītie procentu atmaksas veidi",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Atbalstītie procentu atmaksas veidi", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Atbalstītie procentu atmaksas veidi",
"Charge-off reason": "Izmaksas iemesls" "Charge-off reason": "Izmaksas iemesls",
"Password must contain at least one uppercase letter": "Parolē jāsatur vismaz viens lielais burts",
"Password must contain at least one number": "Parolē ir jāsatur vismaz viens cipars",
"Password must have not consecutive repeating characters": "Parolē nedrīkst būt secīgas atkārtotas rakstzīmes",
"Password must contain at least one special character (@$!%*?&)": "Parolē jāsatur vismaz viena speciālā rakstzīme (@$!%*?&)",
"Password minimun length must be": "Paroles minimālajam garumam jābūt",
"Passwords do not match": "Paroles nesakrīt"
}, },
"links": { "links": {
"Community": "kopiena", "Community": "kopiena",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "व्याज परतावा", "INTEREST REFUND": "व्याज परतावा",
"Supported Interest Refund Types": "समर्थित ब्याज फिर्ता प्रकारहरू", "Supported Interest Refund Types": "समर्थित ब्याज फिर्ता प्रकारहरू",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "समर्थित व्याज परतावा प्रकार", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "समर्थित व्याज परतावा प्रकार",
"Charge-off reason": "चार्ज अफ कारण" "Charge-off reason": "चार्ज अफ कारण",
"Password must contain at least one uppercase letter": "पासवर्डमा कम्तिमा एउटा ठूलो अक्षर हुनु पर्छ",
"Password must contain at least one number": "पासवर्डमा कम्तिमा एउटा नम्बर हुनुपर्छ",
"Password must have not consecutive repeating characters": "पासवर्डमा लगातार दोहोरिने क्यारेक्टरहरू हुनु हुँदैन",
"Password must contain at least one special character (@$!%*?&)": "पासवर्डमा कम्तिमा एउटा विशेष वर्ण हुनुपर्छ (@$!%*?&)",
"Password minimun length must be": "पासवर्ड न्यूनतम लम्बाइ हुनुपर्छ",
"Passwords do not match": "पासवर्डहरू मेल खाँदैनन्"
}, },
"links": { "links": {
"Community": "समुदाय", "Community": "समुदाय",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "REEMBOLSO DE JUROS", "INTEREST REFUND": "REEMBOLSO DE JUROS",
"Supported Interest Refund Types": "Tipos de reembolso de juros suportados", "Supported Interest Refund Types": "Tipos de reembolso de juros suportados",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipos de reembolso de juros suportados", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Tipos de reembolso de juros suportados",
"Charge-off reason": "Motivo da cobrança" "Charge-off reason": "Motivo da cobrança",
"Password must contain at least one uppercase letter": "A senha deve conter pelo menos uma letra maiúscula",
"Password must contain at least one number": "A senha deve conter pelo menos um número",
"Password must have not consecutive repeating characters": "A senha não deve conter caracteres repetidos consecutivos",
"Password must contain at least one special character (@$!%*?&)": "A senha deve conter pelo menos um caractere especial (@$!%*?&)",
"Password minimun length must be": "O comprimento mínimo da senha deve ser",
"Passwords do not match": "As senhas não coincidem"
}, },
"links": { "links": {
"Community": "Comunidade", "Community": "Comunidade",
+7 -1
View File
@@ -2450,7 +2450,13 @@
"INTEREST REFUND": "MAREJESHO YA RIBA", "INTEREST REFUND": "MAREJESHO YA RIBA",
"Supported Interest Refund Types": "Aina za Urejeshaji wa Riba Zinazotumika", "Supported Interest Refund Types": "Aina za Urejeshaji wa Riba Zinazotumika",
"SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Aina za kurejesha riba zinazotumika", "SUPPORTED REFUND TRANSACTIONS FOR INTEREST REFUND": "Aina za kurejesha riba zinazotumika",
"Charge-off reason": "Sababu ya malipo" "Charge-off reason": "Sababu ya malipo",
"Password must contain at least one uppercase letter": "Nenosiri lazima liwe na angalau herufi kubwa moja",
"Password must contain at least one number": "Nenosiri lazima liwe na angalau nambari moja",
"Password must have not consecutive repeating characters": "Nenosiri lazima lisiwe na vibambo vinavyorudiwa mfululizo",
"Password must contain at least one special character (@$!%*?&)": "Nenosiri lazima liwe na angalau herufi moja maalum (@$!%*?&)",
"Password minimun length must be": "Nenosiri la urefu wa chini lazima liwe",
"Passwords do not match": "Manenosiri hayalingani"
}, },
"links": { "links": {
"Community": "Jumuiya", "Community": "Jumuiya",