From 6372b3edf50c65faadcbd703bd114f87437a8ea6 Mon Sep 17 00:00:00 2001
From: Cole Munz <145523609+munzzyy@users.noreply.github.com>
Date: Tue, 7 Jul 2026 01:09:08 -0500
Subject: [PATCH 1/4] Task/improve language localization for NL (#7260)
* Update translations
* Update changelog
---
CHANGELOG.md | 1 +
apps/client/src/locales/messages.nl.xlf | 114 ++++++++++++------------
2 files changed, 58 insertions(+), 57 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26502a243..e968ebdba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Set the change detection strategy to `OnPush` in the _FIRE_ page
+- Improved the language localization for Dutch (`nl`)
- Improved the language localization for French (`fr`)
- Improved the language localization for German (`de`)
diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf
index 455745435..d0b61f75f 100644
--- a/apps/client/src/locales/messages.nl.xlf
+++ b/apps/client/src/locales/messages.nl.xlf
@@ -311,7 +311,7 @@
Paid
- Paid
+ Betaald
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts
122
@@ -387,7 +387,7 @@
and is driven by the efforts of its contributors
- en wordt gedreven door de inspanningen van zijn bijdragers
+ en wordt gedreven door de inspanningen van zijn bijdragers
apps/client/src/app/pages/about/overview/about-overview-page.html
50
@@ -479,7 +479,7 @@
Watch the Ghostfol.io Trailer on YouTube
- Watch the Ghostfol.io Trailer on YouTube
+ Bekijk de Ghostfol.io-trailer op YouTube
apps/client/src/app/pages/landing/landing-page.html
19
@@ -751,7 +751,7 @@
Creation
- Creation
+ Aanmaakdatum
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html
145
@@ -899,7 +899,7 @@
Energy
- Energy
+ Energie
libs/ui/src/lib/i18n.ts
94
@@ -1127,7 +1127,7 @@
Ghostfolio in Numbers: Monthly Active Users (MAU)
- Ghostfolio in Numbers: Monthly Active Users (MAU)
+ Ghostfolio in cijfers: maandelijks actieve gebruikers (MAU)
apps/client/src/app/pages/landing/landing-page.html
63
@@ -1251,7 +1251,7 @@
Consumer Defensive
- Consumer Defensive
+ Basisconsumptiegoederen
libs/ui/src/lib/i18n.ts
93
@@ -1319,7 +1319,7 @@
Utilities
- Utilities
+ Nutsbedrijven
libs/ui/src/lib/i18n.ts
101
@@ -1343,7 +1343,7 @@
Coupon
- Coupon
+ Coupon
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts
127
@@ -1563,7 +1563,7 @@
Financial Planning
- Financial Planning
+ Financiële planning
libs/ui/src/lib/i18n.ts
108
@@ -1707,7 +1707,7 @@
Duration
- Duration
+ Looptijd
apps/client/src/app/components/admin-overview/admin-overview.html
172
@@ -1923,7 +1923,7 @@
Trial
- Trial
+ Proefperiode
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts
126
@@ -2071,7 +2071,7 @@
Consumer Cyclical
- Consumer Cyclical
+ Cyclische consumptiegoederen
libs/ui/src/lib/i18n.ts
92
@@ -2467,7 +2467,7 @@
{VAR_PLURAL, plural, =1 {Profile} other {Profiles}}
- {VAR_PLURAL, plural, =1 {Profile} other {Profiles}}
+ {VAR_PLURAL, plural, =1 {Profiel} other {Profielen}}
apps/client/src/app/components/admin-market-data/admin-market-data.html
249
@@ -2707,7 +2707,7 @@
Apply current market price
- Apply current market price
+ Huidige marktprijs toepassen
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html
238
@@ -2715,7 +2715,7 @@
Subscription History
- Subscription History
+ Abonnementsgeschiedenis
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html
136
@@ -2867,7 +2867,7 @@
Contributors to Ghostfolio
- Contributors to Ghostfolio
+ Bijdragers aan Ghostfolio
apps/client/src/app/pages/about/overview/about-overview-page.html
54
@@ -2907,7 +2907,7 @@
Code
- Code
+ Code
apps/client/src/app/components/admin-overview/admin-overview.html
159
@@ -3215,7 +3215,7 @@
Communication Services
- Communication Services
+ Communicatiediensten
libs/ui/src/lib/i18n.ts
91
@@ -3275,7 +3275,7 @@
Price
- Price
+ Prijs
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html
171
@@ -3283,7 +3283,7 @@
Data Gathering Frequency
- Data Gathering Frequency
+ Frequentie van gegevensverzameling
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
454
@@ -3447,7 +3447,7 @@
just now
- just now
+ zojuist
apps/client/src/app/components/admin-users/admin-users.component.ts
211
@@ -3739,7 +3739,7 @@
Hourly
- Hourly
+ Elk uur
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
214
@@ -3831,7 +3831,7 @@
Expiration
- Expiration
+ Vervaldatum
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html
204
@@ -3951,7 +3951,7 @@
Loan
- Loan
+ Lening
libs/ui/src/lib/i18n.ts
64
@@ -4051,7 +4051,7 @@
Explore
- Explore
+ Verken
apps/client/src/app/pages/resources/overview/resources-overview.component.html
11
@@ -4463,7 +4463,7 @@
Technology
- Technology
+ Technologie
libs/ui/src/lib/i18n.ts
100
@@ -4479,7 +4479,7 @@
Total
- Total
+ Totaal
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html
155
@@ -4599,7 +4599,7 @@
Upgrade to Ghostfolio Premium
- Upgrade to Ghostfolio Premium
+ Upgraden naar Ghostfolio Premium
libs/ui/src/lib/premium-indicator/premium-indicator.component.html
4
@@ -4675,7 +4675,7 @@
Web
- Web
+ Web
libs/ui/src/lib/i18n.ts
120
@@ -4747,7 +4747,7 @@
Category
- Category
+ Categorie
apps/client/src/app/pages/resources/personal-finance-tools/product-page.html
77
@@ -4779,7 +4779,7 @@
Ghostfolio in Numbers: Pulls on Docker Hub
- Ghostfolio in Numbers: Pulls on Docker Hub
+ Ghostfolio in cijfers: downloads op Docker Hub
apps/client/src/app/pages/landing/landing-page.html
101
@@ -5151,7 +5151,7 @@
Basic Materials
- Basic Materials
+ Basismaterialen
libs/ui/src/lib/i18n.ts
90
@@ -5279,7 +5279,7 @@
Oops! Could not delete the asset profiles.
- Oops! Could not delete the asset profiles.
+ Oeps! De activaprofielen konden niet worden verwijderd.
apps/client/src/app/components/admin-market-data/admin-market-data.service.ts
52
@@ -5609,7 +5609,7 @@
Stock Tracking
- Stock Tracking
+ Aandelen volgen
libs/ui/src/lib/i18n.ts
111
@@ -5689,7 +5689,7 @@
Available on
- Available on
+ Beschikbaar op
apps/client/src/app/pages/resources/personal-finance-tools/product-page.html
130
@@ -5897,7 +5897,7 @@
Industrials
- Industrials
+ Industrie
libs/ui/src/lib/i18n.ts
97
@@ -6013,7 +6013,7 @@
Healthcare
- Healthcare
+ Gezondheidszorg
libs/ui/src/lib/i18n.ts
96
@@ -6029,7 +6029,7 @@
Portfolio Filters
- Portfolio Filters
+ Portefeuillefilters
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
63
@@ -6285,7 +6285,7 @@
Expires ()
- Expires ()
+ Verloopt ()
apps/client/src/app/components/admin-users/admin-users.html
34
@@ -6313,7 +6313,7 @@
Fetch market price
- Fetch market price
+ Marktprijs ophalen
libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html
40
@@ -6389,7 +6389,7 @@
Find a holding...
- Find a holding...
+ Zoek een positie...
libs/ui/src/lib/assistant/assistant.component.ts
448
@@ -6442,7 +6442,7 @@
Daily
- Daily
+ Dagelijks
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
210
@@ -6570,7 +6570,7 @@
Jump to a page...
- Jump to a page...
+ Ga naar een pagina...
libs/ui/src/lib/assistant/assistant.component.ts
449
@@ -6758,7 +6758,7 @@
Oops! Could not delete the asset profile.
- Oops! Could not delete the asset profile.
+ Oeps! Het activaprofiel kon niet worden verwijderd.
apps/client/src/app/components/admin-market-data/admin-market-data.service.ts
51
@@ -6862,7 +6862,7 @@
Do you really want to delete these asset profiles?
- Do you really want to delete these asset profiles?
+ Wil je deze activaprofielen echt verwijderen?
apps/client/src/app/components/admin-market-data/admin-market-data.service.ts
67
@@ -7062,7 +7062,7 @@
Change with currency effect Change
- Verandering met valuta effect Verandering
+ Verandering met valuta-effect Verandering
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html
63
@@ -7078,7 +7078,7 @@
Performance with currency effect Performance
- Prestatie met valuta effect Prestatie
+ Prestaties met valuta-effect Prestaties
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html
83
@@ -7126,7 +7126,7 @@
has been copied to the clipboard
- has been copied to the clipboard
+ is naar het klembord gekopieerd
apps/client/src/app/components/admin-overview/admin-overview.component.ts
382
@@ -7146,7 +7146,7 @@
Compare Ghostfolio to -
- Compare Ghostfolio to -
+ Vergelijk Ghostfolio met -
apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html
32
@@ -7202,7 +7202,7 @@
Financial Services
- Financial Services
+ Financiële diensten
libs/ui/src/lib/i18n.ts
95
@@ -7230,7 +7230,7 @@
Delete
- Delete
+ Verwijder
apps/client/src/app/components/admin-market-data/admin-market-data.html
244
@@ -7286,7 +7286,7 @@
Dividend Tracking
- Dividend Tracking
+ Dividend volgen
libs/ui/src/lib/i18n.ts
105
@@ -7346,7 +7346,7 @@
Investment Research
- Investment Research
+ Beleggingsonderzoek
libs/ui/src/lib/i18n.ts
109
@@ -7620,7 +7620,7 @@
Check the system status at
- Check the system status at
+ Controleer de systeemstatus op
apps/client/src/app/pages/about/overview/about-overview-page.html
59
@@ -7760,7 +7760,7 @@
Ghostfolio in Numbers: Stars on GitHub
- Ghostfolio in Numbers: Stars on GitHub
+ Ghostfolio in cijfers: sterren op GitHub
apps/client/src/app/pages/landing/landing-page.html
82
@@ -8082,7 +8082,7 @@
ETF Tracking
- ETF Tracking
+ ETF’s volgen
libs/ui/src/lib/i18n.ts
106
From 9217ff587b0528e74cd733d3fac82498f4e554a3 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Tue, 7 Jul 2026 21:45:49 +0200
Subject: [PATCH 2/4] Task/harmonize subject of mailto links (#7268)
Harmonize subject of mailto links
---
.../components/admin-settings/admin-settings.component.html | 2 +-
.../holding-detail-dialog/holding-detail-dialog.component.ts | 2 +-
.../user-account-membership.component.ts | 2 +-
apps/client/src/app/pages/faq/saas/saas-page.html | 2 +-
apps/client/src/app/pages/pricing/pricing-page.html | 4 ++--
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.html b/apps/client/src/app/components/admin-settings/admin-settings.component.html
index 76af96c4e..8ee6250e5 100644
--- a/apps/client/src/app/components/admin-settings/admin-settings.component.html
+++ b/apps/client/src/app/components/admin-settings/admin-settings.component.html
@@ -21,7 +21,7 @@
Get Access
diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
index b2cdedbc5..c5beb6c2d 100644
--- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
+++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
@@ -456,7 +456,7 @@ export class GfHoldingDetailDialogComponent implements OnInit {
this.assetProfile?.symbol ? ` (${this.assetProfile.symbol})` : ''
}`;
- this.reportDataGlitchMail = `mailto:hi@ghostfol.io?Subject=${reportDataGlitchSubject}&body=Hello%0D%0DI would like to report a data glitch for%0D%0DSymbol: ${this.assetProfile?.symbol}%0DData Source: ${this.assetProfile?.dataSource}%0D%0DAdditional notes:%0D%0DCan you please take a look?%0D%0DKind regards`;
+ this.reportDataGlitchMail = `mailto:hi@ghostfol.io?subject=${reportDataGlitchSubject}&body=Hello%0D%0DI would like to report a data glitch for%0D%0DSymbol: ${this.assetProfile?.symbol}%0DData Source: ${this.assetProfile?.dataSource}%0D%0DAdditional notes:%0D%0DCan you please take a look?%0D%0DKind regards`;
if (this.assetProfile?.assetClass) {
this.assetClass = translate(this.assetProfile?.assetClass);
diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts
index 1b23a6df9..d086867aa 100644
--- a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts
+++ b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts
@@ -52,7 +52,7 @@ export class GfUserAccountMembershipComponent {
public priceId: string;
public routerLinkPricing = publicRoutes.pricing.routerLink;
public trySubscriptionMail =
- 'mailto:hi@ghostfol.io?Subject=Ghostfolio Premium Trial&body=Hello%0D%0DI am interested in Ghostfolio Premium. Can you please send me a coupon code to try it for some time?%0D%0DKind regards';
+ 'mailto:hi@ghostfol.io?subject=Ghostfolio Premium Trial&body=Hello%0D%0DI am interested in Ghostfolio Premium. Can you please send me a coupon code to try it for some time?%0D%0DKind regards';
public user: User;
public constructor(
diff --git a/apps/client/src/app/pages/faq/saas/saas-page.html b/apps/client/src/app/pages/faq/saas/saas-page.html
index e832676bf..fc39acc53 100644
--- a/apps/client/src/app/pages/faq/saas/saas-page.html
+++ b/apps/client/src/app/pages/faq/saas/saas-page.html
@@ -96,7 +96,7 @@
Request your student discount
- here with
+ here with
your university e-mail address.
diff --git a/apps/client/src/app/pages/pricing/pricing-page.html b/apps/client/src/app/pages/pricing/pricing-page.html
index 23693457c..ddd92892a 100644
--- a/apps/client/src/app/pages/pricing/pricing-page.html
+++ b/apps/client/src/app/pages/pricing/pricing-page.html
@@ -332,7 +332,7 @@
}
please
- contact us
@@ -343,7 +343,7 @@
Request it
- here
+ here
with your university e-mail address.
From 6278cf6691c5f09c7a5df81d0580330064948a0e Mon Sep 17 00:00:00 2001
From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com>
Date: Wed, 8 Jul 2026 02:47:38 +0700
Subject: [PATCH 3/4] Task/improve type safety in portfolio performance
component (#7265)
Improve type safety
---
.../home-overview/home-overview.html | 1 -
.../portfolio-performance.component.html | 22 ++--
.../portfolio-performance.component.ts | 103 ++++++++++--------
3 files changed, 68 insertions(+), 58 deletions(-)
diff --git a/apps/client/src/app/components/home-overview/home-overview.html b/apps/client/src/app/components/home-overview/home-overview.html
index 8361c5b88..0ca4912b9 100644
--- a/apps/client/src/app/components/home-overview/home-overview.html
+++ b/apps/client/src/app/components/home-overview/home-overview.html
@@ -86,7 +86,6 @@
- @if (errors?.length > 0 && !isLoading) {
+ @if (errors()?.length > 0 && !isLoading()) {
}
- @if (isLoading) {
+ @if (isLoading()) {
- {{ unit }}
+ {{ unit() }}
- @if (showDetails) {
+ @if (showDetails()) {
diff --git a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts
index 56e75ec1e..a48d77a2d 100644
--- a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts
+++ b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts
@@ -13,10 +13,11 @@ import { GfValueComponent } from '@ghostfolio/ui/value';
import {
ChangeDetectionStrategy,
Component,
+ effect,
ElementRef,
- Input,
- OnChanges,
- ViewChild
+ inject,
+ input,
+ viewChild
} from '@angular/core';
import { IonIcon } from '@ionic/angular/standalone';
import { CountUp } from 'countup.js';
@@ -32,58 +33,68 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
styleUrls: ['./portfolio-performance.component.scss'],
templateUrl: './portfolio-performance.component.html'
})
-export class GfPortfolioPerformanceComponent implements OnChanges {
- @Input() deviceType: string;
- @Input() errors: ResponseError['errors'];
- @Input() isLoading: boolean;
- @Input() locale = getLocale();
- @Input() performance: PortfolioPerformance;
- @Input() precision: number;
- @Input() showDetails: boolean;
- @Input() unit: string;
+export class GfPortfolioPerformanceComponent {
+ public readonly errors = input();
+ public readonly isLoading = input();
+ public readonly locale = input(getLocale());
+ public readonly performance = input.required();
+ public readonly precision = input.required({
+ transform: (value) => {
+ return value >= 0 ? value : 2;
+ }
+ });
+ public readonly showDetails = input(false);
+ public readonly unit = input.required();
- @ViewChild('value') value: ElementRef;
+ private readonly value =
+ viewChild.required>('value');
- public constructor(private notificationService: NotificationService) {
- addIcons({ timeOutline });
- }
+ private readonly notificationService = inject(NotificationService);
- public ngOnChanges() {
- this.precision = this.precision >= 0 ? this.precision : 2;
+ public constructor() {
+ addIcons({ timeOutline });
- if (this.isLoading) {
- if (this.value?.nativeElement) {
- this.value.nativeElement.innerHTML = '';
- }
- } else {
- if (isNumber(this.performance?.currentValueInBaseCurrency)) {
- new CountUp('value', this.performance?.currentValueInBaseCurrency, {
- decimal: getNumberFormatDecimal(this.locale),
- decimalPlaces: this.precision,
- duration: 1,
- separator: getNumberFormatGroup(this.locale)
- }).start();
- } else if (this.showDetails === false) {
- new CountUp(
- 'value',
- this.performance?.netPerformancePercentageWithCurrencyEffect * 100,
- {
- decimal: getNumberFormatDecimal(this.locale),
- decimalPlaces: 2,
- duration: 1,
- separator: getNumberFormatGroup(this.locale)
- }
- ).start();
+ effect(() => {
+ if (this.isLoading()) {
+ if (this.value().nativeElement) {
+ this.value().nativeElement.innerHTML = '';
+ }
} else {
- this.value.nativeElement.innerHTML = '*****';
+ if (isNumber(this.performance().currentValueInBaseCurrency)) {
+ new CountUp('value', this.performance().currentValueInBaseCurrency, {
+ decimal: getNumberFormatDecimal(this.locale()),
+ decimalPlaces: this.precision(),
+ duration: 1,
+ separator: getNumberFormatGroup(this.locale())
+ }).start();
+ } else if (this.showDetails() === false) {
+ new CountUp(
+ 'value',
+ this.performance().netPerformancePercentageWithCurrencyEffect * 100,
+ {
+ decimal: getNumberFormatDecimal(this.locale()),
+ decimalPlaces: 2,
+ duration: 1,
+ separator: getNumberFormatGroup(this.locale())
+ }
+ ).start();
+ } else {
+ this.value().nativeElement.innerHTML = '*****';
+ }
}
- }
+ });
}
- public onShowErrors() {
- const errorMessageParts = [];
+ protected onShowErrors() {
+ const errors = this.errors();
+
+ if (!errors?.length) {
+ return;
+ }
+
+ const errorMessageParts: string[] = [];
- for (const error of this.errors) {
+ for (const error of errors) {
errorMessageParts.push(`${error.symbol} (${error.dataSource})`);
}
From 9d98799b47aa8182d21155cae85bbf68262a749f Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Tue, 7 Jul 2026 21:48:25 +0200
Subject: [PATCH 4/4] Task/reorder updatedAt field in symbol profile data model
(#7270)
Reorder updatedAt
---
prisma/schema.prisma | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 233a63688..ed07d6f47 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -203,11 +203,11 @@ model SymbolProfile {
isActive Boolean @default(true)
isin String?
name String?
- updatedAt DateTime @updatedAt
scraperConfiguration Json?
sectors Json?
symbol String
symbolMapping Json?
+ updatedAt DateTime @updatedAt
url String?
user User? @relation(fields: [userId], onDelete: Cascade, references: [id])
userId String?