Added flags for language change
This commit is contained in:
36
src/app/app.html
Normal file
36
src/app/app.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<mat-toolbar color="primary">
|
||||
<span>{{ 'APP.TITLE' | translate }}</span>
|
||||
<span class="spacer"></span>
|
||||
|
||||
<!-- Language -->
|
||||
<mat-form-field appearance="outline" style="width: 170px; margin-right: 8px;">
|
||||
<mat-select [value]="lang.lang()" (selectionChange)="lang.use($event.value)">
|
||||
<mat-select-trigger>
|
||||
<img class="flag-icon" [src]="lang.lang() === 'de' ? '/assets/flags/de.svg' : '/assets/flags/gb.svg'"
|
||||
alt="" aria-hidden="true">
|
||||
<span style="margin-left: 8px;">
|
||||
{{ lang.lang() === 'de' ? ('LANG.DE' | translate) : ('LANG.EN' | translate) }}
|
||||
</span>
|
||||
</mat-select-trigger>
|
||||
|
||||
<mat-option value="de">
|
||||
<img class="flag-icon" src="/assets/flags/de.svg" alt="" aria-hidden="true">
|
||||
<span> {{ 'LANG.DE' | translate }} </span>
|
||||
</mat-option>
|
||||
|
||||
<mat-option value="en">
|
||||
<img class="flag-icon" src="/assets/flags/gb.svg" alt="" aria-hidden="true">
|
||||
<span> {{ 'LANG.EN' | translate }} </span>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Theme -->
|
||||
<button mat-icon-button (click)="theme.toggle()">
|
||||
<mat-icon>{{ themeIcon() }}</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
|
||||
<main class="container app-surface">
|
||||
<router-outlet />
|
||||
</main>
|
||||
13
src/app/app.scss
Normal file
13
src/app/app.scss
Normal file
@@ -0,0 +1,13 @@
|
||||
.spacer { flex: 1 1 auto; }
|
||||
.container { max-width: 960px; margin: 24px auto; padding: 0 16px; }
|
||||
mat-form-field { --mdc-outlined-text-field-container-shape: 20px; }
|
||||
|
||||
.flag-icon {
|
||||
width: 20px;
|
||||
height: 14px;
|
||||
object-fit: cover;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 0 1px rgba(0,0,0,.08) inset;
|
||||
vertical-align: -2px;
|
||||
}
|
||||
mat-option .flag-icon { margin-right: 8px; }
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, inject } from '@angular/core';
|
||||
import {Component, computed, effect, inject} from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
@@ -22,35 +22,8 @@ import {LanguageService} from './service/language.service';
|
||||
FormsModule,
|
||||
TranslateModule
|
||||
],
|
||||
template: `
|
||||
<mat-toolbar color="primary">
|
||||
<span>{{ 'APP.TITLE' | translate }}</span>
|
||||
<span class="spacer"></span>
|
||||
|
||||
<!-- Sprache -->
|
||||
<mat-form-field appearance="outline" style="width: 150px; margin-right: 8px;">
|
||||
<mat-select [value]="lang.lang()" (selectionChange)="lang.use($event.value)">
|
||||
<mat-option value="de">{{ 'LANG.DE' | translate }}</mat-option>
|
||||
<mat-option value="en">{{ 'LANG.EN' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Theme -->
|
||||
<button mat-icon-button aria-label="Theme umschalten" (click)="theme.toggle()">
|
||||
<mat-icon>{{ themeIcon() }}</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
|
||||
<main class="container app-surface">
|
||||
<router-outlet />
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.spacer { flex: 1 1 auto; }
|
||||
.container { max-width: 960px; margin: 24px auto; padding: 0 16px; }
|
||||
mat-form-field { --mdc-outlined-text-field-container-shape: 20px; }
|
||||
</style>
|
||||
`,
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss',
|
||||
})
|
||||
export class App {
|
||||
readonly theme = inject(ThemeService);
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
|
||||
static readonly THEME_KEY = 'theme';
|
||||
static readonly LANGUAGE_KEY = 'lang';
|
||||
|
||||
static readonly RELOAD_ALL_LANG_LISTENER_KEY = 'language_dirty_flag';
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export class LanguageService {
|
||||
constructor() {
|
||||
this.translate.addLangs(['de', 'en']);
|
||||
this.translate.setFallbackLang('en');
|
||||
this.lang.set(this.getInitial());
|
||||
this.use(this.lang());
|
||||
}
|
||||
|
||||
|
||||
32
src/app/service/reload.service.ts
Normal file
32
src/app/service/reload.service.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Injectable, NgZone, signal } from '@angular/core';
|
||||
import {Constants} from '../constants/Constants';
|
||||
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ReloadService {
|
||||
private readonly _reloadTick = signal(0);
|
||||
readonly reloadTick = this._reloadTick.asReadonly();
|
||||
|
||||
private readonly _languageChangedTick = signal(0);
|
||||
readonly languageChangedTick = this._languageChangedTick.asReadonly();
|
||||
|
||||
constructor(zone: NgZone) {
|
||||
zone.runOutsideAngular(() => {
|
||||
globalThis.addEventListener('storage', (e: StorageEvent) => {
|
||||
this.informListeners(e, zone);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private informListeners(e: StorageEvent, zone: NgZone) {
|
||||
if (e.key === Constants.LANGUAGE_KEY) {
|
||||
zone.run(() => this._languageChangedTick.update(v => v + 1));
|
||||
}
|
||||
}
|
||||
|
||||
bumpLanguageChanged(): void {
|
||||
this._reloadTick.update(v => v + 1);
|
||||
localStorage.setItem(Constants.RELOAD_ALL_LANG_LISTENER_KEY, String(Date.now()));
|
||||
}
|
||||
}
|
||||
5
src/assets/flags/de.svg
Normal file
5
src/assets/flags/de.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480">
|
||||
<path fill="#000" d="M0 0h640v160H0z"/>
|
||||
<path fill="#dd0000" d="M0 160h640v160H0z"/>
|
||||
<path fill="#ffce00" d="M0 320h640v160H0z"/>
|
||||
</svg>
|
||||
10
src/assets/flags/gb.svg
Normal file
10
src/assets/flags/gb.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480">
|
||||
<defs><clipPath id="a"><path d="M0 0h640v480H0z"/></clipPath></defs>
|
||||
<g clip-path="url(#a)">
|
||||
<path fill="#012169" d="M0 0h640v480H0z"/>
|
||||
<path stroke="#fff" stroke-width="60" d="M0 0l640 480M640 0L0 480"/>
|
||||
<path stroke="#c8102e" stroke-width="40" d="M0 0l640 480M640 0L0 480"/>
|
||||
<path fill="#fff" d="M0 192h640v96H0zM272 0h96v480h-96z"/>
|
||||
<path fill="#c8102e" d="M0 208h640v64H0zM288 0h64v480h-64z"/>
|
||||
</g>
|
||||
</svg>
|
||||
Reference in New Issue
Block a user