commit 18dbad838b640eeac629265d2be5b3296f3761ee
Author: Václav Jirák <jirakv95@gmail.com>
Date:   Wed May 15 01:52:39 2019 +0200

    Re #7475 Implemented basic localization with usage examples

diff --git a/webapp/package.json b/webapp/package.json
index a0c0fd5..25e8cc2 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -23,6 +23,8 @@
     "@angular/platform-browser-dynamic": "~7.2.0",
     "@angular/router": "~7.2.0",
     "@ng-bootstrap/ng-bootstrap": "^4.1.1",
+    "@ngx-translate/core": "^11.0.1",
+    "@ngx-translate/http-loader": "^4.0.0",
     "angular-calendar": "^0.27.5",
     "angularx-flatpickr": "^6.1.0",
     "core-js": "^2.5.4",
diff --git a/webapp/src/app/app.module.ts b/webapp/src/app/app.module.ts
index 6462ff4..665f1b7 100644
--- a/webapp/src/app/app.module.ts
+++ b/webapp/src/app/app.module.ts
@@ -7,9 +7,11 @@ import { MenuComponent } from './menu/menu.component';
 import { DashboardModule } from './dashboard/dashboard.module';
 import { HeaderComponent } from './header/header.component';
 import { MatDialogModule } from '@angular/material';
