Add basic language changing functionality

pull/46/head
HardiReady 2018-10-05 09:55:39 +02:00
parent 1d46b301f5
commit 8ea5e188a0
14 changed files with 203 additions and 107 deletions

View File

@ -89,6 +89,21 @@
</ul> </ul>
<ul class="nav navbar-nav pull-right"> <ul class="nav navbar-nav pull-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">
Language
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>
<a (click)="setLanguage('en')">English</a>
</li>
<li>
<a (click)="setLanguage('de')">Deutsch</a>
</li>
</ul>
</li>
<li *ngIf="loginService.hasPermission(4)" routerLinkActive="active"> <li *ngIf="loginService.hasPermission(4)" routerLinkActive="active">
<a routerLink='{{config.adminPanelPath}}' class="link">{{'navigation.top.admin' | translate}}</a> <a routerLink='{{config.adminPanelPath}}' class="link">{{'navigation.top.admin' | translate}}</a>
</li> </li>

View File

@ -9,6 +9,8 @@ import {DomSanitizer} from '@angular/platform-browser';
import {MatIconRegistry} from '@angular/material'; import {MatIconRegistry} from '@angular/material';
import {SpinnerService} from './services/user-interface/spinner/spinner.service'; import {SpinnerService} from './services/user-interface/spinner/spinner.service';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {Language} from './settings/settings-state.model';
import {SettingsService} from './services/settings.service';
declare function require(url: string); declare function require(url: string);
@ -66,6 +68,7 @@ export class AppComponent implements OnInit {
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private spinnerService: SpinnerService, private spinnerService: SpinnerService,
private translate: TranslateService, private translate: TranslateService,
private settingsService: SettingsService,
@Inject(DOCUMENT) private document) { @Inject(DOCUMENT) private document) {
this.initMaterialSvgIcons(); this.initMaterialSvgIcons();
@ -88,7 +91,7 @@ export class AppComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
this.translate.setDefaultLang('de'); this.settingsService.getLanguage().subscribe((language) => this.translate.setDefaultLang(language));
if (this.loginService.hasPermission(2)) { if (this.loginService.hasPermission(2)) {
const fraction = this.loginService.getCurrentUser().squad.fraction; const fraction = this.loginService.getCurrentUser().squad.fraction;
this.promotionService.checkUnconfirmedPromotions(fraction); this.promotionService.checkUnconfirmedPromotions(fraction);
@ -126,12 +129,10 @@ export class AppComponent implements OnInit {
this.document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera this.document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
} }
// TODO: use! setLanguage(language: Language) {
// private setLanguage(settings: SettingsState) { if (language) {
// const { language } = settings; this.settingsService.setLanguage(language);
// if (language) { }
// this.translate.use(language); }
// }
// }
} }

View File

