Browse Source

Merge remote-tracking branch 'origin/main' into task/create-update-activity-dialog-type-safety

pull/7294/head
KenTandrian 2 days ago
parent
commit
84ca01a191
  1. 23
      CHANGELOG.md
  2. 2
      apps/api/src/services/configuration/configuration.service.ts
  3. 3
      apps/client/src/app/app.routes.ts
  4. 2
      apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.html
  5. 3
      apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.ts
  6. 51
      apps/client/src/app/components/home-holdings/home-holdings.component.ts
  7. 79
      apps/client/src/app/components/user-account-settings/user-account-settings.component.ts
  8. 4
      apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts
  9. 3
      apps/client/src/app/pages/webauthn/webauthn-page.component.ts
  10. 6
      apps/client/src/app/pages/webauthn/webauthn-page.html
  11. 2
      apps/client/src/locales/messages.ca.xlf
  12. 94
      apps/client/src/locales/messages.ko.xlf
  13. 4
      apps/client/src/locales/messages.tr.xlf
  14. 2
      libs/common/src/lib/routes/interfaces/internal-route.interface.ts
  15. 3
      libs/common/src/lib/routes/routes.ts
  16. 5
      libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.html
  17. 5
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html
  18. 17
      package-lock.json
  19. 4
      package.json

23
CHANGELOG.md

@ -5,7 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### Unreleased
## Unreleased
### Changed
- Changed the default value of the `DATA_SOURCE_FEAR_AND_GREED_INDEX_STOCKS` environment variable from `RAPID_API` to `MANUAL`
- Upgraded `helmet` from version `7.0.0` to `8.2.0`
### Fixed
- Fixed the display of assets without a currency in the search results of the assistant
- Fixed the display of assets without a currency in the symbol autocomplete component
### Todo
- **Breaking Change**: Set the environment variable `DATA_SOURCE_FEAR_AND_GREED_INDEX_STOCKS=RAPID_API` to keep using _Rapid API_ as the data source of the _Fear & Greed Index_ (market mood)
## 3.24.0 - 2026-07-11
### Added
@ -13,6 +29,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Exposed the `ENABLE_FEATURE_RATE_LIMITING` environment variable to control rate limiting for authentication and sign-up endpoints
- Exposed the `TRUST_PROXY` environment variable to determine the client IP address when running behind a reverse proxy
### Changed
- Rounded the value of the _Fear & Greed Index_ (market mood)
- Improved the language localization for Korean (`ko`)
## 3.23.0 - 2026-07-10
### Changed

2
apps/api/src/services/configuration/configuration.service.ts

