Skip to content

Commit

Permalink
feat(front): add internalization with i18n
Browse files Browse the repository at this point in the history
- Add english , french json
- Add language selection in navbar
- Apply variable from i18n json for all static text
- Use local storage to persist language chosen
- Check browser local to set default value at start app

Reviewed-by: andriacap
  • Loading branch information
andriacap committed Oct 25, 2024
1 parent 1d84aac commit 659c3d8
Show file tree
Hide file tree
Showing 18 changed files with 25,845 additions and 11,205 deletions.
36,490 changes: 25,382 additions & 11,108 deletions admin/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"@asymmetrik/ngx-leaflet-draw": "^4.0.0",
"@ng-bootstrap/ng-bootstrap": "^4.0.0",
"@ng-select/ng-select": "^2.12.1",
"@ngx-translate/core": "^11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
"@swimlane/ngx-datatable": "^14.0.0",
"@syncfusion/ej2-angular-richtexteditor": "^18.1.54",
"@types/jsts": "^0.17.12",
Expand Down
25 changes: 10 additions & 15 deletions admin/src/app/add-photo/add-photo.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,23 @@ <h5 class="modal-title">{{title}} </h5>
<div class="modal-body">
<button *ngIf="inputImage && currentUser.max_level_profil > 5" type="button" class="btn btn-outline-danger btn-delete"
(click)="openDeleteModal(photoModal)">
<i class="icon-bin delete-photo"></i>Supprimer
la photo</button>
<i class="icon-bin delete-photo"></i>"{{ 'ACTIONS.DELETE' | translate: {article:('ARTICLES.LA' | translate), varname: ('COMMONS.PICTURE' | translate) } }}</button>
<div class="inner-checkbox form-group">
<div class="label">Publier la photo :</div>
<div class="label">{{ 'ACTIONS.PUBLISH' | translate: {article:('ARTICLES.LA' | translate), varname: ('COMMONS.PICTURE' | translate) } }} :</div>
<label class="switch ">
<input formControlName="display_gal_photo" type="checkbox" class="success">
<span class="slider round"></span>
</label>
</div>
<div class="row form-item">
<div class="col ">
<label class="label" for="datePhoto">Date approximative </label>
<label class="label" for="datePhoto">{{'GALLERY_MNGMT.APPROXIMATE_DATE' | translate}}</label>
<input InputFeedBack type="text" formControlName="date_photo" id="datePhoto" class="form-control"
placeholder="Date Photo">
<app-form-error controlName="date_photo" errorKey="required"></app-form-error>
</div>
<div class="col ">
<label class="label" for="sousTheme">DATE DE PRISE DE VUE*</label>
<label class="label" for="sousTheme">{{'GALLERY_MNGMT.SHOOTING_DATE' | translate}}*</label>
<div class="input-group">
<input InputFeedBack formControlName="filter_date" class="form-control" placeholder="yyyy-mm-dd"
ngbDatepicker #dto="ngbDatepicker">
Expand All @@ -45,7 +44,7 @@ <h5 class="modal-title">{{title}} </h5>
</div>
<div class="row form-item">
<div class="col">
<label class="label" for="licence">CRÉDIT PHOTOGRAPHIQUE</label>
<label class="label" for="licence">{{'GALLERY_MNGMT.PICTURE_CREDITS' | translate}}</label>
<select InputFeedBack id="licence" formControlName="id_licence_photo" class="form-control">
<option class="select-placeholder" value="">---</option>
<option *ngFor="let licence of licences" [ngValue]="licence.id_licence_photo">{{licence.name_licence_photo}}
Expand All @@ -61,19 +60,18 @@ <h5 class="modal-title">{{title}} </h5>
<input InputFeedBack style="display: none" formControlName="photo_file" accept="image/x-png,image/gif,image/jpeg"
type="file" (change)=onFileSelected($event) #iamgeInput>
<button type="button" *ngIf="!imageLaoded" class="blue-btn" (click)="iamgeInput.click()"><i
class="icon-download"></i>Importer
une photo</button>
class="icon-download"></i>{{'ACTIONS.IMPORT' | translate: {article:('ARTICLES.UNE' | translate), varname: ('COMMONS.PICTURE' | translate) } }}</button>
<app-form-error controlName="photo_file" errorKey="required"></app-form-error>
<div *ngIf="imageLaoded" style="color: #00188F;"><i class="icon-camera"></i>{{imageName}}<i
*ngIf="currentUser.max_level_profil > 5" class="icon-bin remove-file " (click)="removeImage()"></i></div>
<ngb-alert class='alert' *ngIf="alert" [dismissible]="false" type="danger">{{alert}}</ngb-alert>
<div class="custom-control custom-checkbox">
<input type="checkbox" formControlName='main_photo' class="custom-control-input" id="customCheck1">
<label class="custom-control-label" for="customCheck1">Définir comme vignette principale</label>
<label class="custom-control-label" for="customCheck1">{{'GALLERY_MNGMT.THUMBNAIL_MAIN_MESSAGE' | translate}}</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="red-btn" style="margin-right: 10px" (click)="onCancel()">Annuler</button>
<button type="button" class="red-btn" style="margin-right: 10px" (click)="onCancel()">{{'BUTTONS.CANCEL' | translate}}</button>
<button type="submit" class="green-btn" [disabled]="disableButton">{{btn_text}}</button>
</div>
</form>
Expand All @@ -84,13 +82,10 @@ <h5 class="modal-title">{{title}} </h5>
<div class="modal-header">
<h5 class="modal-title"><i class="icon-bin"></i></h5>
</div>
<div class="modal-body">
Êtes-vous sûr de vouloir supprimer cette photo ?
<br>
Sa suppression sera définitive
<div class="modal-body" [innerHTML]="'GALLERY_MNGMT.CONFIRM_DELETE.BODY' | translate">
</div>
<div class="modal-footer">
<button type="button" class="cancel-btn" style="margin-right: 10px" (click)="cancelDelete()">ANNULER</button>
<button type="button" class="cancel-btn" style="margin-right: 10px" (click)="cancelDelete()">{{'BUTTONS.CANCEL' | translate}}</button>
<button type="button" class="green-btn" (click)="deletePhoto()">OUI</button>
</div>
</ng-template>
4 changes: 2 additions & 2 deletions admin/src/app/add-photo/add-photo.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ export class AddPhotoComponent implements OnInit {
imageLaoded = false;
private modalRef: NgbModalRef;
disableButton = false;
btn_text = 'Ajouter';
title = 'Ajouter une photo';
btn_text = 'ACTIONS.ADD';
title = "{{ 'ACTIONS.ADD' | translate: {article:('ARTICLES.UNE' | translate), varname: ('COMMONS.PICTURE' | translate) } }}";
alert: any;
@Output() photoModal = new EventEmitter();
@Input() inputImage = null;
Expand Down
62 changes: 29 additions & 33 deletions admin/src/app/add-site/add-site.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<div *ngIf="loadForm" class="site-block">
<form [formGroup]="siteForm" (submit)="submitSite(siteForm)" disabled>
<div class="inner-checkbox form-group">
<div class="label">Publier:</div>
<div class="label">{{ 'ACTIONS.PUBLISH_DEFAULT' | translate }}:</div>
<label class="switch">
<input formControlName="publish_site" type="checkbox" class="success form-control" />
<span [ngClass]="{
Expand All @@ -16,21 +16,21 @@
</div>
<div class="row form-item">
<div class="col">
<label class="label" for="site-name">Nom du site*</label>
<label class="label" for="site-name">{{ 'FIELDS.NAME' | translate: {article: ('ARTICLES.DU' | translate), varname: ('SITE_MNGMT.SITE' | translate) } }}*</label>
<input InputFeedBack type="text" formControlName="name_site" id="site-name" class="form-control"
placeholder="nom du site" />
placeholder="{{ 'FIELDS.NAME' | translate: {varname: ('SITE_MNGMT.SITE' | translate) } }}" />
<app-form-error controlName="name_site" errorKey="required"></app-form-error>
</div>
<div class="col">
<label class="label" for="site-name">RÉFÉRENCE</label>
<label class="label" for="site-name">{{ 'COMMONS.REFERENCE' | translate }}</label>
<input InputFeedBack type="text" formControlName="ref_site" id="reference" class="form-control"
placeholder="référence" />
placeholder="{{'COMMONS.REFERENCE' | translate }}" />
<app-form-error controlName="ref_site" errorKey="required"></app-form-error>
</div>
</div>
<div class="row form-item">
<div class="col">
<label class="label" for="id_observatory">Observatoire*</label>
<label class="label" for="id_observatory">{{'SITE_MNGMT.OBSERVATORY' | translate}}*</label>
<select InputFeedBack formControlName="id_observatory" id="id_observatory" class="form-control">
<option class="select-placeholder" value="">---</option>
<option *ngFor="let observatory of observatories" [ngValue]="observatory.id">
Expand All @@ -40,7 +40,7 @@
<app-form-error controlName="id_observatory" errorKey="required"></app-form-error>
</div>
<div class="col">
<label class="label" for="city-code">Commune*</label>
<label class="label" for="city-code">{{'SITE_MNGMT.CITY' | translate}}*</label>
<select InputFeedBack formControlName="code_city_site" id="city-code" class="form-control">
<option class="select-placeholder" value="">---</option>
<option *ngFor="let commune of communes" [ngValue]="commune.code_commune">
Expand All @@ -52,9 +52,9 @@
</div>
<div class="row form-item">
<div class="col">
<label class="label" for="theme">Thèmes*</label>
<label class="label" for="theme">{{'SITE_MNGMT.THEME' | translate}}*</label>
<ng-select InputFeedBack formControlName="id_theme" [items]="themes" [multiple]="true"
[closeOnSelect]="false" bindValue="id_theme" bindLabel="name_theme" placeholder="select thèmes">
[closeOnSelect]="false" bindValue="id_theme" bindLabel="name_theme" placeholder="{{ 'ACTIONS.SELECT' | translate: {article:('ARTICLES.LE' | translate), varname: ('SITE_MNGMT.THEME' | translate) } }}">
<ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index">
<input id="item-{{ index }}" [checked]="item$.selected" type="checkbox" />
{{ item.name_theme }}
Expand All @@ -63,9 +63,9 @@
<app-form-error controlName="id_theme" errorKey="required"></app-form-error>
</div>
<div class="col">
<label class="label" for="sousTheme">Sous-thèmes*</label>
<label class="label" for="sousTheme">{{'SITE_MNGMT.SUBTOPIC' | translate}}*</label>
<ng-select InputFeedBack formControlName="id_stheme" [items]="selectedSubthemes" [multiple]="true"
[closeOnSelect]="false" bindValue="id_stheme" bindLabel="name_stheme" placeholder="select sous-thèmes">
[closeOnSelect]="false" bindValue="id_stheme" bindLabel="name_stheme" placeholder="{{ 'ACTIONS.SELECT' | translate: {article:('ARTICLES.LE' | translate), varname: ('SITE_MNGMT.SUBTOPIC' | translate) } }}">
<ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index">
<input id="item-{{ index }}" [checked]="item$.selected" type="checkbox" />
{{ item.name_stheme }}
Expand All @@ -76,7 +76,7 @@
</div>
<div class="row form-item">
<div class="col">
<label class="label" for="main-theme-id">Thème principal</label>
<label class="label" for="main-theme-id">{{'SITE_MNGMT.MAIN_THEME' | translate}}</label>
<select InputFeedBack formControlName="main_theme_id" id="main-theme-id" class="form-control">
<option class="select-placeholder" value="">---</option>
<option *ngFor="let theme of themes" [ngValue]="theme.id_theme">
Expand All @@ -88,45 +88,45 @@
</div>
<div class="row form-item">
<div class="col">
<label class="label" for="longitude">Longitude*</label>
<label class="label" for="longitude">{{'SITE_MNGMT.LONGITUDE' | translate}}*</label>
<input InputFeedBack type="number" formControlName="lng" id="longitude" class="form-control"
placeholder="longitude" />
placeholder="{{'SITE_MNGMT.LONGITUDE' | translate}}" />
<app-form-error controlName="lng" errorKey="lng"></app-form-error>
</div>
<div class="col">
<label class="label" for="latitude">Latitude*</label>
<label class="label" for="latitude">{{'SITE_MNGMT.LATITUDE' | translate}}*</label>
<input InputFeedBack type="number" formControlName="lat" id="latitude" class="form-control"
placeholder="latitude" />
placeholder="{{'SITE_MNGMT.LATITUDE' | translate}}" />
<app-form-error controlName="lat" errorKey="lat"></app-form-error>
</div>
</div>
<div class="form-group">
<label class="label" for="legend_site">Légende*</label>
<label class="label" for="legend_site">{{'SITE_MNGMT.LEGEND' | translate}}*</label>
<textarea InputFeedBack class="form-control" formControlName="legend_site"
placeholder="Ecrivez ici la description du site" id="legend_site" rows="2"></textarea>
placeholder="{{'SITE_MNGMT.PLACEHOLDER_LEGEND' | translate}}" id="legend_site" rows="2"></textarea>
<app-form-error controlName="legend_site" errorKey="required"></app-form-error>
</div>
<div class="form-group">
<label class="label" for="desc">DESCRIPTION</label>
<label class="label" for="desc">{{'SITE_MNGMT.DESCRIPTION' | translate}}</label>
<div id="descRTE">
<ejs-richtexteditor #defaultRTE id='desc' [toolbarSettings]='tools' InputFeedBack formControlName="desc_site" placeholder="Ecrivez ici la description du site">
<ejs-richtexteditor #defaultRTE id='desc' [toolbarSettings]='tools' InputFeedBack formControlName="desc_site" placeholder="{{'SITE_MNGMT.PLACEHOLDER_DESC' | translate}}">
<ng-template #descRTE></ng-template>
</ejs-richtexteditor>
</div>
<app-form-error controlName="desc_site" errorKey="required"></app-form-error>
</div>
<div class="form-group">
<label class="label" for="testim">TÉMOIGNAGES</label>
<label class="label" for="testim">{{'SITE_MNGMT.TESTIMONIALS' | translate}}</label>
<div id="testimRTE">
<ejs-richtexteditor #defaultRTE id='testim' [toolbarSettings]='tools' InputFeedBack formControlName="testim_site" placeholder="Ecrivez ici les témoignages">
<ejs-richtexteditor #defaultRTE id='testim' [toolbarSettings]='tools' InputFeedBack formControlName="testim_site" placeholder="{{'SITE_MNGMT.PLACEHOLDER_TESTIMONIALS' | translate}}">
<ng-template #testimRTE></ng-template>
</ejs-richtexteditor>
</div>
<app-form-error controlName="testim_site" errorKey="required"></app-form-error>
</div>

<div class="form-group">
<label class="label">Photos de site*</label> <small>Conseil : Utiliser des jpeg de même ratio, assez grand mais larg. &lt; 5000px, poids &lt; 5Mo</small>
<label class="label">{{'SITE_MNGMT.SITE_PHOTO' | translate}}*</label> <small> {{ 'COMMONS.ADVICE' | translate}} : {{'SITE_MNGMT.JPEG_INSTRUCTIONS' | translate}}</small>
<div class="preview">
<div class="inner-photo" *ngFor="let photo of photos">
<img *ngIf="photo.imgUrl" class="preview-img" width="120" height="120" [src]="photo.imgUrl" />
Expand All @@ -142,9 +142,9 @@
<input class="form-group" formControlName="notice" style="display: none" type="file"
(change)="noticeSelect($event)" accept="application/pdf" #noticeInput />
<button *ngIf="!noticeName && edit_btn" class="blue-btn" type="button" (click)="noticeInput.click()">
<i class="icon-download"></i> Importer la notice technique
<i class="icon-download"></i>{{ 'ACTIONS.IMPORT' | translate: {article:('ARTICLES.LA' | translate), varname: ('SITE_MNGMT.NOTICE_LABEL' | translate) } }}
</button>
<label *ngIf="noticeName" class="label">notice :</label>
<label *ngIf="noticeName" class="label">{{'SITE_MNGMT.NOTICE_LABEL' | translate}}:</label>
<div *ngIf="noticeName" style="color: #00188f">
{{ noticeName
}}<i *ngIf="edit_btn" class="icon-bin remove-file" (click)="removeNotice()"></i>
Expand All @@ -155,17 +155,17 @@
<div class="submit-btn-group">
<button type="button" *ngIf="id_site" class="btn btn-outline-warning btn-edit"
[class.active_edit]="edit_btn" (click)="editForm()">
<i class="icon-pencil"></i>{{ edit_btn_text }}
<i class="icon-pencil"></i>{{ edit_btn_text | translate }}
</button>
<button class="btn btn-outline-success btn-submit" type="submit" [disabled]="!edit_btn">
{{ submit_btn_text }}
{{ submit_btn_text | translate }}
</button>
<button type="button" *ngIf="id_site && currentUser.max_level_profil > 5"
class="btn btn-outline-danger btn-delete" (click)="openDeleteModal(content)">
<i class="icon-bin delete-site"></i>Supprimer le site
</button>
<button class="btn btn-outline-secondary btn-cancel" type="button" (click)="onCancel()">
Retour à la liste
{{ 'BUTTONS.BACK_TO_LIST' | translate }}
</button>
</div>
</form>
Expand All @@ -183,11 +183,7 @@
<div class="modal-header">
<h5 class="modal-title"><i class="icon-bin"></i></h5>
</div>
<div class="modal-body">
Êtes-vous sûr de vouloir supprimer ce Site ?
<br />
Sa suppression sera définitive
</div>
<div class="modal-body" [innerHTML]="'SITE_MNGMT.CONFIRM_DELETE.BODY' | translate"></div>
<div class="modal-footer">
<button type="button" class="cancel-btn" style="margin-right: 10px" (click)="cancelDelete()">
ANNULER
Expand Down
11 changes: 6 additions & 5 deletions admin/src/app/add-site/add-site.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ export class AddSiteComponent implements OnInit, OnDestroy {
alert: { type: string; message: string };
site: any;
edit_btn = false;
edit_btn_text = 'Éditer';
submit_btn_text = 'Ajouter';
edit_btn_text = 'BUTTONS.EDIT';
submit_btn_text = 'BUTTONS.ADD';
initPhotos: any[] = [];
deleted_photos = [];
new_photos = [];
Expand Down Expand Up @@ -130,7 +130,7 @@ export class AddSiteComponent implements OnInit, OnDestroy {
this.observatories = results[3];
if (this.id_site) {
this.getSite(this.id_site);
this.submit_btn_text = 'Enregistrer';
this.submit_btn_text = 'BUTTONS.SUBMIT';
} else {
this.edit_btn = true;
this.loadForm = true;
Expand Down Expand Up @@ -382,7 +382,7 @@ export class AddSiteComponent implements OnInit, OnDestroy {
console.log('err upload photo', err);
this.spinner.hide();
if (err.error.error === 'image_already_exist') {
this.edit_btn_text = 'Annuler';
this.edit_btn_text = 'BUTTONS.CANCEL';
this.edit_btn = true;
this.setAlert(err.error.image);
} else if (err.status === 403) {
Expand Down Expand Up @@ -648,7 +648,7 @@ export class AddSiteComponent implements OnInit, OnDestroy {
this.initMarker(this.site.geom[0], this.site.geom[1]);
} else {
this.map.addControl(this.drawControl);
this.edit_btn_text = 'Annuler';
this.edit_btn_text = 'BUTTONS.CANCEL';
this.siteForm.enable();
}
this.siteForm.controls['id_stheme'].setValue(this.site.subthemes);
Expand Down Expand Up @@ -689,6 +689,7 @@ export class AddSiteComponent implements OnInit, OnDestroy {
this.deleted_photos.push(photo);
}

// TODO: Traduire les messages liés aux toasts
deleteSite() {
this.sitesService.deleteSite(this.id_site).subscribe(
(res) => {
Expand Down
Loading

0 comments on commit 659c3d8

Please sign in to comment.