@ -26,6 +26,7 @@ import {HttpClientModule} from '@angular/common/http';
import {SpinnerService} from './services/user-interface/spinner/spinner.service'; import {SpinnerService} from './services/user-interface/spinner/spinner.service';
import {MatSnackBarModule} from '@angular/material'; import {MatSnackBarModule} from '@angular/material';
import {HttpClient} from './services/http-client'; import {HttpClient} from './services/http-client';
import {SettingsService} from './services/settings.service';
@NgModule({ @NgModule({
imports: [ imports: [
@ -61,6 +62,7 @@ import {HttpClient} from './services/http-client';
CookieService, CookieService,
SnackBarService, SnackBarService,
SpinnerService, SpinnerService,
SettingsService,
], ],
declarations: [ declarations: [

View File

@ -1,6 +1,7 @@
import {Component, Input, OnInit} from '@angular/core'; import {Component, Input, OnInit} from '@angular/core';
import {FormGroup, NgForm} from '@angular/forms'; import {FormGroup, NgForm} from '@angular/forms';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {SettingsService} from '../../services/settings.service';
@Component({ @Component({
selector: 'show-error', selector: 'show-error',
@ -11,7 +12,7 @@ import {TranslateService} from '@ngx-translate/core';
</div> </div>
</div>` </div>`
}) })
export class ShowErrorComponent implements OnInit { export class ShowErrorComponent {
// tslint:disable-next-line:no-input-rename // tslint:disable-next-line:no-input-rename
@Input('controlPath') controlPath; @Input('controlPath') controlPath;
@ -22,12 +23,10 @@ export class ShowErrorComponent implements OnInit {
private form: FormGroup; private form: FormGroup;
constructor(ngForm: NgForm, constructor(ngForm: NgForm,
private translate: TranslateService) { private translate: TranslateService,
private settingsService: SettingsService) {
this.form = ngForm.form; this.form = ngForm.form;
} this.settingsService.getLanguage().subscribe((language) => this.translate.setDefaultLang(language));
ngOnInit() {
this.translate.setDefaultLang('de');
} }
get errorMessages(): string[] { get errorMessages(): string[] {

View File

@ -1,5 +1,6 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {SettingsService} from '../services/settings.service';
@Component({ @Component({
selector: 'cc-manage-root', selector: 'cc-manage-root',
@ -7,7 +8,8 @@ import {TranslateService} from '@ngx-translate/core';
styleUrls: ['./manage.component.scss'] styleUrls: ['./manage.component.scss']
}) })
export class ManageComponent { export class ManageComponent {
constructor(private translate: TranslateService) { constructor(private translate: TranslateService,
this.translate.setDefaultLang('de'); private settingsService: SettingsService) {
this.settingsService.getLanguage().subscribe((language) => this.translate.setDefaultLang(language));
} }
} }

View File

@ -1,5 +1,6 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {SettingsService} from '../services/settings.service';
@Component({ @Component({
selector: 'cc-public', selector: 'cc-public',
@ -7,7 +8,8 @@ import {TranslateService} from '@ngx-translate/core';
styleUrls: ['./public.component.scss'] styleUrls: ['./public.component.scss']
}) })
export class PublicComponent { export class PublicComponent {
constructor(private translate: TranslateService) { constructor(private translate: TranslateService,
this.translate.setDefaultLang('de'); private settingsService: SettingsService) {
this.settingsService.getLanguage().subscribe((language) => this.translate.setDefaultLang(language));
} }
} }

View File

@ -8,7 +8,7 @@
<th class="col-sm-1">{{'request.confirm.promotion.table.head.participant' | translate}}</th> <th class="col-sm-1">{{'request.confirm.promotion.table.head.participant' | translate}}</th>
<th class="col-sm-1">{{'request.confirm.promotion.table.head.rank.before' | translate}}</th> <th class="col-sm-1">{{'request.confirm.promotion.table.head.rank.before' | translate}}</th>
<th class="col-sm-1">{{'request.confirm.promotion.table.head.rank.after' | translate}}</th> <th class="col-sm-1">{{'request.confirm.promotion.table.head.rank.after' | translate}}</th>
<th class="col-sm-1 ">{{'"request.confirm.promotion.table.head.requester' | translate}}</th> <th class="col-sm-1 ">{{'request.confirm.promotion.table.head.requester' | translate}}</th>
<th class="col-sm-1 text-center">{{'request.confirm.promotion.table.head.date' | translate}}</th> <th class="col-sm-1 text-center">{{'request.confirm.promotion.table.head.date' | translate}}</th>
<th class="col-sm-1 text-center">{{'request.confirm.promotion.table.head.status' | translate}}</th> <th class="col-sm-1 text-center">{{'request.confirm.promotion.table.head.status' | translate}}</th>
<th class="col-sm-2 text-right"></th> <th class="col-sm-2 text-right"></th>

View File

@ -1,5 +1,6 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {SettingsService} from '../services/settings.service';
@Component({ @Component({
selector: 'cc-request-root', selector: 'cc-request-root',
@ -7,7 +8,8 @@ import {TranslateService} from '@ngx-translate/core';
styleUrls: ['request.component.css'] styleUrls: ['request.component.css']
}) })
export class RequestComponent { export class RequestComponent {
constructor(private translate: TranslateService) { constructor(private translate: TranslateService,
translate.setDefaultLang('de'); private settingsService: SettingsService) {
this.settingsService.getLanguage().subscribe((language) => this.translate.setDefaultLang(language));
} }
} }

View File

@ -0,0 +1,21 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
import {Observable} from 'rxjs/internal/Observable';
@Injectable()
export class SettingsService {
language = new BehaviorSubject<string>('de');
constructor() {
}
setLanguage(language: string) {
this.language.next(language);
}
getLanguage(): Observable<string> {
return this.language.asObservable();
}
}

View File

@ -3,6 +3,7 @@ import {Campaign} from '../models/model-interfaces';
import {CampaignService} from '../services/logs/campaign.service'; import {CampaignService} from '../services/logs/campaign.service';
import {ActivatedRoute, Router} from '@angular/router'; import {ActivatedRoute, Router} from '@angular/router';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {SettingsService} from '../services/settings.service';
@Component({ @Component({
selector: 'cc-stats', selector: 'cc-stats',
@ -20,8 +21,9 @@ export class StatisticComponent implements OnInit {
constructor(private campaignService: CampaignService, constructor(private campaignService: CampaignService,
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private translate: TranslateService) { private translate: TranslateService,
this.translate.setDefaultLang('de'); private settingsService: SettingsService) {
this.settingsService.getLanguage().subscribe((language) => this.translate.setDefaultLang(language));
} }
ngOnInit() { ngOnInit() {

View File

@ -11,7 +11,7 @@
"navigation.top.board": "Zum Forum", "navigation.top.board": "Zum Forum",
"navigation.top.overview": "Armeeübersicht", "navigation.top.overview": "Armeeübersicht",
"navigation.top.ranks": "Ränge", "navigation.top.ranks": "Ränge",
"navigation.top.decorations": "Auszeichnungem", "navigation.top.decorations": "Auszeichnungen",
"navigation.top.statistics": "Statistiken", "navigation.top.statistics": "Statistiken",
"navigation.top.login": "Login", "navigation.top.login": "Login",
"navigation.top.logout": "Abmelden", "navigation.top.logout": "Abmelden",

View File

@ -1,2 +1,52 @@
{ {
"public.error.message.required": "{{fieldName}} is a required field",
"public.error.message.min.length": "{{fieldName}} requires at least {{boundary}} characters",
"public.error.message.max.length": "{{fieldName}} is limited to {{boundary}} characters",
"public.error.message.email": "Please enter a valid eMail address",
"public.error.message.no.user": "The choosen user does not exist",
"public.error.message.default": "{{fieldName}} is not valid",
"public.common.search.button": "Search",
"navigation.top.board": "To message board",
"navigation.top.overview": "Army Overview",
"navigation.top.ranks": "Ranks",
"navigation.top.decorations": "Awards",
"navigation.top.statistics": "Statistics",
"navigation.top.login": "Login",
"navigation.top.logout": "Logout",
"navigation.top.management": "Manage",
"navigation.top.management.users": "Users",
"navigation.top.management.squads": "Squads",
"navigation.top.management.decorations": "Decorations",
"navigation.top.management.ranks": "Ranks",
"navigation.top.request": "Request",
"navigation.top.request.open": "Open Requests",
"navigation.top.request.manage": "Requests",
"navigation.top.request.promotion": "Promotion",
"navigation.top.request.award": "Medal/ Ribbon",
"navigation.top.admin": "Admin Panel",
"navigation.button.scroll.top": "Back to top",
"login.headline": "Login",
"login.username": "Username",
"login.password": "Password",
"login.submit": "Submit",
"signup.headline": "Sign Up",
"signup.username": "Username",
"signup.password": "Password",
"signup.secret": "Secret",
"signup.secret.placeholder": "Secret text for message comparison",
"signup.submit": "Submit",
"signup.description": "Dieses Formular nur ausfüllen wenn du einer <b>HL</b> angehörst oder <b>SQL</b> bist. Dabei den Nutzernamen aus dem OPT Forum verwenden! Im Forum eine Nachricht an <a href=\"https://www.opt4.net/dashboard/index.php?conversation-add/&userID=9\" target=\"_blank\">HardiReady</a> senden, in welcher der 'geheime Text' steht, den du bei der Registrierung nutzt.<br> Dabei kann es sich um irgend eine willkürliche Zeichenfolge oder einen Satz handeln - dient nur dem Abgleich. Anschließend wird dein Account aktiviert und du wirst darüber per PN informiert.",
"public.army.headline": "Overview of all players, squads and armies",
"public army.squad.members": "Members:",
"public.army.members": "Army Members:",
"public.army.member.button.back": "Back",
"public.army.member.button.copy": "copy",
"public.army.member.headline": "Awards of {{name}}",
"public.army.member.awards.title": "Title",
"public.army.member.awards.reason": "Reason",
"public.army.member.awards.date": "Decorated at"
} }

View File

@ -1,86 +1,3 @@
{ {
"stats.campaign.manage.edit": "Edit",
"stats.campaign.manage.delete": "Delete",
"stats.campaign.manage.delete.confirm": "Do you really want to delete the campaign \"{{title}}\"?",
"stats.campaign.title.all.time.overview": "All time overview",
"stats.sidebar.campaign.add": "Add campaign",
"stats.sidebar.battle.add": "Add battle",
"stats.sidebar.overview": "Overview",
"stats.sidebar.highscore": "Highscore",
"stats.sidebar.battles": "Battles",
"stats.sidebar.battles.battle.from.date": "at",
"stats.sidebar.battle.manage.edit": "Edit",
"stats.sidebar.battle.manage.delete": "Delete",
"stats.sidebar.battle.manage.delete.confirm": "Do you really want to delete the battle \"{{title}}\"?",
"stats.graph.select.sum.points": "Total Score",
"stats.graph.select.battle.points": "Score per Battle",
"stats.graph.select.player.count": "Player count",
"stats.fraction.select.points": "Score",
"stats.fraction.select.budget": "Budget",
"stats.fraction.select.kills": "Kills",
"stats.fraction.select.friendly.fire": "Friendly Fire",
"stats.fraction.select.vehicle.kills": "Vehicle Kills",
"stats.fraction.select.air.transport": "Air Transport",
"stats.fraction.select.revive": "Revive",
"stats.fraction.select.stabilize": "Stabilized",
"stats.fraction.select.flag": "Flag Possession",
"stats.player.detail.headline": "Campaign Details - {{name}}",
"stats.player.detail.button.back": "Back",
"stats.player.detail.kill.death.ratio": "Kill/Death",
"stats.player.detail.respawn.death.ratio": "Respawn/Death",
"stats.player.detail.graph.average": "Average",
"stats.scoreboard.standings": "Final Score:",
"stats.scoreboard.participants": "Participants:",
"stats.scoreboard.show.logs": "Show Logfile",
"stats.scoreboard.download.csv": "Download CSV",
"stats.scoreboard.tab.scoreboard": "Scoreboard",
"stats.scoreboard.tab.fractions": "Fractions",
"stats.scoreboard.tab.player": "Player",
"stats.scoreboard.fraction.filter.all": "All",
"stats.scoreboard.header.player": "Player",
"stats.scoreboard.header.fraction": "Fraction",
"stats.scoreboard.header.kill": "Kills",
"stats.scoreboard.header.friendly.fire": "Friendly Fire",
"stats.scoreboard.header.revive": "Revive",
"stats.scoreboard.header.capture": "Flag Capture",
"stats.scoreboard.header.vehicle.light": "Vehicle (Light)",
"stats.scoreboard.header.vehicle.heavy": "Vehicle (Heavy)",
"stats.scoreboard.header.vehicle.air": "Vehicle (Air)",
"stats.scoreboard.header.death": "Death",
"stats.scoreboard.header.respawn": "Respawn",
"stats.scoreboard.button.detail": "Campaign statistics for {{name}}",
"stats.highscore.filter.placholder": "Player Name (separate multiple using '&')",
"stats.highscore.filter.button": "Filter",
"stats.highscore.header.name": "Name",
"stats.war.submit.headline.new": "Add new battöe",
"stats.war.submit.headline.edit": "Edit battle",
"stats.war.submit.title": "Title",
"stats.war.submit.campaign": "Campaign",
"stats.war.submit.logfile": "Logfile",
"stats.war.submit.points": "Score",
"stats.war.submit.final.budget": "Final budget",
"stats.war.submit.button.submit": "Submit",
"stats.war.submit.button.cancel": "Cancel",
"stats.war.submit.error.file.format": "Logfile requires RPT, LOG or TXT format",
"stats.campaign.submit.headline.new": "Add new campaign",
"stats.campaign.submit.headline.edit": "Edit campaign",
"stats.campaign.submit.title": "Title",
"stats.campaign.submit.button.submit": "Submit",
"stats.campaign.submit.button.cancel": "Cancel",
"public.error.message.required": "{{fieldName}} is a required field",
"public.error.message.min.length": "{{fieldName}} requires at least {{boundary}} characters",
"public.error.message.max.length": "{{fieldName}} is limited to {{boundary}} characters",
"public.error.message.email": "Please enter a valid eMail address",
"public.error.message.no.user": "The choosen user does not exist",
"public.error.message.default": "{{fieldName}} is not valid",
"public.common.search.button": "Search"
} }

View File

@ -1,3 +1,86 @@
{ {
"public.error.message.required": "{{fieldName}} is a required field",
"public.error.message.min.length": "{{fieldName}} requires at least {{boundary}} characters",
"public.error.message.max.length": "{{fieldName}} is limited to {{boundary}} characters",
"public.error.message.email": "Please enter a valid eMail address",
"public.error.message.no.user": "The choosen user does not exist",
"public.error.message.default": "{{fieldName}} is not valid",
"public.common.search.button": "Search",
"stats.campaign.manage.edit": "Edit",
"stats.campaign.manage.delete": "Delete",
"stats.campaign.manage.delete.confirm": "Do you really want to delete the campaign \"{{title}}\"?",
"stats.campaign.title.all.time.overview": "All time overview",
"stats.sidebar.campaign.add": "Add campaign",
"stats.sidebar.battle.add": "Add battle",
"stats.sidebar.overview": "Overview",
"stats.sidebar.highscore": "Highscore",
"stats.sidebar.battles": "Battles",
"stats.sidebar.battles.battle.from.date": "at",
"stats.sidebar.battle.manage.edit": "Edit",
"stats.sidebar.battle.manage.delete": "Delete",
"stats.sidebar.battle.manage.delete.confirm": "Do you really want to delete the battle \"{{title}}\"?",
"stats.graph.select.sum.points": "Total Score",
"stats.graph.select.battle.points": "Score per Battle",
"stats.graph.select.player.count": "Player count",
"stats.fraction.select.points": "Score",
"stats.fraction.select.budget": "Budget",
"stats.fraction.select.kills": "Kills",
"stats.fraction.select.friendly.fire": "Friendly Fire",
"stats.fraction.select.vehicle.kills": "Vehicle Kills",
"stats.fraction.select.air.transport": "Air Transport",
"stats.fraction.select.revive": "Revive",
"stats.fraction.select.stabilize": "Stabilized",
"stats.fraction.select.flag": "Flag Possession",
"stats.player.detail.headline": "Campaign Details - {{name}}",
"stats.player.detail.button.back": "Back",
"stats.player.detail.kill.death.ratio": "Kill/Death",
"stats.player.detail.respawn.death.ratio": "Respawn/Death",
"stats.player.detail.graph.average": "Average",
"stats.scoreboard.standings": "Final Score:",
"stats.scoreboard.participants": "Participants:",
"stats.scoreboard.show.logs": "Show Logfile",
"stats.scoreboard.download.csv": "Download CSV",
"stats.scoreboard.tab.scoreboard": "Scoreboard",
"stats.scoreboard.tab.fractions": "Fractions",
"stats.scoreboard.tab.player": "Player",
"stats.scoreboard.fraction.filter.all": "All",
"stats.scoreboard.header.player": "Player",
"stats.scoreboard.header.fraction": "Fraction",
"stats.scoreboard.header.kill": "Kills",
"stats.scoreboard.header.friendly.fire": "Friendly Fire",
"stats.scoreboard.header.revive": "Revive",
"stats.scoreboard.header.capture": "Flag Capture",
"stats.scoreboard.header.vehicle.light": "Vehicle (Light)",
"stats.scoreboard.header.vehicle.heavy": "Vehicle (Heavy)",
"stats.scoreboard.header.vehicle.air": "Vehicle (Air)",
"stats.scoreboard.header.death": "Death",
"stats.scoreboard.header.respawn": "Respawn",
"stats.scoreboard.button.detail": "Campaign statistics for {{name}}",
"stats.highscore.filter.placholder": "Player Name (separate multiple using '&')",
"stats.highscore.filter.button": "Filter",
"stats.highscore.header.name": "Name",
"stats.war.submit.headline.new": "Add new battöe",
"stats.war.submit.headline.edit": "Edit battle",
"stats.war.submit.title": "Title",
"stats.war.submit.campaign": "Campaign",
"stats.war.submit.logfile": "Logfile",
"stats.war.submit.points": "Score",
"stats.war.submit.final.budget": "Final budget",
"stats.war.submit.button.submit": "Submit",
"stats.war.submit.button.cancel": "Cancel",
"stats.war.submit.error.file.format": "Logfile requires RPT, LOG or TXT format",
"stats.campaign.submit.headline.new": "Add new campaign",
"stats.campaign.submit.headline.edit": "Edit campaign",
"stats.campaign.submit.title": "Title",
"stats.campaign.submit.button.submit": "Submit",
"stats.campaign.submit.button.cancel": "Cancel"
} }