-import {ProfileSettingsModule} from './profile-settings/profile-settings.module';
-import {HttpClientModule} from '@angular/common/http';
-import {EmployeesModule} from './employees/employees.module';
+import { ProfileSettingsModule } from './profile-settings/profile-settings.module';
+import { HttpClient, HttpClientModule } from '@angular/common/http';
+import { EmployeesModule } from './employees/employees.module';
+import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
+import { TranslateHttpLoader } from '@ngx-translate/http-loader';
 
 @NgModule({
   declarations: [
@@ -21,6 +23,13 @@ import {EmployeesModule} from './employees/employees.module';
     BrowserModule,
     HttpClientModule,
     AppRoutingModule,
+    TranslateModule.forRoot({
+      loader: {
+        provide: TranslateLoader,
+        useFactory: HttpLoaderFactory,
+        deps: [HttpClient]
+      }
+    }),
     DashboardModule,
     MatDialogModule,
     ProfileSettingsModule,
@@ -30,3 +39,7 @@ import {EmployeesModule} from './employees/employees.module';
   bootstrap: [AppComponent]
 })
 export class AppModule { }
+
+export function HttpLoaderFactory(http: HttpClient) {
+  return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
+}
diff --git a/webapp/src/app/dashboard/employer-dashboard/employer-dashboard.component.ts b/webapp/src/app/dashboard/employer-dashboard/employer-dashboard.component.ts
index 9c84fec..ea80567 100644
--- a/webapp/src/app/dashboard/employer-dashboard/employer-dashboard.component.ts
+++ b/webapp/src/app/dashboard/employer-dashboard/employer-dashboard.component.ts
@@ -5,7 +5,8 @@ import {UsersService} from '../../services/users.service';
 import {Requests} from '../../models/requests.model';
 import {UserProfile} from '../../models/user-profile.model';
 import {UserService} from '../../services/user.service';
-import {ProfileService} from "../../services/profile.service";
+import {ProfileService} from '../../services/profile.service';
+import {TimeUnit} from '../../enums/common.enum';
 
 @Component({
   selector: 'app-employer-dashboard',
@@ -27,14 +28,35 @@ export class EmployerDashboardComponent implements OnInit {
   ) { }
 
   ngOnInit() {
-    this.profileService.getProfile()
-      .subscribe((data: UserProfile) => this.profile = data);
+    // this.profileService.getProfile()
+    //   .subscribe((data: UserProfile) => this.profile = data);
+    //
+    // this.usersService.getAuthorizationRequests()
+    //   .subscribe((data: Requests) => this.authorizationRequests = data);
+    //
+    // this.usersService.getVacationRequests()
+    //   .subscribe((data: Requests) => this.daysOffRequests = data);
 
-    this.usersService.getAuthorizationRequests()
-      .subscribe((data: Requests) => this.authorizationRequests = data);
-
-    this.usersService.getVacationRequests()
-      .subscribe((data: Requests) => this.daysOffRequests = data);
+    // Tmp mock
+    this.profile = {
+      id: 1,
+      name: {
+        first: 'Jon',
+        last: 'Doe',
+      },
+      photo: 'http://mosaddek.com/theme/diverse/assets/img/user1.png',
+      settings: {
+        notification: new Date(2019, 3, 25, 18, 0)
+      },
+      vacation: {
+        value: 5,
+        unit: TimeUnit.DAY,
+      },
+      sickDay: {
+        value: 10,
+        unit: TimeUnit.DAY
+      }
+    };
   }
 
   private userApproved(requestId: number, approved: boolean) {
diff --git a/webapp/src/app/day-picker/day-picker.component.html b/webapp/src/app/day-picker/day-picker.component.html
index 33de3cb..54186b2 100644
--- a/webapp/src/app/day-picker/day-picker.component.html
+++ b/webapp/src/app/day-picker/day-picker.component.html
@@ -25,11 +25,13 @@
     </div>
   </div>
 
+  <!-- Refresh attribute for localization purposes (refresh component after change of language -->
   <mwl-calendar-month-view
     [viewDate]="viewDate"
     (dayClicked)="dayClicked($event.day)"
     weekStartsOn="1"
     [locale]="locale"
+    [refresh]="localizationService.currentLanguage"
   >
   </mwl-calendar-month-view>
 </div>
diff --git a/webapp/src/app/day-picker/day-picker.component.ts b/webapp/src/app/day-picker/day-picker.component.ts
index e068c58..74941ba 100644
--- a/webapp/src/app/day-picker/day-picker.component.ts
+++ b/webapp/src/app/day-picker/day-picker.component.ts
@@ -1,5 +1,6 @@
 import { Component, ChangeDetectionStrategy, Output, EventEmitter } from '@angular/core';
 import { CalendarView } from 'angular-calendar';
+import {LocalizationService} from '../localization/localization.service';
 
 @Component({
   selector: 'app-day-picker',
@@ -9,8 +10,7 @@ import { CalendarView } from 'angular-calendar';
 })
 export class DayPickerComponent {
 
-  // TODO Move to language service
-  locale = 'cs';
+  private locale;
 
   // Type of calendar (constant)
   view: CalendarView = CalendarView.Month;
@@ -21,6 +21,14 @@ export class DayPickerComponent {
   // EventEmitter informing about changes of selected date
   @Output() selectedDate = new EventEmitter<Date>();
 
+  constructor(private localizationService: LocalizationService) {
+    this.locale = localizationService.defaultLanguage;
+    localizationService.currentLanguage
+      .subscribe((data) => {
+        this.locale = data;
+      });
+  }
+
   /**
    * Method that is invoked when user clicks on a day.
    * Sets selected date and emits event informing about new selected date.
diff --git a/webapp/src/app/days-off-info/days-off-info.component.html b/webapp/src/app/days-off-info/days-off-info.component.html
index 7949e74..c10302a 100644
--- a/webapp/src/app/days-off-info/days-off-info.component.html
+++ b/webapp/src/app/days-off-info/days-off-info.component.html
@@ -1,19 +1,20 @@
 <div class="days-off-info-container">
 
-  <div class="component-header">
-    Zbývající volno
+  <div class="component-header" translate>
+<!--    TODO-->
+    <span translate>daysOffInfo.remaining</span>
   </div>
 
   <div class="days-off-type-container">
     <span class="days-off-remaining">{{extraVacationRemaining.value}}</span>
     <!--    TODO vypsat jednotky (.unit)-->
-    <span class="days-off-type">Extra dovolená</span>
+    <span class="days-off-type" translate>vacationType.vacation</span>
   </div>
 
   <div class="days-off-type-container">
     <span class="days-off-remaining">{{sickDaysRemaining.value}}</span>
     <!--    TODO vypsat jednotky (.unit)-->
-    <span class="days-off-type">Sickdays</span>
+    <span class="days-off-type" translate>vacationType.sickday</span>
   </div>
 
 </div>
diff --git a/webapp/src/app/days-off-info/days-off-info.component.ts b/webapp/src/app/days-off-info/days-off-info.component.ts
index a1bc6a6..253708f 100644
--- a/webapp/src/app/days-off-info/days-off-info.component.ts
+++ b/webapp/src/app/days-off-info/days-off-info.component.ts
@@ -1,5 +1,6 @@
 import { Component, Input } from '@angular/core';
-import {TimeUnit} from "../enums/common.enum";
+import {TimeUnit} from '../enums/common.enum';
+import {LocalizationService} from '../localization/localization.service';
 
 @Component({
   selector: 'app-days-off-info',
@@ -18,5 +19,5 @@ export class DaysOffInfoComponent {
     unit: TimeUnit;
   };
 
-  constructor() { }
+  constructor(private localizationService: LocalizationService) { }
 }
diff --git a/webapp/src/app/days-off-info/days-off-info.module.ts b/webapp/src/app/days-off-info/days-off-info.module.ts
index 02388c3..dabcda3 100644
--- a/webapp/src/app/days-off-info/days-off-info.module.ts
+++ b/webapp/src/app/days-off-info/days-off-info.module.ts
@@ -1,7 +1,9 @@
 import { NgModule } from '@angular/core';
 import { DaysOffInfoComponent } from './days-off-info.component';
+import {TranslateModule} from '@ngx-translate/core';
 
 @NgModule({
+  imports: [TranslateModule],
   declarations: [ DaysOffInfoComponent ],
   exports:      [ DaysOffInfoComponent ]
 })
diff --git a/webapp/src/app/header/header.component.html b/webapp/src/app/header/header.component.html
index fac7013..4182927 100644
--- a/webapp/src/app/header/header.component.html
+++ b/webapp/src/app/header/header.component.html
@@ -1,7 +1,11 @@
 <div class="row header">
   <img class="logo" src="../../assets/images/logo.png" />
-  <button class="user-info" (click)="onProfileClick()">
-    <img class="user-icon" src="../../assets/images/default-user.png"/>
-    <span class="user-name">{{name}}</span>
-  </button>
+  <div class="language-and-user">
+    <button (click)="localizationService.switchLanguage('cs')">CS</button>
+    <button (click)="localizationService.switchLanguage('en')">EN</button>
+    <button class="user-info" (click)="onProfileClick()">
+      <img class="user-icon" src="../../assets/images/default-user.png"/>
+      <span class="user-name">{{name}}</span>
+    </button>
+  </div>
 </div>
diff --git a/webapp/src/app/header/header.component.sass b/webapp/src/app/header/header.component.sass
index 4e5a1b2..df483b1 100644
--- a/webapp/src/app/header/header.component.sass
+++ b/webapp/src/app/header/header.component.sass
@@ -3,10 +3,12 @@
   background-color: #3F425D
   padding-left: 10px
 
-.user-info
-  height: 100%
+.language-and-user
   margin-left: auto
   margin-right: 0
+  
+.user-info
+  height: 100%
   border: 0
   background-color: transparent
 
diff --git a/webapp/src/app/header/header.component.ts b/webapp/src/app/header/header.component.ts
index ad6214e..5b1a4dd 100644
--- a/webapp/src/app/header/header.component.ts
+++ b/webapp/src/app/header/header.component.ts
@@ -3,6 +3,7 @@ import { MatDialog } from '@angular/material';
 import { ProfileSettingsComponent } from '../profile-settings/profile-settings.component';
 import { ProfileService } from '../services/profile.service';
 import { UserProfile } from '../models/user-profile.model';
+import {LocalizationService} from "../localization/localization.service";
 
 @Component({
   selector: 'app-header',
@@ -16,10 +17,11 @@ export class HeaderComponent {
 
   constructor(
     private dialog: MatDialog,
-    private profileService: ProfileService
+    private profileService: ProfileService,
+    private localizationService: LocalizationService
     ) {
-    profileService.getProfile()
-      .subscribe((data: UserProfile) => this.notificationSettings = new Date(data.settings.notification));
+    // profileService.getProfile()
+    //   .subscribe((data: UserProfile) => this.notificationSettings = new Date(data.settings.notification));
   }
 
   onProfileClick(): void {
diff --git a/webapp/src/app/localization/localization.service.ts b/webapp/src/app/localization/localization.service.ts
new file mode 100644
index 0000000..932ccf5
--- /dev/null
+++ b/webapp/src/app/localization/localization.service.ts
@@ -0,0 +1,29 @@
+import { Injectable } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { registerLocaleData } from '@angular/common';
+import localeEn from '@angular/common/locales/en';
+import localeCs from '@angular/common/locales/cs';
+import { Subject } from 'rxjs';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class LocalizationService {
+  readonly defaultLanguage = 'en';
+
+  currentLanguage: Subject<string>;
+
+  constructor(private translate: TranslateService) {
+    this.currentLanguage = new Subject<string>();
+
+    registerLocaleData(localeEn);
+    registerLocaleData(localeCs);
+
+    translate.setDefaultLang(this.defaultLanguage);
+  }
+
+  switchLanguage(lang: string) {
+    this.translate.use(lang);
+    this.currentLanguage.next(lang);
+  }
+}
diff --git a/webapp/src/app/services/profile.service.ts b/webapp/src/app/services/profile.service.ts
index fca5684..d3578fc 100644
--- a/webapp/src/app/services/profile.service.ts
+++ b/webapp/src/app/services/profile.service.ts
@@ -12,8 +12,8 @@ export class ProfileService {
   constructor(
     private userService: UserService
   ) {
-    userService.getEmployeeProfile(1)
-      .subscribe((data: UserProfile) => this.profile = data);
+    // userService.getEmployeeProfile(1)
+    //   .subscribe((data: UserProfile) => this.profile = data);
   }
 
   getProfile(): Observable<UserProfile> {
diff --git a/webapp/src/assets/i18n/cs.json b/webapp/src/assets/i18n/cs.json
new file mode 100644
index 0000000..fd41a03
--- /dev/null
+++ b/webapp/src/assets/i18n/cs.json
@@ -0,0 +1,9 @@
+{
+  "daysOffInfo": {
+    "remaining": "Zbývající dovolená"
+  },
+  "vacationType": {
+    "vacation": "Extra dovolená",
+    "sickday": "Sickday"
+  }
+}
diff --git a/webapp/src/assets/i18n/en.json b/webapp/src/assets/i18n/en.json
new file mode 100644
index 0000000..e658f88
--- /dev/null
+++ b/webapp/src/assets/i18n/en.json
@@ -0,0 +1,9 @@
+{
+  "daysOffInfo": {
+    "remaining": "Vacation remaining"
+  },
+  "vacationType": {
+    "vacation": "Extra vacation",
+    "sickday": "Sickday"
+  }
+}
