feat(core): implement translation
This commit is contained in:
28
package-lock.json
generated
28
package-lock.json
generated
@@ -21,6 +21,8 @@
|
|||||||
"@fortawesome/free-brands-svg-icons": "^7.0.0",
|
"@fortawesome/free-brands-svg-icons": "^7.0.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^7.0.0",
|
"@fortawesome/free-regular-svg-icons": "^7.0.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
||||||
|
"@ngx-translate/core": "^17.0.0",
|
||||||
|
"@ngx-translate/http-loader": "^17.0.0",
|
||||||
"@primeuix/themes": "^1.2.3",
|
"@primeuix/themes": "^1.2.3",
|
||||||
"@tailwindcss/postcss": "^4.1.12",
|
"@tailwindcss/postcss": "^4.1.12",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
@@ -2600,6 +2602,32 @@
|
|||||||
"@tybys/wasm-util": "^0.10.0"
|
"@tybys/wasm-util": "^0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ngx-translate/core": {
|
||||||
|
"version": "17.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-17.0.0.tgz",
|
||||||
|
"integrity": "sha512-Rft2D5ns2pq4orLZjEtx1uhNuEBerUdpFUG1IcqtGuipj6SavgB8SkxtNQALNDA+EVlvsNCCjC2ewZVtUeN6rg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": ">=16",
|
||||||
|
"@angular/core": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ngx-translate/http-loader": {
|
||||||
|
"version": "17.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-17.0.0.tgz",
|
||||||
|
"integrity": "sha512-hgS8sa0ARjH9ll3PhkLTufeVXNI2DNR2uFKDhBgq13siUXzzVr/a31M6zgecrtwbA34iaBV01hsTMbMS8V7iIw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": ">=16",
|
||||||
|
"@angular/core": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@npmcli/agent": {
|
"node_modules/@npmcli/agent": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz",
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
"@fortawesome/free-brands-svg-icons": "^7.0.0",
|
"@fortawesome/free-brands-svg-icons": "^7.0.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^7.0.0",
|
"@fortawesome/free-regular-svg-icons": "^7.0.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
||||||
|
"@ngx-translate/core": "^17.0.0",
|
||||||
|
"@ngx-translate/http-loader": "^17.0.0",
|
||||||
"@primeuix/themes": "^1.2.3",
|
"@primeuix/themes": "^1.2.3",
|
||||||
"@tailwindcss/postcss": "^4.1.12",
|
"@tailwindcss/postcss": "^4.1.12",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
|
|||||||
6
public/i18n/de.json
Normal file
6
public/i18n/de.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"common": {
|
||||||
|
"home": "Startseite",
|
||||||
|
"about": "Über mich"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
public/i18n/en.json
Normal file
6
public/i18n/en.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"common": {
|
||||||
|
"home": "Home",
|
||||||
|
"about": "About"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ApplicationConfig, LOCALE_ID, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';
|
import { ApplicationConfig, LOCALE_ID, provideAppInitializer, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';
|
||||||
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
||||||
|
|
||||||
import { providePrimeNG } from 'primeng/config';
|
import { providePrimeNG } from 'primeng/config';
|
||||||
@@ -6,9 +6,14 @@ import { Theme } from '../../public/theme/theme';
|
|||||||
|
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import { registerLocaleData } from '@angular/common';
|
import { registerLocaleData } from '@angular/common';
|
||||||
import localeDeAt from '@angular/common/locales/de-AT';
|
import localeDeAt from '@angular/common/locales/de';
|
||||||
import { germanTranslation } from './core/config/translations';
|
import { germanTranslation } from './core/config/translations';
|
||||||
|
|
||||||
|
import {provideTranslateService} from "@ngx-translate/core";
|
||||||
|
import {provideTranslateHttpLoader} from "@ngx-translate/http-loader";
|
||||||
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
|
import { initializeTranslations } from './core/config/translation-init';
|
||||||
|
|
||||||
registerLocaleData(localeDeAt);
|
registerLocaleData(localeDeAt);
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
@@ -16,6 +21,7 @@ export const appConfig: ApplicationConfig = {
|
|||||||
provideBrowserGlobalErrorListeners(),
|
provideBrowserGlobalErrorListeners(),
|
||||||
provideZoneChangeDetection({ eventCoalescing: true }),
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||||
provideRouter(routes, withComponentInputBinding()),
|
provideRouter(routes, withComponentInputBinding()),
|
||||||
|
provideHttpClient(),
|
||||||
{ provide: LOCALE_ID, useValue: 'de-AT' },
|
{ provide: LOCALE_ID, useValue: 'de-AT' },
|
||||||
providePrimeNG({
|
providePrimeNG({
|
||||||
theme: {
|
theme: {
|
||||||
@@ -31,5 +37,12 @@ export const appConfig: ApplicationConfig = {
|
|||||||
},
|
},
|
||||||
translation: germanTranslation, // TODO: dynamic - selected language
|
translation: germanTranslation, // TODO: dynamic - selected language
|
||||||
}),
|
}),
|
||||||
|
provideTranslateService({
|
||||||
|
loader: provideTranslateHttpLoader({
|
||||||
|
prefix: 'i18n/',
|
||||||
|
suffix: '.json'
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
provideAppInitializer(initializeTranslations),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { ThemeSwitchService } from './core/service/theme-switch.service';
|
import { ThemeSwitchService } from './core/service/theme-switch.service';
|
||||||
import { Background } from "./core/components/background/background";
|
import { Background } from "./core/components/background/background";
|
||||||
@@ -11,7 +11,9 @@ import { NavigationBar } from "./core/components/navigation-bar/navigation-bar";
|
|||||||
})
|
})
|
||||||
export class App {
|
export class App {
|
||||||
|
|
||||||
constructor(private themeSwitchService: ThemeSwitchService) {
|
private themeSwitchService = inject(ThemeSwitchService);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
this.themeSwitchService.initialize();
|
this.themeSwitchService.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, ElementRef, HostListener, ViewChild } from '@angular/core';
|
import { Component, ElementRef, HostListener, inject, ViewChild } from '@angular/core';
|
||||||
import { ThemeSwitchService } from '../../service/theme-switch.service';
|
import { ThemeSwitchService } from '../../service/theme-switch.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -9,9 +9,9 @@ import { ThemeSwitchService } from '../../service/theme-switch.service';
|
|||||||
})
|
})
|
||||||
export class Background {
|
export class Background {
|
||||||
|
|
||||||
constructor(
|
private themeSwitchService = inject(ThemeSwitchService);
|
||||||
private themeSwitchService: ThemeSwitchService,
|
|
||||||
) {}
|
constructor() {}
|
||||||
|
|
||||||
@ViewChild('canvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
|
@ViewChild('canvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li class="relative list-none flex flex-row gap-3">
|
<li class="relative list-none flex flex-row gap-3">
|
||||||
<a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">
|
<a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">
|
||||||
Home
|
{{ 'common.home' | translate }}
|
||||||
</a>
|
</a>
|
||||||
<a routerLink="/about" routerLinkActive="active">
|
<a routerLink="/about" routerLinkActive="active">
|
||||||
About
|
{{ 'common.about' | translate }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -26,7 +26,9 @@
|
|||||||
<fa-icon [icon]="faSun"/>
|
<fa-icon [icon]="faSun"/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="language size-[50px]">EN</div>
|
<div class="language size-[50px]" (click)="toggleLanguage()">
|
||||||
|
{{ translateService.getCurrentLang().toUpperCase() }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,34 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { Router, RouterLink, RouterLinkActive } from '@angular/router';
|
import { Router, RouterLink, RouterLinkActive } from '@angular/router';
|
||||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
import { faMoon } from '@fortawesome/free-solid-svg-icons';
|
import { faMoon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faSun } from '@fortawesome/free-solid-svg-icons';
|
import { faSun } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { ThemeSwitchService } from '../../service/theme-switch.service';
|
import { ThemeSwitchService } from '../../service/theme-switch.service';
|
||||||
import { Card } from 'primeng/card';
|
import { Card } from 'primeng/card';
|
||||||
|
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-navigation-bar',
|
selector: 'app-navigation-bar',
|
||||||
imports: [FontAwesomeModule, RouterLink, RouterLinkActive, Card ],
|
imports: [FontAwesomeModule, RouterLink, RouterLinkActive, Card, TranslatePipe],
|
||||||
templateUrl: './navigation-bar.html',
|
templateUrl: './navigation-bar.html',
|
||||||
styleUrl: './navigation-bar.scss'
|
styleUrl: './navigation-bar.scss'
|
||||||
})
|
})
|
||||||
export class NavigationBar {
|
export class NavigationBar {
|
||||||
|
|
||||||
constructor(
|
private router = inject(Router);
|
||||||
private router: Router,
|
protected themeSwitchService = inject(ThemeSwitchService);
|
||||||
protected themeSwitchService: ThemeSwitchService,
|
protected translateService = inject(TranslateService);
|
||||||
) {}
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
isActive(route: string): boolean {
|
isActive(route: string): boolean {
|
||||||
return this.router.url === route;
|
return this.router.url === route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleLanguage(): void {
|
||||||
|
this.translateService.use(this.translateService.getCurrentLang() === 'de' ? 'en' : 'de');
|
||||||
|
}
|
||||||
|
|
||||||
faMoon = faMoon;
|
faMoon = faMoon;
|
||||||
faSun = faSun;
|
faSun = faSun;
|
||||||
|
|
||||||
|
|||||||
22
src/app/core/config/translation-init.ts
Normal file
22
src/app/core/config/translation-init.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { inject } from '@angular/core';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
export function initializeTranslations() {
|
||||||
|
const translate = inject(TranslateService);
|
||||||
|
|
||||||
|
const availableLangs = ['de', 'at', 'en'];
|
||||||
|
translate.addLangs(availableLangs);
|
||||||
|
|
||||||
|
const defaultLang = 'de';
|
||||||
|
let langToUse = translate.getBrowserLang() ?? defaultLang;
|
||||||
|
langToUse = availableLangs.includes(langToUse) ? langToUse : defaultLang;
|
||||||
|
|
||||||
|
translate.setFallbackLang(defaultLang);
|
||||||
|
translate.use(langToUse);
|
||||||
|
|
||||||
|
document.documentElement.lang = langToUse;
|
||||||
|
|
||||||
|
translate.onLangChange.subscribe((event) => {
|
||||||
|
document.documentElement.lang = event.lang;
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -69,7 +69,6 @@ export const germanTranslation: Translation = {
|
|||||||
emptySelectionMessage: 'Kein Element ausgewählt',
|
emptySelectionMessage: 'Kein Element ausgewählt',
|
||||||
emptySearchMessage: 'Keine Ergebnisse gefunden',
|
emptySearchMessage: 'Keine Ergebnisse gefunden',
|
||||||
emptyMessage: 'Keine Optionen verfügbar',
|
emptyMessage: 'Keine Optionen verfügbar',
|
||||||
|
|
||||||
aria: {
|
aria: {
|
||||||
trueLabel: 'Wahr',
|
trueLabel: 'Wahr',
|
||||||
falseLabel: 'Falsch',
|
falseLabel: 'Falsch',
|
||||||
@@ -121,3 +120,132 @@ export const germanTranslation: Translation = {
|
|||||||
rotateLeft: 'Nach links drehen'
|
rotateLeft: 'Nach links drehen'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const austrianTranslation: Translation = {
|
||||||
|
...germanTranslation,
|
||||||
|
monthNames: [
|
||||||
|
'Jänner','Februar','März','April','Mai','Juni',
|
||||||
|
'Juli','August','September','Oktober','November','Dezember'
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const englishTranslation: Translation = {
|
||||||
|
startsWith: 'Starts with',
|
||||||
|
contains: 'Contains',
|
||||||
|
notContains: 'Does not contain',
|
||||||
|
endsWith: 'Ends with',
|
||||||
|
equals: 'Equals',
|
||||||
|
notEquals: 'Not equals',
|
||||||
|
noFilter: 'No Filter',
|
||||||
|
lt: 'Less than',
|
||||||
|
lte: 'Less than or equal to',
|
||||||
|
gt: 'Greater than',
|
||||||
|
gte: 'Greater than or equal to',
|
||||||
|
dateIs: 'Date is',
|
||||||
|
dateIsNot: 'Date is not',
|
||||||
|
dateBefore: 'Date is before',
|
||||||
|
dateAfter: 'Date is after',
|
||||||
|
clear: 'Clear',
|
||||||
|
apply: 'Apply',
|
||||||
|
matchAll: 'Match All',
|
||||||
|
matchAny: 'Match Any',
|
||||||
|
addRule: 'Add Rule',
|
||||||
|
removeRule: 'Remove Rule',
|
||||||
|
accept: 'Yes',
|
||||||
|
reject: 'No',
|
||||||
|
choose: 'Choose',
|
||||||
|
upload: 'Upload',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
completed: 'Completed',
|
||||||
|
pending: 'Pending',
|
||||||
|
fileSizeTypes: ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
|
||||||
|
dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
||||||
|
dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||||||
|
dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
|
||||||
|
monthNames: [
|
||||||
|
'January','February','March','April','May','June',
|
||||||
|
'July','August','September','October','November','December'
|
||||||
|
],
|
||||||
|
monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
|
||||||
|
chooseYear: 'Choose Year',
|
||||||
|
chooseMonth: 'Choose Month',
|
||||||
|
chooseDate: 'Choose Date',
|
||||||
|
prevDecade: 'Previous Decade',
|
||||||
|
nextDecade: 'Next Decade',
|
||||||
|
prevYear: 'Previous Year',
|
||||||
|
nextYear: 'Next Year',
|
||||||
|
prevMonth: 'Previous Month',
|
||||||
|
nextMonth: 'Next Month',
|
||||||
|
prevHour: 'Previous Hour',
|
||||||
|
nextHour: 'Next Hour',
|
||||||
|
prevMinute: 'Previous Minute',
|
||||||
|
nextMinute: 'Next Minute',
|
||||||
|
prevSecond: 'Previous Second',
|
||||||
|
nextSecond: 'Next Second',
|
||||||
|
am: 'AM',
|
||||||
|
pm: 'PM',
|
||||||
|
today: 'Today',
|
||||||
|
weekHeader: 'Wk',
|
||||||
|
firstDayOfWeek: 0,
|
||||||
|
dateFormat: 'mm/dd/yy',
|
||||||
|
weak: 'Weak',
|
||||||
|
medium: 'Medium',
|
||||||
|
strong: 'Strong',
|
||||||
|
passwordPrompt: 'Enter a password',
|
||||||
|
emptyFilterMessage: 'No results found',
|
||||||
|
searchMessage: '{0} results available',
|
||||||
|
selectionMessage: '{0} items selected',
|
||||||
|
emptySelectionMessage: 'No item selected',
|
||||||
|
emptySearchMessage: 'No results found',
|
||||||
|
emptyMessage: 'No options available',
|
||||||
|
aria: {
|
||||||
|
trueLabel: 'True',
|
||||||
|
falseLabel: 'False',
|
||||||
|
nullLabel: 'Not selected',
|
||||||
|
star: '1 Star',
|
||||||
|
stars: '{star} Stars',
|
||||||
|
selectAll: 'Select all items',
|
||||||
|
unselectAll: 'Unselect all items',
|
||||||
|
close: 'Close',
|
||||||
|
previous: 'Previous',
|
||||||
|
next: 'Next',
|
||||||
|
navigation: 'Navigation',
|
||||||
|
scrollTop: 'Scroll to top',
|
||||||
|
moveTop: 'Move to top',
|
||||||
|
moveUp: 'Move up',
|
||||||
|
moveDown: 'Move down',
|
||||||
|
moveBottom: 'Move to bottom',
|
||||||
|
moveToTarget: 'Move to target',
|
||||||
|
moveToSource: 'Move to source',
|
||||||
|
moveAllToTarget: 'Move all to target',
|
||||||
|
moveAllToSource: 'Move all to source',
|
||||||
|
pageLabel: '{page}',
|
||||||
|
firstPageLabel: 'First Page',
|
||||||
|
lastPageLabel: 'Last Page',
|
||||||
|
nextPageLabel: 'Next Page',
|
||||||
|
prevPageLabel: 'Previous Page',
|
||||||
|
rowsPerPageLabel: 'Rows per page',
|
||||||
|
jumpToPageDropdownLabel: 'Select page',
|
||||||
|
jumpToPageInputLabel: 'Enter page',
|
||||||
|
selectRow: 'Row selected',
|
||||||
|
unselectRow: 'Row unselected',
|
||||||
|
expandRow: 'Row expanded',
|
||||||
|
collapseRow: 'Row collapsed',
|
||||||
|
showFilterMenu: 'Show filter menu',
|
||||||
|
hideFilterMenu: 'Hide filter menu',
|
||||||
|
filterOperator: 'Filter operator',
|
||||||
|
filterConstraint: 'Filter constraint',
|
||||||
|
editRow: 'Edit row',
|
||||||
|
saveEdit: 'Save edit',
|
||||||
|
cancelEdit: 'Cancel edit',
|
||||||
|
listView: 'List view',
|
||||||
|
gridView: 'Grid view',
|
||||||
|
slide: 'Slide',
|
||||||
|
slideNumber: '{slideNumber}',
|
||||||
|
zoomImage: 'Zoom image',
|
||||||
|
zoomIn: 'Zoom in',
|
||||||
|
zoomOut: 'Zoom out',
|
||||||
|
rotateRight: 'Rotate right',
|
||||||
|
rotateLeft: 'Rotate left'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>byHaider</title>
|
<title>byHaider</title>
|
||||||
|
|||||||
Reference in New Issue
Block a user