diff --git a/angular.json b/angular.json index 267c8b1..a032859 100644 --- a/angular.json +++ b/angular.json @@ -17,7 +17,8 @@ "index": "src/index.html", "browser": "src/main.ts", "polyfills": [ - "zone.js" + "zone.js", + "@angular/localize/init" ], "tsConfig": "tsconfig.app.json", "assets": [ @@ -51,6 +52,15 @@ ], "outputHashing": "all" }, + "en": { + "localize": ["en"], + "outputPath": "dist/arti-angular-app-en" + }, + "pl": { + "localize": ["pl"], + "outputPath": "dist/arti-angular-app-pl" + }, + "development": { "optimization": false, "extractLicenses": false, @@ -83,7 +93,8 @@ "options": { "polyfills": [ "zone.js", - "zone.js/testing" + "zone.js/testing", + "@angular/localize/init" ], "tsConfig": "tsconfig.spec.json", "assets": [ diff --git a/package-lock.json b/package-lock.json index 414c127..299efb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "@angular/platform-browser": "^18.2.0", "@angular/platform-browser-dynamic": "^18.2.0", "@angular/router": "^18.2.0", + "@ngx-translate/core": "^16.0.3", + "@ngx-translate/http-loader": "^16.0.0", "bootstrap": "^5.3.3", "rxjs": "~7.8.0", "tslib": "^2.3.0", @@ -25,6 +27,7 @@ "@angular-devkit/build-angular": "^18.2.4", "@angular/cli": "^18.2.4", "@angular/compiler-cli": "^18.2.0", + "@angular/localize": "^18.2.4", "@types/jasmine": "~5.1.0", "jasmine-core": "~5.2.0", "karma": "~6.4.0", @@ -1652,6 +1655,30 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@angular/localize": { + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.2.4.tgz", + "integrity": "sha512-3QgfYNwM4Dkd7sWu/JXZfOToporIrgdyi/G8T2zgTtArbvPNbZdSmihpSjKVmsDzB4ScXlOCH/sf0rLKIYkKwQ==", + "dev": true, + "dependencies": { + "@babel/core": "7.25.2", + "@types/babel__core": "7.20.5", + "fast-glob": "3.3.2", + "yargs": "^17.2.1" + }, + "bin": { + "localize-extract": "tools/bundles/src/extract/cli.js", + "localize-migrate": "tools/bundles/src/migrate/cli.js", + "localize-translate": "tools/bundles/src/translate/cli.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/compiler": "18.2.4", + "@angular/compiler-cli": "18.2.4" + } + }, "node_modules/@angular/platform-browser": { "version": "18.2.4", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.4.tgz", @@ -4491,6 +4518,30 @@ "webpack": "^5.54.0" } }, + "node_modules/@ngx-translate/core": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-16.0.3.tgz", + "integrity": "sha512-UPse66z9tRUmIpeorYodXBQY6O4foUmj9jy9cCuuja7lqdOwRBWPzCWqc+qYIXv5L2QoqZdxgHtqoUz+Q9weSA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=16", + "@angular/core": ">=16" + } + }, + "node_modules/@ngx-translate/http-loader": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-16.0.0.tgz", + "integrity": "sha512-l3okOHGVxZ1Bm55OpakSfXvI2yYmVmhYqgwGU4aIQIRUqpkBCrSDZnmrHTcZfsGJzXKB5E2D2rko9i28gBijmA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=16", + "@angular/core": ">=16" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5191,6 +5242,47 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", diff --git a/package.json b/package.json index 5f5e9c2..ae79ccb 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "@angular/platform-browser": "^18.2.0", "@angular/platform-browser-dynamic": "^18.2.0", "@angular/router": "^18.2.0", + "@ngx-translate/core": "^16.0.3", + "@ngx-translate/http-loader": "^16.0.0", "bootstrap": "^5.3.3", "rxjs": "~7.8.0", "tslib": "^2.3.0", @@ -27,6 +29,7 @@ "@angular-devkit/build-angular": "^18.2.4", "@angular/cli": "^18.2.4", "@angular/compiler-cli": "^18.2.0", + "@angular/localize": "^18.2.4", "@types/jasmine": "~5.1.0", "jasmine-core": "~5.2.0", "karma": "~6.4.0", diff --git a/public/flag-icons-main/flags/1x1/pl.svg b/public/flag-icons-main/flags/1x1/pl.svg new file mode 100644 index 0000000..8c43577 --- /dev/null +++ b/public/flag-icons-main/flags/1x1/pl.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/flag-icons-main/flags/1x1/us.svg b/public/flag-icons-main/flags/1x1/us.svg new file mode 100644 index 0000000..a722047 --- /dev/null +++ b/public/flag-icons-main/flags/1x1/us.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/flag-icons-main/flags/4x3/pl.svg b/public/flag-icons-main/flags/4x3/pl.svg new file mode 100644 index 0000000..0fa5145 --- /dev/null +++ b/public/flag-icons-main/flags/4x3/pl.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/flag-icons-main/flags/4x3/us.svg b/public/flag-icons-main/flags/4x3/us.svg new file mode 100644 index 0000000..9cfd0c9 --- /dev/null +++ b/public/flag-icons-main/flags/4x3/us.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/app/about-me/about-me.component.html b/src/app/about-me/about-me.component.html index 20cea5c..55a5d9f 100644 --- a/src/app/about-me/about-me.component.html +++ b/src/app/about-me/about-me.component.html @@ -27,44 +27,8 @@ -
-
-

Jestem doświadczonym inżynierem oprogramowania z ponad 20-letnim doświadczeniem w branży IT.

-

Specjalizuję się w technologiach Java i Angular, a także w rozwijaniu i wdrażaniu skalowalnych aplikacji webowych.

-

Jestem posiadaczem certyfikatu Oracle Cloud Infrastructure 2024 Generative AI Certified Professional oraz wcześniejszych - kwalifikacji w obszarze chmury Oracle i programowania w języku Java.

-

Te umiejętności wspierają moje działania w zakresie wdrażania nowoczesnych rozwiązań opartych na chmurze - oraz tworzenia aplikacji zorientowanych na przyszłość.

- -
- - +
+
diff --git a/src/app/about-me/about-me.component.ts b/src/app/about-me/about-me.component.ts index a2e4b92..da4aa08 100644 --- a/src/app/about-me/about-me.component.ts +++ b/src/app/about-me/about-me.component.ts @@ -1,13 +1,51 @@ -import { Component } from '@angular/core'; -import {NgOptimizedImage} from '@angular/common' +import { Component, OnDestroy } from '@angular/core'; +import { NgOptimizedImage } from '@angular/common' +import { TranslateModule, TranslateService, LangChangeEvent } from "@ngx-translate/core"; +import { Pipe, PipeTransform } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; +import { Subscription } from 'rxjs'; + +@Pipe({ name: 'sanitizeHtml' }) +export class SanitizeHtmlPipe implements PipeTransform { + + constructor(private sanitizer: DomSanitizer) { } + + transform(html: string): any { + return this.sanitizer.bypassSecurityTrustHtml(html); + } +} @Component({ selector: 'app-about-me', standalone: true, - imports: [NgOptimizedImage], + imports: [NgOptimizedImage, TranslateModule], templateUrl: './about-me.component.html', styleUrl: './about-me.component.css' }) -export class AboutMeComponent { -} +export class AboutMeComponent implements OnDestroy{ + + aboutDescription: string | undefined; + private langChangeSub: Subscription; + constructor(private translate: TranslateService) { + + this.langChangeSub = this.translate.onLangChange.subscribe(() => { + this.loadAboutDescription(); + }); + this.loadAboutDescription(); + } + + private loadAboutDescription(): void { + this.translate.get('aboutMe.description').subscribe((text: string) => { + this.aboutDescription = text; + }); + } + + ngOnDestroy(): void { + // Unsubscribe to avoid memory leaks + if (this.langChangeSub) { + this.langChangeSub.unsubscribe(); + } + } + +} \ No newline at end of file diff --git a/src/app/app.component.html b/src/app/app.component.html index a013195..eaa7bdb 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,11 +1,22 @@ - +
+ + + +
+
+ + {{ 'topBar.aboutMe' | translate }} + {{ 'topBar.depreciationCalculator' | translate }} + {{ 'topBar.courses' | translate }} +
+ + + ` \ No newline at end of file diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 800ea59..264c594 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,13 +1,24 @@ import { Component } from '@angular/core'; import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router'; - +import { TranslateService, TranslateModule} from "@ngx-translate/core"; @Component({ selector: 'app-root', standalone: true, - imports: [RouterOutlet, RouterLink, RouterLinkActive], + imports: [ RouterOutlet, TranslateModule ], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent { + constructor( public translate: TranslateService ){ + this.translate.addLangs(['pl', 'en']); + this.translate.setDefaultLang('pl'); + this.translate.use('en'); + } + + // app.component.ts + switchLanguage(language: string) { + this.translate.use(language); + } + title = 'arti-angular-app'; } diff --git a/src/app/app.config.ts b/src/app/app.config.ts index f046db3..0b072ec 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,11 +1,30 @@ -import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; -import { provideHttpClient } from '@angular/common/http'; +import { HttpClient, provideHttpClient} from '@angular/common/http'; + + +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { TranslateHttpLoader } from '@ngx-translate/http-loader'; + +const httpLoaderFactory: (http: HttpClient) => TranslateHttpLoader = (http: HttpClient) => + new TranslateHttpLoader(http, './i18n/', '.json'); +// Configuration function for TranslateModule export const appConfig: ApplicationConfig = { - providers: [provideZoneChangeDetection({ eventCoalescing: true }), - provideRouter(routes), - provideHttpClient()] + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideHttpClient(), + provideRouter(routes), + importProvidersFrom([ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: httpLoaderFactory, + deps: [ HttpClient ], + }, + })]) + ], }; + diff --git a/src/app/asset-calculator/asset-calculator.component.html b/src/app/asset-calculator/asset-calculator.component.html index 9d0f2a1..0f16d06 100644 --- a/src/app/asset-calculator/asset-calculator.component.html +++ b/src/app/asset-calculator/asset-calculator.component.html @@ -1,17 +1,22 @@ -
+
+ +
-
Kalkulator amortyzacyjny
+
+ {{ 'asset-calculator.depreciationCalculator' | translate }} +
-
Środek trwały
+
{{ 'asset-calculator.fixedAsset' | translate }}
- +
@@ -26,7 +31,7 @@
- +
@@ -38,7 +43,7 @@
- +
@@ -49,12 +54,12 @@
- +
@@ -62,17 +67,17 @@ @if( TypeDepreciation.digressive === assetsDepreciationFormGroup.get( 'typeDepreciation' )?.value ) {
- +
- +
}
+ [disabled]=assetsDepreciationFormGroup.invalid (click)=addChangeValue() type="button" value="{{ 'asset-calculator.addChangeValue' | translate }}">
@@ -81,15 +86,15 @@ @if( lifeFormArray.controls.length > 0 ){
-
Zmiany wartości
+
{{ 'asset-calculator.valueChanges' | translate }}
- - - + + + @@ -99,7 +104,7 @@ - } @@ -111,17 +116,17 @@
-

Plan amortyzacji

+

{{ 'asset-calculator.depreciationPlan' | translate }}

LpMiesiącZmiana{{ 'asset-calculator.lp' | translate }}{{ 'asset-calculator.month' | translate }}{{ 'asset-calculator.change' | translate }}
{{$index+1}} +
- - - - - + + + + + @@ -139,17 +144,17 @@ - - - - - - + + + + + + } } @@ -158,5 +163,6 @@ + diff --git a/src/app/asset-calculator/asset-calculator.component.ts b/src/app/asset-calculator/asset-calculator.component.ts index c517a6f..72eec8e 100644 --- a/src/app/asset-calculator/asset-calculator.component.ts +++ b/src/app/asset-calculator/asset-calculator.component.ts @@ -1,11 +1,10 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { ReactiveFormsModule, FormGroup, Validators, FormControl, FormArray } from '@angular/forms'; -import { CurrencyPipe,DecimalPipe,PercentPipe } from '@angular/common'; - +import { DecimalPipe } from '@angular/common'; import {Asset, Positions, AssetPlanPosition, TypeDepreciation, YearMonth, AssetLifeChange, AssetDepreciationMethod, YearMonthUtil } from '../assets/asset'; import {AssetService} from '../assets/service/asset.service' - +import {TranslateModule} from "@ngx-translate/core"; interface FormValues { initialValueAsset: number; @@ -15,11 +14,11 @@ interface FormValues { factor: number; } @Component({ -selector: 'app-asset-calculator', -standalone: true, -imports: [ CurrencyPipe, DecimalPipe, PercentPipe, ReactiveFormsModule ] , -templateUrl: "asset-calculator.component.html", -styleUrl: 'asset-calculator.component.css' + selector: 'app-asset-calculator', + standalone: true, + imports: [ DecimalPipe, ReactiveFormsModule, TranslateModule ] , + templateUrl: "asset-calculator.component.html", + styleUrl: 'asset-calculator.component.css' }) export class AssetCalculatorComponent implements OnInit, OnDestroy{ @@ -40,11 +39,11 @@ export class AssetCalculatorComponent implements OnInit, OnDestroy{ [key in keyof FormValues]: FormControl }); - constructor(private assetService : AssetService ){ + constructor(private assetService : AssetService){ this.assetsDepreciationFormGroup.valueChanges.subscribe( (value) => this.calculate() ); this.lifeFormArray.valueChanges.subscribe( (value) => this.calculate() ); + } - } ngOnInit(): void{ const savedAsset = localStorage.getItem('assetForCalculator'); diff --git a/src/main.ts b/src/main.ts index 35b00f3..ee35435 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,5 @@ +/// + import { bootstrapApplication } from '@angular/platform-browser'; import { appConfig } from './app/app.config'; import { AppComponent } from './app/app.component'; diff --git a/tsconfig.app.json b/tsconfig.app.json index 3775b37..3e50bc3 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -4,7 +4,9 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/app", - "types": [] + "types": [ + "@angular/localize" + ] }, "files": [ "src/main.ts" diff --git a/tsconfig.spec.json b/tsconfig.spec.json index 5fb748d..b4c6282 100644 --- a/tsconfig.spec.json +++ b/tsconfig.spec.json @@ -5,7 +5,8 @@ "compilerOptions": { "outDir": "./out-tsc/spec", "types": [ - "jasmine" + "jasmine", + "@angular/localize" ] }, "include": [
LpRokMiesiącKwota odpisuLączny odpis{{ 'asset-calculator.lp' | translate }}{{ 'asset-calculator.year' | translate }}{{ 'asset-calculator.month' | translate }}{{ 'asset-calculator.amountWriteOf' | translate }}{{ 'asset-calculator.totalWriteOf' | translate }}
-
Łącznie w roku {{position.when.year}} odpis : {{ position.sumThisYear| number:'1.2-2' }}
+
{{ 'asset-calculator.totalInTheYear' | translate:{ year: position.when.year, total : position.sumThisYear| number:'1.2-2' } }}
LpRokMiesiącKwota odpisuLączny odpis
{{ 'asset-calculator.lp' | translate }}{{ 'asset-calculator.year' | translate }}{{ 'asset-calculator.month' | translate }}{{ 'asset-calculator.amountWriteOf' | translate }}{{ 'asset-calculator.totalWriteOf' | translate }}