@ -57,7 +57,7 @@ export class ConfigurationService {
CACHE_TTL: num({ default: CACHE_TTL_NO_CACHE }),
DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }),
DATA_SOURCE_FEAR_AND_GREED_INDEX_STOCKS: str({
default: DataSource.RAPID_API
default: DataSource.MANUAL
}),
DATA_SOURCE_IMPORT: str({ default: DataSource.YAHOO }),
DATA_SOURCES: json({

3
apps/client/src/app/app.routes.ts

@ -128,8 +128,7 @@ export const routes: Routes = [
import('./pages/webauthn/webauthn-page.component').then(
(c) => c.GfWebauthnPageComponent
),
path: internalRoutes.webauthn.path,
title: internalRoutes.webauthn.title
path: internalRoutes.webauthn.path
},
{
path: internalRoutes.zen.path,

2
apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.html

@ -5,7 +5,7 @@
<div class="h4 mb-0">
<span class="mr-2">{{ fearAndGreedIndexText }}</span>
<small class="text-muted"
><strong>{{ fearAndGreedIndex }}</strong
><strong>{{ fearAndGreedIndex | number: '1.0-0' }}</strong
>/100</small
>
</div>

3
apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.ts

@ -1,6 +1,7 @@
import { resolveFearAndGreedIndex } from '@ghostfolio/common/helper';
import { translate } from '@ghostfolio/ui/i18n';
import { DecimalPipe } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
@ -11,7 +12,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgxSkeletonLoaderModule],
imports: [DecimalPipe, NgxSkeletonLoaderModule],
selector: 'gf-fear-and-greed-index',
styleUrls: ['./fear-and-greed-index.component.scss'],
templateUrl: './fear-and-greed-index.component.html'

51
apps/client/src/app/components/home-holdings/home-holdings.component.ts

@ -20,6 +20,7 @@ import {
Component,
CUSTOM_ELEMENTS_SCHEMA,
DestroyRef,
inject,
OnInit
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@ -53,32 +54,34 @@ import { DeviceDetectorService } from 'ngx-device-detector';
export class GfHomeHoldingsComponent implements OnInit {
public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE';
public deviceType: string;
public hasImpersonationId: boolean;
public hasPermissionToAccessHoldingsChart: boolean;
public hasPermissionToCreateActivity: boolean;
public holdings: PortfolioPosition[];
public holdingType: HoldingType = 'ACTIVE';
public holdingTypeOptions: ToggleOption[] = [
protected deviceType: string;
protected hasImpersonationId: boolean;
protected hasPermissionToAccessHoldingsChart: boolean;
protected hasPermissionToCreateActivity: boolean;
protected holdings: PortfolioPosition[];
protected holdingType: HoldingType = 'ACTIVE';
protected readonly holdingTypeOptions: ToggleOption[] = [
{ label: $localize`Active`, value: 'ACTIVE' },
{ label: $localize`Closed`, value: 'CLOSED' }
];
public routerLinkPortfolioActivities =
protected readonly routerLinkPortfolioActivities =
internalRoutes.portfolio.subRoutes.activities.routerLink;
public user: User;
public viewModeFormControl = new FormControl<HoldingsViewMode>(
protected user: User;
protected readonly viewModeFormControl = new FormControl<HoldingsViewMode>(
GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE
);
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private dataService: DataService,
private destroyRef: DestroyRef,
private deviceDetectorService: DeviceDetectorService,
private impersonationStorageService: ImpersonationStorageService,
private router: Router,
private userService: UserService
) {
private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly dataService = inject(DataService);
private readonly destroyRef = inject(DestroyRef);
private readonly deviceDetectorService = inject(DeviceDetectorService);
private readonly impersonationStorageService = inject(
ImpersonationStorageService
);
private readonly router = inject(Router);
private readonly userService = inject(UserService);
public constructor() {
addIcons({ gridOutline, reorderFourOutline });
}
@ -119,6 +122,10 @@ export class GfHomeHoldingsComponent implements OnInit {
this.viewModeFormControl.valueChanges
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((holdingsViewMode) => {
if (!holdingsViewMode) {
return;
}
this.dataService
.putUserSetting({ holdingsViewMode })
.pipe(takeUntilDestroyed(this.destroyRef))
@ -135,13 +142,13 @@ export class GfHomeHoldingsComponent implements OnInit {
});
}
public onChangeHoldingType(aHoldingType: HoldingType) {
protected onChangeHoldingType(aHoldingType: HoldingType) {
this.holdingType = aHoldingType;
this.initialize();
}
public onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) {
protected onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) {
if (dataSource && symbol) {
this.router.navigate([], {
queryParams: { dataSource, symbol, holdingDetailDialog: true }
@ -185,7 +192,7 @@ export class GfHomeHoldingsComponent implements OnInit {
);
}
this.holdings = undefined;
this.holdings = [];
this.fetchHoldings()
.pipe(takeUntilDestroyed(this.destroyRef))

79
apps/client/src/app/components/user-account-settings/user-account-settings.component.ts

@ -20,11 +20,12 @@ import {
Component,
CUSTOM_ELEMENTS_SCHEMA,
DestroyRef,
inject,
OnInit
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import {
FormBuilder,
NonNullableFormBuilder,
FormsModule,
ReactiveFormsModule,
Validators
@ -69,22 +70,22 @@ import { catchError } from 'rxjs/operators';
templateUrl: './user-account-settings.html'
})
export class GfUserAccountSettingsComponent implements OnInit {
public appearancePlaceholder = $localize`Auto`;
public baseCurrency: string;
public closeUserAccountMail: string;
public currencies: string[] = [];
public deleteOwnUserForm = this.formBuilder.group({
protected readonly appearancePlaceholder = $localize`Auto`;
protected readonly baseCurrency: string;
protected closeUserAccountMail: string;
protected readonly currencies: string[] = [];
protected readonly deleteOwnUserForm = inject(NonNullableFormBuilder).group({
accessToken: ['', Validators.required]
});
public hasPermissionToDeleteOwnUser: boolean;
public hasPermissionToRequestOwnUserDeletion: boolean;
public hasPermissionToUpdateViewMode: boolean;
public hasPermissionToUpdateUserSettings: boolean;
public isAccessTokenHidden = true;
public isFingerprintSupported = this.doesBrowserSupportAuthn();
public isWebAuthnEnabled: boolean;
public language = document.documentElement.lang;
public locales = [
protected hasPermissionToDeleteOwnUser: boolean;
protected hasPermissionToRequestOwnUserDeletion: boolean;
protected hasPermissionToUpdateViewMode: boolean;
protected hasPermissionToUpdateUserSettings: boolean;
protected isAccessTokenHidden = true;
protected readonly isFingerprintSupported = this.doesBrowserSupportAuthn();
protected isWebAuthnEnabled: boolean;
protected readonly language = document.documentElement.lang;
protected locales = [
'ca',
'de',
'de-CH',
@ -102,19 +103,18 @@ export class GfUserAccountSettingsComponent implements OnInit {
'uk',
'zh'
];
public user: User;
public constructor(
private changeDetectorRef: ChangeDetectorRef,
private dataService: DataService,
private destroyRef: DestroyRef,
private formBuilder: FormBuilder,
private notificationService: NotificationService,
private settingsStorageService: SettingsStorageService,
private snackBar: MatSnackBar,
private userService: UserService,
public webAuthnService: WebAuthnService
) {
protected user: User;
private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly dataService = inject(DataService);
private readonly destroyRef = inject(DestroyRef);
private readonly notificationService = inject(NotificationService);
private readonly settingsStorageService = inject(SettingsStorageService);
private readonly snackBar = inject(MatSnackBar);
private readonly userService = inject(UserService);
private readonly webAuthnService = inject(WebAuthnService);
public constructor() {
const { baseCurrency, currencies } = this.dataService.fetchInfo();
this.baseCurrency = baseCurrency;
@ -148,7 +148,10 @@ export class GfUserAccountSettingsComponent implements OnInit {
permissions.updateViewMode
);
if (this.user.settings.locale) {
this.locales.push(this.user.settings.locale);
}
this.locales = Array.from(new Set(this.locales)).sort();
this.changeDetectorRef.markForCheck();
@ -162,11 +165,11 @@ export class GfUserAccountSettingsComponent implements OnInit {
this.update();
}
public isCommunityLanguage() {
protected isCommunityLanguage() {
return !['de', 'en'].includes(this.language);
}
public onChangeUserSetting(aKey: string, aValue: string) {
protected onChangeUserSetting(aKey: string, aValue: string) {
this.dataService
.putUserSetting({ [aKey]: aValue })
.pipe(takeUntilDestroyed(this.destroyRef))
@ -190,12 +193,12 @@ export class GfUserAccountSettingsComponent implements OnInit {
});
}
public onCloseAccount() {
protected onCloseAccount() {
this.notificationService.confirm({
confirmFn: () => {
this.dataService
.deleteOwnUser({
accessToken: this.deleteOwnUserForm.get('accessToken').value
accessToken: this.deleteOwnUserForm.controls.accessToken.value
})
.pipe(
catchError(() => {
@ -218,7 +221,7 @@ export class GfUserAccountSettingsComponent implements OnInit {
});
}
public onExperimentalFeaturesChange(aEvent: MatSlideToggleChange) {
protected onExperimentalFeaturesChange(aEvent: MatSlideToggleChange) {
this.dataService
.putUserSetting({ isExperimentalFeatures: aEvent.checked })
.pipe(takeUntilDestroyed(this.destroyRef))
@ -234,13 +237,13 @@ export class GfUserAccountSettingsComponent implements OnInit {
});
}
public onExport() {
protected onExport() {
this.dataService
.fetchExport()
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((data) => {
for (const activity of data.activities) {
delete activity.id;
delete (activity as Omit<typeof activity, 'id'> & { id?: string }).id;
}
downloadAsFile({
@ -254,7 +257,7 @@ export class GfUserAccountSettingsComponent implements OnInit {
});
}
public onRestrictedViewChange(aEvent: MatSlideToggleChange) {
protected onRestrictedViewChange(aEvent: MatSlideToggleChange) {
this.dataService
.putUserSetting({ isRestrictedView: aEvent.checked })
.pipe(takeUntilDestroyed(this.destroyRef))
@ -270,7 +273,7 @@ export class GfUserAccountSettingsComponent implements OnInit {
});
}
public async onSignInWithFingerprintChange(aEvent: MatSlideToggleChange) {
protected async onSignInWithFingerprintChange(aEvent: MatSlideToggleChange) {
if (aEvent.checked) {
try {
await this.registerDevice();
@ -293,7 +296,7 @@ export class GfUserAccountSettingsComponent implements OnInit {
}
}
public onViewModeChange(aEvent: MatSlideToggleChange) {
protected onViewModeChange(aEvent: MatSlideToggleChange) {
this.dataService
.putUserSetting({ viewMode: aEvent.checked === true ? 'ZEN' : 'DEFAULT' })
.pipe(takeUntilDestroyed(this.destroyRef))

4
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts

@ -49,7 +49,7 @@ import {
templateUrl: './user-detail-dialog.html'
})
export class GfUserDetailDialogComponent implements OnInit {
protected baseCurrency: string;
protected readonly baseCurrency: string;
protected readonly getCountryName = getCountryName;
protected readonly subscriptionsDataSource =
new MatTableDataSource<Subscription>();
@ -114,7 +114,7 @@ export class GfUserDetailDialogComponent implements OnInit {
return price !== null;
})
.map(({ price }) => {
return new Big(price);
return new Big(price ?? 0);
})
).toNumber();
}

3
apps/client/src/app/pages/webauthn/webauthn-page.component.ts

@ -1,6 +1,5 @@
import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service';
import { GfLogoComponent } from '@ghostfolio/ui/logo';
import {
ChangeDetectorRef,
@ -15,7 +14,7 @@ import { Router } from '@angular/router';
@Component({
host: { class: 'page' },
imports: [GfLogoComponent, MatButtonModule, MatProgressSpinnerModule],
imports: [MatButtonModule, MatProgressSpinnerModule],
selector: 'gf-webauthn-page',
styleUrls: ['./webauthn-page.scss'],
templateUrl: './webauthn-page.html'

6
apps/client/src/app/pages/webauthn/webauthn-page.html

@ -1,12 +1,6 @@
<div class="container">
<div class="row">
<div class="col">
<div
class="align-items-center d-flex flex-column justify-content-center mb-4 w-100"
>
<gf-logo size="medium" />
</div>
@if (!hasError) {
<div class="col d-flex justify-content-center">
<mat-spinner [diameter]="20" />

2
apps/client/src/locales/messages.ca.xlf

@ -4073,7 +4073,7 @@
</trans-unit>
<trans-unit id="8065260392868074625" datatype="html">
<source>How does <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Ghostfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> work?</source>
<target state="translatetd">Com ho fa <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Ghostfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> treballar?</target>
<target state="translated">Com ho fa <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Ghostfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> treballar?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">286</context>

94
apps/client/src/locales/messages.ko.xlf

@ -433,7 +433,7 @@
</trans-unit>
<trans-unit id="4323470180912194028" datatype="html">
<source>Copy</source>
<target state="new">Copy</target>
<target state="translated">복사</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/notifications/alert-dialog/alert-dialog.html</context>
<context context-type="linenumber">20</context>
@ -605,7 +605,7 @@
</trans-unit>
<trans-unit id="8282940047848889809" datatype="html">
<source>Paid</source>
<target state="new">Paid</target>
<target state="translated">유료</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts</context>
<context context-type="linenumber">122</context>
@ -693,7 +693,7 @@
</trans-unit>
<trans-unit id="5611965261696422586" datatype="html">
<source>and is driven by the efforts of its <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio/graphs/contributors&quot; i18n-title title=&quot;Contributors to Ghostfolio&quot; &gt;"/>contributors<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/></source>
<target state="new"><x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio/graphs/contributors&quot; title=&quot;Contributors to Ghostfolio&quot; &gt;"/>기여자<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>들의 노력으로 발전하고 있습니다</target>
<target state="translated"><x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio/graphs/contributors&quot; title=&quot;Contributors to Ghostfolio&quot; &gt;"/>기여자<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>들의 노력으로 발전하고 있습니다</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/overview/about-overview-page.html</context>
<context context-type="linenumber">50</context>
@ -769,7 +769,7 @@
</trans-unit>
<trans-unit id="8410000928786197012" datatype="html">
<source>Watch the Ghostfol.io Trailer on YouTube</source>
<target state="new">Watch the Ghostfol.io Trailer on YouTube</target>
<target state="translated">YouTube에서 Ghostfol.io 트레일러 보기</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">19</context>
@ -805,7 +805,7 @@
</trans-unit>
<trans-unit id="1806667489382256324" datatype="html">
<source>Category</source>
<target state="new">Category</target>
<target state="translated">카테고리</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">77</context>
@ -869,7 +869,7 @@
</trans-unit>
<trans-unit id="6418462810730461014" datatype="html">
<source>Data Gathering Frequency</source>
<target state="new">Data Gathering Frequency</target>
<target state="translated">데이터 수집 빈도</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html</context>
<context context-type="linenumber">454</context>
@ -913,7 +913,7 @@
</trans-unit>
<trans-unit id="6135731497699355929" datatype="html">
<source>Subscription History</source>
<target state="new">Subscription History</target>
<target state="translated">구독 내역</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html</context>
<context context-type="linenumber">136</context>
@ -1097,7 +1097,7 @@
</trans-unit>
<trans-unit id="5915287617703658226" datatype="html">
<source>Total</source>
<target state="new">Total</target>
<target state="translated">합계</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html</context>
<context context-type="linenumber">155</context>
@ -1721,7 +1721,7 @@
</trans-unit>
<trans-unit id="5289957034780335504" datatype="html">
<source>The source code is fully available as <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot; i18n-title title=&quot;Find Ghostfolio on GitHub&quot; &gt;"/>open source software<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> (OSS) under the <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;GNU Affero General Public License&quot; &gt;"/>AGPL-3.0 license<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/></source>
<target state="new">소스 코드는 <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot; title=&quot;Find Ghostfolio on GitHub&quot; &gt;"/>오픈 소스 소프트웨어<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>로 완전히 공개되어 있으며, <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;GNU Affero General Public License&quot; &gt;"/>AGPL-3.0 라이선스<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 하에 제공됩니다</target>
<target state="translated">소스 코드는 <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot; title=&quot;Find Ghostfolio on GitHub&quot; &gt;"/>오픈 소스 소프트웨어<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>로 완전히 공개되어 있으며, <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;GNU Affero General Public License&quot; &gt;"/>AGPL-3.0 라이선스<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 하에 제공됩니다</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/overview/about-overview-page.html</context>
<context context-type="linenumber">16</context>
@ -2293,7 +2293,7 @@
</trans-unit>
<trans-unit id="8793726805339626615" datatype="html">
<source>Ghostfolio in Numbers: Monthly Active Users (MAU)</source>
<target state="new">Ghostfolio in Numbers: Monthly Active Users (MAU)</target>
<target state="translated">Ghostfolio 통계: 월간 활성 사용자 수(MAU)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">63</context>
@ -2333,7 +2333,7 @@
</trans-unit>
<trans-unit id="4037247308022519888" datatype="html">
<source>The value has been copied to the clipboard</source>
<target state="new">The value has been copied to the clipboard</target>
<target state="translated">값이 클립보드에 복사되었습니다.</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/notifications/alert-dialog/alert-dialog.component.ts</context>
<context context-type="linenumber">46</context>
@ -2493,7 +2493,7 @@
</trans-unit>
<trans-unit id="5463045633785723738" datatype="html">
<source>Coupon</source>
<target state="new">Coupon</target>
<target state="translated">쿠폰</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts</context>
<context context-type="linenumber">127</context>
@ -2529,7 +2529,7 @@
</trans-unit>
<trans-unit id="8664947843178872012" datatype="html">
<source>Close Account</source>
<target state="new">Close Account</target>
<target state="translated">계정 폐쇄</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.html</context>
<context context-type="linenumber">337</context>
@ -2549,7 +2549,7 @@
</trans-unit>
<trans-unit id="4102764207131986196" datatype="html">
<source>Contributors to Ghostfolio</source>
<target state="new">Contributors to Ghostfolio</target>
<target state="translated">Ghostfolio의 기여자</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/overview/about-overview-page.html</context>
<context context-type="linenumber">54</context>
@ -2885,7 +2885,7 @@
</trans-unit>
<trans-unit id="8643034887919513109" datatype="html">
<source>Financial Planning</source>
<target state="new">Financial Planning</target>
<target state="translated">재무 설계</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">108</context>
@ -3221,7 +3221,7 @@
</trans-unit>
<trans-unit id="4489207161748215824" datatype="html">
<source>For security reasons, please delete all activities and accounts first before your Ghostfolio account can be closed.</source>
<target state="new">For security reasons, please delete all activities and accounts first before your Ghostfolio account can be closed.</target>
<target state="translated">보안을 위해 Ghostfolio 계정을 폐쇄하려면 먼저 모든 거래 내역과 계좌를 삭제해 주세요.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.html</context>
<context context-type="linenumber">348</context>
@ -3349,7 +3349,7 @@
</trans-unit>
<trans-unit id="2047393478951255414" datatype="html">
<source>Creation</source>
<target state="new">Creation</target>
<target state="translated">생성</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">185</context>
@ -3389,7 +3389,7 @@
</trans-unit>
<trans-unit id="4733690367258997247" datatype="html">
<source>just now</source>
<target state="new">just now</target>
<target state="translated">방금 전</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.component.ts</context>
<context context-type="linenumber">217</context>
@ -3713,7 +3713,7 @@
</trans-unit>
<trans-unit id="2756436642316668410" datatype="html">
<source>Oops! Could not delete the asset profiles.</source>
<target state="new">Oops! Could not delete the asset profiles.</target>
<target state="translated">이런! 자산 프로필을 삭제할 수 없습니다.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.service.ts</context>
<context context-type="linenumber">52</context>
@ -3801,7 +3801,7 @@
</trans-unit>
<trans-unit id="3824165347269033834" datatype="html">
<source>At Ghostfolio, transparency is at the core of our values. We publish the source code as <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot; i18n-title title=&quot;Find Ghostfolio on GitHub&quot; &gt;"/>open source software<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> (OSS) under the <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;GNU Affero General Public License&quot; &gt;"/>AGPL-3.0 license<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> and we openly share aggregated key metrics of the platform’s operational status.</source>
<target state="new">Ghostfolio는 투명성을 핵심 가치로 삼습니다. 우리는 소스 코드를 <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot; title=&quot;Find Ghostfolio on GitHub&quot; &gt;"/>오픈 소스 소프트웨어<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>로 공개하며, <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;GNU Affero General Public License&quot; &gt;"/>AGPL-3.0 라이선스<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 하에 배포합니다. 또한 플랫폼 운영 현황에 대한 집계된 핵심 지표를 공개적으로 공유합니다.</target>
<target state="translated">Ghostfolio는 투명성을 핵심 가치로 삼습니다. 우리는 소스 코드를 <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot; title=&quot;Find Ghostfolio on GitHub&quot; &gt;"/>오픈 소스 소프트웨어<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>로 공개하며, <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;GNU Affero General Public License&quot; &gt;"/>AGPL-3.0 라이선스<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 하에 배포합니다. 또한 플랫폼 운영 현황에 대한 집계된 핵심 지표를 공개적으로 공유합니다.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">7</context>
@ -3897,7 +3897,7 @@
</trans-unit>
<trans-unit id="6075566839446502414" datatype="html">
<source>Available on</source>
<target state="new">Available on</target>
<target state="translated">이용 가능 플랫폼</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">130</context>
@ -4205,7 +4205,7 @@
</trans-unit>
<trans-unit id="8894377483833272091" datatype="html">
<source>Price</source>
<target state="new">Price</target>
<target state="translated">가격</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html</context>
<context context-type="linenumber">171</context>
@ -4305,7 +4305,7 @@
</trans-unit>
<trans-unit id="6999515396807067782" datatype="html">
<source>Trial</source>
<target state="new">Trial</target>
<target state="translated">체험판</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts</context>
<context context-type="linenumber">126</context>
@ -4613,7 +4613,7 @@
</trans-unit>
<trans-unit id="2640607428459636406" datatype="html">
<source>Hourly</source>
<target state="new">Hourly</target>
<target state="translated">매시간</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts</context>
<context context-type="linenumber">214</context>
@ -4725,7 +4725,7 @@
</trans-unit>
<trans-unit id="3323137014509063489" datatype="html">
<source>Expiration</source>
<target state="new">Expiration</target>
<target state="translated">만료</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html</context>
<context context-type="linenumber">204</context>
@ -5034,7 +5034,7 @@
</trans-unit>
<trans-unit id="237127378624497814" datatype="html">
<source>Upgrade to Ghostfolio Premium</source>
<target state="new">Upgrade to Ghostfolio Premium</target>
<target state="translated">Ghostfolio 프리미엄으로 업그레이드</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/premium-indicator/premium-indicator.component.html</context>
<context context-type="linenumber">4</context>
@ -5122,7 +5122,7 @@
</trans-unit>
<trans-unit id="2191562378582791940" datatype="html">
<source>Stock Tracking</source>
<target state="new">Stock Tracking</target>
<target state="translated">주식 추적</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">111</context>
@ -5146,7 +5146,7 @@
</trans-unit>
<trans-unit id="9167786874272926575" datatype="html">
<source>Web</source>
<target state="new">Web</target>
<target state="translated">웹</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">120</context>
@ -5342,7 +5342,7 @@
</trans-unit>
<trans-unit id="9028573429495160158" datatype="html">
<source>Portfolio Filters</source>
<target state="new">Portfolio Filters</target>
<target state="translated">포트폴리오 필터</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
<context context-type="linenumber">63</context>
@ -5406,7 +5406,7 @@
</trans-unit>
<trans-unit id="1541521390115871091" datatype="html">
<source>{VAR_PLURAL, plural, =1 {Profile} other {Profiles}}</source>
<target state="new">{VAR_PLURAL, plural, =1 {Profile} other {Profiles}}</target>
<target state="translated">{VAR_PLURAL, plural, =1 {프로필} other {프로필}}</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">255</context>
@ -5718,7 +5718,7 @@
</trans-unit>
<trans-unit id="6300009182465422833" datatype="html">
<source>Ghostfolio in Numbers: Pulls on Docker Hub</source>
<target state="new">Ghostfolio in Numbers: Pulls on Docker Hub</target>
<target state="translated">Ghostfolio 통계: Docker Hub 다운로드 수</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">101</context>
@ -6350,7 +6350,7 @@
</trans-unit>
<trans-unit id="3995811497329884593" datatype="html">
<source>Expires <x id="INTERPOLATION" equiv-text="{{ formatDistanceToNow(element.subscription.expiresAt) }}"/> (<x id="INTERPOLATION_1" equiv-text="{{ element.subscription.expiresAt | date: defaultDateFormat }}"/>)</source>
<target state="new">Expires <x id="INTERPOLATION" equiv-text="{{ formatDistanceToNow(element.subscription.expiresAt) }}"/> (<x id="INTERPOLATION_1" equiv-text="{{ element.subscription.expiresAt | date: defaultDateFormat }}"/>)</target>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ formatDistanceToNow(element.subscription.expiresAt) }}"/> 만료 (<x id="INTERPOLATION_1" equiv-text="{{ element.subscription.expiresAt | date: defaultDateFormat }}"/>)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">34</context>
@ -6511,7 +6511,7 @@
</trans-unit>
<trans-unit id="2988589012964101797" datatype="html">
<source>Daily</source>
<target state="new">Daily</target>
<target state="translated">매일</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts</context>
<context context-type="linenumber">210</context>
@ -6811,7 +6811,7 @@
</trans-unit>
<trans-unit id="1284643802050750978" datatype="html">
<source>Oops! Could not delete the asset profile.</source>
<target state="new">Oops! Could not delete the asset profile.</target>
<target state="translated">이런! 자산 프로필을 삭제할 수 없습니다.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.service.ts</context>
<context context-type="linenumber">51</context>
@ -6931,7 +6931,7 @@
</trans-unit>
<trans-unit id="1518717392874668219" datatype="html">
<source>Do you really want to delete these <x id="count" equiv-text="assetProfileCount"/> asset profiles?</source>
<target state="new">Do you really want to delete these <x id="count" equiv-text="assetProfileCount"/> asset profiles?</target>
<target state="translated">이 <x id="count" equiv-text="assetProfileCount"/>개의 자산 프로필을 정말 삭제하시겠습니까?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.service.ts</context>
<context context-type="linenumber">67</context>
@ -7159,7 +7159,7 @@
</trans-unit>
<trans-unit id="6608617124920241143" datatype="html">
<source><x id="START_BLOCK_IF" equiv-text="@if ( assetProfile?.currency &amp;&amp; data.baseCurrency !== assetProfile?.currency ) {"/> Performance with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Performance <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></source>
<target state="new"><x id="START_BLOCK_IF" equiv-text="@if ( SymbolProfile?.currency &amp;&amp; data.baseCurrency !== SymbolProfile?.currency ) {"/> 환율 효과 반영 수익률 <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> 수익률 <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target>
<target state="translated"><x id="START_BLOCK_IF" equiv-text="@if ( assetProfile?.currency &amp;&amp; data.baseCurrency !== assetProfile?.currency ) {"/> 환율 효과 반영 수익률 <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> 수익률 <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html</context>
<context context-type="linenumber">83</context>
@ -7175,7 +7175,7 @@
</trans-unit>
<trans-unit id="6586833258036069278" datatype="html">
<source>Tax Reporting</source>
<target state="new">Tax Reporting</target>
<target state="translated">세금 보고</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">112</context>
@ -7183,7 +7183,7 @@
</trans-unit>
<trans-unit id="8375528527939577247" datatype="html">
<source><x id="START_BLOCK_IF" equiv-text="@if ( assetProfile?.currency &amp;&amp; data.baseCurrency !== assetProfile?.currency ) {"/> Change with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Change <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></source>
<target state="new"><x id="START_BLOCK_IF" equiv-text="@if ( SymbolProfile?.currency &amp;&amp; data.baseCurrency !== SymbolProfile?.currency ) {"/> 환율 효과 반영 변동 <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> 변동 <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target>
<target state="translated"><x id="START_BLOCK_IF" equiv-text="@if ( assetProfile?.currency &amp;&amp; data.baseCurrency !== assetProfile?.currency ) {"/> 환율 효과 반영 변동 <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> 변동 <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html</context>
<context context-type="linenumber">63</context>
@ -7199,7 +7199,7 @@
</trans-unit>
<trans-unit id="6389025757025171607" datatype="html">
<source>Compare Ghostfolio to <x id="INTERPOLATION" equiv-text="{{ personalFinanceTool.name }}"/> - <x id="INTERPOLATION_1" equiv-text="{{ personalFinanceTool.slogan }}"/></source>
<target state="new">Compare Ghostfolio to <x id="INTERPOLATION" equiv-text="{{ personalFinanceTool.name }}"/> - <x id="INTERPOLATION_1" equiv-text="{{ personalFinanceTool.slogan }}"/></target>
<target state="translated">Ghostfolio와 <x id="INTERPOLATION" equiv-text="{{ personalFinanceTool.name }}"/> 비교 - <x id="INTERPOLATION_1" equiv-text="{{ personalFinanceTool.slogan }}"/></target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context>
<context context-type="linenumber">32</context>
@ -7239,7 +7239,7 @@
</trans-unit>
<trans-unit id="3527222903865200876" datatype="html">
<source>Dividend Tracking</source>
<target state="new">Dividend Tracking</target>
<target state="translated">배당 추적</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">105</context>
@ -7303,7 +7303,7 @@
</trans-unit>
<trans-unit id="7547813413369998179" datatype="html">
<source>Delete <x id="INTERPOLATION" equiv-text="{{ selection.selected.length &gt; 1 ? selection.selected.length : &apos;&apos; }}"/> <x id="ICU" equiv-text="{selection.selected.length, plural, =1 {Profile} other {Profiles} }"/></source>
<target state="new">Delete <x id="INTERPOLATION" equiv-text="{{ selection.selected.length &gt; 1 ? selection.selected.length : &apos;&apos; }}"/> <x id="ICU" equiv-text="{selection.selected.length, plural, =1 {Profile} other {Profiles} }"/></target>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ selection.selected.length &gt; 1 ? selection.selected.length : &apos;&apos; }}"/> <x id="ICU" equiv-text="{selection.selected.length, plural, =1 {Profile} other {Profiles} }"/> 삭제</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">250</context>
@ -7419,7 +7419,7 @@
</trans-unit>
<trans-unit id="1550367033316836764" datatype="html">
<source>Investment Research</source>
<target state="new">Investment Research</target>
<target state="translated">투자 리서치</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">109</context>
@ -7701,7 +7701,7 @@
</trans-unit>
<trans-unit id="4060547242431613838" datatype="html">
<source>Net Worth Tracking</source>
<target state="new">Net Worth Tracking</target>
<target state="translated">순자산 추적</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">110</context>
@ -7833,7 +7833,7 @@
</trans-unit>
<trans-unit id="1237494164624005096" datatype="html">
<source>Ghostfolio in Numbers: Stars on GitHub</source>
<target state="new">Ghostfolio in Numbers: Stars on GitHub</target>
<target state="translated">Ghostfolio 통계: GitHub 스타 수</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">82</context>
@ -8139,7 +8139,7 @@
</trans-unit>
<trans-unit id="3910789128199500333" datatype="html">
<source>ETF Tracking</source>
<target state="new">ETF Tracking</target>
<target state="translated">ETF 추적</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">106</context>
@ -8305,7 +8305,7 @@
</trans-unit>
<trans-unit id="2813837590488774096" datatype="html">
<source>Post to Ghostfolio on X (formerly Twitter)</source>
<target state="new">Post to Ghostfolio on X (formerly Twitter)</target>
<target state="translated">X(이전의 Twitter)에서 Ghostfolio에 게시하세요.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/overview/about-overview-page.html</context>
<context context-type="linenumber">85</context>
@ -8526,7 +8526,7 @@
</trans-unit>
<trans-unit id="5199695670214400859" datatype="html">
<source>If you encounter a bug, would like to suggest an improvement or a new <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkFeatures&quot;&gt;"/>feature<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>, please join the Ghostfolio <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg&quot; i18n-title title=&quot;Join the Ghostfolio Slack community&quot; &gt;"/>Slack<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> community, post to <x id="START_LINK_2" equiv-text="&lt;a href=&quot;https://x.com/ghostfolio_&quot; i18n-title title=&quot;Post to Ghostfolio on X (formerly Twitter)&quot; &gt;"/>@ghostfolio_<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/></source>
<target state="new">버그가 발생하거나 개선 사항이나 새로운 <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkFeatures&quot;&gt;"/>기능<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>을 제안하고 싶다면 Ghostfolio <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg&quot; title=&quot;Join the Ghostfolio Slack community&quot; &gt;"/>슬랙<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 커뮤니티에 가입하고 <x id="START_LINK_2" equiv-text="&lt;a href=&quot;https://x.com/ghostfolio_&quot; title=&quot;Post to Ghostfolio on X (formerly Twitter)&quot; &gt;"/>@ghostfolio_<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>에 게시하세요.</target>
<target state="translated">버그가 발생하거나 개선 사항이나 새로운 <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkFeatures&quot;&gt;"/>기능<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>을 제안하고 싶다면 Ghostfolio <x id="START_LINK_1" equiv-text="&lt;a href=&quot;https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg&quot; title=&quot;Join the Ghostfolio Slack community&quot; &gt;"/>슬랙<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 커뮤니티에 가입하고 <x id="START_LINK_2" equiv-text="&lt;a href=&quot;https://x.com/ghostfolio_&quot; title=&quot;Post to Ghostfolio on X (formerly Twitter)&quot; &gt;"/>@ghostfolio_<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>에 게시하세요.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/overview/about-overview-page.html</context>
<context context-type="linenumber">71</context>

4
apps/client/src/locales/messages.tr.xlf

@ -2096,7 +2096,7 @@
</trans-unit>
<trans-unit id="8768104874317770689" datatype="html">
<source>1Y</source>
<target state="trasnlated">1Y</target>
<target state="translated">1Y</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts</context>
<context context-type="linenumber">232</context>
@ -4273,7 +4273,7 @@
</trans-unit>
<trans-unit id="9040028765832531851" datatype="html">
<source>This overview page features a curated collection of personal finance tools compared to the open source alternative <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkAbout&quot;&gt;"/>Ghostfolio<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. If you value transparency, data privacy, and community collaboration, Ghostfolio provides an excellent opportunity to take control of your financial management.</source>
<target state="translatedew">Bu genel bakış sayfası, diğer kişisel finans araçlarının seçilmiş bir koleksiyonunun açık kaynak alternatifi<x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkAbout&quot;&gt;"/>Ghostfolio ile karşılaştırmasını sunmaktadır.<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. Şeffaflığa, veri gizliliğine ve topluluk işbirliğine değer veriyorsanız Ghostfolio, finansal yönetiminizin kontrolünü ele almak için mükemmel Şeffaflığa, veri gizliliğine ve topluluk işbirliğine değer veriyorsanız Ghostfolio, finansal yönetiminizin kontrolünü ele almak için mükemmel bir fırsat sunuyor.</target>
<target state="translated">Bu genel bakış sayfası, diğer kişisel finans araçlarının seçilmiş bir koleksiyonunun açık kaynak alternatifi<x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkAbout&quot;&gt;"/>Ghostfolio ile karşılaştırmasını sunmaktadır.<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. Şeffaflığa, veri gizliliğine ve topluluk işbirliğine değer veriyorsanız Ghostfolio, finansal yönetiminizin kontrolünü ele almak için mükemmel bir fırsat sunuyor.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context>
<context context-type="linenumber">9</context>

2
libs/common/src/lib/routes/interfaces/internal-route.interface.ts

@ -5,5 +5,5 @@ export interface InternalRoute {
path?: string;
routerLink: string[];
subRoutes?: Record<string, InternalRoute>;
title: string;
title?: string;
}

3
libs/common/src/lib/routes/routes.ts

@ -153,8 +153,7 @@ export const internalRoutes = {
webauthn: {
excludeFromAssistant: true,
path: 'webauthn',
routerLink: ['/webauthn'],
title: $localize`Sign in`
routerLink: ['/webauthn']
},
zen: {
excludeFromAssistant: true,

5
libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.html

@ -8,7 +8,10 @@
@if (item && isAsset(item)) {
<br />
<small class="text-muted"
>{{ item?.symbol ?? '' | gfSymbol }} · {{ item?.currency }}
>{{ item?.symbol ?? '' | gfSymbol }}
@if (item.currency) {
· {{ item.currency }}
}
@if (item?.assetSubClassString) {
· {{ item.assetSubClassString }}
}

5
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html

@ -25,7 +25,10 @@
}
</span>
<small class="text-muted"
>{{ lookupItem.symbol | gfSymbol }} · {{ lookupItem.currency }}
>{{ lookupItem.symbol | gfSymbol }}
@if (lookupItem.currency) {
· {{ lookupItem.currency }}
}
@if (lookupItem.assetSubClass) {
· {{ lookupItem.assetSubClassString }}
}

17
package-lock.json

@ -1,12 +1,12 @@
{
"name": "ghostfolio",
"version": "3.23.0",
"version": "3.24.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ghostfolio",
"version": "3.23.0",
"version": "3.24.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
@ -72,7 +72,7 @@
"fast-redact": "3.5.0",
"fuse.js": "7.3.0",
"google-spreadsheet": "3.2.0",
"helmet": "7.0.0",
"helmet": "8.2.0",
"http-status-codes": "2.3.0",
"ionicons": "8.0.13",
"jsonpath": "1.3.0",
@ -21897,12 +21897,15 @@
}
},
"node_modules/helmet": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-7.0.0.tgz",
"integrity": "sha512-MsIgYmdBh460ZZ8cJC81q4XJknjG567wzEmv46WOBblDb6TUd3z8/GhgmsM9pn8g2B80tAJ4m5/d3Bi1KrSUBQ==",
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-8.2.0.tgz",
"integrity": "sha512-DRgTIUgnWcJ62KyarxxziuqYxKGnR6Rgg19BlbucN/dpmJbl1XOit6qvoOX0ZT+HhWe5OUVhU/a1zpGyc1xA0Q==",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
"node": ">=18.0.0"
},
"funding": {
"url": "https://github.com/sponsors/EvanHahn"
}
},
"node_modules/hono": {

4
package.json

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "3.23.0",
"version": "3.24.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",
@ -116,7 +116,7 @@
"fast-redact": "3.5.0",
"fuse.js": "7.3.0",
"google-spreadsheet": "3.2.0",
"helmet": "7.0.0",
"helmet": "8.2.0",
"http-status-codes": "2.3.0",
"ionicons": "8.0.13",
"jsonpath": "1.3.0",

Loading…
Cancel
Save