Commit 7c437826 authored by Homada.Boumedane's avatar Homada.Boumedane Committed by Florent Poittevin
Browse files

feat: multi-Language date format with angular material datepicker

parent 61fea542
......@@ -60,6 +60,7 @@ import {FormlyMaterialModule} from "@ngx-formly/material";
import {
TranslateLoader,
TranslateModule,
TranslateService,
} from "@ngx-translate/core";
import {TranslateHttpLoader} from "@ngx-translate/http-loader";
import {NgxsReduxDevtoolsPluginModule} from "@ngxs/devtools-plugin";
......@@ -88,6 +89,13 @@ import {AppComponent} from "./app.component";
import {LanguageSelectorPresentational} from "./components/presentationals/language-selector/language-selector.presentational";
import {MainToolbarDesktopHorizontalPresentational} from "./components/presentationals/main-toolbar/main-toolbar-desktop-horizontal/main-toolbar-desktop-horizontal.presentational";
import {PageNotFoundPresentational} from "./components/presentationals/page-not-found/page-not-found.presentational";
import {registerLocaleData} from "@angular/common";
import localeEn from "@angular/common/locales/en";
import localeDe from "@angular/common/locales/de";
import localeDeExtra from "@angular/common/locales/extra/de";
import localeFr from "@angular/common/locales/fr";
import localeFrExtra from "@angular/common/locales/extra/fr";
import {CUSTOM_DATE_FORMATS} from "@shared/date-adapter";
const presentationals = [
AppComponent,
......@@ -149,6 +157,9 @@ export function hljsLanguages(): any {
{name: "json", func: json},
];
}
registerLocaleData(localeEn, "en");
registerLocaleData(localeDe, "de", localeDeExtra);
registerLocaleData(localeFr, "fr", localeFrExtra);
@NgModule({
declarations: [
......@@ -251,7 +262,8 @@ export function hljsLanguages(): any {
},
{provide: MAT_DATE_LOCALE, useValue: navigator.language},
{provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]},
{provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS},
//{provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS},
{provide: MAT_DATE_FORMATS, useValue: CUSTOM_DATE_FORMATS},
ErrorsSkipperService,
{provide: HIGHLIGHT_OPTIONS, useValue: {languages: hljsLanguages}},
],
......@@ -261,6 +273,11 @@ export function hljsLanguages(): any {
bootstrap: [AppComponent],
})
export class AppModule {
constructor(private translate: TranslateService) {
translate.addLangs(["en", "de", "fr"]);
translate.setDefaultLang("fr");
translate.use("fr");
}
}
// required for AOT compilation
......
......@@ -104,6 +104,7 @@
[for]="openingDateDatepicker"
></mat-datepicker-toggle>
<mat-datepicker [touchUi]="breakpointService.isSmallerThanMd()"
(opened)="changeLanguage()"
#openingDateDatepicker
></mat-datepicker>
</mat-form-field>
......@@ -118,6 +119,7 @@
[for]="closingDateDatepicker"
></mat-datepicker-toggle>
<mat-datepicker [touchUi]="breakpointService.isSmallerThanMd()"
(opened)="changeLanguage()"
#closingDateDatepicker
></mat-datepicker>
</mat-form-field>
......
......@@ -11,9 +11,11 @@ import {
FormBuilder,
Validators,
} from "@angular/forms";
import {DateAdapter} from "@angular/material/core";
import {NotificationHelper} from "@app/features/preservation-space/notification/helper/notification.helper";
import {BreakpointService} from "@app/shared/services/breakpoint.service";
import {sharedResearchDomainActionNameSpace} from "@app/shared/stores/research-domain/shared-research-domain.action";
import {AppState} from "@app/stores/app.state";
import {environment} from "@environments/environment";
import {
DisseminationPolicy,
......@@ -26,6 +28,7 @@ import {
Role,
SubmissionPolicy,
} from "@models";
import {Store} from "@ngxs/store";
import {SharedAbstractFormPresentational} from "@shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational";
import {PersonOrgUnitRoleMode} from "@shared/components/presentationals/shared-person-orgunit-role/shared-person-orgunit-role.presentational";
import {SharedSearchableSingleSelectPresentational} from "@shared/components/presentationals/shared-searchable-single-select/shared-searchable-single-select.presentational";
......@@ -53,6 +56,7 @@ import {
isNullOrUndefined,
MappingObject,
MappingObjectUtil,
MemoizedUtil,
OrderEnum,
PropertyName,
ResourceNameSpace,
......@@ -154,6 +158,8 @@ export class AdminOrganizationalUnitFormPresentational extends SharedAbstractFor
constructor(protected readonly _changeDetectorRef: ChangeDetectorRef,
protected readonly _elementRef: ElementRef,
private readonly _fb: FormBuilder,
private readonly _store: Store,
private readonly dateAdapter: DateAdapter<Date>,
public readonly breakpointService: BreakpointService) {
super(_changeDetectorRef, _elementRef);
}
......@@ -290,6 +296,11 @@ export class AdminOrganizationalUnitFormPresentational extends SharedAbstractFor
this._computeExtraSearchParameterCategory(source);
}
changeLanguage(): void {
const selectedLanguage = MemoizedUtil.selectSnapshot(this._store, AppState, state => state.appLanguage);
this.dateAdapter.setLocale(selectedLanguage);
}
private _creationForUserAskingInNotificationRequest(): void {
if (isNullOrUndefined(this.urlQueryParameters) || MappingObjectUtil.size(this.urlQueryParameters) === 0) {
return;
......
......@@ -64,6 +64,7 @@
[for]="publicationDateDatepicker"
></mat-datepicker-toggle>
<mat-datepicker [touchUi]="breakpointService.isSmallerThanMd()"
(opened)="changeLanguage()"
#publicationDateDatepicker
></mat-datepicker>
<mat-error #errors></mat-error>
......@@ -364,6 +365,7 @@
[for]="collectionBeginDatepicker"
></mat-datepicker-toggle>
<mat-datepicker [touchUi]="breakpointService.isSmallerThanMd()"
(opened)="changeLanguage()"
#collectionBeginDatepicker
></mat-datepicker>
<mat-error #errors></mat-error>
......@@ -385,6 +387,7 @@
[for]="collectionEndDatepicker"
></mat-datepicker-toggle>
<mat-datepicker [touchUi]="breakpointService.isSmallerThanMd()"
(opened)="changeLanguage()"
#collectionEndDatepicker
></mat-datepicker>
<mat-error #errors></mat-error>
......
......@@ -57,7 +57,7 @@ import {
isNotNullNorUndefined,
isNullOrUndefined,
KeyValue,
MappingObjectUtil,
MappingObjectUtil, MemoizedUtil,
OrderEnum,
PropertyName,
ResourceNameSpace,
......@@ -66,6 +66,9 @@ import {
urlSeparator,
EnumUtil,
} from "solidify-frontend";
import {DateAdapter} from "@angular/material/core";
import {AppState} from "@app/stores/app.state";
import {Store} from "@ngxs/store";
@Component({
selector: "dlcm-deposit-form",
......@@ -162,7 +165,9 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
private readonly _fb: FormBuilder,
private readonly dialog: MatDialog,
public readonly breakpointService: BreakpointService,
private readonly _translateService: TranslateService) {
private readonly _translateService: TranslateService,
private readonly _store: Store,
private readonly dateAdapter: DateAdapter<Date>) {
super(_changeDetectorRef, _elementRef);
}
......@@ -187,7 +192,6 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
}),
));
}
protected initNewForm(): void {
this.initEmbargoAccessLevel(Enums.Deposit.AccessEnum.PUBLIC);
let formDesc = {
......@@ -386,6 +390,11 @@ export class DepositFormPresentational extends SharedAbstractFormPresentational<
return Enums.Deposit.StatusEnumTranslate;
}
changeLanguage(): void {
const selectedLanguage = MemoizedUtil.selectSnapshot(this._store, AppState, state => state.appLanguage);
this.dateAdapter.setLocale(selectedLanguage);
}
}
class FormComponentFormDefinition extends BaseFormDefinition {
......
......@@ -98,6 +98,7 @@
[for]="openingDateDatepicker"
></mat-datepicker-toggle>
<mat-datepicker [touchUi]="breakpointService.isSmallerThanMd()"
(opened)="changeLanguage()"
#openingDateDatepicker
></mat-datepicker>
</mat-form-field>
......@@ -114,6 +115,7 @@
[for]="closingDateDatepicker"
></mat-datepicker-toggle>
<mat-datepicker [touchUi]="breakpointService.isSmallerThanMd()"
(opened)="changeLanguage()"
#closingDateDatepicker
></mat-datepicker>
</mat-form-field>
......
......@@ -11,7 +11,9 @@ import {
FormBuilder,
Validators,
} from "@angular/forms";
import {DateAdapter} from "@angular/material/core";
import {NotificationHelper} from "@app/features/preservation-space/notification/helper/notification.helper";
import {AppState} from "@app/stores/app.state";
import {environment} from "@environments/environment";
import {
OrganizationalUnit,
......@@ -21,6 +23,7 @@ import {
SubmissionPolicy,
} from "@models";
import {Navigate} from "@ngxs/router-plugin";
import {Store} from "@ngxs/store";
import {SharedAbstractFormPresentational} from "@shared/components/presentationals/shared-abstract-form/shared-abstract-form.presentational";
import {PersonOrgUnitRoleMode} from "@shared/components/presentationals/shared-person-orgunit-role/shared-person-orgunit-role.presentational";
import {LocalModelAttributeEnum} from "@shared/enums/model-attribute.enum";
......@@ -46,6 +49,7 @@ import {
MappingObject,
MappingObjectUtil,
MARK_AS_TRANSLATABLE,
MemoizedUtil,
NotificationService,
ObservableUtil,
OrderEnum,
......@@ -110,6 +114,8 @@ export class PreservationSpaceOrganizationalUnitFormPresentational extends Share
constructor(protected readonly _changeDetectorRef: ChangeDetectorRef,
protected readonly _elementRef: ElementRef,
private readonly _fb: FormBuilder,
private readonly _store: Store,
private readonly dateAdapter: DateAdapter<Date>,
public readonly breakpointService: BreakpointService,
private readonly _notificationService: NotificationService,
public readonly securityService: SecurityService) {
......@@ -205,6 +211,11 @@ export class PreservationSpaceOrganizationalUnitFormPresentational extends Share
this._computeExtraSearchParameterCategory(source);
}
changeLanguage(): void {
const selectedLanguage = MemoizedUtil.selectSnapshot(this._store, AppState, state => state.appLanguage);
this.dateAdapter.setLocale(selectedLanguage);
}
private _computeExtraSearchParameterCategory(value: string): void {
if (isNullOrUndefined(value) || isEmptyString(value)) {
MappingObjectUtil.delete(this.extraSearchParameterSource, this.KEY_SOURCE as string);
......
import {DatePipe} from "@angular/common";
import {NativeDateAdapter} from "@angular/material/core";
export interface DateDisplay {
year: string;
month: string;
day: string;
}
export const CUSTOM_DATE_FORMATS = {
parse: {
dateInput: {month: "short", year: "numeric", day: "numeric"}
},
display: {
dateInput: "customInput",
monthYearLabel: {year: "numeric", month: "short"},
dateA11yLabel: {year: "numeric", month: "long", day: "numeric"},
monthYearA11yLabel: {year: "numeric", month: "long"},
}
};
export class CustomDatePickerAdapter extends NativeDateAdapter {
parse(value: string | number): Date | null {
if ((typeof value === "string") && (value.indexOf(".") > -1)) {
const str: string[] = value.split(".");
if (str.length < 2 || isNaN(+str[0]) || isNaN(+str[1]) || isNaN(+str[2])) {
return null;
}
return new Date(Number(str[2]), Number(str[1]) - 1, Number(str[0]));
}
const timestamp: number = typeof value === "number" ? value : Date.parse(value);
return isNaN(timestamp) ? null : new Date(timestamp);
}
format(date: Date, display: string | DateDisplay): string {
if (display === "customInput") {
return new DatePipe(this.locale).transform(date, "shortDate");
} else {
if (this.locale === "fr") {
return new DatePipe(this.locale).transform(date, "dd.MM.yyyy");
} else {
return new DatePipe(this.locale).transform(date, "MM/dd/yyyy");
}
}
}
}
......@@ -7,6 +7,7 @@ import {
FormsModule,
ReactiveFormsModule,
} from "@angular/forms";
import {DateAdapter, MAT_DATE_FORMATS} from "@angular/material/core";
import {
MAT_DIALOG_DEFAULT_OPTIONS,
MatDialogConfig,
......@@ -79,6 +80,7 @@ import {SharedSnackbarPresentational} from "@shared/components/presentationals/s
import {SharedStarRatingPresentational} from "@shared/components/presentationals/shared-star-rating/shared-star-rating.presentational";
import {SharedTocPresentational} from "@shared/components/presentationals/shared-toc/shared-toc.presentational";
import {SharedUrlInputNavigationPresentational} from "@shared/components/presentationals/shared-url-input-navigation/shared-url-input-navigation.presentational";
import {CUSTOM_DATE_FORMATS, CustomDatePickerAdapter} from "@shared/date-adapter";
import {SharedAlternativeButtonDirective} from "@shared/directives/shared-alternative-button/shared-alternative-button.directive";
import {SharedButtonSpinnerDirective} from "@shared/directives/shared-button-spinner/shared-button-spinner.directive";
import {SharedDataTestDirective} from "@shared/directives/shared-data-test/shared-data-test.directive";
......@@ -309,6 +311,7 @@ const modules = [
{provide: FILE_VISUALIZERS, useClass: MolFileVisualizerService, multi: true},
{provide: FILE_VISUALIZERS, useClass: TextFileVisualizerService, multi: true},
{provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: {panelClass: "dlcm-dialogs", hasBackdrop: true} as MatDialogConfig},
{provide: DateAdapter, useClass: CustomDatePickerAdapter},
// TODO reactive this class when find a solution for public url to visualize all type of document
//{provide: FILE_VISUALIZERS, useClass: Ng2XsViewerVisualizerService, multi: true},
// TODO use Video VideoFileVisualizerService when all video will be supported and when add a converter
......
import {PersonRole} from "@admin/models/person-role.model";
import {HttpClient} from "@angular/common/http";
import {Injectable} from "@angular/core";
import {DateAdapter} from "@angular/material/core";
import {RoutesEnum} from "@app/shared/enums/routes.enum";
import {SessionStorageEnum} from "@app/shared/enums/session-storage.enum";
import {ThemeEnum} from "@app/shared/enums/theme.enum";
......@@ -161,6 +162,7 @@ export class AppState extends BasicState<AppStateModel> {
private apiService: ApiService,
private httpClient: HttpClient,
private notificationService: NotificationService,
private dateAdapter: DateAdapter<Date>,
private readonly _actions$: Actions) {
super();
}
......@@ -356,6 +358,7 @@ export class AppState extends BasicState<AppStateModel> {
});
sessionStorage.setItem(SessionStorageEnum.language, action.language);
this.dateAdapter.setLocale(action.language);
return this.translate.use(action.language).pipe(
tap(() => {
ctx.dispatch(new AppAction.ChangeAppLanguageSuccess(action));
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment