commit 69da708699a5d0ebb5d7c770eb8060c54294d651
Author: castic96 <zdenek.castoral.jr@gmail.com>
Date:   Thu Apr 23 23:13:45 2020 +0200

    Re #7905: Lokalizace FE
    - vytvořeny překlady cz a en
    - překlady definovány v JSON souborech

diff --git a/fe/fulltextsearch/package-lock.json b/fe/fulltextsearch/package-lock.json
index 32b9bfe..7e23e78 100644
--- a/fe/fulltextsearch/package-lock.json
+++ b/fe/fulltextsearch/package-lock.json
@@ -1770,6 +1770,19 @@
         "webpack-sources": "1.4.3"
       }
     },
+    "@ngx-translate/core": {
+      "version": "12.1.2",
+      "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-12.1.2.tgz",
+      "integrity": "sha512-ZudJsqIxTKlLmPoqK8gJY3UpMGujR0Xm7HfXL6AR79yGRS23QqpjAhMfx4v5qUCcHMmQ9/78bW8QJLfp31c7vQ=="
+    },
+    "@ngx-translate/http-loader": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-4.0.0.tgz",
+      "integrity": "sha512-x8LumqydWD7eX9yQTAVeoCM9gFUIGVTUjZqbxdAUavAA3qVnk9wCQux7iHLPXpydl8vyQmLoPQR+fFU+DUDOMA==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
     "@npmcli/ci-detect": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.2.0.tgz",
@@ -2239,11 +2252,6 @@
       "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
       "dev": true
     },
-    "angular-x-image-viewer": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/angular-x-image-viewer/-/angular-x-image-viewer-2.0.1.tgz",
-      "integrity": "sha512-wt+wVwBOYqDlsJb8yqVKf5RyuZZmG0oZCG4w98ChQqBkZ3IyuuyrwP9lcsf1vOKs/0nfWrTob3YqfEppVlOLAA=="
-    },
     "ansi-colors": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
diff --git a/fe/fulltextsearch/package.json b/fe/fulltextsearch/package.json
index 70596c1..c894e81 100644
--- a/fe/fulltextsearch/package.json
+++ b/fe/fulltextsearch/package.json
@@ -24,6 +24,8 @@
     "@fortawesome/angular-fontawesome": "^0.6.1",
     "@fortawesome/fontawesome-svg-core": "^1.2.28",
     "@fortawesome/free-solid-svg-icons": "^5.13.0",
+    "@ngx-translate/core": "^12.1.2",
+    "@ngx-translate/http-loader": "^4.0.0",
     "bootstrap": "^4.4.1",
     "jquery": "^3.4.1",
     "ngx-image-viewer": "^1.0.13",
diff --git a/fe/fulltextsearch/src/app/app.component.ts b/fe/fulltextsearch/src/app/app.component.ts
index 68478a8..07c957e 100644
--- a/fe/fulltextsearch/src/app/app.component.ts
+++ b/fe/fulltextsearch/src/app/app.component.ts
@@ -1,4 +1,5 @@
 import { Component } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
 
 @Component({
   selector: 'app-root',
@@ -6,4 +7,11 @@ import { Component } from '@angular/core';
   styleUrls: ['./app.component.css']
 })
 export class AppComponent {
+  constructor(translate: TranslateService) {
+    translate.addLangs(['en', 'de', 'cz']);
+    translate.setDefaultLang('en');
+
+    const browserLang = translate.getBrowserLang();
+    translate.use(browserLang.match(/en|de|cz/) ? browserLang : 'en');
+  }
 }
diff --git a/fe/fulltextsearch/src/app/app.module.ts b/fe/fulltextsearch/src/app/app.module.ts
index adae009..3e66abe 100644
--- a/fe/fulltextsearch/src/app/app.module.ts
+++ b/fe/fulltextsearch/src/app/app.module.ts
@@ -1,6 +1,6 @@
 import { BrowserModule } from '@angular/platform-browser';
 import { NgModule } from '@angular/core';
