Browse Source

Bugfix/localization of date pickers (#8232)

* Fix localization of date pickers

* Update changelog
pull/8230/head^2
Thomas Kaul 4 days ago
committed by GitHub
parent
commit
853914ca14
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      CHANGELOG.md
  2. 18
      apps/client/src/app/app.component.ts
  3. 6
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts
  4. 13
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  5. 9
      libs/ui/src/lib/account-balances/account-balances.component.ts
  6. 11
      libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts

5
CHANGELOG.md

@ -20,6 +20,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the performance of the historical market data table of the admin control panel by loading only the latest market price per asset profile - Improved the performance of the historical market data table of the admin control panel by loading only the latest market price per asset profile
- Introduced a cooldown of 12 hours for the asset profile and exchange rate gathering on activity creation by retaining the completed jobs - Introduced a cooldown of 12 hours for the asset profile and exchange rate gathering on activity creation by retaining the completed jobs
### Fixed
- Fixed the missing localization of the date picker in the _FIRE_ calculator
- Fixed the missing localization of the date picker in the asset profile details dialog of the admin control panel
## 3.88.0 - 2026-10-17 ## 3.88.0 - 2026-10-17
### Added ### Added

18
apps/client/src/app/app.component.ts

@ -25,6 +25,7 @@ import {
OnInit OnInit
} from '@angular/core'; } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DateAdapter } from '@angular/material/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { import {
@ -39,7 +40,7 @@ import { Chart } from 'chart.js';
import { addIcons } from 'ionicons'; import { addIcons } from 'ionicons';
import { openOutline } from 'ionicons/icons'; import { openOutline } from 'ionicons/icons';
import { DeviceDetectorService } from 'ngx-device-detector'; import { DeviceDetectorService } from 'ngx-device-detector';
import { filter } from 'rxjs/operators'; import { distinctUntilChanged, filter, map } from 'rxjs/operators';
import { GfFooterComponent } from './components/footer/footer.component'; import { GfFooterComponent } from './components/footer/footer.component';
import { GfHeaderComponent } from './components/header/header.component'; import { GfHeaderComponent } from './components/header/header.component';
@ -75,6 +76,7 @@ export class GfAppComponent implements OnInit {
private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly dataService = inject(DataService); private readonly dataService = inject(DataService);
private readonly dateAdapter = inject<DateAdapter<Date, string>>(DateAdapter);
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
private readonly deviceDetectorService = inject(DeviceDetectorService); private readonly deviceDetectorService = inject(DeviceDetectorService);
private readonly dialog = inject(MatDialog); private readonly dialog = inject(MatDialog);
@ -212,6 +214,20 @@ export class GfAppComponent implements OnInit {
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });
this.userService.stateChanged
.pipe(
map(({ user }) => {
return user?.settings.locale;
}),
distinctUntilChanged(),
takeUntilDestroyed(this.destroyRef)
)
.subscribe((locale) => {
if (locale) {
this.dateAdapter.setLocale(locale);
}
});
this.userService.stateChanged this.userService.stateChanged
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((state) => { .subscribe((state) => {

6
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts

@ -1,5 +1,5 @@
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_LOCALE, MCP_ENDPOINT } from '@ghostfolio/common/config'; import { MCP_ENDPOINT } from '@ghostfolio/common/config';
import { CreateAccessDto, UpdateAccessDto } from '@ghostfolio/common/dtos'; import { CreateAccessDto, UpdateAccessDto } from '@ghostfolio/common/dtos';
import { canApplyFiltersToAccess } from '@ghostfolio/common/helper'; import { canApplyFiltersToAccess } from '@ghostfolio/common/helper';
import { Filter, PortfolioPosition } from '@ghostfolio/common/interfaces'; import { Filter, PortfolioPosition } from '@ghostfolio/common/interfaces';
@ -48,7 +48,6 @@ import {
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { DateAdapter } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDatepickerModule } from '@angular/material/datepicker';
import { import {
MAT_DIALOG_DATA, MAT_DIALOG_DATA,
@ -108,7 +107,6 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
private readonly data = private readonly data =
inject<CreateOrUpdateAccessDialogParams>(MAT_DIALOG_DATA); inject<CreateOrUpdateAccessDialogParams>(MAT_DIALOG_DATA);
private readonly dateAdapter = inject<DateAdapter<Date, string>>(DateAdapter);
private readonly dataService = inject(DataService); private readonly dataService = inject(DataService);
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
@ -189,8 +187,6 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit {
this.hasExperimentalFeatures = settings.isExperimentalFeatures ?? false; this.hasExperimentalFeatures = settings.isExperimentalFeatures ?? false;
this.tags = getTagFilters(tags); this.tags = getTagFilters(tags);
this.dateAdapter.setLocale(settings.locale ?? DEFAULT_LOCALE);
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });

13
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts

@ -6,10 +6,7 @@ import {
DEFAULT_LOCALE DEFAULT_LOCALE
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos'; import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos';
import { import { getStringOrNull } from '@ghostfolio/common/helper';
getDateFormatString,
getStringOrNull
} from '@ghostfolio/common/helper';
import { import {
AssetClassSelectorOption, AssetClassSelectorOption,
LookupItem LookupItem
@ -41,7 +38,6 @@ import {
} from '@angular/forms'; } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDatepickerModule } from '@angular/material/datepicker';
import { import {
MAT_DIALOG_DATA, MAT_DIALOG_DATA,
@ -102,7 +98,6 @@ export class GfCreateOrUpdateActivityDialogComponent {
protected currencies: string[] = []; protected currencies: string[] = [];
protected currencyOfAssetProfile: string | undefined; protected currencyOfAssetProfile: string | undefined;
protected currentMarketPrice: number | null = null; protected currentMarketPrice: number | null = null;
protected defaultDateFormat: string;
protected defaultLookupItems: LookupItem[] = []; protected defaultLookupItems: LookupItem[] = [];
protected hasPermissionToCreateOwnTag: boolean; protected hasPermissionToCreateOwnTag: boolean;
protected isLoading = false; protected isLoading = false;
@ -119,7 +114,6 @@ export class GfCreateOrUpdateActivityDialogComponent {
private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly dataService = inject(DataService); private readonly dataService = inject(DataService);
private readonly dateAdapter = inject<DateAdapter<Date, string>>(DateAdapter);
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
private readonly dialogRef = private readonly dialogRef =
inject<MatDialogRef<GfCreateOrUpdateActivityDialogComponent>>(MatDialogRef); inject<MatDialogRef<GfCreateOrUpdateActivityDialogComponent>>(MatDialogRef);
@ -127,7 +121,6 @@ export class GfCreateOrUpdateActivityDialogComponent {
private readonly impersonationStorageService = inject( private readonly impersonationStorageService = inject(
ImpersonationStorageService ImpersonationStorageService
); );
private locale = inject<string>(MAT_DATE_LOCALE);
private readonly userService = inject(UserService); private readonly userService = inject(UserService);
public constructor() { public constructor() {
@ -143,15 +136,11 @@ export class GfCreateOrUpdateActivityDialogComponent {
!this.impersonationStorageService.getId() && !this.impersonationStorageService.getId() &&
hasPermission(this.data.user?.permissions, permissions.createOwnTag); hasPermission(this.data.user?.permissions, permissions.createOwnTag);
this.locale = this.data.user.settings.locale ?? DEFAULT_LOCALE;
this.mode = this.data.activity?.id ? 'update' : 'create'; this.mode = this.data.activity?.id ? 'update' : 'create';
this.dateAdapter.setLocale(this.locale);
const { currencies } = this.dataService.fetchInfo(); const { currencies } = this.dataService.fetchInfo();
this.currencies = currencies; this.currencies = currencies;
this.defaultDateFormat = getDateFormatString(this.locale);
this.dataService this.dataService
.fetchPortfolioHoldings({ .fetchPortfolioHoldings({

9
libs/ui/src/lib/account-balances/account-balances.component.ts

@ -11,7 +11,6 @@ import {
Component, Component,
EventEmitter, EventEmitter,
OnChanges, OnChanges,
OnInit,
Output, Output,
effect, effect,
inject, inject,
@ -25,7 +24,6 @@ import {
ReactiveFormsModule ReactiveFormsModule
} from '@angular/forms'; } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { DateAdapter } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
@ -63,7 +61,7 @@ import { GfValueComponent } from '../value';
styleUrls: ['./account-balances.component.scss'], styleUrls: ['./account-balances.component.scss'],
templateUrl: './account-balances.component.html' templateUrl: './account-balances.component.html'
}) })
export class GfAccountBalancesComponent implements OnChanges, OnInit { export class GfAccountBalancesComponent implements OnChanges {
@Output() accountBalanceCreated = new EventEmitter<CreateAccountBalanceDto>(); @Output() accountBalanceCreated = new EventEmitter<CreateAccountBalanceDto>();
@Output() accountBalanceDeleted = new EventEmitter<string>(); @Output() accountBalanceDeleted = new EventEmitter<string>();
@ -94,7 +92,6 @@ export class GfAccountBalancesComponent implements OnChanges, OnInit {
>(); >();
public maxDate = new Date(); public maxDate = new Date();
private dateAdapter = inject<DateAdapter<Date, string>>(DateAdapter);
private notificationService = inject(NotificationService); private notificationService = inject(NotificationService);
public constructor() { public constructor() {
@ -112,10 +109,6 @@ export class GfAccountBalancesComponent implements OnChanges, OnInit {
}); });
} }
public ngOnInit() {
this.dateAdapter.setLocale(this.locale());
}
public ngOnChanges() { public ngOnChanges() {
if (this.accountBalances()) { if (this.accountBalances()) {
this.dataSource = new MatTableDataSource(this.accountBalances()); this.dataSource = new MatTableDataSource(this.accountBalances());

11
libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts

@ -6,7 +6,6 @@ import {
Component, Component,
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
DestroyRef, DestroyRef,
OnInit,
inject inject
} from '@angular/core'; } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@ -17,7 +16,6 @@ import {
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDatepickerModule } from '@angular/material/datepicker';
import { import {
MAT_DIALOG_DATA, MAT_DIALOG_DATA,
@ -50,7 +48,7 @@ import { HistoricalMarketDataEditorDialogParams } from './interfaces/interfaces'
styleUrls: ['./historical-market-data-editor-dialog.scss'], styleUrls: ['./historical-market-data-editor-dialog.scss'],
templateUrl: 'historical-market-data-editor-dialog.html' templateUrl: 'historical-market-data-editor-dialog.html'
}) })
export class GfHistoricalMarketDataEditorDialogComponent implements OnInit { export class GfHistoricalMarketDataEditorDialogComponent {
public readonly data = public readonly data =
inject<HistoricalMarketDataEditorDialogParams>(MAT_DIALOG_DATA); inject<HistoricalMarketDataEditorDialogParams>(MAT_DIALOG_DATA);
@ -60,23 +58,16 @@ export class GfHistoricalMarketDataEditorDialogComponent implements OnInit {
}); });
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
private readonly locale =
this.data.user.settings.locale ?? inject<string>(MAT_DATE_LOCALE);
public constructor( public constructor(
private adminService: AdminService, private adminService: AdminService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private dataService: DataService, private dataService: DataService,
private dateAdapter: DateAdapter<Date, string>,
public dialogRef: MatDialogRef<GfHistoricalMarketDataEditorDialogComponent> public dialogRef: MatDialogRef<GfHistoricalMarketDataEditorDialogComponent>
) { ) {
addIcons({ calendarClearOutline, refreshOutline }); addIcons({ calendarClearOutline, refreshOutline });
} }
public ngOnInit() {
this.dateAdapter.setLocale(this.locale);
}
public onCancel() { public onCancel() {
this.dialogRef.close({ withRefresh: false }); this.dialogRef.close({ withRefresh: false });
} }

Loading…
Cancel
Save