Skip to content

Commit

Permalink
feat: add support translate title of properties in validation errors
Browse files Browse the repository at this point in the history
  • Loading branch information
EndyKaufman committed Sep 11, 2020
1 parent 6c7fa3c commit dbba241
Show file tree
Hide file tree
Showing 33 changed files with 1,493 additions and 327 deletions.
4 changes: 2 additions & 2 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@
"with": "apps/demo/src/environments/environment.prod.ts"
}
],
"optimization": false,
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"buildOptimizer": true,
"serviceWorker": true
}
}
Expand Down
71 changes: 55 additions & 16 deletions apps/demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { HttpClient } from '@angular/common/http';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { updateValidatorMessagesStorage } from 'ngx-dynamic-form-builder';
import { TranslocoService } from '@ngneat/transloco';
import { updateValidatorMessagesStorage, updateValidatorTitlesStorage } from 'ngx-dynamic-form-builder';
import { forkJoin, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { AppRoutes } from './app.routes';
import { Language } from './shared/interfaces/language-interface';

Expand All @@ -15,11 +18,32 @@ export class AppComponent {
title = 'app';
routes = AppRoutes;
languages: Language[] = [
{ code: 'en', title: 'English' },
{ code: 'ru', title: 'Russian' },
// t(English)
{
code: 'en',
title: 'English',
staticValidatorMessages: {
'$constraint1 do not match to $property': '$constraint1 do not match to $property',
'The company name must be longer than 15': 'The company name must be longer than 15',
},
},
// t(Russian)
{
code: 'ru',
title: 'Russian',
staticValidatorMessages: {
'$constraint1 do not match to $property': '$constraint1 не равно $property',
'The company name must be longer than 15': 'Название компании должно быть длиннее 15',
},
},
];

constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer, public httpClient: HttpClient) {
constructor(
iconRegistry: MatIconRegistry,
sanitizer: DomSanitizer,
public httpClient: HttpClient,
private readonly translocoService: TranslocoService
) {
iconRegistry.addSvgIcon(
'github-circle',
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/github-circle.svg')
Expand All @@ -32,23 +56,38 @@ export class AppComponent {
'translate',
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/g_translate-24px.svg')
);
// translocoService.setFallbackLangForMissingTranslation({ fallbackLang: 'en' });
}

changeLanguage(currentLanguage: Language) {
const foundedLang = this.languages.find((lang) => lang.code === currentLanguage.code);
changeLanguage(newLanguage: Language) {
const foundedLang = this.languages.find((lang) => lang.code === newLanguage.code);
if (foundedLang) {
if (!foundedLang.dictionaries) {
this.httpClient
.get<{ [key: string]: string }>(`./assets/i18n/class-validator-messages/${currentLanguage.code}.json`)
.subscribe((dictionaries) => {
if (foundedLang) {
foundedLang.dictionaries = dictionaries;
updateValidatorMessagesStorage(foundedLang.dictionaries);
}
});
if (!foundedLang.validatorMessages) {
forkJoin({
messages: this.httpClient
.get<{ [key: string]: string }>(
`${document.baseURI}assets/i18n/class-validator-messages/${newLanguage.code}.json`
)
.pipe(catchError(() => of({}))),
titles: this.httpClient
.get<{ [key: string]: string }>(`${document.baseURI}assets/i18n/${newLanguage.code}.json`)
.pipe(catchError(() => of({}))),
}).subscribe(({ messages, titles }) => {
if (foundedLang) {
foundedLang.validatorMessages = messages;
foundedLang.validatorTitles = titles;
updateValidatorMessagesStorage({
...foundedLang.validatorMessages,
...foundedLang.staticValidatorMessages,
});
updateValidatorTitlesStorage(foundedLang.validatorTitles);
}
});
} else {
updateValidatorMessagesStorage(foundedLang.dictionaries);
updateValidatorMessagesStorage({ ...foundedLang.validatorMessages, ...foundedLang.staticValidatorMessages });
updateValidatorTitlesStorage(foundedLang.validatorTitles);
}
}
this.translocoService.setActiveLang(newLanguage.code);
}
}
2 changes: 2 additions & 0 deletions apps/demo/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { MyErrorStateMatcher } from './shared/utils/my-error-state-matcher';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog';
import { MarkdownModule } from 'ngx-markdown';
import { TranslocoRootModule } from './transloco/transloco-root.module';

@NgModule({
declarations: [AppComponent],
Expand All @@ -27,6 +28,7 @@ import { MarkdownModule } from 'ngx-markdown';
NavbarModule.forRoot(),
RouterModule.forRoot(AppRoutes, { preloadingStrategy: PreloadAllModules, initialNavigation: 'enabled' }),
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
TranslocoRootModule,
],
providers: [
{ provide: ErrorStateMatcher, useClass: MyErrorStateMatcher },
Expand Down
1 change: 1 addition & 0 deletions apps/demo/src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ export * from './shared/pipes/safe-html.pipe';
export * from './shared/utils/custom-transforms';
export * from './shared/utils/custom-validators';
export * from './shared/utils/my-error-state-matcher';
export * from './transloco/transloco-root.module';
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<mat-icon svgIcon="translate"></mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="setCurrent(lang)" *ngFor="let lang of languages || []">{{ lang.title }}</button>
<button mat-menu-item (click)="setCurrent(lang)" *ngFor="let lang of languages || []">
{{ lang.title || '' | transloco }}
</button>
</mat-menu>
</ng-container>
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { TranslocoModule } from '@ngneat/transloco';
import { NavbarLanguagesButtonsComponent } from './navbar-languages-buttons.component';

@NgModule({
imports: [CommonModule, MatMenuModule, MatButtonModule, MatIconModule],
imports: [CommonModule, MatMenuModule, MatButtonModule, MatIconModule, TranslocoModule],
declarations: [NavbarLanguagesButtonsComponent],
exports: [NavbarLanguagesButtonsComponent],
})
Expand Down
4 changes: 2 additions & 2 deletions apps/demo/src/app/others/navbar/navbar.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</mat-menu>
</span>
<a [routerLink]="['home']" mat-button>
{{ title }}
{{ title | transloco }}
</a>
<navbar-languages-buttons
[languages]="languages"
Expand Down Expand Up @@ -65,5 +65,5 @@
<ng-template let-item="item" #menuItemContent>
<mat-icon [svgIcon]="item.svgIcon" *ngIf="item.svgIcon"></mat-icon>
<mat-icon *ngIf="item.icon">{{ item.icon }}</mat-icon>
<span>{{ item.title }}</span>
<span>{{ item.title | transloco }}</span>
</ng-template>
2 changes: 2 additions & 0 deletions apps/demo/src/app/others/navbar/navbar.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MatIconModule } from '@angular/material/icon';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatMenuModule } from '@angular/material/menu';
import { NavbarLanguagesButtonsModule } from '../navbar-languages-buttons/navbar-languages-buttons.module';
import { TranslocoModule } from '@ngneat/transloco';

@NgModule({
imports: [
Expand All @@ -19,6 +20,7 @@ import { NavbarLanguagesButtonsModule } from '../navbar-languages-buttons/navbar
FlexLayoutModule,
MatMenuModule,
NavbarLanguagesButtonsModule,
TranslocoModule,
],
entryComponents: [NavbarComponent],
exports: [NavbarComponent],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
<div
class="experimental-page"
fxLayout.gt-md="row"
fxLayout.lt-md="column"
fxLayoutAlign="space-evenly stretch"
fxLayoutAlign.lt-md="center">
<div
fxFlex.gt-sm="50">
<ngx-docs-example
title="Experimental: user panel"
[html]="source.html"
[ts]="source.ts"
[launch]="source.launch">
<div class="body">
<exp-user-panel></exp-user-panel>
</div>
</ngx-docs-example>
<ngx-docs-example
title="Experimental: login panel"
[html]="loginSource.html"
[ts]="loginSource.ts"
[launch]="loginSource.launch">
<div class="body">
<exp-login-panel></exp-login-panel>
</div>
</ngx-docs-example>
<ngx-docs-example
title="Experimental: registration panel"
[html]="registrationSource.html"
[ts]="registrationSource.ts"
[launch]="registrationSource.launch">
<div class="body">
<exp-registration-panel></exp-registration-panel>
</div>
</ngx-docs-example>
</div>
<source-tabs
title="Other files"
[files]="otherFiles"
fxFlex.gt-sm="50"></source-tabs>
class="experimental-page"
fxLayout.gt-md="row"
fxLayout.lt-md="column"
fxLayoutAlign="space-evenly stretch"
fxLayoutAlign.lt-md="center"
>
<div fxFlex.gt-sm="50">
<ngx-docs-example
title="{{ 'Experimental: user panel' | transloco }}"
[html]="source.html"
[ts]="source.ts"
[launch]="source.launch"
>
<div class="body">
<exp-user-panel></exp-user-panel>
</div>
</ngx-docs-example>
<ngx-docs-example
title="{{ 'Experimental: login panel' | transloco }}"
[html]="loginSource.html"
[ts]="loginSource.ts"
[launch]="loginSource.launch"
>
<div class="body">
<exp-login-panel></exp-login-panel>
</div>
</ngx-docs-example>
<ngx-docs-example
title="{{ 'Experimental: registration panel' | transloco }}"
[html]="registrationSource.html"
[ts]="registrationSource.ts"
[launch]="registrationSource.launch"
>
<div class="body">
<exp-registration-panel></exp-registration-panel>
</div>
</ngx-docs-example>
</div>
<source-tabs title="{{ 'Other files' | transloco }}" [files]="otherFiles" fxFlex.gt-sm="50"></source-tabs>
</div>
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { NgModule } from '@angular/core';
import { ExperimentalPageComponent } from './experimental-page.component';
import { FlexLayoutModule } from '@angular/flex-layout';
import { ModuleWithProviders } from '@angular/core';
import { SharedModule } from '../../shared/shared.module';
import { RouterModule } from '@angular/router';
import { ExperimentalPageRoutes } from './experimental-page.routes';
import { TranslocoModule } from '@ngneat/transloco';
import { DocsExampleModule } from '../../others/docs-example/docs-example.module';
import { SourceTabsModule } from '../../others/source-tabs/source-tabs.module';
import { ExpUserPanelModule } from '../../panels/exp-user-panel/exp-user-panel.module';
import { ExpLoginPanelModule } from '../../panels/exp-login-panel/exp-login-panel.module';
import { DocsExampleModule } from '../../others/docs-example/docs-example.module';
import { ExpRegistrationPanelModule } from '../../panels/exp-registration-panel/exp-registration-panel.module';
import { ExpUserPanelModule } from '../../panels/exp-user-panel/exp-user-panel.module';
import { SharedModule } from '../../shared/shared.module';
import { ExperimentalPageComponent } from './experimental-page.component';
import { ExperimentalPageRoutes } from './experimental-page.routes';

@NgModule({
imports: [
Expand All @@ -21,6 +21,7 @@ import { ExpRegistrationPanelModule } from '../../panels/exp-registration-panel/
ExpRegistrationPanelModule.forRoot(),
RouterModule.forChild(ExperimentalPageRoutes),
SourceTabsModule.forRoot(),
TranslocoModule,
],
entryComponents: [ExperimentalPageComponent],
exports: [ExperimentalPageComponent],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export const ExperimentalPageRoutes: Routes = [
component: ExperimentalPageComponent,
data: {
name: 'experimental',
title: 'Experimental',
/**
* t(Experimental + i18n)
*/
title: 'Experimental + i18n',
visible: true,
},
children: [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,24 @@
<form
[formGroup]="form"
*ngIf="form?.customValidateErrors | async as errors"
novalidate>
<h3>Group form</h3>
<mat-form-field class="full-width">
<input
matInput
formControlName="username"
placeholder="Username">
<mat-error *ngIf="errors?.username?.length">{{errors?.username[0]}}</mat-error>
</mat-form-field>
<mat-form-field class="full-width">
<input
matInput
type="password"
formControlName="password"
placeholder="Password">
<mat-error *ngIf="errors?.password?.length">{{errors?.password[0]}}</mat-error>
</mat-form-field>
<div class="full-width">
<p>Form status: {{ form.status | json }}</p>
<p>
Form class-validator errors: {{errors|json}}
</p>
<p>
Form native errors: {{form?.nativeValidateErrors|async|json}}
</p>
<p *ngIf="savedItem">Login user data: {{savedItem|json}}</p>
</div>
<div class="full-width">
<button
mat-raised-button
(click)="onLoginClick()"
[disabled]="!form.valid"
cdkFocusInitial>
Login
</button>
</div>
<form [formGroup]="form" *ngIf="form?.customValidateErrors | async as errors" novalidate>
<h3>{{ 'Login form' | transloco }}</h3>
<mat-form-field class="full-width">
<!--t(username)-->
<input matInput formControlName="username" [placeholder]="'Username' | transloco" />
<mat-error *ngIf="errors?.username?.length">{{ errors?.username[0] }}</mat-error>
</mat-form-field>
<mat-form-field class="full-width">
<!--t(password)-->
<input matInput type="password" formControlName="password" [placeholder]="'Password' | transloco" />
<mat-error *ngIf="errors?.password?.length">{{ errors?.password[0] }}</mat-error>
</mat-form-field>
<div class="full-width">
<p>{{ 'Form status:' | transloco }} {{ form.status | json }}</p>
<p>{{ 'Form class-validator errors:' | transloco }} {{ errors | json }}</p>
<p>{{ 'Form native errors:' | transloco }} {{ form?.nativeValidateErrors | async | json }}</p>
<p *ngIf="savedItem">{{ 'Login user data:' | transloco }} {{ savedItem | json }}</p>
</div>
<div class="full-width">
<button mat-raised-button (click)="onLoginClick()" [disabled]="!form.valid" cdkFocusInitial>
{{ 'Login' | transloco }}
</button>
</div>
</form>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { SharedModule } from '../../shared/shared.module';
import { MatInputModule } from '@angular/material/input';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { TranslocoModule } from '@ngneat/transloco';

@NgModule({
imports: [
Expand All @@ -17,6 +18,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
FormsModule,
ReactiveFormsModule,
FlexLayoutModule,
TranslocoModule,
],
entryComponents: [ExpLoginPanelComponent],
exports: [ExpLoginPanelComponent],
Expand Down
Loading

0 comments on commit dbba241

Please sign in to comment.