-import { HttpClientModule } from '@angular/common/http';
+import { HttpClient, HttpClientModule } from '@angular/common/http';
 
 import { AppRoutingModule } from './app-routing.module';
 import { AppComponent } from './app.component';
@@ -33,6 +33,12 @@ import { DatePipe } from '@angular/common';
 import { BrowseDetailsComponent } from './components/pages/browse/browse-details/browse-details.component';
 import { ImageViewerModule } from 'ngx-image-viewer';
 import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
+import { TranslateHttpLoader } from '@ngx-translate/http-loader';
+import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
+
+export function HttpLoaderFactory(httpClient: HttpClient) {
+  return new TranslateHttpLoader(httpClient, '../assets/i18n/', '-lang.json');
+}
 
 @NgModule({
   declarations: [
@@ -68,7 +74,14 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
     MatSidenavModule,
     MatListModule,
     ImageViewerModule.forRoot(),
-    FontAwesomeModule
+    FontAwesomeModule,
+    TranslateModule.forRoot({
+      loader: {
+        provide: TranslateLoader,
+        useFactory: HttpLoaderFactory,
+        deps: [HttpClient]
+      }
+    })
   ],
   providers: [DataHolderService, DatePipe],
   bootstrap: [AppComponent]
diff --git a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.html b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.html
index 42acfe7..37627d2 100644
--- a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.html
+++ b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.html
@@ -8,22 +8,22 @@
     <mat-nav-list (click)="drawer.close()">
       <a mat-list-item routerLink="">
         <mat-icon>home</mat-icon>
-        Home</a>
+        {{'app-main-nav.home' | translate}}</a>
       <a mat-list-item routerLink="search">
         <mat-icon>search</mat-icon>
-        Search</a>
+        {{'app-main-nav.search' | translate}}</a>
       <a mat-list-item routerLink="browse">
         <mat-icon>list</mat-icon>
-        Browse</a>
+        {{'app-main-nav.browse' | translate}}</a>
       <a mat-list-item routerLink="upload">
         <mat-icon>backup</mat-icon>
-        Upload</a>
+        {{'app-main-nav.upload' | translate}}</a>
       <a mat-list-item (click)="openAboutDialog()">
         <mat-icon>info</mat-icon>
-        About</a>
+        {{'app-main-nav.about' | translate}}</a>
       <a mat-list-item routerLink="help">
         <mat-icon>help</mat-icon>
-        Help</a>
+        {{'app-main-nav.help' | translate}}</a>
     </mat-nav-list>
   </mat-sidenav>
   <mat-sidenav-content>
@@ -40,20 +40,20 @@
       <div class="app-logo" routerLink="" style="outline: none">
         <span style="display: flex;">
         <mat-icon>search</mat-icon>
-        <div>FULL TEXT SEARCH<br> APPLICATION</div>
+        <div>{{'app-main-nav.title1' | translate}}<br> {{'app-main-nav.title2' | translate}}</div>
       </span>
       </div>
       <!-- left navigation items -->
-      <a mat-button class="noHover active" routerLink="search" *ngIf="!(isHandset$ | async)">Search</a>
-      <a mat-button routerLink="browse" *ngIf="!(isHandset$ | async)">Browse</a>
-      <a mat-button routerLink="upload" *ngIf="!(isHandset$ | async)">Upload</a>
+      <a mat-button class="noHover active" routerLink="search" *ngIf="!(isHandset$ | async)">{{'app-main-nav.search' | translate}}</a>
+      <a mat-button routerLink="browse" *ngIf="!(isHandset$ | async)">{{'app-main-nav.browse' | translate}}</a>
+      <a mat-button routerLink="upload" *ngIf="!(isHandset$ | async)">{{'app-main-nav.upload' | translate}}</a>
       <!-- navigation items space -->
       <div class="space"></div>
       <!-- right navigation items -->
-      <a mat-button (click)="openAboutDialog()" *ngIf="!(isHandset$ | async)">About</a>
-      <a mat-button routerLink="help" *ngIf="!(isHandset$ | async)">Help</a>
-      <select (change)="onLanguageSelect($event)">
-        <option *ngFor="let language of languages">{{language}}</option>
+      <a mat-button (click)="openAboutDialog()" *ngIf="!(isHandset$ | async)">{{'app-main-nav.about' | translate}}</a>
+      <a mat-button routerLink="help" *ngIf="!(isHandset$ | async)">{{'app-main-nav.help' | translate}}</a>
+      <select #langSelect (change)="onLanguageSelect($event, langSelect)">
+        <option *ngFor="let lang of translate.getLangs()" [value]="lang" [selected]="lang === translate.currentLang">{{lang | uppercase}}</option>
       </select>
     </mat-toolbar>
     <ng-content></ng-content>
diff --git a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.ts b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.ts
index aa219d4..8f6f375 100644
--- a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.ts
+++ b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.ts
@@ -3,8 +3,9 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
 import { Observable } from 'rxjs';
 import { map, shareReplay } from 'rxjs/operators';
 import { AboutDialogComponent } from '../../shared-components/about-dialog/about-dialog.component';
-import {MatDialog} from '@angular/material/dialog';
-import {LoggerService} from '../../../services/logger/logger.service';
+import { MatDialog } from '@angular/material/dialog';
+import { LoggerService } from '../../../services/logger/logger.service';
+import { TranslateService } from '@ngx-translate/core';
 
 @Component({
   selector: 'app-main-nav',
@@ -13,8 +14,6 @@ import {LoggerService} from '../../../services/logger/logger.service';
 })
 export class MainNavComponent {
 
-  languages: string[] = ['EN', 'DE', 'CZ'];
-
   isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
     .pipe(
       map(result => result.matches),
@@ -23,15 +22,16 @@ export class MainNavComponent {
 
   constructor(private breakpointObserver: BreakpointObserver,
               public dialog: MatDialog,
-              private LOGGER: LoggerService) {}
+              private LOGGER: LoggerService,
+              public translate: TranslateService ) {}
 
   openAboutDialog() {
     this.dialog.open(AboutDialogComponent, { panelClass: 'custom-dialog-container' });
   }
 
-  onLanguageSelect(event) {
-    console.log(event.target.value);
-    this.LOGGER.error('Selected language ' + event.target.value);
+  onLanguageSelect(event, langSelect) {
+    this.translate.use(langSelect.value);
+    this.LOGGER.info('Selected language: ' + event.target.value);
   }
 
 }
diff --git a/fe/fulltextsearch/src/app/components/pages/browse/browse.component.html b/fe/fulltextsearch/src/app/components/pages/browse/browse.component.html
index 84d470e..be89c79 100644
--- a/fe/fulltextsearch/src/app/components/pages/browse/browse.component.html
+++ b/fe/fulltextsearch/src/app/components/pages/browse/browse.component.html
@@ -1,7 +1,7 @@
 <div class="page-top-margin">
   <div class="text-box mat-elevation-z8">
     <div class="card">
-      <h1 class="card-header">All documents</h1>
+      <h1 class="card-header">{{'app-browse.card-header' | translate}}</h1>
       <div>
         <app-table-browse></app-table-browse>
       </div>
diff --git a/fe/fulltextsearch/src/app/components/pages/browse/table/table.component.html b/fe/fulltextsearch/src/app/components/pages/browse/table/table.component.html
index b3e8e3c..c245ace 100644
--- a/fe/fulltextsearch/src/app/components/pages/browse/table/table.component.html
+++ b/fe/fulltextsearch/src/app/components/pages/browse/table/table.component.html
@@ -2,13 +2,13 @@
   <table mat-table class="full-width-table" matSort aria-label="Elements">
     <!-- Id Column -->
     <ng-container matColumnDef="id">
-      <th mat-header-cell *matHeaderCellDef mat-sort-header>Id</th>
+      <th mat-header-cell *matHeaderCellDef mat-sort-header>{{'app-table-browse.id' | translate}}</th>
       <td mat-cell *matCellDef="let row">{{row.id}}</td>
     </ng-container>
 
     <!-- Name Column -->
     <ng-container matColumnDef="documentName">
-      <th mat-header-cell *matHeaderCellDef mat-sort-header>Document name</th>
+      <th mat-header-cell *matHeaderCellDef mat-sort-header>{{'app-table-browse.document-name' | translate}}</th>
       <td mat-cell *matCellDef="let row">
         <a routerLink="/browse/{{row.documentName}}">
         {{row.documentName}}
@@ -18,13 +18,13 @@
 
     <!-- Test Column -->
     <ng-container matColumnDef="originDate">
-      <th mat-header-cell *matHeaderCellDef mat-sort-header>Origin date</th>
+      <th mat-header-cell *matHeaderCellDef mat-sort-header>{{'app-table-browse.origin-date' | translate}}</th>
       <td mat-cell *matCellDef="let row">{{row.originDate | date:'d. M. yyyy'}}</td>
     </ng-container>
 
     <!-- Test Column -->
     <ng-container matColumnDef="uploadedDate">
-      <th mat-header-cell *matHeaderCellDef mat-sort-header>Uploaded date</th>
+      <th mat-header-cell *matHeaderCellDef mat-sort-header>{{'app-table-browse.uploaded-date' | translate}}</th>
       <td mat-cell *matCellDef="let row">{{row.uploadedDate | date:'d. M. yyyy'}}</td>
     </ng-container>
 
diff --git a/fe/fulltextsearch/src/app/components/pages/help/help.component.html b/fe/fulltextsearch/src/app/components/pages/help/help.component.html
index fd1d14f..57a0b55 100644
--- a/fe/fulltextsearch/src/app/components/pages/help/help.component.html
+++ b/fe/fulltextsearch/src/app/components/pages/help/help.component.html
@@ -1,52 +1,17 @@
 <div class="page-top-margin">
   <div class="text-box">
     <div class="card">
-      <h1 class="card-header">Help</h1>
+      <h1 class="card-header">{{'app-help.card-header' | translate}}</h1>
       <div class="card-body">
-        <h2 class="card-title">How it is works</h2>
-        <p class="card-text">Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,
-          dolor nunc faucibus
-          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque
-          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at
-          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et
-          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi
-          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam
-          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
-          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.
-          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio
-          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.</p>
-        <h2 class="card-title">Manual</h2>
-        <p class="card-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Et harum quidem rerum facilis est et expedita
-          distinctio. Aenean id metus id velit ullamcorper pulvinar. Curabitur bibendum justo non orci. Etiam egestas
-          wisi a erat. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Nulla non arcu lacinia neque faucibus
-          fringilla. Etiam dui sem, fermentum vitae, sagittis id, malesuada in, quam. Quis autem vel eum iure reprehenderit
-          qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas
-          nulla pariatur? Aliquam erat volutpat. Aliquam id dolor.</p>
-        <h2 class="card-title">FAQ</h2>
-        <p class="card-text">Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,
-          dolor nunc faucibus
-          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque
-          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at
-          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et
-          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi
-          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam
-          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
-          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.
-          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio
-          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.</p>
-        <h2 class="card-title">Support</h2>
-        <p class="card-text">Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,
-          dolor nunc faucibus
-          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque
-          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at
-          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et
-          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi
-          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam
-          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
-          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.
-          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio
-          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.</p>
-        <h2>Contact admin</h2>
+        <h2 class="card-title">{{'app-help.how-it-works-title' | translate}}</h2>
+        <p class="card-text">{{'app-help.how-it-works-text' | translate}}</p>
+        <h2 class="card-title">{{'app-help.manual-title' | translate}}</h2>
+        <p class="card-text">{{'app-help.manual-text' | translate}}</p>
+        <h2 class="card-title">{{'app-help.faq-title' | translate}}</h2>
+        <p class="card-text">{{'app-help.faq-text' | translate}}</p>
+        <h2 class="card-title">{{'app-help.support-title' | translate}}</h2>
+        <p class="card-text">{{'app-help.support-text' | translate}}</p>
+        <h2>{{'app-help.contact-admin-title' | translate}}</h2>
         <address>
           <a href="mailto:jim@rock.com">jim@rock.com</a><br>
           <a href="tel:+13115552368">(311) 555-2368</a>
diff --git a/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.html b/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.html
index 1775e29..af1ffee 100644
--- a/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.html
+++ b/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.html
@@ -14,7 +14,7 @@
                  class="image" src="data:image/jpg;base64,{{row.imageCut}}"
                  (load)="draw(row,row.randomId + 'Img' , row.randomId + 'Canvas' )"/>
             <canvas id="{{row.randomId + 'Canvas'}}" style="position: absolute;" title="Result">
-              Your browser does not support the HTML5 canvas tag.
+              {{'app-search-paginator.canvas-error' | translate}}
             </canvas>
           </div>
         </div>
diff --git a/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.ts b/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.ts
index 7303f2e..add5f73 100644
--- a/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.ts
+++ b/fe/fulltextsearch/src/app/components/pages/search/search-paginator/search-paginator.component.ts
@@ -1,11 +1,11 @@
-import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
+import {Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core';
 import { MatPaginator } from '@angular/material/paginator';
 import { MatTableDataSource } from '@angular/material/table';
 import { TextRegion } from '../../../../model/parts/TextRegion';
 import { SearchResponse } from '../../../../model/SearchResponse';
-import Utils from '../../../../../Utils';
-import {DrawerService} from '../../../../services/drawer/drawer.service';
-import {LoggerService} from '../../../../services/logger/logger.service';
+import { DrawerService } from '../../../../services/drawer/drawer.service';
+import { LoggerService } from '../../../../services/logger/logger.service';
+import { TranslateService } from '@ngx-translate/core';
 
 @Component({
   selector: 'app-search-paginator',
@@ -20,10 +20,13 @@ export class SearchPaginatorComponent implements OnChanges {
   /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
   displayedColumns = ['image'];
 
-  constructor(private LOGGER: LoggerService, private drawer: DrawerService) {}
+  constructor(private LOGGER: LoggerService, private drawer: DrawerService, private translate: TranslateService) {
+
+  }
 
   ngOnChanges(changes: SimpleChanges): void {
     this.tableDataSource = new MatTableDataSource<TextRegion>(this.inputData.textRegions);
+    // this.tableDataSource.paginator._intl.itemsPerPageLabel = this.translate.instant('app-search-paginator.items-per-page');
     this.tableDataSource.paginator = this.paginator;
   }
 
diff --git a/fe/fulltextsearch/src/app/components/pages/search/search.component.html b/fe/fulltextsearch/src/app/components/pages/search/search.component.html
index ac8f041..b66fb32 100644
--- a/fe/fulltextsearch/src/app/components/pages/search/search.component.html
+++ b/fe/fulltextsearch/src/app/components/pages/search/search.component.html
@@ -8,8 +8,8 @@
     </div>-->
     <div class="row" *ngIf="data">
       <p class="card-header">
-        <span>Searching expression: </span><b>{{data.expression}}</b><br>
-        <span>Documents found: </span><b>{{data.textRegions.length}}</b>
+        <span>{{'app-search.expression' | translate}}</span><b>{{data.expression}}</b><br>
+        <span>{{'app-search.found' | translate}}</span><b>{{data.textRegions.length}}</b>
       </p>
     </div>
     <div class="row">
diff --git a/fe/fulltextsearch/src/app/components/pages/upload/upload.component.html b/fe/fulltextsearch/src/app/components/pages/upload/upload.component.html
index 2227e30..4cde75e 100644
--- a/fe/fulltextsearch/src/app/components/pages/upload/upload.component.html
+++ b/fe/fulltextsearch/src/app/components/pages/upload/upload.component.html
@@ -1,12 +1,12 @@
 <div class="page-top-margin">
   <div class="text-box">
     <div class="card">
-      <h1 class="card-header">Upload files</h1>
+      <h1 class="card-header">{{'app-upload.card-header' | translate}}</h1>
       <div class="card-body">
         <div class="row justify-content-center align-items-center">
           <input type="file" (change)="onFilesSelected($event)" multiple #fileInput accept="image/jpeg, image/png, application/xml, text/xml">
-          <button class="btn btn-outline-secondary" type="button" (click)="fileInput.click()">Pick files</button>
-          <button class="btn btn-outline-secondary" type="button" (click)="onUpload()">Upload</button>
+          <button class="btn btn-outline-secondary" type="button" (click)="fileInput.click()">{{'app-upload.pick-files' | translate}}</button>
+          <button class="btn btn-outline-secondary" type="button" (click)="onUpload()">{{'app-upload.upload' | translate}}</button>
         </div>
         <mat-progress-bar mode="determinate" [value]="progress" color="warn"></mat-progress-bar>
         <div class="row justify-content-center align-items-center">
diff --git a/fe/fulltextsearch/src/app/components/shared-components/about-dialog/about-dialog.component.html b/fe/fulltextsearch/src/app/components/shared-components/about-dialog/about-dialog.component.html
index c5467cb..724d46a 100644
--- a/fe/fulltextsearch/src/app/components/shared-components/about-dialog/about-dialog.component.html
+++ b/fe/fulltextsearch/src/app/components/shared-components/about-dialog/about-dialog.component.html
@@ -1,5 +1,5 @@
 <div class="dialog-header">
-  <h1 mat-dialog-title>About</h1>
+  <h1 mat-dialog-title>{{'app-about-dialog.title' | translate}}</h1>
   <span class="clickable" mat-dialog-close>
         <mat-icon>clear</mat-icon>
   </span>
@@ -7,16 +7,10 @@
 
 <mat-dialog-content>
 
-  <span><b>App version(FE):</b> </span> {{appVersionFE}}<br>
-  <span><b>App version(BE):</b></span> {{appVersionBE}}<br>
-  <span><b>Solr version:</b></span> {{solrVersion}}<br>
-  <h3><b>Project made by ASWI team ANONYMOUS(2020)</b></h3>
-  <p>
-    Lorem Ipsum is simply dummy text of the printing and
-    typesetting industry. Lorem Ipsum has been the industry's
-    standard dummy text ever since the 1500s, when an unknown
-    printer took a galley of type and scrambled it to make a
-    type specimen book.
-  </p>
+  <span><b>{{'app-about-dialog.fe-version' | translate}}</b> </span> {{appVersionFE}}<br>
+  <span><b>{{'app-about-dialog.be-version' | translate}}</b></span> {{appVersionBE}}<br>
+  <span><b>{{'app-about-dialog.solr-version' | translate}}</b></span> {{solrVersion}}<br>
+  <h3><b>{{'app-about-dialog.header3' | translate}}</b></h3>
+  <p>{{'app-about-dialog.paragraph' | translate}}</p>
 
 </mat-dialog-content>
diff --git a/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.html b/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.html
index f586a27..6f61adb 100644
--- a/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.html
+++ b/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.html
@@ -5,12 +5,12 @@
     <mat-icon>search</mat-icon>
   </span>
     </div>
-    <input type="text" class="form-control" [(ngModel)]="expression" (keyup.enter) = "onSubmit()" placeholder="Enter text to search..." aria-label="Search" aria-describedby="basic-addon2">
+    <input type="text" class="form-control" [(ngModel)]="expression" (keyup.enter) = "onSubmit()" placeholder="{{'app-search-box.placeholder' | translate}}" aria-label="Search" aria-describedby="basic-addon2">
     <div class="input-group-append">
       <span class="input-group-text clickable" id="clear-icon">
         <mat-icon *ngIf="expression" matSuffix aria-label="Clear" (click)="expression=''">clear</mat-icon>
       </span>
-      <button class="btn btn-outline-secondary" type="button" (click)="onSubmit()">Search</button>
+      <button class="btn btn-outline-secondary" type="button" (click)="onSubmit()">{{'app-search-box.search' | translate}}</button>
     </div>
   </div>
 </div>
diff --git a/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.ts b/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.ts
index e945172..c39995e 100644
--- a/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.ts
+++ b/fe/fulltextsearch/src/app/components/shared-components/search-box/search-box.component.ts
@@ -3,7 +3,6 @@ import { SearchRequest } from '../../../model/SearchRequest';
 import { QueryService } from '../../../services/query/query.service';
 import { Router } from '@angular/router';
 import { DataHolderService } from '../../../services/data-holder/data-holder.service';
-import {SearchComponent} from '../../pages/search/search.component';
 import {Subscription} from 'rxjs';
 
 @Component({
diff --git a/fe/fulltextsearch/src/assets/i18n/cz-lang.json b/fe/fulltextsearch/src/assets/i18n/cz-lang.json
new file mode 100644
index 0000000..dce9154
--- /dev/null
+++ b/fe/fulltextsearch/src/assets/i18n/cz-lang.json
@@ -0,0 +1,59 @@
+{
+  "app-title": "Fulltext search app",
+  "app-main-nav": {
+    "title1": "FULLTEXT SEARCH",
+    "title2": "APPLICATION",
+    "home": "Domů",
+    "search": "Vyhledat",
+    "browse": "Procházet",
+    "upload": "Nahrát",
+    "about": "O nás",
+    "help": "Pomoc"
+  },
+  "app-search-box": {
+    "search": "Vyhledat",
+    "placeholder": "Zadejte text k vyhledání..."
+  },
+  "app-search": {
+    "expression": "Hledaný výraz: ",
+    "found": "Nalezeno dokumentů: "
+  },
+  "app-search-paginator": {
+    "canvas-error": "Váš prohlížeč nepodporuje HTML5 canvas tag.",
+    "items-per-page": "Položek na stránku:"
+  },
+  "app-browse": {
+    "card-header": "Všechny dokumenty"
+  },
+  "app-table-browse": {
+    "id": "Id",
+    "document-name": "Název dokumentu",
+    "origin-date": "Datum vytvoření",
+    "uploaded-date": "Datum nahrání"
+  },
+  "app-upload": {
+    "card-header": "Nahrát soubory",
+    "pick-files": "Vybrat soubory",
+    "upload": "Nahrát"
+  },
+  "app-about-dialog": {
+    "title": "O nás",
+    "fe-version": "Verze aplikace (FE):",
+    "be-version": "Verze aplikace (BE):",
+    "solr-version": "Verze Solr:",
+    "header3": "Projekt vytvořen týmem ANONYMOUS v rámci projektu ASWI (2020)",
+    "paragraph": "    Lorem Ipsum is simply dummy text of the printing and\n    typesetting industry. Lorem Ipsum has been the industry's\n    standard dummy text ever since the 1500s, when an unknown\n    printer took a galley of type and scrambled it to make a\n    type specimen book."
+  },
+  "app-help": {
+    "card-header": "Pomoc",
+    "how-it-works-title": "Jak to funguje",
+    "how-it-works-text": "Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,\n          dolor nunc faucibus\n          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque\n          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at\n          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et\n          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi\n          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam\n          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora\n          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.\n          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio\n          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.",
+    "manual-title": "Návod",
+    "manual-text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Et harum quidem rerum facilis est et expedita\n          distinctio. Aenean id metus id velit ullamcorper pulvinar. Curabitur bibendum justo non orci. Etiam egestas\n          wisi a erat. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Nulla non arcu lacinia neque faucibus\n          fringilla. Etiam dui sem, fermentum vitae, sagittis id, malesuada in, quam. Quis autem vel eum iure reprehenderit\n          qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas\n          nulla pariatur? Aliquam erat volutpat. Aliquam id dolor.",
+    "faq-title": "Nejčastější dotazy",
+    "faq-text": "Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,\n          dolor nunc faucibus\n          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque\n          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at\n          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et\n          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi\n          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam\n          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora\n          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.\n          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio\n          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.",
+    "support-title": "Podpora",
+    "support-text": "Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,\n          dolor nunc faucibus\n          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque\n          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at\n          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et\n          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi\n          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam\n          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora\n          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.\n          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio\n          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.",
+    "contact-admin-title": "Kontakt na administrátora"
+  }
+}
diff --git a/fe/fulltextsearch/src/assets/i18n/de-lang.json b/fe/fulltextsearch/src/assets/i18n/de-lang.json
new file mode 100644
index 0000000..e69de29
diff --git a/fe/fulltextsearch/src/assets/i18n/en-lang.json b/fe/fulltextsearch/src/assets/i18n/en-lang.json
new file mode 100644
index 0000000..42a6269
--- /dev/null
+++ b/fe/fulltextsearch/src/assets/i18n/en-lang.json
@@ -0,0 +1,59 @@
+{
+  "app-title": "Fulltext search app",
+  "app-main-nav": {
+    "title1": "FULLTEXT SEARCH",
+    "title2": "APPLICATION",
+    "home": "Home",
+    "search": "Search",
+    "browse": "Browse",
+    "upload": "Upload",
+    "about": "About",
+    "help": "Help"
+  },
+  "app-search-box": {
+    "search": "Search",
+    "placeholder": "Enter text to search..."
+  },
+  "app-search": {
+    "expression": "Searching expression: ",
+    "found": "Documents found: "
+  },
+  "app-search-paginator": {
+    "canvas-error": "Your browser does not support the HTML5 canvas tag.",
+    "items-per-page": "Items per page:"
+  },
+  "app-browse": {
+    "card-header": "All documents"
+  },
+  "app-table-browse": {
+    "id": "Id",
+    "document-name": "Document name",
+    "origin-date": "Origin date",
+    "uploaded-date": "Uploaded date"
+  },
+  "app-upload": {
+    "card-header": "Upload files",
+    "pick-files": "Pick files",
+    "upload": "Upload"
+  },
+  "app-about-dialog": {
+    "title": "About",
+    "fe-version": "App version (FE):",
+    "be-version": "App version (BE):",
+    "solr-version": "Solr version:",
+    "header3": "Project made by ASWI team ANONYMOUS (2020)",
+    "paragraph": "    Lorem Ipsum is simply dummy text of the printing and\n    typesetting industry. Lorem Ipsum has been the industry's\n    standard dummy text ever since the 1500s, when an unknown\n    printer took a galley of type and scrambled it to make a\n    type specimen book."
+  },
+  "app-help": {
+    "card-header": "Help",
+    "how-it-works-title": "How it is works",
+    "how-it-works-text": "Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,\n          dolor nunc faucibus\n          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque\n          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at\n          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et\n          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi\n          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam\n          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora\n          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.\n          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio\n          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.",
+    "manual-title": "Manual",
+    "manual-text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Et harum quidem rerum facilis est et expedita\n          distinctio. Aenean id metus id velit ullamcorper pulvinar. Curabitur bibendum justo non orci. Etiam egestas\n          wisi a erat. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Nulla non arcu lacinia neque faucibus\n          fringilla. Etiam dui sem, fermentum vitae, sagittis id, malesuada in, quam. Quis autem vel eum iure reprehenderit\n          qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas\n          nulla pariatur? Aliquam erat volutpat. Aliquam id dolor.",
+    "faq-title": "FAQ",
+    "faq-text": "Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,\n          dolor nunc faucibus\n          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque\n          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at\n          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et\n          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi\n          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam\n          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora\n          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.\n          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio\n          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.",
+    "support-title": "Support",
+    "support-text": "Praesent in mauris eu tortor porttitor accumsan. Duis bibendum, lectus ut viverra rhoncus,\n          dolor nunc faucibus\n          libero, eget facilisis enim ipsum id lacus. Sed ac dolor sit amet purus malesuada congue. Integer pellentesque\n          quam vel velit. Morbi leo mi, nonummy eget tristique non, rhoncus non leo. Phasellus rhoncus. Donec quis nibh at\n          felis congue commodo. Integer pellentesque quam vel velit. Integer in sapien. Cum sociis natoque penatibus et\n          magnis dis parturient montes, nascetur ridiculus mus. Maecenas aliquet accumsan leo. Pellentesque habitant morbi\n          tristique senectus et netus et malesuada fames ac turpis egestas. In dapibus augue non sapien. Neque porro quisquam\n          est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora\n          incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Praesent id justo in neque elementum ultrices.\n          In convallis. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio\n          a lectus. Mauris tincidunt sem sed arcu. Vivamus porttitor turpis ac leo.",
+    "contact-admin-title": "Contact admin"
+  }
+}
