Browse Source

Merge remote changes and synchronize schema for isActive property

pull/4469/head
tobikugel 3 weeks ago
parent
commit
c85a87bdcb
  1. 52
      CHANGELOG.md
  2. 4
      DEVELOPMENT.md
  3. 2
      README.md
  4. 4
      apps/api/src/app/admin/admin.controller.ts
  5. 27
      apps/api/src/app/admin/admin.service.ts
  6. 2
      apps/api/src/app/app.module.ts
  7. 8
      apps/api/src/app/auth/auth.service.ts
  8. 27
      apps/api/src/app/endpoints/ai/ai.controller.ts
  9. 2
      apps/api/src/app/endpoints/ai/ai.module.ts
  10. 4
      apps/api/src/app/endpoints/ai/ai.service.ts
  11. 46
      apps/api/src/app/endpoints/assets/assets.controller.ts
  12. 11
      apps/api/src/app/endpoints/assets/assets.module.ts
  13. 3
      apps/api/src/app/export/export.controller.ts
  14. 96
      apps/api/src/app/export/export.service.ts
  15. 10
      apps/api/src/app/import/create-account-with-balances.dto.ts
  16. 7
      apps/api/src/app/import/import-data.dto.ts
  17. 4
      apps/api/src/app/import/import.service.ts
  18. 2
      apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts
  19. 25
      apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts
  20. 4
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  21. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts
  22. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts
  23. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts
  24. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts
  25. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts
  26. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts
  27. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts
  28. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts
  29. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts
  30. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts
  31. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
  32. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts
  33. 0
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.spec.ts
  34. 969
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts
  35. 959
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts
  36. 96
      apps/api/src/app/portfolio/portfolio.service.ts
  37. 8
      apps/api/src/app/sitemap/sitemap.controller.ts
  38. 35
      apps/api/src/app/user/user.controller.ts
  39. 35
      apps/api/src/app/user/user.service.ts
  40. 684
      apps/api/src/assets/cryptocurrencies/cryptocurrencies.json
  41. 4
      apps/api/src/assets/site.webmanifest
  42. 4
      apps/api/src/assets/sitemap.xml
  43. 3
      apps/api/src/environments/environment.prod.ts
  44. 3
      apps/api/src/environments/environment.ts
  45. 2
      apps/api/src/helper/object.helper.spec.ts
  46. 2
      apps/api/src/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor.ts
  47. 43
      apps/api/src/main.ts
  48. 6
      apps/api/src/middlewares/html-template.middleware.ts
  49. 17
      apps/api/src/services/configuration/configuration.service.ts
  50. 2
      apps/api/src/services/cron.service.ts
  51. 2
      apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts
  52. 21
      apps/api/src/services/data-provider/data-provider.service.ts
  53. 21
      apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
  54. 4
      apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts
  55. 1
      apps/api/src/services/interfaces/environment.interface.ts
  56. 21
      apps/api/src/services/queues/data-gathering/data-gathering.service.ts
  57. 2
      apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
  58. 71
      apps/api/src/services/symbol-profile/symbol-profile.service.ts
  59. 8
      apps/client/ngsw-config.json
  60. 3
      apps/client/project.json
  61. 2
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html
  62. 5
      apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts
  63. 44
      apps/client/src/app/components/admin-overview/admin-overview.component.ts
  64. 67
      apps/client/src/app/components/admin-overview/admin-overview.html
  65. 45
      apps/client/src/app/components/admin-users/admin-users.component.ts
  66. 11
      apps/client/src/app/components/admin-users/admin-users.html
  67. 2
      apps/client/src/app/components/header/header.component.html
  68. 2
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html
  69. 4
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html
  70. 4
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts
  71. 3
      apps/client/src/app/components/user-account-settings/user-account-settings.component.ts
  72. 2
      apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html
  73. 32
      apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts
  74. 90
      apps/client/src/app/pages/portfolio/analysis/analysis-page.html
  75. 2
      apps/client/src/app/pages/portfolio/analysis/analysis-page.module.ts
  76. 7
      apps/client/src/app/pages/register/register-page.component.ts
  77. 2
      apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html
  78. 17
      apps/client/src/app/services/admin.service.ts
  79. 36
      apps/client/src/app/services/data.service.ts
  80. 4
      apps/client/src/app/services/user/user.service.ts
  81. 5
      apps/client/src/index.html
  82. 156
      apps/client/src/locales/messages.ca.xlf
  83. 156
      apps/client/src/locales/messages.de.xlf
  84. 156
      apps/client/src/locales/messages.es.xlf
  85. 210
      apps/client/src/locales/messages.fr.xlf
  86. 180
      apps/client/src/locales/messages.it.xlf
  87. 156
      apps/client/src/locales/messages.nl.xlf
  88. 156
      apps/client/src/locales/messages.pl.xlf
  89. 156
      apps/client/src/locales/messages.pt.xlf
  90. 230
      apps/client/src/locales/messages.tr.xlf
  91. 162
      apps/client/src/locales/messages.uk.xlf
  92. 150
      apps/client/src/locales/messages.xlf
  93. 156
      apps/client/src/locales/messages.zh.xlf
  94. 2
      apps/client/src/styles.scss
  95. 5
      libs/common/src/lib/config.ts
  96. 4
      libs/common/src/lib/interfaces/account-balance.interface.ts
  97. 7
      libs/common/src/lib/interfaces/admin-data.interface.ts
  98. 4
      libs/common/src/lib/interfaces/export.interface.ts
  99. 4
      libs/common/src/lib/interfaces/index.ts
  100. 1
      libs/common/src/lib/interfaces/portfolio-summary.interface.ts

52
CHANGELOG.md

@ -7,15 +7,65 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Changed
- Improved the static portfolio analysis rule: Emergency fund setup by supporting assets
- Restricted the historical market data gathering to active asset profiles
## 2.148.0 - 2025-03-24
### Added
- Improved the usability of the user account registration
- Added the `isActive` flag to the asset profile model
### Changed
- Improved the language localization for German (`de`)
- Upgraded `ngx-skeleton-loader` from version `9.0.0` to `10.0.0`
## 2.147.0 - 2025-03-22
### Added
- Added support for filtering in the _Copy AI prompt to clipboard_ actions on the analysis page (experimental)
- Added support for generating a new _Security Token_ via the users table of the admin control panel
- Added an endpoint to localize the `site.webmanifest`
- Added the _Storybook_ path to the `sitemap.xml` file
### Changed
- Improved the export functionality by applying filters on accounts and tags
- Improved the symbol validation in the _Yahoo Finance_ service (get asset profiles)
- Eliminated `firstOrderDate` from the summary of the portfolio details endpoint in favor of using `dateOfFirstActivity` from the user endpoint
- Refactored `lodash.uniq` with `Array.from(new Set(...))`
- Refreshed the cryptocurrencies list
- Improved the language localization for German (`de`)
- Improved the language localization for Turkish (`tr`)
### Fixed
- Fixed an issue in the activities import functionality related to the account balances
- Changed client-side dates to be sent in UTC format to ensure date consistency
- Benchmark endpoint
- Exchange rate endpoint
## 2.146.0 - 2025-03-15
### Changed
- Improved the usability of the user account registration
- Improved the usability of the _Copy AI prompt to clipboard_ actions on the analysis page (experimental)
- Formatted the name in the _Financial Modeling Prep_ service
- Removed the exchange rates from the overview of the admin control panel
- Improved the language localization for German (`de`)
- Upgraded `angular` from version `19.0.5` to `19.2.1`
- Upgraded `Nx` from version `20.3.2` to `20.5.0`
- Upgraded `prettier` from version `3.5.1` to `3.5.3`
- Upgraded `prisma` from version `6.4.1` to `6.5.0`
### Fixed
- Fixed an issue with serving _Storybook_ related to the `contentSecurityPolicy`
## 2.145.1 - 2025-03-10

4
DEVELOPMENT.md

@ -60,6 +60,10 @@ Remove permission in `UserService` using `without()`
Use `@if (user?.settings?.isExperimentalFeatures) {}` in HTML template
## Component Library (_Storybook_)
https://ghostfol.io/development/storybook
## Git
### Rebase

2
README.md

@ -47,7 +47,7 @@ Ghostfolio is for you if you are...
- ✅ Create, update and delete transactions
- ✅ Multi account management
- ✅ Portfolio performance: Time-weighted rate of return (TWR) for `Today`, `WTD`, `MTD`, `YTD`, `1Y`, `5Y`, `Max`
- ✅ Portfolio performance: Return on Average Investment (ROAI) for `Today`, `WTD`, `MTD`, `YTD`, `1Y`, `5Y`, `Max`
- ✅ Various charts
- ✅ Static analysis to identify potential risks in your portfolio
- ✅ Import and export transactions

4
apps/api/src/app/admin/admin.controller.ts

@ -83,7 +83,7 @@ export class AdminController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async gatherMax(): Promise<void> {
const assetProfileIdentifiers =
await this.dataGatheringService.getAllAssetProfileIdentifiers();
await this.dataGatheringService.getAllActiveAssetProfileIdentifiers();
await this.dataGatheringService.addJobsToQueue(
assetProfileIdentifiers.map(({ dataSource, symbol }) => {
@ -110,7 +110,7 @@ export class AdminController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async gatherProfileData(): Promise<void> {
const assetProfileIdentifiers =
await this.dataGatheringService.getAllAssetProfileIdentifiers();
await this.dataGatheringService.getAllActiveAssetProfileIdentifiers();
await this.dataGatheringService.addJobsToQueue(
assetProfileIdentifiers.map(({ dataSource, symbol }) => {

27
apps/api/src/app/admin/admin.service.ts

@ -10,7 +10,6 @@ import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import {
DEFAULT_CURRENCY,
PROPERTY_CURRENCIES,
PROPERTY_IS_READ_ONLY_MODE,
PROPERTY_IS_USER_SIGNUP_ENABLED
@ -138,31 +137,6 @@ export class AdminService {
}
public async get(): Promise<AdminData> {
const exchangeRates = this.exchangeRateDataService
.getCurrencies()
.filter((currency) => {
return currency !== DEFAULT_CURRENCY;
})
.map((currency) => {
const label1 = DEFAULT_CURRENCY;
const label2 = currency;
return {
label1,
label2,
dataSource:
DataSource[
this.configurationService.get('DATA_SOURCE_EXCHANGE_RATES')
],
symbol: `${label1}${label2}`,
value: this.exchangeRateDataService.toCurrency(
1,
DEFAULT_CURRENCY,
currency
)
};
});
const [settings, transactionCount, userCount] = await Promise.all([
this.propertyService.get(),
this.prismaService.order.count(),
@ -170,7 +144,6 @@ export class AdminService {
]);
return {
exchangeRates,
settings,
transactionCount,
userCount,

2
apps/api/src/app/app.module.ts

@ -32,6 +32,7 @@ import { AuthModule } from './auth/auth.module';
import { CacheModule } from './cache/cache.module';
import { AiModule } from './endpoints/ai/ai.module';
import { ApiKeysModule } from './endpoints/api-keys/api-keys.module';
import { AssetsModule } from './endpoints/assets/assets.module';
import { BenchmarksModule } from './endpoints/benchmarks/benchmarks.module';
import { GhostfolioModule } from './endpoints/data-providers/ghostfolio/ghostfolio.module';
import { MarketDataModule } from './endpoints/market-data/market-data.module';
@ -61,6 +62,7 @@ import { UserModule } from './user/user.module';
AiModule,
ApiKeysModule,
AssetModule,
AssetsModule,
AuthDeviceModule,
AuthModule,
BenchmarksModule,

8
apps/api/src/app/auth/auth.service.ts

@ -20,10 +20,10 @@ export class AuthService {
public async validateAnonymousLogin(accessToken: string): Promise<string> {
return new Promise(async (resolve, reject) => {
try {
const hashedAccessToken = this.userService.createAccessToken(
accessToken,
this.configurationService.get('ACCESS_TOKEN_SALT')
);
const hashedAccessToken = this.userService.createAccessToken({
password: accessToken,
salt: this.configurationService.get('ACCESS_TOKEN_SALT')
});
const [user] = await this.userService.users({
where: { accessToken: hashedAccessToken }

27
apps/api/src/app/endpoints/ai/ai.controller.ts

@ -1,5 +1,6 @@
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { ApiService } from '@ghostfolio/api/services/api/api.service';
import {
DEFAULT_CURRENCY,
DEFAULT_LANGUAGE_CODE
@ -8,7 +9,14 @@ import { AiPromptResponse } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import type { AiPromptMode, RequestWithUser } from '@ghostfolio/common/types';
import { Controller, Get, Inject, Param, UseGuards } from '@nestjs/common';
import {
Controller,
Get,
Inject,
Param,
Query,
UseGuards
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
@ -18,6 +26,7 @@ import { AiService } from './ai.service';
export class AiController {
public constructor(
private readonly aiService: AiService,
private readonly apiService: ApiService,
@Inject(REQUEST) private readonly request: RequestWithUser
) {}
@ -25,9 +34,23 @@ export class AiController {
@HasPermission(permissions.readAiPrompt)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getPrompt(
@Param('mode') mode: AiPromptMode
@Param('mode') mode: AiPromptMode,
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string
): Promise<AiPromptResponse> {
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags
});
const prompt = await this.aiService.getPrompt({
filters,
mode,
impersonationId: undefined,
languageCode:

2
apps/api/src/app/endpoints/ai/ai.module.ts

@ -7,6 +7,7 @@ import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.servic
import { RulesService } from '@ghostfolio/api/app/portfolio/rules.service';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
@ -25,6 +26,7 @@ import { AiService } from './ai.service';
@Module({
controllers: [AiController],
imports: [
ApiModule,
ConfigurationModule,
DataProviderModule,
ExchangeRateDataModule,

4
apps/api/src/app/endpoints/ai/ai.service.ts

@ -1,4 +1,5 @@
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { Filter } from '@ghostfolio/common/interfaces';
import type { AiPromptMode } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
@ -8,12 +9,14 @@ export class AiService {
public constructor(private readonly portfolioService: PortfolioService) {}
public async getPrompt({
filters,
impersonationId,
languageCode,
mode,
userCurrency,
userId
}: {
filters?: Filter[];
impersonationId: string;
languageCode: string;
mode: AiPromptMode;
@ -21,6 +24,7 @@ export class AiService {
userId: string;
}) {
const { holdings } = await this.portfolioService.getDetails({
filters,
impersonationId,
userId
});

46
apps/api/src/app/endpoints/assets/assets.controller.ts

@ -0,0 +1,46 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { interpolate } from '@ghostfolio/common/helper';
import {
Controller,
Get,
Param,
Res,
Version,
VERSION_NEUTRAL
} from '@nestjs/common';
import { Response } from 'express';
import { readFileSync } from 'fs';
import { join } from 'path';
@Controller('assets')
export class AssetsController {
private webManifest = '';
public constructor(
public readonly configurationService: ConfigurationService
) {
try {
this.webManifest = readFileSync(
join(__dirname, 'assets', 'site.webmanifest'),
'utf8'
);
} catch {}
}
@Get('/:languageCode/site.webmanifest')
@Version(VERSION_NEUTRAL)
public getWebManifest(
@Param('languageCode') languageCode: string,
@Res() response: Response
): void {
const rootUrl = this.configurationService.get('ROOT_URL');
const webManifest = interpolate(this.webManifest, {
languageCode,
rootUrl
});
response.setHeader('Content-Type', 'application/json');
response.send(webManifest);
}
}

11
apps/api/src/app/endpoints/assets/assets.module.ts

@ -0,0 +1,11 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { Module } from '@nestjs/common';
import { AssetsController } from './assets.controller';
@Module({
controllers: [AssetsController],
providers: [ConfigurationService]
})
export class AssetsModule {}

3
apps/api/src/app/export/export.controller.ts

@ -21,10 +21,11 @@ export class ExportController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async export(
@Query('accounts') filterByAccounts?: string,
@Query('activityIds') activityIds?: string[],
@Query('activityIds') filterByActivityIds?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('tags') filterByTags?: string
): Promise<Export> {
const activityIds = filterByActivityIds?.split(',') ?? [];
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,

96
apps/api/src/app/export/export.service.ts

@ -28,6 +28,22 @@ export class ExportService {
}): Promise<Export> {
const platformsMap: { [platformId: string]: Platform } = {};
let { activities } = await this.orderService.getOrders({
filters,
userCurrency,
userId,
includeDrafts: true,
sortColumn: 'date',
sortDirection: 'asc',
withExcludedAccounts: true
});
if (activityIds?.length > 0) {
activities = activities.filter(({ id }) => {
return activityIds.includes(id);
});
}
const accounts = (
await this.accountService.accounts({
include: {
@ -39,57 +55,55 @@ export class ExportService {
},
where: { userId }
})
).map(
({
balance,
balances,
comment,
currency,
id,
isExcluded,
name,
Platform: platform,
platformId
}) => {
if (platformId) {
platformsMap[platformId] = platform;
}
return {
)
.filter(({ id }) => {
return activities.length > 0
? activities.some(({ accountId }) => {
return accountId === id;
})
: true;
})
.map(
({
balance,
balances: balances.map(({ date, value }) => {
return { date: date.toISOString(), value };
}),
balances,
comment,
currency,
id,
isExcluded,
name,
Platform: platform,
platformId
};
}
);
let { activities } = await this.orderService.getOrders({
filters,
userCurrency,
userId,
includeDrafts: true,
sortColumn: 'date',
sortDirection: 'asc',
withExcludedAccounts: true
});
}) => {
if (platformId) {
platformsMap[platformId] = platform;
}
if (activityIds) {
activities = activities.filter((activity) => {
return activityIds.includes(activity.id);
});
}
return {
balance,
balances: balances.map(({ date, value }) => {
return { date: date.toISOString(), value };
}),
comment,
currency,
id,
isExcluded,
name,
platformId
};
}
);
const tags = (await this.tagService.getTagsForUser(userId))
.filter(({ isUsed }) => {
return isUsed;
})
.filter(
({ id, isUsed }) =>
isUsed &&
activities.some((activity) => {
return activity.tags.some(({ id: tagId }) => {
return tagId === id;
});
})
)
.map(({ id, name }) => {
return {
id,

10
apps/api/src/app/import/create-account-with-balances.dto.ts

@ -0,0 +1,10 @@
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto';
import { AccountBalance } from '@ghostfolio/common/interfaces';
import { IsArray, IsOptional } from 'class-validator';
export class CreateAccountWithBalancesDto extends CreateAccountDto {
@IsArray()
@IsOptional()
balances?: AccountBalance;
}

7
apps/api/src/app/import/import-data.dto.ts

@ -1,15 +1,16 @@
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto';
import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
import { Type } from 'class-transformer';
import { IsArray, IsOptional, ValidateNested } from 'class-validator';
import { CreateAccountWithBalancesDto } from './create-account-with-balances.dto';
export class ImportDataDto {
@IsOptional()
@IsArray()
@Type(() => CreateAccountDto)
@Type(() => CreateAccountWithBalancesDto)
@ValidateNested({ each: true })
accounts: CreateAccountDto[];
accounts: CreateAccountWithBalancesDto[];
@IsArray()
@Type(() => CreateOrderDto)

4
apps/api/src/app/import/import.service.ts

@ -300,6 +300,7 @@ export class ImportService {
figiShareClass,
holdings,
id,
isActive,
isin,
name,
scraperConfiguration,
@ -375,6 +376,7 @@ export class ImportService {
figiShareClass,
holdings,
id,
isActive,
isin,
name,
scraperConfiguration,
@ -586,7 +588,7 @@ export class ImportService {
const assetProfiles: {
[assetProfileIdentifier: string]: Partial<SymbolProfile>;
} = {};
const dataSources = await this.dataProviderService.getDataSources();
const dataSources = await this.dataProviderService.getDataSources({ user });
for (const [
index,

2
apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts

@ -5,7 +5,7 @@ import {
} from '@ghostfolio/common/interfaces';
import { PortfolioSnapshot } from '@ghostfolio/common/models';
export class MWRPortfolioCalculator extends PortfolioCalculator {
export class MwrPortfolioCalculator extends PortfolioCalculator {
protected calculateOverallPerformance(): PortfolioSnapshot {
throw new Error('Method not implemented.');
}

25
apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts

@ -8,12 +8,14 @@ import { Filter, HistoricalDataItem } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common';
import { MWRPortfolioCalculator } from './mwr/portfolio-calculator';
import { MwrPortfolioCalculator } from './mwr/portfolio-calculator';
import { PortfolioCalculator } from './portfolio-calculator';
import { TWRPortfolioCalculator } from './twr/portfolio-calculator';
import { RoaiPortfolioCalculator } from './roai/portfolio-calculator';
import { TwrPortfolioCalculator } from './twr/portfolio-calculator';
export enum PerformanceCalculationType {
MWR = 'MWR', // Money-Weighted Rate of Return
ROAI = 'ROAI', // Return on Average Investment
TWR = 'TWR' // Time-Weighted Rate of Return
}
@ -44,7 +46,7 @@ export class PortfolioCalculatorFactory {
}): PortfolioCalculator {
switch (calculationType) {
case PerformanceCalculationType.MWR:
return new MWRPortfolioCalculator({
return new MwrPortfolioCalculator({
accountBalanceItems,
activities,
currency,
@ -56,15 +58,28 @@ export class PortfolioCalculatorFactory {
portfolioSnapshotService: this.portfolioSnapshotService,
redisCacheService: this.redisCacheService
});
case PerformanceCalculationType.TWR:
return new TWRPortfolioCalculator({
case PerformanceCalculationType.ROAI:
return new RoaiPortfolioCalculator({
accountBalanceItems,
activities,
currency,
filters,
userId,
configurationService: this.configurationService,
currentRateService: this.currentRateService,
exchangeRateDataService: this.exchangeRateDataService,
portfolioSnapshotService: this.portfolioSnapshotService,
redisCacheService: this.redisCacheService
});
case PerformanceCalculationType.TWR:
return new TwrPortfolioCalculator({
accountBalanceItems,
activities,
currency,
filters,
userId,
configurationService: this.configurationService,
currentRateService: this.currentRateService,
exchangeRateDataService: this.exchangeRateDataService,
portfolioSnapshotService: this.portfolioSnapshotService,
redisCacheService: this.redisCacheService

4
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -49,7 +49,7 @@ import {
min,
subDays
} from 'date-fns';
import { isNumber, sortBy, sum, uniq, uniqBy } from 'lodash';
import { isNumber, sortBy, sum, uniqBy } from 'lodash';
export abstract class PortfolioCalculator {
protected static readonly ENABLE_LOGGING = false;
@ -222,7 +222,7 @@ export abstract class PortfolioCalculator {
const exchangeRatesByCurrency =
await this.exchangeRateDataService.getExchangeRatesByCurrency({
currencies: uniq(Object.values(currencies)),
currencies: Array.from(new Set(Object.values(currencies))),
endDate: endOfDay(this.endDate),
startDate: this.startDate,
targetCurrency: this.currency

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts

@ -137,7 +137,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts

@ -122,7 +122,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts

@ -107,7 +107,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts

@ -136,7 +136,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts

@ -107,7 +107,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'USD',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts

@ -120,7 +120,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts

@ -107,7 +107,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'USD',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts

@ -107,7 +107,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'USD',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts

@ -135,7 +135,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'USD',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts

@ -84,7 +84,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities: [],
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts

@ -116,7 +116,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

2
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts

@ -116,7 +116,7 @@ describe('PortfolioCalculator', () => {
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});

0
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.spec.ts

969
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

@ -0,0 +1,969 @@
import { PortfolioCalculator } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator';
import { PortfolioOrderItem } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order-item.interface';
import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,
SymbolMetrics
} from '@ghostfolio/common/interfaces';
import { PortfolioSnapshot, TimelinePosition } from '@ghostfolio/common/models';
import { DateRange } from '@ghostfolio/common/types';
import { Logger } from '@nestjs/common';
import { Big } from 'big.js';
import { addMilliseconds, differenceInDays, format, isBefore } from 'date-fns';
import { cloneDeep, sortBy } from 'lodash';
export class RoaiPortfolioCalculator extends PortfolioCalculator {
private chartDates: string[];
protected calculateOverallPerformance(
positions: TimelinePosition[]
): PortfolioSnapshot {
let currentValueInBaseCurrency = new Big(0);
let grossPerformance = new Big(0);
let grossPerformanceWithCurrencyEffect = new Big(0);
let hasErrors = false;
let netPerformance = new Big(0);
let totalFeesWithCurrencyEffect = new Big(0);
const totalInterestWithCurrencyEffect = new Big(0);
let totalInvestment = new Big(0);
let totalInvestmentWithCurrencyEffect = new Big(0);
let totalTimeWeightedInvestment = new Big(0);
let totalTimeWeightedInvestmentWithCurrencyEffect = new Big(0);
for (const currentPosition of positions) {
if (currentPosition.feeInBaseCurrency) {
totalFeesWithCurrencyEffect = totalFeesWithCurrencyEffect.plus(
currentPosition.feeInBaseCurrency
);
}
if (currentPosition.valueInBaseCurrency) {
currentValueInBaseCurrency = currentValueInBaseCurrency.plus(
currentPosition.valueInBaseCurrency
);
} else {
hasErrors = true;
}
if (currentPosition.investment) {
totalInvestment = totalInvestment.plus(currentPosition.investment);
totalInvestmentWithCurrencyEffect =
totalInvestmentWithCurrencyEffect.plus(
currentPosition.investmentWithCurrencyEffect
);
} else {
hasErrors = true;
}
if (currentPosition.grossPerformance) {
grossPerformance = grossPerformance.plus(
currentPosition.grossPerformance
);
grossPerformanceWithCurrencyEffect =
grossPerformanceWithCurrencyEffect.plus(
currentPosition.grossPerformanceWithCurrencyEffect
);
netPerformance = netPerformance.plus(currentPosition.netPerformance);
} else if (!currentPosition.quantity.eq(0)) {
hasErrors = true;
}
if (currentPosition.timeWeightedInvestment) {
totalTimeWeightedInvestment = totalTimeWeightedInvestment.plus(
currentPosition.timeWeightedInvestment
);
totalTimeWeightedInvestmentWithCurrencyEffect =
totalTimeWeightedInvestmentWithCurrencyEffect.plus(
currentPosition.timeWeightedInvestmentWithCurrencyEffect
);
} else if (!currentPosition.quantity.eq(0)) {
Logger.warn(
`Missing historical market data for ${currentPosition.symbol} (${currentPosition.dataSource})`,
'PortfolioCalculator'
);
hasErrors = true;
}
}
return {
currentValueInBaseCurrency,
hasErrors,
positions,
totalFeesWithCurrencyEffect,
totalInterestWithCurrencyEffect,
totalInvestment,
totalInvestmentWithCurrencyEffect,
activitiesCount: this.activities.filter(({ type }) => {
return ['BUY', 'SELL'].includes(type);
}).length,
createdAt: new Date(),
errors: [],
historicalData: [],
totalLiabilitiesWithCurrencyEffect: new Big(0),
totalValuablesWithCurrencyEffect: new Big(0)
};
}
protected getSymbolMetrics({
chartDateMap,
dataSource,
end,
exchangeRates,
marketSymbolMap,
start,
symbol
}: {
chartDateMap?: { [date: string]: boolean };
end: Date;
exchangeRates: { [dateString: string]: number };
marketSymbolMap: {
[date: string]: { [symbol: string]: Big };
};
start: Date;
} & AssetProfileIdentifier): SymbolMetrics {
const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)];
const currentValues: { [date: string]: Big } = {};
const currentValuesWithCurrencyEffect: { [date: string]: Big } = {};
let fees = new Big(0);
let feesAtStartDate = new Big(0);
let feesAtStartDateWithCurrencyEffect = new Big(0);
let feesWithCurrencyEffect = new Big(0);
let grossPerformance = new Big(0);
let grossPerformanceWithCurrencyEffect = new Big(0);
let grossPerformanceAtStartDate = new Big(0);
let grossPerformanceAtStartDateWithCurrencyEffect = new Big(0);
let grossPerformanceFromSells = new Big(0);
let grossPerformanceFromSellsWithCurrencyEffect = new Big(0);
let initialValue: Big;
let initialValueWithCurrencyEffect: Big;
let investmentAtStartDate: Big;
let investmentAtStartDateWithCurrencyEffect: Big;
const investmentValuesAccumulated: { [date: string]: Big } = {};
const investmentValuesAccumulatedWithCurrencyEffect: {
[date: string]: Big;
} = {};
const investmentValuesWithCurrencyEffect: { [date: string]: Big } = {};
let lastAveragePrice = new Big(0);
let lastAveragePriceWithCurrencyEffect = new Big(0);
const netPerformanceValues: { [date: string]: Big } = {};
const netPerformanceValuesWithCurrencyEffect: { [date: string]: Big } = {};
const timeWeightedInvestmentValues: { [date: string]: Big } = {};
const timeWeightedInvestmentValuesWithCurrencyEffect: {
[date: string]: Big;
} = {};
const totalAccountBalanceInBaseCurrency = new Big(0);
let totalDividend = new Big(0);
let totalDividendInBaseCurrency = new Big(0);
let totalInterest = new Big(0);
let totalInterestInBaseCurrency = new Big(0);
let totalInvestment = new Big(0);
let totalInvestmentFromBuyTransactions = new Big(0);
let totalInvestmentFromBuyTransactionsWithCurrencyEffect = new Big(0);
let totalInvestmentWithCurrencyEffect = new Big(0);
let totalLiabilities = new Big(0);
let totalLiabilitiesInBaseCurrency = new Big(0);
let totalQuantityFromBuyTransactions = new Big(0);
let totalUnits = new Big(0);
let totalValuables = new Big(0);
let totalValuablesInBaseCurrency = new Big(0);
let valueAtStartDate: Big;
let valueAtStartDateWithCurrencyEffect: Big;
// Clone orders to keep the original values in this.orders
let orders: PortfolioOrderItem[] = cloneDeep(
this.activities.filter(({ SymbolProfile }) => {
return SymbolProfile.symbol === symbol;
})
);
if (orders.length <= 0) {
return {
currentValues: {},
currentValuesWithCurrencyEffect: {},
feesWithCurrencyEffect: new Big(0),
grossPerformance: new Big(0),
grossPerformancePercentage: new Big(0),
grossPerformancePercentageWithCurrencyEffect: new Big(0),
grossPerformanceWithCurrencyEffect: new Big(0),
hasErrors: false,
initialValue: new Big(0),
initialValueWithCurrencyEffect: new Big(0),
investmentValuesAccumulated: {},
investmentValuesAccumulatedWithCurrencyEffect: {},
investmentValuesWithCurrencyEffect: {},
netPerformance: new Big(0),
netPerformancePercentage: new Big(0),
netPerformancePercentageWithCurrencyEffectMap: {},
netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {},
netPerformanceWithCurrencyEffectMap: {},
timeWeightedInvestment: new Big(0),
timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalAccountBalanceInBaseCurrency: new Big(0),
totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0),
totalInterest: new Big(0),
totalInterestInBaseCurrency: new Big(0),
totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilities: new Big(0),
totalLiabilitiesInBaseCurrency: new Big(0),
totalValuables: new Big(0),
totalValuablesInBaseCurrency: new Big(0)
};
}
const dateOfFirstTransaction = new Date(orders[0].date);
const endDateString = format(end, DATE_FORMAT);
const startDateString = format(start, DATE_FORMAT);
const unitPriceAtStartDate = marketSymbolMap[startDateString]?.[symbol];
const unitPriceAtEndDate = marketSymbolMap[endDateString]?.[symbol];
if (
!unitPriceAtEndDate ||
(!unitPriceAtStartDate && isBefore(dateOfFirstTransaction, start))
) {
return {
currentValues: {},
currentValuesWithCurrencyEffect: {},
feesWithCurrencyEffect: new Big(0),
grossPerformance: new Big(0),
grossPerformancePercentage: new Big(0),
grossPerformancePercentageWithCurrencyEffect: new Big(0),
grossPerformanceWithCurrencyEffect: new Big(0),
hasErrors: true,
initialValue: new Big(0),
initialValueWithCurrencyEffect: new Big(0),
investmentValuesAccumulated: {},
investmentValuesAccumulatedWithCurrencyEffect: {},
investmentValuesWithCurrencyEffect: {},
netPerformance: new Big(0),
netPerformancePercentage: new Big(0),
netPerformancePercentageWithCurrencyEffectMap: {},
netPerformanceWithCurrencyEffectMap: {},
netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {},
timeWeightedInvestment: new Big(0),
timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalAccountBalanceInBaseCurrency: new Big(0),
totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0),
totalInterest: new Big(0),
totalInterestInBaseCurrency: new Big(0),
totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilities: new Big(0),
totalLiabilitiesInBaseCurrency: new Big(0),
totalValuables: new Big(0),
totalValuablesInBaseCurrency: new Big(0)
};
}
// Add a synthetic order at the start and the end date
orders.push({
date: startDateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
itemType: 'start',
quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol
},
type: 'BUY',
unitPrice: unitPriceAtStartDate
});
orders.push({
date: endDateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
itemType: 'end',
SymbolProfile: {
dataSource,
symbol
},
quantity: new Big(0),
type: 'BUY',
unitPrice: unitPriceAtEndDate
});
let lastUnitPrice: Big;
const ordersByDate: { [date: string]: PortfolioOrderItem[] } = {};
for (const order of orders) {
ordersByDate[order.date] = ordersByDate[order.date] ?? [];
ordersByDate[order.date].push(order);
}
if (!this.chartDates) {
this.chartDates = Object.keys(chartDateMap).sort();
}
for (const dateString of this.chartDates) {
if (dateString < startDateString) {
continue;
} else if (dateString > endDateString) {
break;
}
if (ordersByDate[dateString]?.length > 0) {
for (const order of ordersByDate[dateString]) {
order.unitPriceFromMarketData =
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice;
}
} else {
orders.push({
date: dateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol
},
type: 'BUY',
unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice,
unitPriceFromMarketData:
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice
});
}
const lastOrder = orders.at(-1);
lastUnitPrice = lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice;
}
// Sort orders so that the start and end placeholder order are at the correct
// position
orders = sortBy(orders, ({ date, itemType }) => {
let sortIndex = new Date(date);
if (itemType === 'end') {
sortIndex = addMilliseconds(sortIndex, 1);
} else if (itemType === 'start') {
sortIndex = addMilliseconds(sortIndex, -1);
}
return sortIndex.getTime();
});
const indexOfStartOrder = orders.findIndex(({ itemType }) => {
return itemType === 'start';
});
const indexOfEndOrder = orders.findIndex(({ itemType }) => {
return itemType === 'end';
});
let totalInvestmentDays = 0;
let sumOfTimeWeightedInvestments = new Big(0);
let sumOfTimeWeightedInvestmentsWithCurrencyEffect = new Big(0);
for (let i = 0; i < orders.length; i += 1) {
const order = orders[i];
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log();
console.log();
console.log(
i + 1,
order.date,
order.type,
order.itemType ? `(${order.itemType})` : ''
);
}
const exchangeRateAtOrderDate = exchangeRates[order.date];
if (order.type === 'DIVIDEND') {
const dividend = order.quantity.mul(order.unitPrice);
totalDividend = totalDividend.plus(dividend);
totalDividendInBaseCurrency = totalDividendInBaseCurrency.plus(
dividend.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'INTEREST') {
const interest = order.quantity.mul(order.unitPrice);
totalInterest = totalInterest.plus(interest);
totalInterestInBaseCurrency = totalInterestInBaseCurrency.plus(
interest.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'ITEM') {
const valuables = order.quantity.mul(order.unitPrice);
totalValuables = totalValuables.plus(valuables);
totalValuablesInBaseCurrency = totalValuablesInBaseCurrency.plus(
valuables.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'LIABILITY') {
const liabilities = order.quantity.mul(order.unitPrice);
totalLiabilities = totalLiabilities.plus(liabilities);
totalLiabilitiesInBaseCurrency = totalLiabilitiesInBaseCurrency.plus(
liabilities.mul(exchangeRateAtOrderDate ?? 1)
);
}
if (order.itemType === 'start') {
// Take the unit price of the order as the market price if there are no
// orders of this symbol before the start date
order.unitPrice =
indexOfStartOrder === 0
? orders[i + 1]?.unitPrice
: unitPriceAtStartDate;
}
if (order.fee) {
order.feeInBaseCurrency = order.fee.mul(currentExchangeRate ?? 1);
order.feeInBaseCurrencyWithCurrencyEffect = order.fee.mul(
exchangeRateAtOrderDate ?? 1
);
}
const unitPrice = ['BUY', 'SELL'].includes(order.type)
? order.unitPrice
: order.unitPriceFromMarketData;
if (unitPrice) {
order.unitPriceInBaseCurrency = unitPrice.mul(currentExchangeRate ?? 1);
order.unitPriceInBaseCurrencyWithCurrencyEffect = unitPrice.mul(
exchangeRateAtOrderDate ?? 1
);
}
const valueOfInvestmentBeforeTransaction = totalUnits.mul(
order.unitPriceInBaseCurrency
);
const valueOfInvestmentBeforeTransactionWithCurrencyEffect =
totalUnits.mul(order.unitPriceInBaseCurrencyWithCurrencyEffect);
if (!investmentAtStartDate && i >= indexOfStartOrder) {
investmentAtStartDate = totalInvestment ?? new Big(0);
investmentAtStartDateWithCurrencyEffect =
totalInvestmentWithCurrencyEffect ?? new Big(0);
valueAtStartDate = valueOfInvestmentBeforeTransaction;
valueAtStartDateWithCurrencyEffect =
valueOfInvestmentBeforeTransactionWithCurrencyEffect;
}
let transactionInvestment = new Big(0);
let transactionInvestmentWithCurrencyEffect = new Big(0);
if (order.type === 'BUY') {
transactionInvestment = order.quantity
.mul(order.unitPriceInBaseCurrency)
.mul(getFactor(order.type));
transactionInvestmentWithCurrencyEffect = order.quantity
.mul(order.unitPriceInBaseCurrencyWithCurrencyEffect)
.mul(getFactor(order.type));
totalQuantityFromBuyTransactions =
totalQuantityFromBuyTransactions.plus(order.quantity);
totalInvestmentFromBuyTransactions =
totalInvestmentFromBuyTransactions.plus(transactionInvestment);
totalInvestmentFromBuyTransactionsWithCurrencyEffect =
totalInvestmentFromBuyTransactionsWithCurrencyEffect.plus(
transactionInvestmentWithCurrencyEffect
);
} else if (order.type === 'SELL') {
if (totalUnits.gt(0)) {
transactionInvestment = totalInvestment
.div(totalUnits)
.mul(order.quantity)
.mul(getFactor(order.type));
transactionInvestmentWithCurrencyEffect =
totalInvestmentWithCurrencyEffect
.div(totalUnits)
.mul(order.quantity)
.mul(getFactor(order.type));
}
}
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log('order.quantity', order.quantity.toNumber());
console.log('transactionInvestment', transactionInvestment.toNumber());
console.log(
'transactionInvestmentWithCurrencyEffect',
transactionInvestmentWithCurrencyEffect.toNumber()
);
}
const totalInvestmentBeforeTransaction = totalInvestment;
const totalInvestmentBeforeTransactionWithCurrencyEffect =
totalInvestmentWithCurrencyEffect;
totalInvestment = totalInvestment.plus(transactionInvestment);
totalInvestmentWithCurrencyEffect =
totalInvestmentWithCurrencyEffect.plus(
transactionInvestmentWithCurrencyEffect
);
if (i >= indexOfStartOrder && !initialValue) {
if (
i === indexOfStartOrder &&
!valueOfInvestmentBeforeTransaction.eq(0)
) {
initialValue = valueOfInvestmentBeforeTransaction;
initialValueWithCurrencyEffect =
valueOfInvestmentBeforeTransactionWithCurrencyEffect;
} else if (transactionInvestment.gt(0)) {
initialValue = transactionInvestment;
initialValueWithCurrencyEffect =
transactionInvestmentWithCurrencyEffect;
}
}
fees = fees.plus(order.feeInBaseCurrency ?? 0);
feesWithCurrencyEffect = feesWithCurrencyEffect.plus(
order.feeInBaseCurrencyWithCurrencyEffect ?? 0
);
totalUnits = totalUnits.plus(order.quantity.mul(getFactor(order.type)));
const valueOfInvestment = totalUnits.mul(order.unitPriceInBaseCurrency);
const valueOfInvestmentWithCurrencyEffect = totalUnits.mul(
order.unitPriceInBaseCurrencyWithCurrencyEffect
);
const grossPerformanceFromSell =
order.type === 'SELL'
? order.unitPriceInBaseCurrency
.minus(lastAveragePrice)
.mul(order.quantity)
: new Big(0);
const grossPerformanceFromSellWithCurrencyEffect =
order.type === 'SELL'
? order.unitPriceInBaseCurrencyWithCurrencyEffect
.minus(lastAveragePriceWithCurrencyEffect)
.mul(order.quantity)
: new Big(0);
grossPerformanceFromSells = grossPerformanceFromSells.plus(
grossPerformanceFromSell
);
grossPerformanceFromSellsWithCurrencyEffect =
grossPerformanceFromSellsWithCurrencyEffect.plus(
grossPerformanceFromSellWithCurrencyEffect
);
lastAveragePrice = totalQuantityFromBuyTransactions.eq(0)
? new Big(0)
: totalInvestmentFromBuyTransactions.div(
totalQuantityFromBuyTransactions
);
lastAveragePriceWithCurrencyEffect = totalQuantityFromBuyTransactions.eq(
0
)
? new Big(0)
: totalInvestmentFromBuyTransactionsWithCurrencyEffect.div(
totalQuantityFromBuyTransactions
);
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log(
'grossPerformanceFromSells',
grossPerformanceFromSells.toNumber()
);
console.log(
'grossPerformanceFromSellWithCurrencyEffect',
grossPerformanceFromSellWithCurrencyEffect.toNumber()
);
}
const newGrossPerformance = valueOfInvestment
.minus(totalInvestment)
.plus(grossPerformanceFromSells);
const newGrossPerformanceWithCurrencyEffect =
valueOfInvestmentWithCurrencyEffect
.minus(totalInvestmentWithCurrencyEffect)
.plus(grossPerformanceFromSellsWithCurrencyEffect);
grossPerformance = newGrossPerformance;
grossPerformanceWithCurrencyEffect =
newGrossPerformanceWithCurrencyEffect;
if (order.itemType === 'start') {
feesAtStartDate = fees;
feesAtStartDateWithCurrencyEffect = feesWithCurrencyEffect;
grossPerformanceAtStartDate = grossPerformance;
grossPerformanceAtStartDateWithCurrencyEffect =
grossPerformanceWithCurrencyEffect;
}
if (i > indexOfStartOrder) {
// Only consider periods with an investment for the calculation of
// the time weighted investment
if (
valueOfInvestmentBeforeTransaction.gt(0) &&
['BUY', 'SELL'].includes(order.type)
) {
// Calculate the number of days since the previous order
const orderDate = new Date(order.date);
const previousOrderDate = new Date(orders[i - 1].date);
let daysSinceLastOrder = differenceInDays(
orderDate,
previousOrderDate
);
if (daysSinceLastOrder <= 0) {
// The time between two activities on the same day is unknown
// -> Set it to the smallest floating point number greater than 0
daysSinceLastOrder = Number.EPSILON;
}
// Sum up the total investment days since the start date to calculate
// the time weighted investment
totalInvestmentDays += daysSinceLastOrder;
sumOfTimeWeightedInvestments = sumOfTimeWeightedInvestments.add(
valueAtStartDate
.minus(investmentAtStartDate)
.plus(totalInvestmentBeforeTransaction)
.mul(daysSinceLastOrder)
);
sumOfTimeWeightedInvestmentsWithCurrencyEffect =
sumOfTimeWeightedInvestmentsWithCurrencyEffect.add(
valueAtStartDateWithCurrencyEffect
.minus(investmentAtStartDateWithCurrencyEffect)
.plus(totalInvestmentBeforeTransactionWithCurrencyEffect)
.mul(daysSinceLastOrder)
);
}
currentValues[order.date] = valueOfInvestment;
currentValuesWithCurrencyEffect[order.date] =
valueOfInvestmentWithCurrencyEffect;
netPerformanceValues[order.date] = grossPerformance
.minus(grossPerformanceAtStartDate)
.minus(fees.minus(feesAtStartDate));
netPerformanceValuesWithCurrencyEffect[order.date] =
grossPerformanceWithCurrencyEffect
.minus(grossPerformanceAtStartDateWithCurrencyEffect)
.minus(
feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect)
);
investmentValuesAccumulated[order.date] = totalInvestment;
investmentValuesAccumulatedWithCurrencyEffect[order.date] =
totalInvestmentWithCurrencyEffect;
investmentValuesWithCurrencyEffect[order.date] = (
investmentValuesWithCurrencyEffect[order.date] ?? new Big(0)
).add(transactionInvestmentWithCurrencyEffect);
timeWeightedInvestmentValues[order.date] =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
: new Big(0);
timeWeightedInvestmentValuesWithCurrencyEffect[order.date] =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div(
totalInvestmentDays
)
: new Big(0);
}
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log('totalInvestment', totalInvestment.toNumber());
console.log(
'totalInvestmentWithCurrencyEffect',
totalInvestmentWithCurrencyEffect.toNumber()
);
console.log(
'totalGrossPerformance',
grossPerformance.minus(grossPerformanceAtStartDate).toNumber()
);
console.log(
'totalGrossPerformanceWithCurrencyEffect',
grossPerformanceWithCurrencyEffect
.minus(grossPerformanceAtStartDateWithCurrencyEffect)
.toNumber()
);
}
if (i === indexOfEndOrder) {
break;
}
}
const totalGrossPerformance = grossPerformance.minus(
grossPerformanceAtStartDate
);
const totalGrossPerformanceWithCurrencyEffect =
grossPerformanceWithCurrencyEffect.minus(
grossPerformanceAtStartDateWithCurrencyEffect
);
const totalNetPerformance = grossPerformance
.minus(grossPerformanceAtStartDate)
.minus(fees.minus(feesAtStartDate));
const timeWeightedAverageInvestmentBetweenStartAndEndDate =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
: new Big(0);
const timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div(
totalInvestmentDays
)
: new Big(0);
const grossPerformancePercentage =
timeWeightedAverageInvestmentBetweenStartAndEndDate.gt(0)
? totalGrossPerformance.div(
timeWeightedAverageInvestmentBetweenStartAndEndDate
)
: new Big(0);
const grossPerformancePercentageWithCurrencyEffect =
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.gt(
0
)
? totalGrossPerformanceWithCurrencyEffect.div(
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
)
: new Big(0);
const feesPerUnit = totalUnits.gt(0)
? fees.minus(feesAtStartDate).div(totalUnits)
: new Big(0);
const feesPerUnitWithCurrencyEffect = totalUnits.gt(0)
? feesWithCurrencyEffect
.minus(feesAtStartDateWithCurrencyEffect)
.div(totalUnits)
: new Big(0);
const netPerformancePercentage =
timeWeightedAverageInvestmentBetweenStartAndEndDate.gt(0)
? totalNetPerformance.div(
timeWeightedAverageInvestmentBetweenStartAndEndDate
)
: new Big(0);
const netPerformancePercentageWithCurrencyEffectMap: {
[key: DateRange]: Big;
} = {};
const netPerformanceWithCurrencyEffectMap: {
[key: DateRange]: Big;
} = {};
for (const dateRange of [
'1d',
'1y',
'5y',
'max',
'mtd',
'wtd',
'ytd'
// TODO:
// ...eachYearOfInterval({ end, start })
// .filter((date) => {
// return !isThisYear(date);
// })
// .map((date) => {
// return format(date, 'yyyy');
// })
] as DateRange[]) {
const dateInterval = getIntervalFromDateRange(dateRange);
const endDate = dateInterval.endDate;
let startDate = dateInterval.startDate;
if (isBefore(startDate, start)) {
startDate = start;
}
const rangeEndDateString = format(endDate, DATE_FORMAT);
const rangeStartDateString = format(startDate, DATE_FORMAT);
const currentValuesAtDateRangeStartWithCurrencyEffect =
currentValuesWithCurrencyEffect[rangeStartDateString] ?? new Big(0);
const investmentValuesAccumulatedAtStartDateWithCurrencyEffect =
investmentValuesAccumulatedWithCurrencyEffect[rangeStartDateString] ??
new Big(0);
const grossPerformanceAtDateRangeStartWithCurrencyEffect =
currentValuesAtDateRangeStartWithCurrencyEffect.minus(
investmentValuesAccumulatedAtStartDateWithCurrencyEffect
);
let average = new Big(0);
let dayCount = 0;
for (let i = this.chartDates.length - 1; i >= 0; i -= 1) {
const date = this.chartDates[i];
if (date > rangeEndDateString) {
continue;
} else if (date < rangeStartDateString) {
break;
}
if (
investmentValuesAccumulatedWithCurrencyEffect[date] instanceof Big &&
investmentValuesAccumulatedWithCurrencyEffect[date].gt(0)
) {
average = average.add(
investmentValuesAccumulatedWithCurrencyEffect[date].add(
grossPerformanceAtDateRangeStartWithCurrencyEffect
)
);
dayCount++;
}
}
if (dayCount > 0) {
average = average.div(dayCount);
}
netPerformanceWithCurrencyEffectMap[dateRange] =
netPerformanceValuesWithCurrencyEffect[rangeEndDateString]?.minus(
// If the date range is 'max', take 0 as a start value. Otherwise,
// the value of the end of the day of the start date is taken which
// differs from the buying price.
dateRange === 'max'
? new Big(0)
: (netPerformanceValuesWithCurrencyEffect[rangeStartDateString] ??
new Big(0))
) ?? new Big(0);
netPerformancePercentageWithCurrencyEffectMap[dateRange] = average.gt(0)
? netPerformanceWithCurrencyEffectMap[dateRange].div(average)
: new Big(0);
}
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log(
`
${symbol}
Unit price: ${orders[indexOfStartOrder].unitPrice.toFixed(
2
)} -> ${unitPriceAtEndDate.toFixed(2)}
Total investment: ${totalInvestment.toFixed(2)}
Total investment with currency effect: ${totalInvestmentWithCurrencyEffect.toFixed(
2
)}
Time weighted investment: ${timeWeightedAverageInvestmentBetweenStartAndEndDate.toFixed(
2
)}
Time weighted investment with currency effect: ${timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.toFixed(
2
)}
Total dividend: ${totalDividend.toFixed(2)}
Gross performance: ${totalGrossPerformance.toFixed(
2
)} / ${grossPerformancePercentage.mul(100).toFixed(2)}%
Gross performance with currency effect: ${totalGrossPerformanceWithCurrencyEffect.toFixed(
2
)} / ${grossPerformancePercentageWithCurrencyEffect
.mul(100)
.toFixed(2)}%
Fees per unit: ${feesPerUnit.toFixed(2)}
Fees per unit with currency effect: ${feesPerUnitWithCurrencyEffect.toFixed(
2
)}
Net performance: ${totalNetPerformance.toFixed(
2
)} / ${netPerformancePercentage.mul(100).toFixed(2)}%
Net performance with currency effect: ${netPerformancePercentageWithCurrencyEffectMap[
'max'
].toFixed(2)}%`
);
}
return {
currentValues,
currentValuesWithCurrencyEffect,
feesWithCurrencyEffect,
grossPerformancePercentage,
grossPerformancePercentageWithCurrencyEffect,
initialValue,
initialValueWithCurrencyEffect,
investmentValuesAccumulated,
investmentValuesAccumulatedWithCurrencyEffect,
investmentValuesWithCurrencyEffect,
netPerformancePercentage,
netPerformancePercentageWithCurrencyEffectMap,
netPerformanceValues,
netPerformanceValuesWithCurrencyEffect,
netPerformanceWithCurrencyEffectMap,
timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect,
totalAccountBalanceInBaseCurrency,
totalDividend,
totalDividendInBaseCurrency,
totalInterest,
totalInterestInBaseCurrency,
totalInvestment,
totalInvestmentWithCurrencyEffect,
totalLiabilities,
totalLiabilitiesInBaseCurrency,
totalValuables,
totalValuablesInBaseCurrency,
grossPerformance: totalGrossPerformance,
grossPerformanceWithCurrencyEffect:
totalGrossPerformanceWithCurrencyEffect,
hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate),
netPerformance: totalNetPerformance,
timeWeightedInvestment:
timeWeightedAverageInvestmentBetweenStartAndEndDate,
timeWeightedInvestmentWithCurrencyEffect:
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
};
}
}

959
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts

@ -1,969 +1,24 @@
import { PortfolioCalculator } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator';
import { PortfolioOrderItem } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order-item.interface';
import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,
SymbolMetrics
} from '@ghostfolio/common/interfaces';
import { PortfolioSnapshot, TimelinePosition } from '@ghostfolio/common/models';
import { DateRange } from '@ghostfolio/common/types';
import { PortfolioSnapshot } from '@ghostfolio/common/models';
import { Logger } from '@nestjs/common';
import { Big } from 'big.js';
import { addMilliseconds, differenceInDays, format, isBefore } from 'date-fns';
import { cloneDeep, sortBy } from 'lodash';
export class TWRPortfolioCalculator extends PortfolioCalculator {
private chartDates: string[];
protected calculateOverallPerformance(
positions: TimelinePosition[]
): PortfolioSnapshot {
let currentValueInBaseCurrency = new Big(0);
let grossPerformance = new Big(0);
let grossPerformanceWithCurrencyEffect = new Big(0);
let hasErrors = false;
let netPerformance = new Big(0);
let totalFeesWithCurrencyEffect = new Big(0);
const totalInterestWithCurrencyEffect = new Big(0);
let totalInvestment = new Big(0);
let totalInvestmentWithCurrencyEffect = new Big(0);
let totalTimeWeightedInvestment = new Big(0);
let totalTimeWeightedInvestmentWithCurrencyEffect = new Big(0);
for (const currentPosition of positions) {
if (currentPosition.feeInBaseCurrency) {
totalFeesWithCurrencyEffect = totalFeesWithCurrencyEffect.plus(
currentPosition.feeInBaseCurrency
);
}
if (currentPosition.valueInBaseCurrency) {
currentValueInBaseCurrency = currentValueInBaseCurrency.plus(
currentPosition.valueInBaseCurrency
);
} else {
hasErrors = true;
}
if (currentPosition.investment) {
totalInvestment = totalInvestment.plus(currentPosition.investment);
totalInvestmentWithCurrencyEffect =
totalInvestmentWithCurrencyEffect.plus(
currentPosition.investmentWithCurrencyEffect
);
} else {
hasErrors = true;
}
if (currentPosition.grossPerformance) {
grossPerformance = grossPerformance.plus(
currentPosition.grossPerformance
);
grossPerformanceWithCurrencyEffect =
grossPerformanceWithCurrencyEffect.plus(
currentPosition.grossPerformanceWithCurrencyEffect
);
netPerformance = netPerformance.plus(currentPosition.netPerformance);
} else if (!currentPosition.quantity.eq(0)) {
hasErrors = true;
}
if (currentPosition.timeWeightedInvestment) {
totalTimeWeightedInvestment = totalTimeWeightedInvestment.plus(
currentPosition.timeWeightedInvestment
);
totalTimeWeightedInvestmentWithCurrencyEffect =
totalTimeWeightedInvestmentWithCurrencyEffect.plus(
currentPosition.timeWeightedInvestmentWithCurrencyEffect
);
} else if (!currentPosition.quantity.eq(0)) {
Logger.warn(
`Missing historical market data for ${currentPosition.symbol} (${currentPosition.dataSource})`,
'PortfolioCalculator'
);
hasErrors = true;
}
}
return {
currentValueInBaseCurrency,
hasErrors,
positions,
totalFeesWithCurrencyEffect,
totalInterestWithCurrencyEffect,
totalInvestment,
totalInvestmentWithCurrencyEffect,
activitiesCount: this.activities.filter(({ type }) => {
return ['BUY', 'SELL'].includes(type);
}).length,
createdAt: new Date(),
errors: [],
historicalData: [],
totalLiabilitiesWithCurrencyEffect: new Big(0),
totalValuablesWithCurrencyEffect: new Big(0)
};
export class TwrPortfolioCalculator extends PortfolioCalculator {
protected calculateOverallPerformance(): PortfolioSnapshot {
throw new Error('Method not implemented.');
}
protected getSymbolMetrics({
chartDateMap,
dataSource,
end,
exchangeRates,
marketSymbolMap,
start,
symbol
}: {
chartDateMap?: { [date: string]: boolean };
protected getSymbolMetrics({}: {
end: Date;
exchangeRates: { [dateString: string]: number };
marketSymbolMap: {
[date: string]: { [symbol: string]: Big };
};
start: Date;
step?: number;
} & AssetProfileIdentifier): SymbolMetrics {
const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)];
const currentValues: { [date: string]: Big } = {};
const currentValuesWithCurrencyEffect: { [date: string]: Big } = {};
let fees = new Big(0);
let feesAtStartDate = new Big(0);
let feesAtStartDateWithCurrencyEffect = new Big(0);
let feesWithCurrencyEffect = new Big(0);
let grossPerformance = new Big(0);
let grossPerformanceWithCurrencyEffect = new Big(0);
let grossPerformanceAtStartDate = new Big(0);
let grossPerformanceAtStartDateWithCurrencyEffect = new Big(0);
let grossPerformanceFromSells = new Big(0);
let grossPerformanceFromSellsWithCurrencyEffect = new Big(0);
let initialValue: Big;
let initialValueWithCurrencyEffect: Big;
let investmentAtStartDate: Big;
let investmentAtStartDateWithCurrencyEffect: Big;
const investmentValuesAccumulated: { [date: string]: Big } = {};
const investmentValuesAccumulatedWithCurrencyEffect: {
[date: string]: Big;
} = {};
const investmentValuesWithCurrencyEffect: { [date: string]: Big } = {};
let lastAveragePrice = new Big(0);
let lastAveragePriceWithCurrencyEffect = new Big(0);
const netPerformanceValues: { [date: string]: Big } = {};
const netPerformanceValuesWithCurrencyEffect: { [date: string]: Big } = {};
const timeWeightedInvestmentValues: { [date: string]: Big } = {};
const timeWeightedInvestmentValuesWithCurrencyEffect: {
[date: string]: Big;
} = {};
const totalAccountBalanceInBaseCurrency = new Big(0);
let totalDividend = new Big(0);
let totalDividendInBaseCurrency = new Big(0);
let totalInterest = new Big(0);
let totalInterestInBaseCurrency = new Big(0);
let totalInvestment = new Big(0);
let totalInvestmentFromBuyTransactions = new Big(0);
let totalInvestmentFromBuyTransactionsWithCurrencyEffect = new Big(0);
let totalInvestmentWithCurrencyEffect = new Big(0);
let totalLiabilities = new Big(0);
let totalLiabilitiesInBaseCurrency = new Big(0);
let totalQuantityFromBuyTransactions = new Big(0);
let totalUnits = new Big(0);
let totalValuables = new Big(0);
let totalValuablesInBaseCurrency = new Big(0);
let valueAtStartDate: Big;
let valueAtStartDateWithCurrencyEffect: Big;
// Clone orders to keep the original values in this.orders
let orders: PortfolioOrderItem[] = cloneDeep(
this.activities.filter(({ SymbolProfile }) => {
return SymbolProfile.symbol === symbol;
})
);
if (orders.length <= 0) {
return {
currentValues: {},
currentValuesWithCurrencyEffect: {},
feesWithCurrencyEffect: new Big(0),
grossPerformance: new Big(0),
grossPerformancePercentage: new Big(0),
grossPerformancePercentageWithCurrencyEffect: new Big(0),
grossPerformanceWithCurrencyEffect: new Big(0),
hasErrors: false,
initialValue: new Big(0),
initialValueWithCurrencyEffect: new Big(0),
investmentValuesAccumulated: {},
investmentValuesAccumulatedWithCurrencyEffect: {},
investmentValuesWithCurrencyEffect: {},
netPerformance: new Big(0),
netPerformancePercentage: new Big(0),
netPerformancePercentageWithCurrencyEffectMap: {},
netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {},
netPerformanceWithCurrencyEffectMap: {},
timeWeightedInvestment: new Big(0),
timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalAccountBalanceInBaseCurrency: new Big(0),
totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0),
totalInterest: new Big(0),
totalInterestInBaseCurrency: new Big(0),
totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilities: new Big(0),
totalLiabilitiesInBaseCurrency: new Big(0),
totalValuables: new Big(0),
totalValuablesInBaseCurrency: new Big(0)
};
}
const dateOfFirstTransaction = new Date(orders[0].date);
const endDateString = format(end, DATE_FORMAT);
const startDateString = format(start, DATE_FORMAT);
const unitPriceAtStartDate = marketSymbolMap[startDateString]?.[symbol];
const unitPriceAtEndDate = marketSymbolMap[endDateString]?.[symbol];
if (
!unitPriceAtEndDate ||
(!unitPriceAtStartDate && isBefore(dateOfFirstTransaction, start))
) {
return {
currentValues: {},
currentValuesWithCurrencyEffect: {},
feesWithCurrencyEffect: new Big(0),
grossPerformance: new Big(0),
grossPerformancePercentage: new Big(0),
grossPerformancePercentageWithCurrencyEffect: new Big(0),
grossPerformanceWithCurrencyEffect: new Big(0),
hasErrors: true,
initialValue: new Big(0),
initialValueWithCurrencyEffect: new Big(0),
investmentValuesAccumulated: {},
investmentValuesAccumulatedWithCurrencyEffect: {},
investmentValuesWithCurrencyEffect: {},
netPerformance: new Big(0),
netPerformancePercentage: new Big(0),
netPerformancePercentageWithCurrencyEffectMap: {},
netPerformanceWithCurrencyEffectMap: {},
netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {},
timeWeightedInvestment: new Big(0),
timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalAccountBalanceInBaseCurrency: new Big(0),
totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0),
totalInterest: new Big(0),
totalInterestInBaseCurrency: new Big(0),
totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilities: new Big(0),
totalLiabilitiesInBaseCurrency: new Big(0),
totalValuables: new Big(0),
totalValuablesInBaseCurrency: new Big(0)
};
}
// Add a synthetic order at the start and the end date
orders.push({
date: startDateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
itemType: 'start',
quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol
},
type: 'BUY',
unitPrice: unitPriceAtStartDate
});
orders.push({
date: endDateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
itemType: 'end',
SymbolProfile: {
dataSource,
symbol
},
quantity: new Big(0),
type: 'BUY',
unitPrice: unitPriceAtEndDate
});
let lastUnitPrice: Big;
const ordersByDate: { [date: string]: PortfolioOrderItem[] } = {};
for (const order of orders) {
ordersByDate[order.date] = ordersByDate[order.date] ?? [];
ordersByDate[order.date].push(order);
}
if (!this.chartDates) {
this.chartDates = Object.keys(chartDateMap).sort();
}
for (const dateString of this.chartDates) {
if (dateString < startDateString) {
continue;
} else if (dateString > endDateString) {
break;
}
if (ordersByDate[dateString]?.length > 0) {
for (const order of ordersByDate[dateString]) {
order.unitPriceFromMarketData =
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice;
}
} else {
orders.push({
date: dateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol
},
type: 'BUY',
unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice,
unitPriceFromMarketData:
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice
});
}
const lastOrder = orders.at(-1);
lastUnitPrice = lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice;
}
// Sort orders so that the start and end placeholder order are at the correct
// position
orders = sortBy(orders, ({ date, itemType }) => {
let sortIndex = new Date(date);
if (itemType === 'end') {
sortIndex = addMilliseconds(sortIndex, 1);
} else if (itemType === 'start') {
sortIndex = addMilliseconds(sortIndex, -1);
}
return sortIndex.getTime();
});
const indexOfStartOrder = orders.findIndex(({ itemType }) => {
return itemType === 'start';
});
const indexOfEndOrder = orders.findIndex(({ itemType }) => {
return itemType === 'end';
});
let totalInvestmentDays = 0;
let sumOfTimeWeightedInvestments = new Big(0);
let sumOfTimeWeightedInvestmentsWithCurrencyEffect = new Big(0);
for (let i = 0; i < orders.length; i += 1) {
const order = orders[i];
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log();
console.log();
console.log(
i + 1,
order.date,
order.type,
order.itemType ? `(${order.itemType})` : ''
);
}
const exchangeRateAtOrderDate = exchangeRates[order.date];
if (order.type === 'DIVIDEND') {
const dividend = order.quantity.mul(order.unitPrice);
totalDividend = totalDividend.plus(dividend);
totalDividendInBaseCurrency = totalDividendInBaseCurrency.plus(
dividend.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'INTEREST') {
const interest = order.quantity.mul(order.unitPrice);
totalInterest = totalInterest.plus(interest);
totalInterestInBaseCurrency = totalInterestInBaseCurrency.plus(
interest.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'ITEM') {
const valuables = order.quantity.mul(order.unitPrice);
totalValuables = totalValuables.plus(valuables);
totalValuablesInBaseCurrency = totalValuablesInBaseCurrency.plus(
valuables.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'LIABILITY') {
const liabilities = order.quantity.mul(order.unitPrice);
totalLiabilities = totalLiabilities.plus(liabilities);
totalLiabilitiesInBaseCurrency = totalLiabilitiesInBaseCurrency.plus(
liabilities.mul(exchangeRateAtOrderDate ?? 1)
);
}
if (order.itemType === 'start') {
// Take the unit price of the order as the market price if there are no
// orders of this symbol before the start date
order.unitPrice =
indexOfStartOrder === 0
? orders[i + 1]?.unitPrice
: unitPriceAtStartDate;
}
if (order.fee) {
order.feeInBaseCurrency = order.fee.mul(currentExchangeRate ?? 1);
order.feeInBaseCurrencyWithCurrencyEffect = order.fee.mul(
exchangeRateAtOrderDate ?? 1
);
}
const unitPrice = ['BUY', 'SELL'].includes(order.type)
? order.unitPrice
: order.unitPriceFromMarketData;
if (unitPrice) {
order.unitPriceInBaseCurrency = unitPrice.mul(currentExchangeRate ?? 1);
order.unitPriceInBaseCurrencyWithCurrencyEffect = unitPrice.mul(
exchangeRateAtOrderDate ?? 1
);
}
const valueOfInvestmentBeforeTransaction = totalUnits.mul(
order.unitPriceInBaseCurrency
);
const valueOfInvestmentBeforeTransactionWithCurrencyEffect =
totalUnits.mul(order.unitPriceInBaseCurrencyWithCurrencyEffect);
if (!investmentAtStartDate && i >= indexOfStartOrder) {
investmentAtStartDate = totalInvestment ?? new Big(0);
investmentAtStartDateWithCurrencyEffect =
totalInvestmentWithCurrencyEffect ?? new Big(0);
valueAtStartDate = valueOfInvestmentBeforeTransaction;
valueAtStartDateWithCurrencyEffect =
valueOfInvestmentBeforeTransactionWithCurrencyEffect;
}
let transactionInvestment = new Big(0);
let transactionInvestmentWithCurrencyEffect = new Big(0);
if (order.type === 'BUY') {
transactionInvestment = order.quantity
.mul(order.unitPriceInBaseCurrency)
.mul(getFactor(order.type));
transactionInvestmentWithCurrencyEffect = order.quantity
.mul(order.unitPriceInBaseCurrencyWithCurrencyEffect)
.mul(getFactor(order.type));
totalQuantityFromBuyTransactions =
totalQuantityFromBuyTransactions.plus(order.quantity);
totalInvestmentFromBuyTransactions =
totalInvestmentFromBuyTransactions.plus(transactionInvestment);
totalInvestmentFromBuyTransactionsWithCurrencyEffect =
totalInvestmentFromBuyTransactionsWithCurrencyEffect.plus(
transactionInvestmentWithCurrencyEffect
);
} else if (order.type === 'SELL') {
if (totalUnits.gt(0)) {
transactionInvestment = totalInvestment
.div(totalUnits)
.mul(order.quantity)
.mul(getFactor(order.type));
transactionInvestmentWithCurrencyEffect =
totalInvestmentWithCurrencyEffect
.div(totalUnits)
.mul(order.quantity)
.mul(getFactor(order.type));
}
}
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log('order.quantity', order.quantity.toNumber());
console.log('transactionInvestment', transactionInvestment.toNumber());
console.log(
'transactionInvestmentWithCurrencyEffect',
transactionInvestmentWithCurrencyEffect.toNumber()
);
}
const totalInvestmentBeforeTransaction = totalInvestment;
const totalInvestmentBeforeTransactionWithCurrencyEffect =
totalInvestmentWithCurrencyEffect;
totalInvestment = totalInvestment.plus(transactionInvestment);
totalInvestmentWithCurrencyEffect =
totalInvestmentWithCurrencyEffect.plus(
transactionInvestmentWithCurrencyEffect
);
if (i >= indexOfStartOrder && !initialValue) {
if (
i === indexOfStartOrder &&
!valueOfInvestmentBeforeTransaction.eq(0)
) {
initialValue = valueOfInvestmentBeforeTransaction;
initialValueWithCurrencyEffect =
valueOfInvestmentBeforeTransactionWithCurrencyEffect;
} else if (transactionInvestment.gt(0)) {
initialValue = transactionInvestment;
initialValueWithCurrencyEffect =
transactionInvestmentWithCurrencyEffect;
}
}
fees = fees.plus(order.feeInBaseCurrency ?? 0);
feesWithCurrencyEffect = feesWithCurrencyEffect.plus(
order.feeInBaseCurrencyWithCurrencyEffect ?? 0
);
totalUnits = totalUnits.plus(order.quantity.mul(getFactor(order.type)));
const valueOfInvestment = totalUnits.mul(order.unitPriceInBaseCurrency);
const valueOfInvestmentWithCurrencyEffect = totalUnits.mul(
order.unitPriceInBaseCurrencyWithCurrencyEffect
);
const grossPerformanceFromSell =
order.type === 'SELL'
? order.unitPriceInBaseCurrency
.minus(lastAveragePrice)
.mul(order.quantity)
: new Big(0);
const grossPerformanceFromSellWithCurrencyEffect =
order.type === 'SELL'
? order.unitPriceInBaseCurrencyWithCurrencyEffect
.minus(lastAveragePriceWithCurrencyEffect)
.mul(order.quantity)
: new Big(0);
grossPerformanceFromSells = grossPerformanceFromSells.plus(
grossPerformanceFromSell
);
grossPerformanceFromSellsWithCurrencyEffect =
grossPerformanceFromSellsWithCurrencyEffect.plus(
grossPerformanceFromSellWithCurrencyEffect
);
lastAveragePrice = totalQuantityFromBuyTransactions.eq(0)
? new Big(0)
: totalInvestmentFromBuyTransactions.div(
totalQuantityFromBuyTransactions
);
lastAveragePriceWithCurrencyEffect = totalQuantityFromBuyTransactions.eq(
0
)
? new Big(0)
: totalInvestmentFromBuyTransactionsWithCurrencyEffect.div(
totalQuantityFromBuyTransactions
);
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log(
'grossPerformanceFromSells',
grossPerformanceFromSells.toNumber()
);
console.log(
'grossPerformanceFromSellWithCurrencyEffect',
grossPerformanceFromSellWithCurrencyEffect.toNumber()
);
}
const newGrossPerformance = valueOfInvestment
.minus(totalInvestment)
.plus(grossPerformanceFromSells);
const newGrossPerformanceWithCurrencyEffect =
valueOfInvestmentWithCurrencyEffect
.minus(totalInvestmentWithCurrencyEffect)
.plus(grossPerformanceFromSellsWithCurrencyEffect);
grossPerformance = newGrossPerformance;
grossPerformanceWithCurrencyEffect =
newGrossPerformanceWithCurrencyEffect;
if (order.itemType === 'start') {
feesAtStartDate = fees;
feesAtStartDateWithCurrencyEffect = feesWithCurrencyEffect;
grossPerformanceAtStartDate = grossPerformance;
grossPerformanceAtStartDateWithCurrencyEffect =
grossPerformanceWithCurrencyEffect;
}
if (i > indexOfStartOrder) {
// Only consider periods with an investment for the calculation of
// the time weighted investment
if (
valueOfInvestmentBeforeTransaction.gt(0) &&
['BUY', 'SELL'].includes(order.type)
) {
// Calculate the number of days since the previous order
const orderDate = new Date(order.date);
const previousOrderDate = new Date(orders[i - 1].date);
let daysSinceLastOrder = differenceInDays(
orderDate,
previousOrderDate
);
if (daysSinceLastOrder <= 0) {
// The time between two activities on the same day is unknown
// -> Set it to the smallest floating point number greater than 0
daysSinceLastOrder = Number.EPSILON;
}
// Sum up the total investment days since the start date to calculate
// the time weighted investment
totalInvestmentDays += daysSinceLastOrder;
sumOfTimeWeightedInvestments = sumOfTimeWeightedInvestments.add(
valueAtStartDate
.minus(investmentAtStartDate)
.plus(totalInvestmentBeforeTransaction)
.mul(daysSinceLastOrder)
);
sumOfTimeWeightedInvestmentsWithCurrencyEffect =
sumOfTimeWeightedInvestmentsWithCurrencyEffect.add(
valueAtStartDateWithCurrencyEffect
.minus(investmentAtStartDateWithCurrencyEffect)
.plus(totalInvestmentBeforeTransactionWithCurrencyEffect)
.mul(daysSinceLastOrder)
);
}
currentValues[order.date] = valueOfInvestment;
currentValuesWithCurrencyEffect[order.date] =
valueOfInvestmentWithCurrencyEffect;
netPerformanceValues[order.date] = grossPerformance
.minus(grossPerformanceAtStartDate)
.minus(fees.minus(feesAtStartDate));
netPerformanceValuesWithCurrencyEffect[order.date] =
grossPerformanceWithCurrencyEffect
.minus(grossPerformanceAtStartDateWithCurrencyEffect)
.minus(
feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect)
);
investmentValuesAccumulated[order.date] = totalInvestment;
investmentValuesAccumulatedWithCurrencyEffect[order.date] =
totalInvestmentWithCurrencyEffect;
investmentValuesWithCurrencyEffect[order.date] = (
investmentValuesWithCurrencyEffect[order.date] ?? new Big(0)
).add(transactionInvestmentWithCurrencyEffect);
timeWeightedInvestmentValues[order.date] =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
: new Big(0);
timeWeightedInvestmentValuesWithCurrencyEffect[order.date] =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div(
totalInvestmentDays
)
: new Big(0);
}
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log('totalInvestment', totalInvestment.toNumber());
console.log(
'totalInvestmentWithCurrencyEffect',
totalInvestmentWithCurrencyEffect.toNumber()
);
console.log(
'totalGrossPerformance',
grossPerformance.minus(grossPerformanceAtStartDate).toNumber()
);
console.log(
'totalGrossPerformanceWithCurrencyEffect',
grossPerformanceWithCurrencyEffect
.minus(grossPerformanceAtStartDateWithCurrencyEffect)
.toNumber()
);
}
if (i === indexOfEndOrder) {
break;
}
}
const totalGrossPerformance = grossPerformance.minus(
grossPerformanceAtStartDate
);
const totalGrossPerformanceWithCurrencyEffect =
grossPerformanceWithCurrencyEffect.minus(
grossPerformanceAtStartDateWithCurrencyEffect
);
const totalNetPerformance = grossPerformance
.minus(grossPerformanceAtStartDate)
.minus(fees.minus(feesAtStartDate));
const timeWeightedAverageInvestmentBetweenStartAndEndDate =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
: new Big(0);
const timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect =
totalInvestmentDays > 0
? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div(
totalInvestmentDays
)
: new Big(0);
const grossPerformancePercentage =
timeWeightedAverageInvestmentBetweenStartAndEndDate.gt(0)
? totalGrossPerformance.div(
timeWeightedAverageInvestmentBetweenStartAndEndDate
)
: new Big(0);
const grossPerformancePercentageWithCurrencyEffect =
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.gt(
0
)
? totalGrossPerformanceWithCurrencyEffect.div(
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
)
: new Big(0);
const feesPerUnit = totalUnits.gt(0)
? fees.minus(feesAtStartDate).div(totalUnits)
: new Big(0);
const feesPerUnitWithCurrencyEffect = totalUnits.gt(0)
? feesWithCurrencyEffect
.minus(feesAtStartDateWithCurrencyEffect)
.div(totalUnits)
: new Big(0);
const netPerformancePercentage =
timeWeightedAverageInvestmentBetweenStartAndEndDate.gt(0)
? totalNetPerformance.div(
timeWeightedAverageInvestmentBetweenStartAndEndDate
)
: new Big(0);
const netPerformancePercentageWithCurrencyEffectMap: {
[key: DateRange]: Big;
} = {};
const netPerformanceWithCurrencyEffectMap: {
[key: DateRange]: Big;
} = {};
for (const dateRange of [
'1d',
'1y',
'5y',
'max',
'mtd',
'wtd',
'ytd'
// TODO:
// ...eachYearOfInterval({ end, start })
// .filter((date) => {
// return !isThisYear(date);
// })
// .map((date) => {
// return format(date, 'yyyy');
// })
] as DateRange[]) {
const dateInterval = getIntervalFromDateRange(dateRange);
const endDate = dateInterval.endDate;
let startDate = dateInterval.startDate;
if (isBefore(startDate, start)) {
startDate = start;
}
const rangeEndDateString = format(endDate, DATE_FORMAT);
const rangeStartDateString = format(startDate, DATE_FORMAT);
const currentValuesAtDateRangeStartWithCurrencyEffect =
currentValuesWithCurrencyEffect[rangeStartDateString] ?? new Big(0);
const investmentValuesAccumulatedAtStartDateWithCurrencyEffect =
investmentValuesAccumulatedWithCurrencyEffect[rangeStartDateString] ??
new Big(0);
const grossPerformanceAtDateRangeStartWithCurrencyEffect =
currentValuesAtDateRangeStartWithCurrencyEffect.minus(
investmentValuesAccumulatedAtStartDateWithCurrencyEffect
);
let average = new Big(0);
let dayCount = 0;
for (let i = this.chartDates.length - 1; i >= 0; i -= 1) {
const date = this.chartDates[i];
if (date > rangeEndDateString) {
continue;
} else if (date < rangeStartDateString) {
break;
}
if (
investmentValuesAccumulatedWithCurrencyEffect[date] instanceof Big &&
investmentValuesAccumulatedWithCurrencyEffect[date].gt(0)
) {
average = average.add(
investmentValuesAccumulatedWithCurrencyEffect[date].add(
grossPerformanceAtDateRangeStartWithCurrencyEffect
)
);
dayCount++;
}
}
if (dayCount > 0) {
average = average.div(dayCount);
}
netPerformanceWithCurrencyEffectMap[dateRange] =
netPerformanceValuesWithCurrencyEffect[rangeEndDateString]?.minus(
// If the date range is 'max', take 0 as a start value. Otherwise,
// the value of the end of the day of the start date is taken which
// differs from the buying price.
dateRange === 'max'
? new Big(0)
: (netPerformanceValuesWithCurrencyEffect[rangeStartDateString] ??
new Big(0))
) ?? new Big(0);
netPerformancePercentageWithCurrencyEffectMap[dateRange] = average.gt(0)
? netPerformanceWithCurrencyEffectMap[dateRange].div(average)
: new Big(0);
}
if (PortfolioCalculator.ENABLE_LOGGING) {
console.log(
`
${symbol}
Unit price: ${orders[indexOfStartOrder].unitPrice.toFixed(
2
)} -> ${unitPriceAtEndDate.toFixed(2)}
Total investment: ${totalInvestment.toFixed(2)}
Total investment with currency effect: ${totalInvestmentWithCurrencyEffect.toFixed(
2
)}
Time weighted investment: ${timeWeightedAverageInvestmentBetweenStartAndEndDate.toFixed(
2
)}
Time weighted investment with currency effect: ${timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.toFixed(
2
)}
Total dividend: ${totalDividend.toFixed(2)}
Gross performance: ${totalGrossPerformance.toFixed(
2
)} / ${grossPerformancePercentage.mul(100).toFixed(2)}%
Gross performance with currency effect: ${totalGrossPerformanceWithCurrencyEffect.toFixed(
2
)} / ${grossPerformancePercentageWithCurrencyEffect
.mul(100)
.toFixed(2)}%
Fees per unit: ${feesPerUnit.toFixed(2)}
Fees per unit with currency effect: ${feesPerUnitWithCurrencyEffect.toFixed(
2
)}
Net performance: ${totalNetPerformance.toFixed(
2
)} / ${netPerformancePercentage.mul(100).toFixed(2)}%
Net performance with currency effect: ${netPerformancePercentageWithCurrencyEffectMap[
'max'
].toFixed(2)}%`
);
}
return {
currentValues,
currentValuesWithCurrencyEffect,
feesWithCurrencyEffect,
grossPerformancePercentage,
grossPerformancePercentageWithCurrencyEffect,
initialValue,
initialValueWithCurrencyEffect,
investmentValuesAccumulated,
investmentValuesAccumulatedWithCurrencyEffect,
investmentValuesWithCurrencyEffect,
netPerformancePercentage,
netPerformancePercentageWithCurrencyEffectMap,
netPerformanceValues,
netPerformanceValuesWithCurrencyEffect,
netPerformanceWithCurrencyEffectMap,
timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect,
totalAccountBalanceInBaseCurrency,
totalDividend,
totalDividendInBaseCurrency,
totalInterest,
totalInterestInBaseCurrency,
totalInvestment,
totalInvestmentWithCurrencyEffect,
totalLiabilities,
totalLiabilitiesInBaseCurrency,
totalValuables,
totalValuablesInBaseCurrency,
grossPerformance: totalGrossPerformance,
grossPerformanceWithCurrencyEffect:
totalGrossPerformanceWithCurrencyEffect,
hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate),
netPerformance: totalNetPerformance,
timeWeightedInvestment:
timeWeightedAverageInvestmentBetweenStartAndEndDate,
timeWeightedInvestmentWithCurrencyEffect:
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
};
throw new Error('Method not implemented.');
}
}

96
apps/api/src/app/portfolio/portfolio.service.ts

@ -82,7 +82,7 @@ import {
parseISO,
set
} from 'date-fns';
import { isEmpty, uniq } from 'lodash';
import { isEmpty } from 'lodash';
import { PortfolioCalculator } from './calculator/portfolio-calculator';
import {
@ -295,7 +295,7 @@ export class PortfolioService {
activities,
filters,
userId,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: this.request.user.Settings.settings.baseCurrency
});
@ -372,7 +372,7 @@ export class PortfolioService {
activities,
filters,
userId,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: userCurrency
});
@ -569,7 +569,7 @@ export class PortfolioService {
const emergencyFundInCash = emergencyFund
.minus(
this.getEmergencyFundPositionsValueInBaseCurrency({
this.getEmergencyFundHoldingsValueInBaseCurrency({
holdings
})
)
@ -608,8 +608,8 @@ export class PortfolioService {
userCurrency,
userId,
balanceInBaseCurrency: cashDetails.balanceInBaseCurrency,
emergencyFundPositionsValueInBaseCurrency:
this.getEmergencyFundPositionsValueInBaseCurrency({
emergencyFundHoldingsValueInBaseCurrency:
this.getEmergencyFundHoldingsValueInBaseCurrency({
holdings
})
});
@ -680,7 +680,7 @@ export class PortfolioService {
const portfolioCalculator = this.calculatorFactory.createCalculator({
activities,
userId,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: userCurrency
});
@ -950,7 +950,7 @@ export class PortfolioService {
activities,
filters,
userId,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: this.request.user.Settings.settings.baseCurrency
});
@ -1116,7 +1116,7 @@ export class PortfolioService {
activities,
filters,
userId,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: userCurrency
});
@ -1263,7 +1263,11 @@ export class PortfolioService {
[
new EmergencyFundSetup(
this.exchangeRateDataService,
userSettings.emergencyFund
this.getTotalEmergencyFund({
userSettings,
emergencyFundHoldingsValueInBaseCurrency:
this.getEmergencyFundHoldingsValueInBaseCurrency({ holdings })
}).toNumber()
)
],
userSettings
@ -1585,7 +1589,7 @@ export class PortfolioService {
return dividendsByGroup;
}
private getEmergencyFundPositionsValueInBaseCurrency({
private getEmergencyFundHoldingsValueInBaseCurrency({
holdings
}: {
holdings: PortfolioDetails['holdings'];
@ -1600,14 +1604,14 @@ export class PortfolioService {
);
});
let valueInBaseCurrencyOfEmergencyFundPositions = new Big(0);
let valueInBaseCurrencyOfEmergencyFundHoldings = new Big(0);
for (const { valueInBaseCurrency } of emergencyFundHoldings) {
valueInBaseCurrencyOfEmergencyFundPositions =
valueInBaseCurrencyOfEmergencyFundPositions.plus(valueInBaseCurrency);
valueInBaseCurrencyOfEmergencyFundHoldings =
valueInBaseCurrencyOfEmergencyFundHoldings.plus(valueInBaseCurrency);
}
return valueInBaseCurrencyOfEmergencyFundPositions.toNumber();
return valueInBaseCurrencyOfEmergencyFundHoldings.toNumber();
}
private getInitialCashPosition({
@ -1774,7 +1778,7 @@ export class PortfolioService {
private async getSummary({
balanceInBaseCurrency,
emergencyFundPositionsValueInBaseCurrency,
emergencyFundHoldingsValueInBaseCurrency,
filteredValueInBaseCurrency,
impersonationId,
portfolioCalculator,
@ -1782,7 +1786,7 @@ export class PortfolioService {
userId
}: {
balanceInBaseCurrency: number;
emergencyFundPositionsValueInBaseCurrency: number;
emergencyFundHoldingsValueInBaseCurrency: number;
filteredValueInBaseCurrency: Big;
impersonationId: string;
portfolioCalculator: PortfolioCalculator;
@ -1827,12 +1831,10 @@ export class PortfolioService {
const dividendInBaseCurrency =
await portfolioCalculator.getDividendInBaseCurrency();
const emergencyFund = new Big(
Math.max(
emergencyFundPositionsValueInBaseCurrency,
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
)
);
const totalEmergencyFund = this.getTotalEmergencyFund({
emergencyFundHoldingsValueInBaseCurrency,
userSettings: user.Settings?.settings as UserSettings
});
const fees = await portfolioCalculator.getFeesInBaseCurrency();
@ -1858,8 +1860,8 @@ export class PortfolioService {
}).toNumber();
const cash = new Big(balanceInBaseCurrency)
.minus(emergencyFund)
.plus(emergencyFundPositionsValueInBaseCurrency)
.minus(totalEmergencyFund)
.plus(emergencyFundHoldingsValueInBaseCurrency)
.toNumber();
const committedFunds = new Big(totalBuy).minus(totalSell);
@ -1918,7 +1920,6 @@ export class PortfolioService {
annualizedPerformancePercentWithCurrencyEffect,
cash,
excludedAccountsAndActivities,
firstOrderDate,
netPerformance,
netPerformancePercentage,
netPerformancePercentageWithCurrencyEffect,
@ -1929,11 +1930,11 @@ export class PortfolioService {
currentValueInBaseCurrency: currentValueInBaseCurrency.toNumber(),
dividendInBaseCurrency: dividendInBaseCurrency.toNumber(),
emergencyFund: {
assets: emergencyFundPositionsValueInBaseCurrency,
cash: emergencyFund
.minus(emergencyFundPositionsValueInBaseCurrency)
assets: emergencyFundHoldingsValueInBaseCurrency,
cash: totalEmergencyFund
.minus(emergencyFundHoldingsValueInBaseCurrency)
.toNumber(),
total: emergencyFund.toNumber()
total: totalEmergencyFund.toNumber()
},
fees: fees.toNumber(),
filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(),
@ -1941,7 +1942,7 @@ export class PortfolioService {
? filteredValueInBaseCurrency.div(netWorth).toNumber()
: undefined,
fireWealth: new Big(currentValueInBaseCurrency)
.minus(emergencyFundPositionsValueInBaseCurrency)
.minus(emergencyFundHoldingsValueInBaseCurrency)
.toNumber(),
grossPerformance: new Big(netPerformance).plus(fees).toNumber(),
grossPerformanceWithCurrencyEffect: new Big(
@ -1986,6 +1987,21 @@ export class PortfolioService {
);
}
private getTotalEmergencyFund({
emergencyFundHoldingsValueInBaseCurrency,
userSettings
}: {
emergencyFundHoldingsValueInBaseCurrency: number;
userSettings: UserSettings;
}) {
return new Big(
Math.max(
emergencyFundHoldingsValueInBaseCurrency,
userSettings?.emergencyFund ?? 0
)
);
}
private getUserCurrency(aUser?: UserWithSettings) {
return (
aUser?.Settings?.settings.baseCurrency ??
@ -2032,14 +2048,16 @@ export class PortfolioService {
where: { id: filters[0].id }
});
} else {
const accountIds = uniq(
activities
.filter(({ accountId }) => {
return accountId;
})
.map(({ accountId }) => {
return accountId;
})
const accountIds = Array.from(
new Set(
activities
.filter(({ accountId }) => {
return accountId;
})
.map(({ accountId }) => {
return accountId;
})
)
);
currentAccounts = await this.accountService.accounts({

8
apps/api/src/app/sitemap/sitemap.controller.ts

@ -9,8 +9,8 @@ import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools'
import { Controller, Get, Res, VERSION_NEUTRAL, Version } from '@nestjs/common';
import { format } from 'date-fns';
import { Response } from 'express';
import * as fs from 'fs';
import * as path from 'path';
import { readFileSync } from 'fs';
import { join } from 'path';
@Controller('sitemap.xml')
export class SitemapController {
@ -20,8 +20,8 @@ export class SitemapController {
private readonly configurationService: ConfigurationService
) {
try {
this.sitemapXml = fs.readFileSync(
path.join(__dirname, 'assets', 'sitemap.xml'),
this.sitemapXml = readFileSync(
join(__dirname, 'assets', 'sitemap.xml'),
'utf8'
);
} catch {}

35
apps/api/src/app/user/user.controller.ts

@ -1,8 +1,13 @@
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { User, UserSettings } from '@ghostfolio/common/interfaces';
import {
AccessTokenResponse,
User,
UserSettings
} from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
@ -36,6 +41,7 @@ export class UserController {
public constructor(
private readonly configurationService: ConfigurationService,
private readonly jwtService: JwtService,
private readonly prismaService: PrismaService,
private readonly propertyService: PropertyService,
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly userService: UserService
@ -47,10 +53,10 @@ export class UserController {
public async deleteOwnUser(
@Body() data: DeleteOwnUserDto
): Promise<UserModel> {
const hashedAccessToken = this.userService.createAccessToken(
data.accessToken,
this.configurationService.get('ACCESS_TOKEN_SALT')
);
const hashedAccessToken = this.userService.createAccessToken({
password: data.accessToken,
salt: this.configurationService.get('ACCESS_TOKEN_SALT')
});
const [user] = await this.userService.users({
where: { accessToken: hashedAccessToken, id: this.request.user.id }
@ -85,6 +91,25 @@ export class UserController {
});
}
@HasPermission(permissions.accessAdminControl)
@Post(':id/access-token')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async generateAccessToken(
@Param('id') id: string
): Promise<AccessTokenResponse> {
const { accessToken, hashedAccessToken } =
this.userService.generateAccessToken({
userId: id
});
await this.prismaService.user.update({
data: { accessToken: hashedAccessToken },
where: { id }
});
return { accessToken };
}
@Get()
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getUser(

35
apps/api/src/app/user/user.service.ts

@ -67,13 +67,33 @@ export class UserService {
return this.prismaService.user.count(args);
}
public createAccessToken(password: string, salt: string): string {
public createAccessToken({
password,
salt
}: {
password: string;
salt: string;
}): string {
const hash = createHmac('sha512', salt);
hash.update(password);
return hash.digest('hex');
}
public generateAccessToken({ userId }: { userId: string }) {
const accessToken = this.createAccessToken({
password: userId,
salt: getRandomString(10)
});
const hashedAccessToken = this.createAccessToken({
password: accessToken,
salt: this.configurationService.get('ACCESS_TOKEN_SALT')
});
return { accessToken, hashedAccessToken };
}
public async getUser(
{ Account, id, permissions, Settings, subscription }: UserWithSettings,
aLocale = locale
@ -433,7 +453,7 @@ export class UserService {
data.provider = 'ANONYMOUS';
}
let user = await this.prismaService.user.create({
const user = await this.prismaService.user.create({
data: {
...data,
Account: {
@ -464,14 +484,11 @@ export class UserService {
}
if (data.provider === 'ANONYMOUS') {
const accessToken = this.createAccessToken(user.id, getRandomString(10));
const hashedAccessToken = this.createAccessToken(
accessToken,
this.configurationService.get('ACCESS_TOKEN_SALT')
);
const { accessToken, hashedAccessToken } = this.generateAccessToken({
userId: user.id
});
user = await this.prismaService.user.update({
await this.prismaService.user.update({
data: { accessToken: hashedAccessToken },
where: { id: user.id }
});

684
apps/api/src/assets/cryptocurrencies/cryptocurrencies.json

File diff suppressed because it is too large

4
apps/client/src/assets/site.webmanifest → apps/api/src/assets/site.webmanifest

@ -25,7 +25,7 @@
"name": "Ghostfolio",
"orientation": "portrait",
"short_name": "Ghostfolio",
"start_url": "/en/",
"start_url": "/${languageCode}/",
"theme_color": "#FFFFFF",
"url": "https://ghostfol.io"
"url": "${rootUrl}"
}

4
apps/api/src/assets/sitemap.xml

@ -92,6 +92,10 @@
<loc>https://ghostfol.io/de/ueber-uns/oss-friends</loc>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/development/storybook</loc>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en</loc>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>

3
apps/api/src/environments/environment.prod.ts

@ -1,4 +1,7 @@
import { DEFAULT_HOST, DEFAULT_PORT } from '@ghostfolio/common/config';
export const environment = {
production: true,
rootUrl: `http://${DEFAULT_HOST}:${DEFAULT_PORT}`,
version: `${require('../../../../package.json').version}`
};

3
apps/api/src/environments/environment.ts

@ -1,4 +1,7 @@
import { DEFAULT_HOST } from '@ghostfolio/common/config';
export const environment = {
production: false,
rootUrl: `https://${DEFAULT_HOST}:4200`,
version: 'dev'
};

2
apps/api/src/helper/object.helper.spec.ts

@ -1519,7 +1519,6 @@ describe('redactAttributes', () => {
annualizedPerformancePercentWithCurrencyEffect: 0.1694019484552876,
cash: null,
excludedAccountsAndActivities: null,
firstOrderDate: '2017-01-02T23:00:00.000Z',
netPerformance: null,
netPerformancePercentage: 2.3039314216696174,
netPerformancePercentageWithCurrencyEffect: 2.3589806001456606,
@ -3023,7 +3022,6 @@ describe('redactAttributes', () => {
annualizedPerformancePercentWithCurrencyEffect: 0.1694019484552876,
cash: null,
excludedAccountsAndActivities: null,
firstOrderDate: '2017-01-02T23:00:00.000Z',
netPerformance: null,
netPerformancePercentage: 2.3039314216696174,
netPerformancePercentageWithCurrencyEffect: 2.3589806001456606,

2
apps/api/src/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor.ts

@ -26,7 +26,7 @@ export class TransformDataSourceInRequestInterceptor<T>
const request = http.getRequest();
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
if (request.body.activities) {
if (request.body?.activities) {
request.body.activities = request.body.activities.map((activity) => {
if (DataSource[activity.dataSource]) {
return activity;

43
apps/api/src/main.ts

@ -1,3 +1,9 @@
import {
DEFAULT_HOST,
DEFAULT_PORT,
STORYBOOK_PATH
} from '@ghostfolio/common/config';
import {
Logger,
LogLevel,
@ -7,6 +13,7 @@ import {
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import type { NestExpressApplication } from '@nestjs/platform-express';
import { NextFunction, Request, Response } from 'express';
import helmet from 'helmet';
import { AppModule } from './app/app.module';
@ -50,26 +57,30 @@ async function bootstrap() {
app.useBodyParser('json', { limit: '10mb' });
if (configService.get<string>('ENABLE_FEATURE_SUBSCRIPTION') === 'true') {
app.use(
helmet({
contentSecurityPolicy: {
directives: {
connectSrc: ["'self'", 'https://js.stripe.com'], // Allow connections to Stripe
frameSrc: ["'self'", 'https://js.stripe.com'], // Allow loading frames from Stripe
scriptSrc: ["'self'", "'unsafe-inline'", 'https://js.stripe.com'], // Allow inline scripts and scripts from Stripe
scriptSrcAttr: ["'self'", "'unsafe-inline'"], // Allow inline event handlers
styleSrc: ["'self'", "'unsafe-inline'"] // Allow inline styles
}
},
crossOriginOpenerPolicy: false // Disable Cross-Origin-Opener-Policy header (for Internet Identity)
})
);
app.use((req: Request, res: Response, next: NextFunction) => {
if (req.path.startsWith(STORYBOOK_PATH)) {
next();
} else {
helmet({
contentSecurityPolicy: {
directives: {
connectSrc: ["'self'", 'https://js.stripe.com'], // Allow connections to Stripe
frameSrc: ["'self'", 'https://js.stripe.com'], // Allow loading frames from Stripe
scriptSrc: ["'self'", "'unsafe-inline'", 'https://js.stripe.com'], // Allow inline scripts and scripts from Stripe
scriptSrcAttr: ["'self'", "'unsafe-inline'"], // Allow inline event handlers
styleSrc: ["'self'", "'unsafe-inline'"] // Allow inline styles
}
},
crossOriginOpenerPolicy: false // Disable Cross-Origin-Opener-Policy header (for Internet Identity)
})(req, res, next);
}
});
}
app.use(HtmlTemplateMiddleware);
const HOST = configService.get<string>('HOST') || '0.0.0.0';
const PORT = configService.get<number>('PORT') || 3333;
const HOST = configService.get<string>('HOST') || DEFAULT_HOST;
const PORT = configService.get<number>('PORT') || DEFAULT_PORT;
await app.listen(PORT, HOST, () => {
logLogo();

6
apps/api/src/middlewares/html-template.middleware.ts

@ -2,7 +2,7 @@ import { environment } from '@ghostfolio/api/environments/environment';
import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service';
import {
DEFAULT_LANGUAGE_CODE,
DEFAULT_ROOT_URL,
STORYBOOK_PATH,
SUPPORTED_LANGUAGE_CODES
} from '@ghostfolio/common/config';
import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper';
@ -125,11 +125,11 @@ export const HtmlTemplateMiddleware = async (
}
const currentDate = format(new Date(), DATE_FORMAT);
const rootUrl = process.env.ROOT_URL || DEFAULT_ROOT_URL;
const rootUrl = process.env.ROOT_URL || environment.rootUrl;
if (
path.startsWith('/api/') ||
path.startsWith('/development/storybook') ||
path.startsWith(STORYBOOK_PATH) ||
isFileRequest(path) ||
!environment.production
) {

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

@ -1,11 +1,13 @@
import { environment } from '@ghostfolio/api/environments/environment';
import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface';
import {
CACHE_TTL_NO_CACHE,
DEFAULT_HOST,
DEFAULT_PORT,
DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY,
DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY,
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY,
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT,
DEFAULT_ROOT_URL
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT
} from '@ghostfolio/common/config';
import { Injectable } from '@nestjs/common';
@ -38,6 +40,9 @@ export class ConfigurationService {
DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER: json({
default: []
}),
DATA_SOURCES_LEGACY: json({
default: []
}),
ENABLE_FEATURE_FEAR_AND_GREED_INDEX: bool({ default: false }),
ENABLE_FEATURE_READ_ONLY_MODE: bool({ default: false }),
ENABLE_FEATURE_SOCIAL_LOGIN: bool({ default: false }),
@ -49,11 +54,11 @@ export class ConfigurationService {
GOOGLE_SHEETS_ACCOUNT: str({ default: '' }),
GOOGLE_SHEETS_ID: str({ default: '' }),
GOOGLE_SHEETS_PRIVATE_KEY: str({ default: '' }),
HOST: host({ default: '0.0.0.0' }),
HOST: host({ default: DEFAULT_HOST }),
JWT_SECRET_KEY: str({}),
MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }),
MAX_CHART_ITEMS: num({ default: 365 }),
PORT: port({ default: 3333 }),
PORT: port({ default: DEFAULT_PORT }),
PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY: num({
default: DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY
}),
@ -71,7 +76,9 @@ export class ConfigurationService {
REDIS_PASSWORD: str({ default: '' }),
REDIS_PORT: port({ default: 6379 }),
REQUEST_TIMEOUT: num({ default: ms('3 seconds') }),
ROOT_URL: url({ default: DEFAULT_ROOT_URL }),
ROOT_URL: url({
default: environment.rootUrl
}),
STRIPE_PUBLIC_KEY: str({ default: '' }),
STRIPE_SECRET_KEY: str({ default: '' }),
TWITTER_ACCESS_TOKEN: str({ default: 'dummyAccessToken' }),

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

@ -57,7 +57,7 @@ export class CronService {
public async runEverySundayAtTwelvePm() {
if (await this.isDataGatheringEnabled()) {
const assetProfileIdentifiers =
await this.dataGatheringService.getAllAssetProfileIdentifiers();
await this.dataGatheringService.getAllActiveAssetProfileIdentifiers();
await this.dataGatheringService.addJobsToQueue(
assetProfileIdentifiers.map(({ dataSource, symbol }) => {

2
apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts

@ -170,6 +170,8 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface {
symbol = quotes[0].symbol;
}
} catch {}
} else if (symbol?.endsWith(`-${DEFAULT_CURRENCY}`)) {
throw new Error(`${symbol} is not valid`);
} else {
symbol = this.convertToYahooFinanceSymbol(symbol);
}

21
apps/api/src/services/data-provider/data-provider.service.ts

@ -30,7 +30,7 @@ import type { Granularity, UserWithSettings } from '@ghostfolio/common/types';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { DataSource, MarketData, SymbolProfile } from '@prisma/client';
import { Big } from 'big.js';
import { eachDayOfInterval, format, isValid } from 'date-fns';
import { eachDayOfInterval, format, isBefore, isValid } from 'date-fns';
import { groupBy, isEmpty, isNumber, uniqWith } from 'lodash';
import ms from 'ms';
@ -154,9 +154,22 @@ export class DataProviderService {
return DataSource[this.configurationService.get('DATA_SOURCE_IMPORT')];
}
public async getDataSources(): Promise<DataSource[]> {
public async getDataSources({
user
}: {
user: UserWithSettings;
}): Promise<DataSource[]> {
let dataSourcesKey: 'DATA_SOURCES' | 'DATA_SOURCES_LEGACY' = 'DATA_SOURCES';
if (
isBefore(user.createdAt, new Date('2025-03-23')) &&
this.configurationService.get('DATA_SOURCES_LEGACY')?.length > 0
) {
dataSourcesKey = 'DATA_SOURCES_LEGACY';
}
const dataSources: DataSource[] = this.configurationService
.get('DATA_SOURCES')
.get(dataSourcesKey)
.map((dataSource) => {
return DataSource[dataSource];
});
@ -608,7 +621,7 @@ export class DataProviderService {
return { items: lookupItems };
}
const dataSources = await this.getDataSources();
const dataSources = await this.getDataSources({ user });
const dataProviderServices = dataSources.map((dataSource) => {
return this.getDataProvider(DataSource[dataSource]);

21
apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts

@ -12,6 +12,7 @@ import {
IDataProviderHistoricalResponse,
IDataProviderResponse
} from '@ghostfolio/api/services/interfaces/interfaces';
import { REPLACE_NAME_PARTS } from '@ghostfolio/common/config';
import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper';
import {
DataProviderInfo,
@ -186,7 +187,7 @@ export class FinancialModelingPrepService implements DataProviderInterface {
response.isin = assetProfile.isin;
}
response.name = assetProfile.companyName;
response.name = this.formatName({ name: assetProfile.companyName });
if (assetProfile.website) {
response.url = assetProfile.website;
@ -398,7 +399,7 @@ export class FinancialModelingPrepService implements DataProviderInterface {
assetSubClass: undefined, // TODO
dataProviderInfo: this.getDataProviderInfo(),
dataSource: this.getName(),
name: companyName
name: this.formatName({ name: companyName })
};
});
} else {
@ -414,12 +415,12 @@ export class FinancialModelingPrepService implements DataProviderInterface {
items = result.map(({ currency, name, symbol }) => {
return {
currency,
name,
symbol,
assetClass: undefined, // TODO
assetSubClass: undefined, // TODO
dataProviderInfo: this.getDataProviderInfo(),
dataSource: this.getName()
dataSource: this.getName(),
name: this.formatName({ name })
};
});
}
@ -438,6 +439,18 @@ export class FinancialModelingPrepService implements DataProviderInterface {
return { items };
}
private formatName({ name }: { name: string }) {
if (name) {
for (const part of REPLACE_NAME_PARTS) {
name = name.replace(part, '');
}
name = name.trim();
}
return name;
}
private getUrl({ version }: { version: number }) {
return `https://financialmodelingprep.com/api/v${version}`;
}

4
apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts

@ -23,7 +23,7 @@ import {
isToday,
subDays
} from 'date-fns';
import { isNumber, uniq } from 'lodash';
import { isNumber } from 'lodash';
import ms from 'ms';
@Injectable()
@ -515,7 +515,7 @@ export class ExchangeRateDataService {
}
}
return uniq(currencies).filter(Boolean).sort();
return Array.from(new Set(currencies)).filter(Boolean).sort();
}
private prepareCurrencyPairs(aCurrencies: string[]) {

1
apps/api/src/services/interfaces/environment.interface.ts

@ -16,6 +16,7 @@ export interface Environment extends CleanedEnvAccessors {
DATA_SOURCE_IMPORT: string;
DATA_SOURCES: string[];
DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER: string[];
DATA_SOURCES_LEGACY: string[];
ENABLE_FEATURE_FEAR_AND_GREED_INDEX: boolean;
ENABLE_FEATURE_READ_ONLY_MODE: boolean;
ENABLE_FEATURE_SOCIAL_LOGIN: boolean;

21
apps/api/src/services/queues/data-gathering/data-gathering.service.ts

@ -159,7 +159,8 @@ export class DataGatheringService {
);
if (!assetProfileIdentifiers) {
assetProfileIdentifiers = await this.getAllAssetProfileIdentifiers();
assetProfileIdentifiers =
await this.getAllActiveAssetProfileIdentifiers();
}
if (assetProfileIdentifiers.length <= 0) {
@ -296,11 +297,14 @@ export class DataGatheringService {
);
}
public async getAllAssetProfileIdentifiers(): Promise<
public async getAllActiveAssetProfileIdentifiers(): Promise<
AssetProfileIdentifier[]
> {
const symbolProfiles = await this.prismaService.symbolProfile.findMany({
orderBy: [{ symbol: 'asc' }]
orderBy: [{ symbol: 'asc' }],
where: {
isActive: true
}
});
return symbolProfiles
@ -370,9 +374,11 @@ export class DataGatheringService {
withUserSubscription?: boolean;
}): Promise<IDataGatheringItem[]> {
const symbolProfiles =
await this.symbolProfileService.getSymbolProfilesByUserSubscription({
withUserSubscription
});
await this.symbolProfileService.getActiveSymbolProfilesByUserSubscription(
{
withUserSubscription
}
);
const assetProfileIdentifiersWithCompleteMarketData =
await this.getAssetProfileIdentifiersWithCompleteMarketData();
@ -436,6 +442,9 @@ export class DataGatheringService {
},
scraperConfiguration: true,
symbol: true
},
where: {
isActive: true
}
})
)

2
apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts

@ -68,7 +68,7 @@ export class PortfolioSnapshotProcessor {
const portfolioCalculator = this.calculatorFactory.createCalculator({
accountBalanceItems,
activities,
calculationType: PerformanceCalculationType.TWR,
calculationType: PerformanceCalculationType.ROAI,
currency: job.data.userCurrency,
filters: job.data.filters,
userId: job.data.userId

71
apps/api/src/services/symbol-profile/symbol-profile.service.ts

@ -35,6 +35,41 @@ export class SymbolProfileService {
});
}
public async getActiveSymbolProfilesByUserSubscription({
withUserSubscription = false
}: {
withUserSubscription?: boolean;
}) {
return this.prismaService.symbolProfile.findMany({
include: {
Order: {
include: {
User: true
}
}
},
orderBy: [{ symbol: 'asc' }],
where: {
isActive: true,
Order: withUserSubscription
? {
some: {
User: {
Subscription: { some: { expiresAt: { gt: new Date() } } }
}
}
}
: {
every: {
User: {
Subscription: { none: { expiresAt: { gt: new Date() } } }
}
}
}
}
});
}
public async getSymbolProfiles(
aAssetProfileIdentifiers: AssetProfileIdentifier[]
): Promise<EnhancedSymbolProfile[]> {
@ -91,40 +126,6 @@ export class SymbolProfileService {
});
}
public async getSymbolProfilesByUserSubscription({
withUserSubscription = false
}: {
withUserSubscription?: boolean;
}) {
return this.prismaService.symbolProfile.findMany({
include: {
Order: {
include: {
User: true
}
}
},
orderBy: [{ symbol: 'asc' }],
where: {
Order: withUserSubscription
? {
some: {
User: {
Subscription: { some: { expiresAt: { gt: new Date() } } }
}
}
}
: {
every: {
User: {
Subscription: { none: { expiresAt: { gt: new Date() } } }
}
}
}
}
});
}
public updateAssetProfileIdentifier(
oldAssetProfileIdentifier: AssetProfileIdentifier,
newAssetProfileIdentifier: AssetProfileIdentifier
@ -152,6 +153,7 @@ export class SymbolProfileService {
countries,
currency,
holdings,
isActive,
name,
scraperConfiguration,
sectors,
@ -168,6 +170,7 @@ export class SymbolProfileService {
countries,
currency,
holdings,
isActive,
name,
scraperConfiguration,
sectors,

8
apps/client/ngsw-config.json

@ -6,13 +6,7 @@
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/assets/site.webmanifest",
"/*.css",
"/*.js"
]
"files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"]
}
},
{

3
apps/client/project.json

@ -146,9 +146,6 @@
{
"command": "shx cp apps/client/src/assets/robots.txt dist/apps/client"
},
{
"command": "shx cp apps/client/src/assets/site.webmanifest dist/apps/client"
},
{
"command": "shx cp node_modules/ionicons/dist/index.js dist/apps/client"
},

2
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html

@ -69,7 +69,7 @@
</div>
<mat-tab-group
animationDuration="0"
animationDuration="0ms"
[mat-stretch-tabs]="false"
[ngClass]="{ 'd-none': isLoadingActivities }"
>

5
apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts

@ -20,7 +20,6 @@ import {
} from '@angular/forms';
import { MatDialogRef } from '@angular/material/dialog';
import { isISO4217CurrencyCode } from 'class-validator';
import { uniq } from 'lodash';
import { Subject, takeUntil } from 'rxjs';
import { CreateAssetProfileDialogMode } from './interfaces/interfaces';
@ -87,7 +86,9 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy {
this.createAssetProfileForm.get('addCurrency').value as string
).toUpperCase();
const currencies = uniq([...this.customCurrencies, currency]).sort();
const currencies = Array.from(
new Set([...this.customCurrencies, currency])
).sort();
this.dataService
.putAdminSetting(PROPERTY_CURRENCIES, {

44
apps/client/src/app/components/admin-overview/admin-overview.component.ts

@ -6,7 +6,6 @@ import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import {
PROPERTY_COUPONS,
PROPERTY_CURRENCIES,
PROPERTY_IS_DATA_GATHERING_ENABLED,
PROPERTY_IS_READ_ONLY_MODE,
PROPERTY_IS_USER_SIGNUP_ENABLED,
@ -41,8 +40,6 @@ import { takeUntil } from 'rxjs/operators';
export class AdminOverviewComponent implements OnDestroy, OnInit {
public couponDuration: StringValue = '14 days';
public coupons: Coupon[];
public customCurrencies: string[];
public exchangeRates: { label1: string; label2: string; value: number }[];
public hasPermissionForSubscription: boolean;
public hasPermissionForSystemMessage: boolean;
public hasPermissionToToggleReadOnlyMode: boolean;
@ -138,19 +135,6 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
});
}
public onDeleteCurrency(aCurrency: string) {
this.notificationService.confirm({
confirmFn: () => {
const currencies = this.customCurrencies.filter((currency) => {
return currency !== aCurrency;
});
this.putAdminSetting({ key: PROPERTY_CURRENCIES, value: currencies });
},
confirmType: ConfirmationDialogType.Warn,
title: $localize`Do you really want to delete this currency?`
});
}
public onDeleteSystemMessage() {
this.notificationService.confirm({
confirmFn: () => {
@ -231,25 +215,17 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
this.adminService
.fetchAdminData()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(
({ exchangeRates, settings, transactionCount, userCount, version }) => {
this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? [];
this.customCurrencies = settings[PROPERTY_CURRENCIES] as string[];
this.exchangeRates = exchangeRates;
this.isDataGatheringEnabled =
settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false
? false
: true;
this.systemMessage = settings[
PROPERTY_SYSTEM_MESSAGE
] as SystemMessage;
this.transactionCount = transactionCount;
this.userCount = userCount;
this.version = version;
.subscribe(({ settings, transactionCount, userCount, version }) => {
this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? [];
this.isDataGatheringEnabled =
settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false ? false : true;
this.systemMessage = settings[PROPERTY_SYSTEM_MESSAGE] as SystemMessage;
this.transactionCount = transactionCount;
this.userCount = userCount;
this.version = version;
this.changeDetectorRef.markForCheck();
}
);
this.changeDetectorRef.markForCheck();
});
}
private generateCouponCode(aLength: number) {

67
apps/client/src/app/components/admin-overview/admin-overview.html

@ -30,73 +30,6 @@
}
</div>
</div>
<div class="align-items-start d-flex my-3">
<div class="w-50" i18n>Exchange Rates</div>
<div class="w-50">
<table>
@for (exchangeRate of exchangeRates; track exchangeRate) {
<tr>
<td>
<gf-value [locale]="user?.settings?.locale" [value]="1" />
</td>
<td class="pl-1">{{ exchangeRate.label1 }}</td>
<td class="px-1">=</td>
<td align="right">
<gf-value
class="d-inline-block"
[locale]="user?.settings?.locale"
[precision]="4"
[value]="exchangeRate.value"
/>
</td>
<td class="pl-1">{{ exchangeRate.label2 }}</td>
<td>
<button
class="mx-1 no-min-width px-2"
mat-button
[matMenuTriggerFor]="exchangeRateActionsMenu"
(click)="$event.stopPropagation()"
>
<ion-icon name="ellipsis-horizontal" />
</button>
<mat-menu
#exchangeRateActionsMenu="matMenu"
class="h-100 mx-1 no-min-width px-2"
xPosition="before"
>
<a
mat-menu-item
[queryParams]="{
assetProfileDialog: true,
dataSource: exchangeRate.dataSource,
symbol: exchangeRate.symbol
}"
[routerLink]="['/admin', 'market-data']"
>
<span class="align-items-center d-flex">
<ion-icon class="mr-2" name="create-outline" />
<span i18n>Edit</span>
</span>
</a>
@if (customCurrencies.includes(exchangeRate.label2)) {
<hr class="m-0" />
<button
mat-menu-item
(click)="onDeleteCurrency(exchangeRate.label2)"
>
<span class="align-items-center d-flex">
<ion-icon class="mr-2" name="trash-outline" />
<span i18n>Delete</span>
</span>
</button>
}
</mat-menu>
</td>
</tr>
}
</table>
</div>
</div>
<div class="d-flex my-3">
<div class="w-50" i18n>User Signup</div>
<div class="w-50">

45
apps/client/src/app/components/admin-users/admin-users.component.ts

@ -1,9 +1,4 @@
import { ConfirmationDialogType } from '@ghostfolio/client/core/notification/confirmation-dialog/confirmation-dialog.type';
import { NotificationService } from '@ghostfolio/client/core/notification/notification.service';
import { AdminService } from '@ghostfolio/client/services/admin.service';
import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { getDateFormatString, getEmojiFlag } from '@ghostfolio/common/helper';
import { AdminUsers, InfoItem, User } from '@ghostfolio/common/interfaces';
@ -26,11 +21,18 @@ import {
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ConfirmationDialogType } from '../../core/notification/confirmation-dialog/confirmation-dialog.type';
import { NotificationService } from '../../core/notification/notification.service';
import { AdminService } from '../../services/admin.service';
import { DataService } from '../../services/data.service';
import { ImpersonationStorageService } from '../../services/impersonation-storage.service';
import { UserService } from '../../services/user/user.service';
@Component({
selector: 'gf-admin-users',
standalone: false,
styleUrls: ['./admin-users.scss'],
templateUrl: './admin-users.html',
standalone: false
templateUrl: './admin-users.html'
})
export class AdminUsersComponent implements OnDestroy, OnInit {
@ViewChild(MatPaginator) paginator: MatPaginator;
@ -55,6 +57,7 @@ export class AdminUsersComponent implements OnDestroy, OnInit {
private dataService: DataService,
private impersonationStorageService: ImpersonationStorageService,
private notificationService: NotificationService,
private tokenStorageService: TokenStorageService,
private userService: UserService
) {
this.info = this.dataService.fetchInfo();
@ -140,6 +143,32 @@ export class AdminUsersComponent implements OnDestroy, OnInit {
});
}
public onGenerateAccessToken(aUserId: string) {
this.notificationService.confirm({
confirmFn: () => {
this.dataService
.generateAccessToken(aUserId)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ accessToken }) => {
this.notificationService.alert({
discardFn: () => {
if (aUserId === this.user.id) {
this.tokenStorageService.signOut();
this.userService.remove();
document.location.href = `/${document.documentElement.lang}`;
}
},
message: accessToken,
title: $localize`Security token`
});
});
},
confirmType: ConfirmationDialogType.Warn,
title: $localize`Do you really want to generate a new security token for this user?`
});
}
public onImpersonateUser(aId: string) {
if (aId) {
this.impersonationStorageService.setId(aId);

11
apps/client/src/app/components/admin-users/admin-users.html

@ -239,8 +239,17 @@
<span i18n>Impersonate User</span>
</span>
</button>
<hr class="m-0" />
}
<button
mat-menu-item
(click)="onGenerateAccessToken(element.id)"
>
<span class="align-items-center d-flex">
<ion-icon class="mr-2" name="key-outline" />
<span i18n>Generate Security Token</span>
</span>
</button>
<hr class="m-0" />
<button
mat-menu-item
[disabled]="element.id === user?.id"

2
apps/client/src/app/components/header/header.component.html

@ -134,7 +134,7 @@
</button>
<mat-menu
#assistantMenu="matMenu"
class="assistant"
class="no-max-width"
xPosition="before"
[overlapTrigger]="true"
(closed)="assistantElement?.setIsOpen(false)"

2
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html

@ -308,7 +308,7 @@
</div>
<mat-tab-group
animationDuration="0"
animationDuration="0ms"
class="mb-5"
[mat-stretch-tabs]="false"
[ngClass]="{ 'd-none': !dataSource?.data.length }"

4
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html

@ -117,8 +117,8 @@
<ng-container i18n>Net Performance</ng-container>
<abbr
class="initialism ml-2 text-muted"
title="Time-Weighted Rate of Return"
>(TWR)</abbr
title="Return on Average Investment"
>(ROAI)</abbr
>
</div>
<div class="flex-column flex-wrap justify-content-end">

4
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts

@ -40,8 +40,8 @@ export class PortfolioSummaryComponent implements OnChanges {
public ngOnChanges() {
if (this.summary) {
if (this.summary.firstOrderDate) {
this.timeInMarket = formatDistanceToNow(this.summary.firstOrderDate, {
if (this.user.dateOfFirstActivity) {
this.timeInMarket = formatDistanceToNow(this.user.dateOfFirstActivity, {
locale: getDateFnsLocale(this.language)
});
} else {

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

@ -24,7 +24,6 @@ import { FormBuilder, Validators } from '@angular/forms';
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
import { MatSnackBar } from '@angular/material/snack-bar';
import { format, parseISO } from 'date-fns';
import { uniq } from 'lodash';
import ms from 'ms';
import { EMPTY, Subject, throwError } from 'rxjs';
import { catchError, takeUntil } from 'rxjs/operators';
@ -108,7 +107,7 @@ export class UserAccountSettingsComponent implements OnDestroy, OnInit {
);
this.locales.push(this.user.settings.locale);
this.locales = uniq(this.locales.sort());
this.locales = Array.from(new Set(this.locales)).sort();
this.changeDetectorRef.markForCheck();
}

2
apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html

@ -8,7 +8,7 @@
<div class="flex-grow-1" mat-dialog-content>
<mat-stepper
#stepper
animationDuration="0"
animationDuration="0ms"
[linear]="true"
[orientation]="stepperOrientation"
[selectedIndex]="importStep"

32
apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts

@ -16,7 +16,14 @@ import type { AiPromptMode, GroupBy } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n';
import { Clipboard } from '@angular/cdk/clipboard';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import {
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
import { MatMenuTrigger } from '@angular/material/menu';
import { MatSnackBar } from '@angular/material/snack-bar';
import { SymbolProfile } from '@prisma/client';
import { isNumber, sortBy } from 'lodash';
@ -32,6 +39,8 @@ import { takeUntil } from 'rxjs/operators';
standalone: false
})
export class AnalysisPageComponent implements OnDestroy, OnInit {
@ViewChild(MatMenuTrigger) actionsMenuButton!: MatMenuTrigger;
public benchmark: Partial<SymbolProfile>;
public benchmarkDataItems: HistoricalDataItem[] = [];
public benchmarks: Partial<SymbolProfile>[];
@ -46,10 +55,12 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
public investments: InvestmentItem[];
public investmentTimelineDataLabel = $localize`Investment`;
public investmentsByGroup: InvestmentItem[];
public isLoadingAnalysisPrompt: boolean;
public isLoadingBenchmarkComparator: boolean;
public isLoadingDividendTimelineChart: boolean;
public isLoadingInvestmentChart: boolean;
public isLoadingInvestmentTimelineChart: boolean;
public isLoadingPortfolioPrompt: boolean;
public mode: GroupBy = 'month';
public modeOptions: ToggleOption[] = [
{ label: $localize`Monthly`, value: 'month' },
@ -143,8 +154,17 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
}
public onCopyPromptToClipboard(mode: AiPromptMode) {
if (mode === 'analysis') {
this.isLoadingAnalysisPrompt = true;
} else if (mode === 'portfolio') {
this.isLoadingPortfolioPrompt = true;
}
this.dataService
.fetchPrompt(mode)
.fetchPrompt({
mode,
filters: this.userService.getFilters()
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ prompt }) => {
this.clipboard.copy(prompt);
@ -163,6 +183,14 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
.subscribe(() => {
window.open('https://duck.ai', '_blank');
});
this.actionsMenuButton.closeMenu();
if (mode === 'analysis') {
this.isLoadingAnalysisPrompt = false;
} else if (mode === 'portfolio') {
this.isLoadingPortfolioPrompt = false;
}
});
}

90
apps/client/src/app/pages/portfolio/analysis/analysis-page.html

@ -5,6 +5,7 @@
<div class="col-lg">
<div class="d-flex justify-content-end">
<button
#actionsMenuButton
class="mx-1 no-min-width px-2"
mat-stroked-button
[matMenuTriggerFor]="actionsMenu"
@ -12,39 +13,62 @@
>
<ion-icon name="ellipsis-vertical" />
</button>
<mat-menu #actionsMenu="matMenu" xPosition="before">
<button
mat-menu-item
[disabled]="!hasPermissionToReadAiPrompt"
(click)="onCopyPromptToClipboard('portfolio')"
>
<span class="align-items-center d-flex">
@if (user?.subscription?.type === 'Basic') {
<gf-premium-indicator class="mr-2" />
} @else {
<ion-icon class="mr-2" name="copy-outline" />
}
<ng-container i18n
>Copy portfolio data to clipboard for AI prompt</ng-container
>
</span>
</button>
<button
mat-menu-item
[disabled]="!hasPermissionToReadAiPrompt"
(click)="onCopyPromptToClipboard('analysis')"
>
<span class="align-items-center d-flex">
@if (user?.subscription?.type === 'Basic') {
<gf-premium-indicator class="mr-2" />
} @else {
<ion-icon class="mr-2" name="copy-outline" />
}
<ng-container i18n
>Copy AI prompt to clipboard for analysis</ng-container
>
</span>
</button>
<mat-menu
#actionsMenu="matMenu"
class="no-max-width"
xPosition="before"
>
<div (click)="$event.stopPropagation()">
<button
mat-menu-item
[disabled]="!hasPermissionToReadAiPrompt"
(click)="onCopyPromptToClipboard('portfolio')"
>
<span class="align-items-center d-flex">
@if (user?.subscription?.type === 'Basic') {
<gf-premium-indicator class="mr-2" />
} @else {
@if (isLoadingPortfolioPrompt) {
<mat-spinner
class="mr-2"
color="accent"
[diameter]="16"
/>
} @else {
<ion-icon class="mr-2" name="copy-outline" />
}
}
<ng-container i18n
>Copy portfolio data to clipboard for AI
prompt</ng-container
>
</span>
</button>
<button
mat-menu-item
[disabled]="!hasPermissionToReadAiPrompt"
(click)="onCopyPromptToClipboard('analysis')"
>
<span class="align-items-center d-flex">
@if (user?.subscription?.type === 'Basic') {
<gf-premium-indicator class="mr-2" />
} @else {
@if (isLoadingAnalysisPrompt) {
<mat-spinner
class="mr-2"
color="accent"
[diameter]="16"
/>
} @else {
<ion-icon class="mr-2" name="copy-outline" />
}
}
<ng-container i18n
>Copy AI prompt to clipboard for analysis</ng-container
>
</span>
</button>
</div>
</mat-menu>
</div>
</div>

2
apps/client/src/app/pages/portfolio/analysis/analysis-page.module.ts

@ -10,6 +10,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatMenuModule } from '@angular/material/menu';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { AnalysisPageRoutingModule } from './analysis-page-routing.module';
@ -29,6 +30,7 @@ import { AnalysisPageComponent } from './analysis-page.component';
MatButtonModule,
MatCardModule,
MatMenuModule,
MatProgressSpinnerModule,
NgxSkeletonLoaderModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]

7
apps/client/src/app/pages/register/register-page.component.ts

@ -61,15 +61,18 @@ export class RegisterPageComponent implements OnDestroy, OnInit {
public async onLoginWithInternetIdentity() {
try {
const { authToken } = await this.internetIdentityService.login();
this.tokenStorageService.saveToken(authToken);
this.router.navigate(['/']);
await this.router.navigate(['/']);
} catch {}
}
public openShowAccessTokenDialog() {
const dialogRef = this.dialog.open(ShowAccessTokenDialog, {
disableClose: true,
width: '30rem'
height: this.deviceType === 'mobile' ? '98vh' : undefined,
width: this.deviceType === 'mobile' ? '100vw' : '30rem'
});
dialogRef

2
apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html

@ -5,7 +5,7 @@
}
</h1>
<div class="px-0" mat-dialog-content>
<mat-stepper #stepper animationDuration="0ms" linear>
<mat-stepper #stepper animationDuration="0ms" [linear]="true">
<mat-step editable="false" [completed]="isDisclaimerChecked">
<ng-template i18n matStepLabel>Terms and Conditions</ng-template>
<div class="pt-2">

17
apps/client/src/app/services/admin.service.ts

@ -8,7 +8,6 @@ import {
PROPERTY_API_KEY_GHOSTFOLIO
} from '@ghostfolio/common/config';
import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,
AdminData,
@ -25,7 +24,6 @@ import { Injectable } from '@angular/core';
import { SortDirection } from '@angular/material/sort';
import { DataSource, MarketData, Platform } from '@prisma/client';
import { JobStatus } from 'bull';
import { format } from 'date-fns';
import { switchMap } from 'rxjs';
import { environment } from '../../environments/environment';
@ -186,19 +184,8 @@ export class AdminService {
);
}
public gatherSymbol({
dataSource,
date,
symbol
}: AssetProfileIdentifier & {
date?: Date;
}) {
let url = `/api/v1/admin/gather/${dataSource}/${symbol}`;
if (date) {
url = `${url}/${format(date, DATE_FORMAT)}`;
}
public gatherSymbol({ dataSource, symbol }: AssetProfileIdentifier) {
const url = `/api/v1/admin/gather/${dataSource}/${symbol}`;
return this.http.post<MarketData | void>(url, {});
}

36
apps/client/src/app/services/data.service.ts

@ -22,6 +22,7 @@ import { PropertyDto } from '@ghostfolio/api/services/property/property.dto';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import {
Access,
AccessTokenResponse,
AccountBalancesResponse,
Accounts,
AiPromptResponse,
@ -57,6 +58,7 @@ import { translate } from '@ghostfolio/ui/i18n';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { SortDirection } from '@angular/material/sort';
import { utc } from '@date-fns/utc';
import {
AccountBalance,
DataSource,
@ -281,7 +283,7 @@ export class DataService {
symbol: string;
}) {
return this.http.get<IDataProviderHistoricalResponse>(
`/api/v1/exchange-rate/${symbol}/${format(date, DATE_FORMAT)}`
`/api/v1/exchange-rate/${symbol}/${format(date, DATE_FORMAT, { in: utc })}`
);
}
@ -363,10 +365,7 @@ export class DataService {
}
return this.http.get<BenchmarkMarketDataDetails>(
`/api/v1/benchmarks/${dataSource}/${symbol}/${format(
startDate,
DATE_FORMAT
)}`,
`/api/v1/benchmarks/${dataSource}/${symbol}/${format(startDate, DATE_FORMAT, { in: utc })}`,
{ params }
);
}
@ -531,12 +530,6 @@ export class DataService {
})
.pipe(
map((response) => {
if (response.summary?.firstOrderDate) {
response.summary.firstOrderDate = parseISO(
response.summary.firstOrderDate
);
}
if (response.holdings) {
for (const symbol of Object.keys(response.holdings)) {
response.holdings[symbol].assetClassLabel = translate(
@ -655,8 +648,18 @@ export class DataService {
return this.http.get<PortfolioReportResponse>('/api/v1/portfolio/report');
}
public fetchPrompt(mode: AiPromptMode) {
return this.http.get<AiPromptResponse>(`/api/v1/ai/prompt/${mode}`);
public fetchPrompt({
filters,
mode
}: {
filters?: Filter[];
mode: AiPromptMode;
}) {
const params = this.buildFiltersAsQueryParams({ filters });
return this.http.get<AiPromptResponse>(`/api/v1/ai/prompt/${mode}`, {
params
});
}
public fetchPublicPortfolio(aAccessId: string) {
@ -683,6 +686,13 @@ export class DataService {
return this.http.get<Tag[]>('/api/v1/tags');
}
public generateAccessToken(aUserId: string) {
return this.http.post<AccessTokenResponse>(
`/api/v1/user/${aUserId}/access-token`,
{}
);
}
public loginAnonymous(accessToken: string) {
return this.http.post<OAuthResponse>('/api/v1/auth/anonymous', {
accessToken

4
apps/client/src/app/services/user/user.service.ts

@ -1,5 +1,3 @@
import { SubscriptionInterstitialDialogParams } from '@ghostfolio/client/components/subscription-interstitial-dialog/interfaces/interfaces';
import { SubscriptionInterstitialDialog } from '@ghostfolio/client/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component';
import { Filter, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -13,6 +11,8 @@ import { Observable, Subject, of } from 'rxjs';
import { throwError } from 'rxjs';
import { catchError, map, takeUntil } from 'rxjs/operators';
import { SubscriptionInterstitialDialogParams } from '../../components/subscription-interstitial-dialog/interfaces/interfaces';
import { SubscriptionInterstitialDialog } from '../../components/subscription-interstitial-dialog/subscription-interstitial-dialog.component';
import { UserStoreActions } from './user-store.actions';
import { UserStoreState } from './user-store.state';

5
apps/client/src/index.html

@ -45,7 +45,10 @@
sizes="16x16"
type="image/png"
/>
<link href="../assets/site.webmanifest" rel="manifest" />
<link
href="../api/assets/${languageCode}/site.webmanifest"
rel="manifest"
/>
</head>
<body>
<gf-root></gf-root>

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

@ -1185,10 +1185,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -1219,11 +1215,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -1967,15 +1959,7 @@
<target state="translated">Està segur qeu vol eliminar aquest cupó?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Està segur que vol eliminar aquesta divisa?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="297546430113071258" datatype="html">
@ -1983,7 +1967,7 @@
<target state="translated">Està segur que vol eliminar aquest missatge del sistema?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -1991,7 +1975,7 @@
<target state="translated">Està segur que vol depurar el cache?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -1999,7 +1983,7 @@
<target state="translated">Si us plau, afegeixi el seu missatge del sistema:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="8fe73a4787b8068b2ba61f54ab7e0f9af2ea1fc9" datatype="html">
@ -2034,14 +2018,6 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Tipus de Canvi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Afegir Divisa</target>
@ -2055,7 +2031,7 @@
<target state="translated">Registrar Usuari</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -2063,7 +2039,7 @@
<target state="translated">Mode Només Lecutra</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="4f986b5ab20fe31ca54d7345a73b6b2402ddd350" datatype="html">
@ -2071,7 +2047,7 @@
<target state="translated">Recollida de Dades</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -2079,7 +2055,7 @@
<target state="translated">Missatge del Sistema</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -2087,7 +2063,7 @@
<target state="translated">Estableix el Missatge</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -2095,7 +2071,7 @@
<target state="translated">Coupons</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -2103,7 +2079,7 @@
<target state="translated">Afegir</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -2115,7 +2091,7 @@
<target state="translated">Ordre</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -2123,7 +2099,7 @@
<target state="translated">Depurar el Cache</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="e587f3aaad8881a0b7732fb3e86df8a4c91f25d2" datatype="html">
@ -2247,7 +2223,7 @@
<target state="translated">Està segur que vol eliminar aquest usuari?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="a3db2898b85fed425f03294b839a98cef247a2dc" datatype="html">
@ -2295,7 +2271,7 @@
<target state="translated">Eliminar Usuari</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
@ -2499,7 +2475,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="024cdb2814b0cb3f4ced148f1a0b9854447cb214" datatype="html">
@ -2675,7 +2651,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2687,7 +2663,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -3367,7 +3343,7 @@
<target state="new">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="4941836956820527118" datatype="html">
@ -3375,7 +3351,7 @@
<target state="new">Do you really want to close your Ghostfolio account?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -3383,7 +3359,7 @@
<target state="new">Do you really want to remove this sign in method?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="5724720497710437101" datatype="html">
@ -3391,7 +3367,7 @@
<target state="new">Oops! There was an error setting up biometric authentication.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="121cc5391cd2a5115bc2b3160379ee5b36cd7716" datatype="html">
@ -5063,7 +5039,7 @@
<target state="new">Dividend</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -5075,11 +5051,11 @@
<target state="new">Investment</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -5091,7 +5067,7 @@
<target state="new">Monthly</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8036977202721714375" datatype="html">
@ -5099,7 +5075,7 @@
<target state="new">Yearly</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -5115,7 +5091,7 @@
<target state="new">Absolute Asset Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -5123,7 +5099,7 @@
<target state="new"> Asset Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -5131,7 +5107,7 @@
<target state="new">Absolute Currency Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -5139,7 +5115,7 @@
<target state="new"> Currency Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -5147,7 +5123,7 @@
<target state="new"> Absolute Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -5155,7 +5131,7 @@
<target state="new"> Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -5163,7 +5139,7 @@
<target state="new">Top</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -5171,7 +5147,7 @@
<target state="new">Bottom</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -5179,7 +5155,7 @@
<target state="new">Portfolio Evolution</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
@ -5187,7 +5163,7 @@
<target state="new">Investment Timeline</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -5195,7 +5171,7 @@
<target state="new">Current Streak</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -5203,7 +5179,7 @@
<target state="new">Longest Streak</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="6410cffb96159fcff46d91effc26df0e240bc0e3" datatype="html">
@ -5211,7 +5187,7 @@
<target state="new">Dividend Timeline</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -6675,7 +6651,7 @@
<target state="new">Extreme Fear</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6683,7 +6659,7 @@
<target state="new">Extreme Greed</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6691,7 +6667,7 @@
<target state="new">Neutral</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="3c33a66194384cf8c14e25170416767efa56fd98" datatype="html">
@ -6995,7 +6971,7 @@
<target state="new">United States</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7613,7 +7589,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7709,7 +7685,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7748,12 +7724,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7761,7 +7737,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7828,6 +7804,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

156
apps/client/src/locales/messages.de.xlf

@ -264,10 +264,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -298,11 +294,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -626,15 +618,7 @@
<target state="translated">Möchtest du diesen Gutscheincode wirklich löschen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Möchtest du diese Währung wirklich löschen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -642,7 +626,7 @@
<target state="translated">Möchtest du den Cache wirklich leeren?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -650,7 +634,7 @@
<target state="translated">Bitte gebe deine Systemmeldung ein:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -697,14 +681,6 @@
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Wechselkurse</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Währung hinzufügen</target>
@ -718,7 +694,7 @@
<target state="translated">Systemmeldung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -726,7 +702,7 @@
<target state="translated">Systemmeldung setzen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -734,7 +710,7 @@
<target state="translated">Lese-Modus</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -742,7 +718,7 @@
<target state="translated">Gutscheincodes</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -750,7 +726,7 @@
<target state="translated">Hinzufügen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -762,7 +738,7 @@
<target state="translated">Verwaltung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -770,7 +746,7 @@
<target state="translated">Cache leeren</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -778,7 +754,7 @@
<target state="translated">Möchtest du diesen Benutzer wirklich löschen?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
@ -1046,7 +1022,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -1686,7 +1662,7 @@
<target state="translated">Möchtest du diese Anmeldemethode wirklich löschen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -2142,7 +2118,7 @@
<target state="translated">Zeitstrahl der Investitionen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -2150,7 +2126,7 @@
<target state="translated">Gewinner</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -2158,7 +2134,7 @@
<target state="translated">Verlierer</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -2786,7 +2762,7 @@
<target state="translated">Monatlich</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2842,7 +2818,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2854,7 +2830,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="4550487415324294802" datatype="html">
@ -2930,7 +2906,7 @@
<target state="translated">Automatisch</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -2978,7 +2954,7 @@
<target state="translated">Portfolio Wertentwicklung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
@ -3298,7 +3274,7 @@
<target state="translated">Zeitstrahl der Dividenden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="7765499580020598783" datatype="html">
@ -3306,7 +3282,7 @@
<target state="translated">Dividenden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -3326,7 +3302,7 @@
<target state="translated">Benutzer Registrierung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="8763985977445247551" datatype="html">
@ -3414,7 +3390,7 @@
<target state="translated">Jährlich</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="72640258012696878" datatype="html">
@ -3926,7 +3902,7 @@
<target state="translated">Benutzer löschen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="4239552960465242484" datatype="html">
@ -4162,7 +4138,7 @@
<target state="translated">Aktueller Streak</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4170,7 +4146,7 @@
<target state="translated">Längster Streak</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="4845030128243887325" datatype="html">
@ -6103,7 +6079,7 @@
<target state="translated">Extreme Angst</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6111,7 +6087,7 @@
<target state="translated">Extreme Gier</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6119,7 +6095,7 @@
<target state="translated">Neutral</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="7183719827884539616" datatype="html">
@ -6135,7 +6111,7 @@
<target state="translated">Möchtest du diese Systemmeldung wirklich löschen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="d762c43328624b5dd81f3c6a3023203ae9a7553f" datatype="html">
@ -6291,11 +6267,11 @@
<target state="translated">Einlage</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6307,7 +6283,7 @@
<target state="translated"> Absolute Anlage Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -6315,7 +6291,7 @@
<target state="translated"> Anlage Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6323,7 +6299,7 @@
<target state="translated"> Absolute Währungsperformance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6331,7 +6307,7 @@
<target state="translated"> Währungsperformance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6339,7 +6315,7 @@
<target state="translated"> Absolute Netto Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6347,7 +6323,7 @@
<target state="translated"> Netto Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6455,7 +6431,7 @@
<target state="translated">Daten einholen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6627,7 +6603,7 @@
<target state="translated">Möchtest du dieses Ghostfolio Konto wirklich schliessen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6675,7 +6651,7 @@
<target state="translated">Ups! Beim Einrichten der biometrischen Authentifizierung ist ein Fehler aufgetreten.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6995,7 +6971,7 @@
<target state="translated">USA</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7613,7 +7589,7 @@
<target state="translated">KI-Anweisung wurde in die Zwischenablage kopiert</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7709,7 +7685,7 @@
<target state="translated">Öffne Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7748,12 +7724,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="translated">Kopiere Portfolio-Daten in die Zwischenablage für KI-Anweisung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7761,7 +7737,7 @@
<target state="translated">Kopiere KI-Anweisung in die Zwischenablage für Analyse</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7828,6 +7804,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="translated">Sicherheits-Token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="translated">Möchtest du für diesen Benutzer wirklich einen neuen Sicherheits-Token generieren?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="translated">Sicherheits-Token generieren</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="translated">Vereinigtes Königreich</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

156
apps/client/src/locales/messages.es.xlf

@ -265,10 +265,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -299,11 +295,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -627,15 +619,7 @@
<target state="translated">¿Estás seguro de eliminar este cupón?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">¿Estás seguro de eliminar esta divisa?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -643,7 +627,7 @@
<target state="translated">¿Estás seguro de limpiar la caché?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -651,7 +635,7 @@
<target state="translated">Por favor, establece tu mensaje del sistema:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -698,14 +682,6 @@
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Tipos de cambio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Añadir divisa</target>
@ -719,7 +695,7 @@
<target state="translated">Mensaje del sistema</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -727,7 +703,7 @@
<target state="translated">Establecer mensaje</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -735,7 +711,7 @@
<target state="translated">Modo de solo lectura</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -743,7 +719,7 @@
<target state="translated">Cupones</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -751,7 +727,7 @@
<target state="translated">Añadir</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -763,7 +739,7 @@
<target state="translated">Tareas domésticas</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -771,7 +747,7 @@
<target state="translated">Limpiar caché</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -779,7 +755,7 @@
<target state="translated">¿Estás seguro de eliminar este usuario?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
@ -1047,7 +1023,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -1687,7 +1663,7 @@
<target state="translated">¿Estás seguro de eliminar este método de acceso?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -2143,7 +2119,7 @@
<target state="translated">Cronología de la inversión</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -2151,7 +2127,7 @@
<target state="translated">Lo mejor</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -2159,7 +2135,7 @@
<target state="translated">Lo peor</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -2815,7 +2791,7 @@
<target state="translated">Mensual</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
@ -2843,7 +2819,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2855,7 +2831,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="4550487415324294802" datatype="html">
@ -2931,7 +2907,7 @@
<target state="translated">Automático</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -2979,7 +2955,7 @@
<target state="translated">Evolución cartera</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
@ -3299,7 +3275,7 @@
<target state="translated">Dividendo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -3311,7 +3287,7 @@
<target state="translated">Calendario de dividendos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="7608037008789240367" datatype="html">
@ -3327,7 +3303,7 @@
<target state="translated">Registro de usuario</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="8763985977445247551" datatype="html">
@ -3415,7 +3391,7 @@
<target state="translated">Anual</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="72640258012696878" datatype="html">
@ -3927,7 +3903,7 @@
<target state="new">Delete User</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="4239552960465242484" datatype="html">
@ -4163,7 +4139,7 @@
<target state="new">Current Streak</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4171,7 +4147,7 @@
<target state="new">Longest Streak</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="4845030128243887325" datatype="html">
@ -6104,7 +6080,7 @@
<target state="new">Extreme Fear</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6112,7 +6088,7 @@
<target state="new">Extreme Greed</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6120,7 +6096,7 @@
<target state="new">Neutral</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="7183719827884539616" datatype="html">
@ -6136,7 +6112,7 @@
<target state="new">Do you really want to delete this system message?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="d762c43328624b5dd81f3c6a3023203ae9a7553f" datatype="html">
@ -6292,11 +6268,11 @@
<target state="translated">Inversión</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6308,7 +6284,7 @@
<target state="new">Absolute Asset Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -6316,7 +6292,7 @@
<target state="new"> Asset Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6324,7 +6300,7 @@
<target state="new">Absolute Currency Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6332,7 +6308,7 @@
<target state="new"> Currency Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6340,7 +6316,7 @@
<target state="new"> Absolute Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6348,7 +6324,7 @@
<target state="new"> Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6456,7 +6432,7 @@
<target state="new">Data Gathering</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6628,7 +6604,7 @@
<target state="translated">¿Estás seguro de querer borrar tu cuenta de Ghostfolio?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6676,7 +6652,7 @@
<target state="new">Oops! There was an error setting up biometric authentication.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6996,7 +6972,7 @@
<target state="new">United States</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7614,7 +7590,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7710,7 +7686,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7749,12 +7725,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7762,7 +7738,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7829,6 +7805,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

210
apps/client/src/locales/messages.fr.xlf

@ -320,10 +320,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -354,11 +350,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -882,15 +874,7 @@
<target state="translated">Voulez-vous vraiment supprimer ce code promotionnel ?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Voulez-vous vraiment supprimer cette devise ?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -898,7 +882,7 @@
<target state="translated">Voulez-vous vraiment vider le cache ?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -906,7 +890,7 @@
<target state="translated">Veuillez définir votre message système :</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -933,14 +917,6 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Taux de Conversion</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Ajouter Devise</target>
@ -970,7 +946,7 @@
<target state="translated">Inscription de Nouveaux Utilisateurs</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -978,7 +954,7 @@
<target state="translated">Mode Lecture Seule</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -986,7 +962,7 @@
<target state="translated">Message Système</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -994,7 +970,7 @@
<target state="translated">Définir Message</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -1002,7 +978,7 @@
<target state="translated">Codes promotionnels</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -1010,7 +986,7 @@
<target state="translated">Ajouter</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -1022,7 +998,7 @@
<target state="translated">Maintenance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -1030,7 +1006,7 @@
<target state="translated">Vider le Cache</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -1038,7 +1014,7 @@
<target state="translated">Voulez-vous vraiment supprimer cet·te utilisateur·rice ?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
@ -1358,7 +1334,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -1378,7 +1354,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -1390,7 +1366,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -1902,7 +1878,7 @@
<target state="translated">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="1257540657265073416" datatype="html">
@ -1942,7 +1918,7 @@
<target state="translated">Voulez-vous vraiment supprimer cette méthode de connexion ?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -2742,7 +2718,7 @@
<target state="translated">Dividende</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -2762,7 +2738,7 @@
<target state="translated">Mensuel</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -2778,7 +2754,7 @@
<target state="translated">Haut</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -2786,7 +2762,7 @@
<target state="translated">Bas</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -2794,7 +2770,7 @@
<target state="translated">Évolution du Portefeuille</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
@ -2802,7 +2778,7 @@
<target state="translated">Historique des Investissements</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="6410cffb96159fcff46d91effc26df0e240bc0e3" datatype="html">
@ -2810,7 +2786,7 @@
<target state="translated">Historique des Dividendes</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -2867,7 +2843,7 @@
</trans-unit>
<trans-unit id="82fe55446d3fad9db11eb79caaedf325587b9c0a" datatype="html">
<source> Hello, <x id="INTERPOLATION" equiv-text="{{ publicPortfolioDetails?.alias ?? &apos;someone&apos; }}"/> has shared a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> with you! </source>
<target state="new"> Bonjour, <x id="INTERPOLATION" equiv-text="{{ portfolioPublicDetails?.alias ?? ’someone’ }}"/> a partagé un <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Portefeuille<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> avec vous ! </target>
<target state="new"> Bonjour, <x id="INTERPOLATION" equiv-text="{{ portfolioPublicDetails?.alias ?? &apos;someone&apos; }}"/> a partagé un <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Portefeuille<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> avec vous ! </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">4</context>
@ -3414,7 +3390,7 @@
<target state="translated">Annuel</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="72640258012696878" datatype="html">
@ -3926,7 +3902,7 @@
<target state="translated">Supprimer l’Utilisateur</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="4239552960465242484" datatype="html">
@ -4162,7 +4138,7 @@
<target state="translated">Série en cours</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4170,7 +4146,7 @@
<target state="translated">Série la plus longue</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="4845030128243887325" datatype="html">
@ -4363,7 +4339,7 @@
</trans-unit>
<trans-unit id="860b5bad5cced4ac7b854f429968a91f8d74ea6e" datatype="html">
<source>Add Asset Profile</source>
<target state="translated">Ajouter un Profil d&apos;Actif</target>
<target state="translated">Ajouter un Profil dActif</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html</context>
<context context-type="linenumber">7</context>
@ -4755,7 +4731,7 @@
</trans-unit>
<trans-unit id="8d0f35e084b3902a5b04ee86cfde0d4b991a93af" 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; 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="translated"> Chez Ghostfolio, la transparence est le centre de notre attention. Nous publions le code source sous <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;"/>open source software<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> (OSS) sous la <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;"/>licence AGPL-3.0<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> et nous partageons ouvertement les indicateurs clés agrégés sur l&apos;état opérationnel de la plateforme. </target>
<target state="translated"> Chez Ghostfolio, la transparence est le centre de notre attention. Nous publions le code source sous <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;"/>open source software<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> (OSS) sous la <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;"/>licence AGPL-3.0<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> et nous partageons ouvertement les indicateurs clés agrégés sur létat opérationnel de la plateforme. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6</context>
@ -4823,7 +4799,7 @@
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<target state="translated">Temps d&apos;activité des serveurs</target>
<target state="translated">Temps dactivité des serveurs</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">132</context>
@ -4863,7 +4839,7 @@
</trans-unit>
<trans-unit id="84e1290e06dcaba8e890116cd795d79ef89ccc90" datatype="html">
<source>Discover other exciting Open Source Software projects</source>
<target state="translated">Découvrez d&apos;autres projets passionnants de logiciels Open Source</target>
<target state="translated">Découvrez dautres projets passionnants de logiciels Open Source</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/oss-friends/oss-friends-page.html</context>
<context context-type="linenumber">9</context>
@ -4919,7 +4895,7 @@
</trans-unit>
<trans-unit id="f251aca95a00756de48b14172b02d33f175661fc" datatype="html">
<source> Ghostfolio is a privacy-first, open source dashboard for your personal finances. Break down your asset allocation, know your net worth and make solid, data-driven investment decisions. </source>
<target state="translated"> Ghostfolio est un tableau de bord open-source axé sur la confidentialité pour votre Gestion de Patrimoine. Décomposez votre répartition d&apos;actifs, connaissez votre valeur nette et prenez des décisions d&apos;investissement solides et basées sur des données. </target>
<target state="translated"> Ghostfolio est un tableau de bord open-source axé sur la confidentialité pour votre Gestion de Patrimoine. Décomposez votre répartition d’actifs, connaissez votre valeur nette et prenez des décisions d’investissement solides et basées sur des données. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">9</context>
@ -4955,7 +4931,7 @@
</trans-unit>
<trans-unit id="c8ef12032b654cfd51b9ae1082fde84247945e03" datatype="html">
<source> Protect your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>assets<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>. Refine your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>personal investment strategy<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>. </source>
<target state="translated"> Protégez vos <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>actifs<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>. Affinez votre <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>stratégie d&apos;investissement personnelle.<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>. </target>
<target state="translated"> Protégez vos <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>actifs<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>. Affinez votre <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>stratégie dinvestissement personnelle.<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">225</context>
@ -5003,7 +4979,7 @@
</trans-unit>
<trans-unit id="3756fe4769648222e9a3143d6a140e55afd7424b" datatype="html">
<source> Benefit from continuous improvements through a strong community. </source>
<target state="translated"> Bénéficiez d&apos;améliorations continues grâce à une communauté impliquée. </target>
<target state="translated"> Bénéficiez daméliorations continues grâce à une communauté impliquée. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">263</context>
@ -5043,7 +5019,7 @@
</trans-unit>
<trans-unit id="2e95d2cbc69d45e5ecf3eb92c2972e8cb4ff3ec6" datatype="html">
<source>interested in getting insights of your portfolio composition</source>
<target state="translated">êtes intéressés d&apos;avoir un aperçu de la composition de votre portefeuille</target>
<target state="translated">êtes intéressés davoir un aperçu de la composition de votre portefeuille</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">291</context>
@ -5075,7 +5051,7 @@
</trans-unit>
<trans-unit id="0a6c37c2d3a8c41e7e44f020aefb1c667ac150dc" datatype="html">
<source>interested in financial independence</source>
<target state="translated">êtes intéressés d&apos;atteindre l&apos;indépendance financière</target>
<target state="translated">êtes intéressés d’atteindre l’indépendance financière</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">307</context>
@ -5107,7 +5083,7 @@
</trans-unit>
<trans-unit id="ae508ae33a02ae69247d9e4d84e98b610209ef3b" datatype="html">
<source> What our <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>users<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> are saying </source>
<target state="translated"> Qu&apos;en pensent <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>nos utilisateurs<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> </target>
<target state="translated"> Quen pensent <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>nos utilisateurs<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">327</context>
@ -5147,7 +5123,7 @@
</trans-unit>
<trans-unit id="57aad8c9d23cc4f0bbb0abf4f3313bfb85154592" datatype="html">
<source> Add any of your historical transactions </source>
<target state="translated"> Ajoutez l&apos;une de vos transactions historiques </target>
<target state="translated"> Ajoutez lune de vos transactions historiques </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">405</context>
@ -5183,7 +5159,7 @@
</trans-unit>
<trans-unit id="dbe66b4824faaff93249a96c9ce23c237b446ed5" datatype="html">
<source> Get the full picture of your personal finances across multiple platforms. </source>
<target state="translated"> Obtenez une vue d&apos;ensemble de vos finances personnelles sur plusieurs plateformes. </target>
<target state="translated"> Obtenez une vue densemble de vos finances personnelles sur plusieurs plateformes. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">242</context>
@ -5644,7 +5620,7 @@
</trans-unit>
<trans-unit id="a92a0e8a2e70e4a0735b714680629187d2b6f23e" 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="translated"> Cette page d&apos;aperçu présente une collection d&apos;outils de finances personnelles comparés à la solution 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;"/>. Si vous accordez de l&apos;importance à la transparence, à la confidentialité des données et à la collaboration communautaire, Ghostfolio vous offre une excellente occasion de prendre le contrôle de votre gestion financière. </target>
<target state="translated"> Cette page d’aperçu présente une collection d’outils de finances personnelles comparés à la solution 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;"/>. Si vous accordez de limportance à la transparence, à la confidentialité des données et à la collaboration communautaire, Ghostfolio vous offre une excellente occasion de prendre le contrôle de votre gestion financière. </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">8</context>
@ -5652,7 +5628,7 @@
</trans-unit>
<trans-unit id="bd90980cf63dc92053b4b209cc82b609fded14e9" datatype="html">
<source> Explore the links below to compare a variety of personal finance tools with Ghostfolio. </source>
<target state="translated"> Explorez les liens ci-dessous pour comparer une variété d&apos;outils de finances personnelles avec Ghostfolio. </target>
<target state="translated"> Explorez les liens ci-dessous pour comparer une variété doutils de finances personnelles avec Ghostfolio. </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">16</context>
@ -5692,7 +5668,7 @@
</trans-unit>
<trans-unit id="2d66779e125a3e4e53fc001b8faf70864231082c" datatype="html">
<source> Ghostfolio is an open source software (OSS), providing a cost-effective alternative to <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> making it particularly suitable for individuals on a tight budget, such as those <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;../en/blog/2023/07/exploring-the-path-to-fire&quot; &gt;"/>pursuing Financial Independence, Retire Early (FIRE)<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>. By leveraging the collective efforts of a community of developers and personal finance enthusiasts, Ghostfolio continuously enhances its capabilities, security, and user experience. </source>
<target state="translated"> Ghostfolio est un logiciel open source (OSS), offrant une alternative économique, <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> le rendant particulièrement adaptée aux personnes disposant d&apos;un budget serré, telles que celles qui <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;../en/blog/2023/07/exploring-the-path-to-fire&quot; &gt;"/>cherchent à atteindre le mouvement Financial Independence, Retire Early (FIRE)<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>. En s&apos;appuyant sur les efforts collectifs d&apos;une communauté de développeurs et de passionnés de finances personnelles, Ghostfolio améliore continuellement ses fonctionnalités, sa sécurité et son expérience utilisateur. </target>
<target state="translated"> Ghostfolio est un logiciel open source (OSS), offrant une alternative économique, <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> le rendant particulièrement adaptée aux personnes disposant dun budget serré, telles que celles qui <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;../en/blog/2023/07/exploring-the-path-to-fire&quot; &gt;"/>cherchent à atteindre le mouvement Financial Independence, Retire Early (FIRE)<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>. En s’appuyant sur les efforts collectifs d’une communauté de développeurs et de passionnés de finances personnelles, Ghostfolio améliore continuellement ses fonctionnalités, sa sécurité et son expérience utilisateur. </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">32</context>
@ -5720,7 +5696,7 @@
</trans-unit>
<trans-unit id="986ed5a2e3edee8d10d65a7c087b226879ebaecc" datatype="html">
<source> Please note that the information provided in the Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table is based on our independent research and analysis. This website is not affiliated with <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot;&gt;"/>GitHub<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. </source>
<target state="translated"> Veuillez noter que les informations fournies dans le Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> via la table de comparaison se basent de nos recherches et analyses indépendantes. Ce site n&apos;est pas affilié à <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> ou tout autre produit mentionné dans la comparaison. Le paysage des outils de finances personnelles évoluant, il est essentiel de vérifier tout détail ou changement spécifique directement sur la page du produit concerné. Certaines données doivent être mises à jour ? Aidez-nous à maintenir les données exactes sur <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot;&gt;"/>GitHub<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. </target>
<target state="translated"> Veuillez noter que les informations fournies dans le Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> via la table de comparaison se basent de nos recherches et analyses indépendantes. Ce site nest pas affilié à <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> ou tout autre produit mentionné dans la comparaison. Le paysage des outils de finances personnelles évoluant, il est essentiel de vérifier tout détail ou changement spécifique directement sur la page du produit concerné. Certaines données doivent être mises à jour ? Aidez-nous à maintenir les données exactes sur <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot;&gt;"/>GitHub<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/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">311</context>
@ -5852,7 +5828,7 @@
</trans-unit>
<trans-unit id="5e848e3fe28ec248b20a7dfb7e874a379312c1f6" datatype="html">
<source>Revenue for lending out money</source>
<target state="translated">Revenue lié au prêt d&apos;argent</target>
<target state="translated">Revenue lié au prêt dargent</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html</context>
<context context-type="linenumber">49</context>
@ -6000,7 +5976,7 @@
</trans-unit>
<trans-unit id="cd206f0509271d9e611747bef0713c7df048d3af" datatype="html">
<source>No entries...</source>
<target state="translated">Pas d&apos;entrées ...</target>
<target state="translated">Pas dentrées ...</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/assistant/assistant.html</context>
<context context-type="linenumber">63</context>
@ -6012,7 +5988,7 @@
</trans-unit>
<trans-unit id="779aa6949e9d62c58ad44357d11a3157ef6780f5" datatype="html">
<source>Asset Profile</source>
<target state="translated">Profil d&apos;Actif</target>
<target state="translated">Profil dActif</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-jobs/admin-jobs.html</context>
<context context-type="linenumber">35</context>
@ -6020,7 +5996,7 @@
</trans-unit>
<trans-unit id="6786981261778452561" datatype="html">
<source>Do you really want to delete this asset profile?</source>
<target state="translated">Confirmez la suppressoion de ce profil d&apos;actif?</target>
<target state="translated">Confirmez la suppressoion de ce profil dactif?</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">37</context>
@ -6103,7 +6079,7 @@
<target state="translated">Extreme Peur</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6111,7 +6087,7 @@
<target state="translated">Extreme Cupidité</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6119,7 +6095,7 @@
<target state="translated">Neutre</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="7183719827884539616" datatype="html">
@ -6135,7 +6111,7 @@
<target state="translated">Confirmer la suppresion de ce message système?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="d762c43328624b5dd81f3c6a3023203ae9a7553f" datatype="html">
@ -6252,7 +6228,7 @@
</trans-unit>
<trans-unit id="2570446216260149991" datatype="html">
<source>Oops! Could not grant access.</source>
<target state="translated">Oops! Impossible d&apos;accorder l&apos;accès.</target>
<target state="translated">Oops! Impossible d’accorder l’accès.</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.component.ts</context>
<context context-type="linenumber">91</context>
@ -6268,7 +6244,7 @@
</trans-unit>
<trans-unit id="5570511897986600686" datatype="html">
<source>Job Queue</source>
<target state="translated">File d&apos;attente</target>
<target state="translated">File dattente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/admin/admin-page-routing.module.ts</context>
<context context-type="linenumber">25</context>
@ -6291,11 +6267,11 @@
<target state="translated">Investissement</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6307,7 +6283,7 @@
<target state="translated">Performance des Actifs en valeur absolue</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -6315,7 +6291,7 @@
<target state="translated"> Performance des Actifs </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6323,7 +6299,7 @@
<target state="translated">Performance des devises en valeur absolue</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6331,7 +6307,7 @@
<target state="translated"> Performance des devises </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6339,7 +6315,7 @@
<target state="translated"> Performance nette absolue </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6347,7 +6323,7 @@
<target state="translated"> Performance nette </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6412,7 +6388,7 @@
</trans-unit>
<trans-unit id="f42ea256db85ae2dba48b04a7bf0eb1614abac2f" datatype="html">
<source> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/>, based on your total assets of <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> and a withdrawal rate of 4%. </source>
<target state="translated"> Si vous prenez votre retraite aujourd&apos;hui, vous pourrez retirer <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> par an<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> ou <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> par mois<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/>, sur la base de vos actifs totaux de <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> et un taux de retrait de 4 %. </target>
<target state="translated"> Si vous prenez votre retraite aujourdhui, vous pourrez retirer <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> par an<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> ou <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> par mois<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/>, sur la base de vos actifs totaux de <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> et un taux de retrait de 4 %. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">67</context>
@ -6455,7 +6431,7 @@
<target state="translated">Collecter les données</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6576,7 +6552,7 @@
</trans-unit>
<trans-unit id="8236987838684066590" datatype="html">
<source>This action is not allowed.</source>
<target state="translated">Cette action n&apos;est pas autorisée.</target>
<target state="translated">Cette action nest pas autorisée.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/core/http-response.interceptor.ts</context>
<context context-type="linenumber">64</context>
@ -6627,7 +6603,7 @@
<target state="translated">Confirmer la suppresion de votre compte Ghostfolio ?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6672,10 +6648,10 @@
</trans-unit>
<trans-unit id="5724720497710437101" datatype="html">
<source>Oops! There was an error setting up biometric authentication.</source>
<target state="translated">Oops! Une erreur s&apos;est produite lors de la configuration de l&apos;authentification biométrique.</target>
<target state="translated">Oops! Une erreur s’est produite lors de la configuration de l’authentification biométrique.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6736,7 +6712,7 @@
</trans-unit>
<trans-unit id="8e82d0437ea637850bb6cb99332b72422c723aae" datatype="html">
<source> Would you like to <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>refine<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>personal investment strategy<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>? </source>
<target state="translated"> Souhaitez-vous <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>affiner<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> votre <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>stratégie d&apos;investissement personnelle<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>? </target>
<target state="translated"> Souhaitez-vous <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>affiner<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> votre <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>stratégie dinvestissement personnelle<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>? </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">211</context>
@ -6995,7 +6971,7 @@
<target state="translated">Etats-Unis</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7613,7 +7589,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7709,7 +7685,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7748,12 +7724,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7761,7 +7737,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7828,6 +7804,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

180
apps/client/src/locales/messages.it.xlf

@ -265,10 +265,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -299,11 +295,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -627,15 +619,7 @@
<target state="translated">Vuoi davvero eliminare questo buono?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Vuoi davvero eliminare questa valuta?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -643,7 +627,7 @@
<target state="translated">Vuoi davvero svuotare la cache?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -651,7 +635,7 @@
<target state="translated">Imposta il messaggio di sistema:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -698,14 +682,6 @@
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Tassi di cambio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Aggiungi valuta</target>
@ -719,7 +695,7 @@
<target state="translated">Messaggio di sistema</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -727,7 +703,7 @@
<target state="translated">Imposta messaggio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -735,7 +711,7 @@
<target state="translated">Modalità di sola lettura</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -743,7 +719,7 @@
<target state="translated">Buoni sconto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -751,7 +727,7 @@
<target state="translated">Aggiungi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -763,7 +739,7 @@
<target state="translated">Bilancio domestico</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -771,7 +747,7 @@
<target state="translated">Svuota la cache</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -779,7 +755,7 @@
<target state="translated">Vuoi davvero eliminare questo utente?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
@ -1047,7 +1023,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -1687,7 +1663,7 @@
<target state="translated">Vuoi davvero rimuovere questo metodo di accesso?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -2143,7 +2119,7 @@
<target state="translated">Cronologia degli investimenti</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -2151,7 +2127,7 @@
<target state="translated">In alto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -2159,7 +2135,7 @@
<target state="translated">In basso</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -2815,7 +2791,7 @@
<target state="translated">Mensile</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
@ -2843,7 +2819,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2855,7 +2831,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="4550487415324294802" datatype="html">
@ -2931,7 +2907,7 @@
<target state="translated">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -2979,7 +2955,7 @@
<target state="translated">Evoluzione del portafoglio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
@ -3299,7 +3275,7 @@
<target state="translated">Dividendi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -3311,7 +3287,7 @@
<target state="translated">Cronologia dei dividendi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="7608037008789240367" datatype="html">
@ -3327,7 +3303,7 @@
<target state="translated">Registrazione utente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="8763985977445247551" datatype="html">
@ -3415,7 +3391,7 @@
<target state="translated">Annuale</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="72640258012696878" datatype="html">
@ -3927,7 +3903,7 @@
<target state="translated">Elimina l’utente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="4239552960465242484" datatype="html">
@ -4163,7 +4139,7 @@
<target state="translated">Serie attuale</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4171,7 +4147,7 @@
<target state="translated">Serie più lunga</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="4845030128243887325" datatype="html">
@ -5813,7 +5789,7 @@
</trans-unit>
<trans-unit id="f9bca20021a037716a70b9ab5a189768141e5bcc" datatype="html">
<source>One-time fee, annual account fees</source>
<target state="translated">Commissione una tantum, commissioni annuali per l&apos;account</target>
<target state="translated">Commissione una tantum, commissioni annuali per laccount</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html</context>
<context context-type="linenumber">33</context>
@ -6013,7 +5989,7 @@
</trans-unit>
<trans-unit id="779aa6949e9d62c58ad44357d11a3157ef6780f5" datatype="html">
<source>Asset Profile</source>
<target state="translated">Profilo dell&apos;asset</target>
<target state="translated">Profilo dellasset</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-jobs/admin-jobs.html</context>
<context context-type="linenumber">35</context>
@ -6104,7 +6080,7 @@
<target state="translated">Paura estrema</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6112,7 +6088,7 @@
<target state="translated">Avidità estrema</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6120,7 +6096,7 @@
<target state="translated">Neutrale</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="7183719827884539616" datatype="html">
@ -6136,7 +6112,7 @@
<target state="translated">Confermi di voler cancellare questo messaggio di sistema?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="d762c43328624b5dd81f3c6a3023203ae9a7553f" datatype="html">
@ -6205,7 +6181,7 @@
</trans-unit>
<trans-unit id="4405333887341433096" datatype="html">
<source>The current market price is</source>
<target state="translated">L&apos;attuale prezzo di mercato è</target>
<target state="translated">Lattuale prezzo di mercato è</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">399</context>
@ -6253,7 +6229,7 @@
</trans-unit>
<trans-unit id="2570446216260149991" datatype="html">
<source>Oops! Could not grant access.</source>
<target state="translated">Ops! Impossibile abilitare l&apos;accesso.</target>
<target state="translated">Ops! Impossibile abilitare laccesso.</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.component.ts</context>
<context context-type="linenumber">91</context>
@ -6292,11 +6268,11 @@
<target state="translated">Investimento</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6305,18 +6281,18 @@
</trans-unit>
<trans-unit id="e19955db970092b9cde70be2cea163ab6adfac97" datatype="html">
<source>Absolute Asset Performance</source>
<target state="translated">Rendimento assoluto dell&apos;Asset</target>
<target state="translated">Rendimento assoluto dellAsset</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
<source> Asset Performance </source>
<target state="translated"> Rendimento dell&apos;Asset </target>
<target state="translated"> Rendimento dellAsset </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6324,7 +6300,7 @@
<target state="translated">Rendimento assoluto della Valuta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6332,7 +6308,7 @@
<target state="translated"> Rendimento della Valuta </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6340,7 +6316,7 @@
<target state="translated"> Rendimento assoluto della Valuta </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6348,7 +6324,7 @@
<target state="translated"> Rendimento Netto </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6413,7 +6389,7 @@
</trans-unit>
<trans-unit id="f42ea256db85ae2dba48b04a7bf0eb1614abac2f" datatype="html">
<source> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/>, based on your total assets of <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> and a withdrawal rate of 4%. </source>
<target state="translated"> Se andassi in pensione oggi, saresti in grado di prelevare <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> all&apos;anno<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> o <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> al mese<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/>, calcolato sul valore totale dei tuoi asset di <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> e un prelievo costante del 4%. </target>
<target state="translated"> Se andassi in pensione oggi, saresti in grado di prelevare <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> allanno<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> o <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/> al mese<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/>, calcolato sul valore totale dei tuoi asset di <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [isCurrency]=&quot;true&quot; [locale]=&quot;user?.settings?.locale&quot; [unit]=&quot;user?.settings?.baseCurrency&quot; [value]=&quot;fireWealth?.toNumber()&quot; /&gt;"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/> e un prelievo costante del 4%. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">67</context>
@ -6456,7 +6432,7 @@
<target state="translated">Raccolta Dati</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6513,7 +6489,7 @@
</trans-unit>
<trans-unit id="2998033970178753887" datatype="html">
<source>Oops! It looks like you’re making too many requests. Please slow down a bit.</source>
<target state="translated">Ops! Sembra tu stia facendo troppe richieste. Rallenta un po&apos; per favore.</target>
<target state="translated">Ops! Sembra tu stia facendo troppe richieste. Rallenta un po per favore.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/core/http-response.interceptor.ts</context>
<context context-type="linenumber">103</context>
@ -6628,7 +6604,7 @@
<target state="translated">Confermi di voler chiudere il tuo account Ghostfolio?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6641,7 +6617,7 @@
</trans-unit>
<trans-unit id="3c1ef66d62e3ecb5f661c8ffb89e1b1c46275684" datatype="html">
<source>Close Account</source>
<target state="translated">Chiudi l&apos;account</target>
<target state="translated">Chiudi laccount</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">283</context>
@ -6665,7 +6641,7 @@
</trans-unit>
<trans-unit id="8289b77182a57fbf7ebe3bfd506b85e3fdd9e537" datatype="html">
<source> Join now <x id="START_BLOCK_IF" equiv-text="@if (hasPermissionForDemo) {"/> or check out the example account <x id="CLOSE_BLOCK_IF" equiv-text="}"/></source>
<target state="translated"> Registrati adesso <x id="START_BLOCK_IF" equiv-text="@if (hasPermissionForDemo) {"/> o prova l&apos;account demo <x id="CLOSE_BLOCK_IF" equiv-text="}"/></target>
<target state="translated"> Registrati adesso <x id="START_BLOCK_IF" equiv-text="@if (hasPermissionForDemo) {"/> o prova laccount demo <x id="CLOSE_BLOCK_IF" equiv-text="}"/></target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">434</context>
@ -6673,10 +6649,10 @@
</trans-unit>
<trans-unit id="5724720497710437101" datatype="html">
<source>Oops! There was an error setting up biometric authentication.</source>
<target state="translated">Ops! C&apos;è stato un errore impostando l&apos;autenticazione biometrica.</target>
<target state="translated">Ops! C’è stato un errore impostando l’autenticazione biometrica.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6996,7 +6972,7 @@
<target state="translated">Stati Uniti</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7145,7 +7121,7 @@
</trans-unit>
<trans-unit id="5beadaafe995fa04343008b0ab57e579c9fc81b9" datatype="html">
<source>From the beginning</source>
<target state="translated">Dall&apos;inizio</target>
<target state="translated">Dallinizio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">60</context>
@ -7614,7 +7590,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7710,7 +7686,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7749,12 +7725,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7762,7 +7738,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7829,6 +7805,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

156
apps/client/src/locales/messages.nl.xlf

@ -264,10 +264,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -298,11 +294,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -626,15 +618,7 @@
<target state="translated">Wil je deze coupon echt verwijderen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Wil je deze valuta echt verwijderen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -642,7 +626,7 @@
<target state="translated">Wil je echt de cache legen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -650,7 +634,7 @@
<target state="translated">Stel je systeemboodschap in:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -697,14 +681,6 @@
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Wisselkoersen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Valuta toevoegen</target>
@ -718,7 +694,7 @@
<target state="translated">Systeembericht</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -726,7 +702,7 @@
<target state="translated">Bericht instellen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -734,7 +710,7 @@
<target state="translated">Alleen lezen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -742,7 +718,7 @@
<target state="translated">Coupons</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -750,7 +726,7 @@
<target state="translated">Toevoegen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -762,7 +738,7 @@
<target state="translated">Huishouding</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -770,7 +746,7 @@
<target state="translated">Cache legen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -778,7 +754,7 @@
<target state="translated">Wilt je deze gebruiker echt verwijderen?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
@ -1046,7 +1022,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -1686,7 +1662,7 @@
<target state="translated">Wil je deze aanmeldingsmethode echt verwijderen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -2142,7 +2118,7 @@
<target state="translated">Tijdlijn investeringen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -2150,7 +2126,7 @@
<target state="translated">Winnaars</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -2158,7 +2134,7 @@
<target state="translated">Verliezers</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -2814,7 +2790,7 @@
<target state="translated">Maandelijks</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
@ -2842,7 +2818,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2854,7 +2830,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="4550487415324294802" datatype="html">
@ -2930,7 +2906,7 @@
<target state="translated">Automatisch</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -2978,7 +2954,7 @@
<target state="translated">Waardeontwikkeling van portefeuille</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
@ -3298,7 +3274,7 @@
<target state="translated">Dividend</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -3310,7 +3286,7 @@
<target state="translated">Tijdlijn dividend</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="7608037008789240367" datatype="html">
@ -3326,7 +3302,7 @@
<target state="translated">Account aanmaken</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="8763985977445247551" datatype="html">
@ -3414,7 +3390,7 @@
<target state="translated">Jaarlijks</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="72640258012696878" datatype="html">
@ -3926,7 +3902,7 @@
<target state="translated">Gebruiker verwijderen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="4239552960465242484" datatype="html">
@ -4162,7 +4138,7 @@
<target state="translated">Huidige reeks</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4170,7 +4146,7 @@
<target state="translated">Langste reeks</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="4845030128243887325" datatype="html">
@ -6103,7 +6079,7 @@
<target state="new">Extreme Fear</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6111,7 +6087,7 @@
<target state="new">Extreme Greed</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6119,7 +6095,7 @@
<target state="new">Neutral</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="7183719827884539616" datatype="html">
@ -6135,7 +6111,7 @@
<target state="new">Do you really want to delete this system message?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="d762c43328624b5dd81f3c6a3023203ae9a7553f" datatype="html">
@ -6291,11 +6267,11 @@
<target state="new">Investment</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6307,7 +6283,7 @@
<target state="new">Absolute Asset Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -6315,7 +6291,7 @@
<target state="new"> Asset Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6323,7 +6299,7 @@
<target state="new">Absolute Currency Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6331,7 +6307,7 @@
<target state="new"> Currency Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6339,7 +6315,7 @@
<target state="new"> Absolute Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6347,7 +6323,7 @@
<target state="new"> Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6455,7 +6431,7 @@
<target state="new">Data Gathering</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6627,7 +6603,7 @@
<target state="new">Do you really want to close your Ghostfolio account?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6675,7 +6651,7 @@
<target state="new">Oops! There was an error setting up biometric authentication.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6995,7 +6971,7 @@
<target state="new">United States</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7613,7 +7589,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7709,7 +7685,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7748,12 +7724,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7761,7 +7737,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7828,6 +7804,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

156
apps/client/src/locales/messages.pl.xlf

@ -1113,10 +1113,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -1147,11 +1143,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -1791,15 +1783,7 @@
<target state="translated">Czy naprawdę chcesz usunąć ten kupon?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Czy naprawdę chcesz usunąć tę walutę?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="297546430113071258" datatype="html">
@ -1807,7 +1791,7 @@
<target state="translated">Czy naprawdę chcesz usunąć tę wiadomość systemową?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -1815,7 +1799,7 @@
<target state="translated">Czy naprawdę chcesz wyczyścić pamięć podręczną?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -1823,7 +1807,7 @@
<target state="translated">Proszę ustawić swoją wiadomość systemową:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="8fe73a4787b8068b2ba61f54ab7e0f9af2ea1fc9" datatype="html">
@ -1858,14 +1842,6 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Kursy Walut</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Dodaj Walutę</target>
@ -1879,7 +1855,7 @@
<target state="translated">Rejestracja Użytkownika</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -1887,7 +1863,7 @@
<target state="translated">Tryb Tylko do Odczytu</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -1895,7 +1871,7 @@
<target state="translated">Wiadomość Systemowa</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -1903,7 +1879,7 @@
<target state="translated">Ustaw Wiadomość</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -1911,7 +1887,7 @@
<target state="translated">Kupony</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -1919,7 +1895,7 @@
<target state="translated">Dodaj</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -1931,7 +1907,7 @@
<target state="translated">Konserwacja</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -1939,7 +1915,7 @@
<target state="translated">Wyczyszczenie pamięci podręcznej</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="e587f3aaad8881a0b7732fb3e86df8a4c91f25d2" datatype="html">
@ -2083,7 +2059,7 @@
<target state="translated">Czy na pewno chcesz usunąć tego użytkownika?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="a3db2898b85fed425f03294b839a98cef247a2dc" datatype="html">
@ -2131,7 +2107,7 @@
<target state="translated">Usuń Użytkownika</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
@ -2311,7 +2287,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -2331,7 +2307,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2343,7 +2319,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -3099,7 +3075,7 @@
<target state="translated">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -3107,7 +3083,7 @@
<target state="translated">Czy na pewno chcesz usunąć tą metode logowania?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="121cc5391cd2a5115bc2b3160379ee5b36cd7716" datatype="html">
@ -4663,7 +4639,7 @@
<target state="translated">Dywidenda</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -4683,7 +4659,7 @@
<target state="translated">Miesięcznie</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8036977202721714375" datatype="html">
@ -4691,7 +4667,7 @@
<target state="translated">Rocznie</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -4707,7 +4683,7 @@
<target state="translated">Największe wzrosty</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -4715,7 +4691,7 @@
<target state="translated">Największy spadek</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -4723,7 +4699,7 @@
<target state="translated">Rozwój portfela</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
@ -4731,7 +4707,7 @@
<target state="translated">Oś czasu inwestycji</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -4739,7 +4715,7 @@
<target state="translated">Obecna passa</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4747,7 +4723,7 @@
<target state="translated">Najdłuższa passa</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="6410cffb96159fcff46d91effc26df0e240bc0e3" datatype="html">
@ -4755,7 +4731,7 @@
<target state="translated">Oś czasu dywidend</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -6079,7 +6055,7 @@
<target state="translated">Skrajny Strach</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6087,7 +6063,7 @@
<target state="translated">Skrajna Zachłanność</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6095,7 +6071,7 @@
<target state="translated">Neutralny</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="3c33a66194384cf8c14e25170416767efa56fd98" datatype="html">
@ -6291,11 +6267,11 @@
<target state="translated">Inwestycje</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6307,7 +6283,7 @@
<target state="translated">Łączny wynik aktywów</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -6315,7 +6291,7 @@
<target state="translated"> Wyniki aktywów </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6323,7 +6299,7 @@
<target state="translated">Łączny wynik walut</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6331,7 +6307,7 @@
<target state="translated"> Wynik walut </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6339,7 +6315,7 @@
<target state="translated"> Łączna wartość netto </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6347,7 +6323,7 @@
<target state="translated"> Wynik netto </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6455,7 +6431,7 @@
<target state="translated">Gromadzenie Danych</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6627,7 +6603,7 @@
<target state="translated">Czy na pewno chcesz zamknąć swoje konto Ghostfolio?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6675,7 +6651,7 @@
<target state="translated">Ups! Wystąpił błąd podczas konfigurowania uwierzytelniania biometrycznego.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6995,7 +6971,7 @@
<target state="translated">Stany Zjednoczone</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7613,7 +7589,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7709,7 +7685,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7748,12 +7724,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7761,7 +7737,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7828,6 +7804,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

156
apps/client/src/locales/messages.pt.xlf

@ -320,10 +320,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -354,11 +350,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -786,15 +778,7 @@
<target state="translated">Deseja realmente eliminar este cupão?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Deseja realmente excluir esta moeda?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -802,7 +786,7 @@
<target state="translated">Deseja realmente limpar a cache?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -810,7 +794,7 @@
<target state="translated">Por favor, defina a sua mensagem do sistema:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -829,14 +813,6 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Taxas de Câmbio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Adicionar Moeda</target>
@ -850,7 +826,7 @@
<target state="translated">Mensagem de Sistema</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -858,7 +834,7 @@
<target state="translated">Definir Mensagem</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -866,7 +842,7 @@
<target state="translated">Modo Somente Leitura</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -874,7 +850,7 @@
<target state="translated">Cupões</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -882,7 +858,7 @@
<target state="translated">Adicionar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -894,7 +870,7 @@
<target state="translated">Manutenção</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -902,7 +878,7 @@
<target state="translated">Limpar Cache</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -910,7 +886,7 @@
<target state="translated">Deseja realmente excluir este utilizador?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
@ -1230,7 +1206,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -1250,7 +1226,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -1262,7 +1238,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -1886,7 +1862,7 @@
<target state="translated">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="1257540657265073416" datatype="html">
@ -1926,7 +1902,7 @@
<target state="translated">Deseja realmente remover este método de início de sessão?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -2646,7 +2622,7 @@
<target state="translated">Mensalmente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -2662,7 +2638,7 @@
<target state="translated">Topo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -2670,7 +2646,7 @@
<target state="translated">Fundo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -2678,7 +2654,7 @@
<target state="translated">Evolução do Portefólio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
@ -2686,7 +2662,7 @@
<target state="translated">Cronograma de Investimento</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -3258,7 +3234,7 @@
<target state="translated">Registo do Utilizador</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="ec2d3a89b366d1ca80be056e9e71f0165ae75c7b" datatype="html">
@ -3366,7 +3342,7 @@
<target state="translated">Dividendos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -3378,7 +3354,7 @@
<target state="translated">Cronograma de Dividendos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="7608037008789240367" datatype="html">
@ -3414,7 +3390,7 @@
<target state="translated">Anualmente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="72640258012696878" datatype="html">
@ -3926,7 +3902,7 @@
<target state="translated">Apagar Utilizador</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="4239552960465242484" datatype="html">
@ -4162,7 +4138,7 @@
<target state="translated">Série Atual</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4170,7 +4146,7 @@
<target state="translated">Série mais Longa</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="4845030128243887325" datatype="html">
@ -6103,7 +6079,7 @@
<target state="new">Extreme Fear</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6111,7 +6087,7 @@
<target state="new">Extreme Greed</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6119,7 +6095,7 @@
<target state="new">Neutral</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="7183719827884539616" datatype="html">
@ -6135,7 +6111,7 @@
<target state="new">Do you really want to delete this system message?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="d762c43328624b5dd81f3c6a3023203ae9a7553f" datatype="html">
@ -6291,11 +6267,11 @@
<target state="new">Investment</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6307,7 +6283,7 @@
<target state="new">Absolute Asset Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -6315,7 +6291,7 @@
<target state="new"> Asset Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6323,7 +6299,7 @@
<target state="new">Absolute Currency Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6331,7 +6307,7 @@
<target state="new"> Currency Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6339,7 +6315,7 @@
<target state="new"> Absolute Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6347,7 +6323,7 @@
<target state="new"> Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6455,7 +6431,7 @@
<target state="new">Data Gathering</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6627,7 +6603,7 @@
<target state="new">Do you really want to close your Ghostfolio account?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6675,7 +6651,7 @@
<target state="new">Oops! There was an error setting up biometric authentication.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6995,7 +6971,7 @@
<target state="new">United States</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7613,7 +7589,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7709,7 +7685,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7748,12 +7724,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7761,7 +7737,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7828,6 +7804,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

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

@ -1073,10 +1073,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -1107,11 +1103,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -1695,15 +1687,7 @@
<target state="translated">Önbelleği temizlemeyi gerçekten istiyor musunuz?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Bu para birimini silmeyi gerçekten istiyor musunuz?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -1711,7 +1695,7 @@
<target state="translated">Önbelleği temizlemeyi gerçekten istiyor musunuz</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -1719,7 +1703,7 @@
<target state="translated">Lütfen sistem mesajınızı belirleyin:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -1746,14 +1730,6 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<target state="translated">Döviz Kurları</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">Para Birimi Ekle</target>
@ -1783,7 +1759,7 @@
<target state="translated">Kullanıcı Kaydı</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -1791,7 +1767,7 @@
<target state="translated">Salt okunur mod</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -1799,7 +1775,7 @@
<target state="translated">Sistem Mesajı</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -1807,7 +1783,7 @@
<target state="translated">Mesaj Belirle</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -1815,7 +1791,7 @@
<target state="translated">Kupon</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -1823,7 +1799,7 @@
<target state="translated">Ekle</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -1835,7 +1811,7 @@
<target state="translated">Genel Ayarlar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -1843,7 +1819,7 @@
<target state="translated">Önbelleği temizle</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="e587f3aaad8881a0b7732fb3e86df8a4c91f25d2" datatype="html">
@ -1939,7 +1915,7 @@
<target state="translated">Bu kullanıcıyı silmeyi gerçekten istiyor musunu?</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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="e08a77594f3d89311cdf6da5090044270909c194" datatype="html">
@ -1991,7 +1967,7 @@
<target state="translated">Kullanıcıyı Sil</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
@ -2159,7 +2135,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -2179,7 +2155,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2191,7 +2167,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -3580,7 +3556,7 @@
</trans-unit>
<trans-unit id="ae508ae33a02ae69247d9e4d84e98b610209ef3b" datatype="html">
<source> What our <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>users<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> are saying </source>
<target state="new"> What our <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>users<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> are saying </target>
<target state="translated"><x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Kullanıcılarımızın<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> görüşleri </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">327</context>
@ -3644,7 +3620,7 @@
</trans-unit>
<trans-unit id="80abe38d82bca467f47bbb65f821a115cf9dfdc1" datatype="html">
<source> Are <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>you<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> ready? </source>
<target state="new"> Are <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>you<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> ready? </target>
<target state="translated"><x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Hazır<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> mısınız? </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">431</context>
@ -4143,7 +4119,7 @@
<target state="translated">Temettü</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -4163,7 +4139,7 @@
<target state="translated">Aylık</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8036977202721714375" datatype="html">
@ -4171,7 +4147,7 @@
<target state="translated">Yıllık</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -4187,7 +4163,7 @@
<target state="translated">Üst</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -4195,7 +4171,7 @@
<target state="translated">Alt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -4203,7 +4179,7 @@
<target state="translated">Portföyün Gelişimi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
@ -4211,7 +4187,7 @@
<target state="translated">Yatırım Zaman Çizelgesi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -4219,7 +4195,7 @@
<target state="translated">Güncel Seri</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4227,7 +4203,7 @@
<target state="translated">En Uzun Seri</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="6410cffb96159fcff46d91effc26df0e240bc0e3" datatype="html">
@ -4235,7 +4211,7 @@
<target state="translated">Temettü Zaman Çizelgesi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -4919,7 +4895,7 @@
<target state="translated">Otomatik</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="1257540657265073416" datatype="html">
@ -4959,7 +4935,7 @@
<target state="translated">Bu giriş yöntemini kaldırmayı gerçekten istiyor musunuz?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="3c33a66194384cf8c14e25170416767efa56fd98" datatype="html">
@ -6103,7 +6079,7 @@
<target state="translated">Aşırı Korku</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6111,7 +6087,7 @@
<target state="translated">Aşırı Açgözlülük</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6119,7 +6095,7 @@
<target state="translated">Nötr</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="7183719827884539616" datatype="html">
@ -6135,7 +6111,7 @@
<target state="translated">Bu sistem mesajını silmeyi gerçekten istiyor musunuz?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="d762c43328624b5dd81f3c6a3023203ae9a7553f" datatype="html">
@ -6228,7 +6204,7 @@
</trans-unit>
<trans-unit id="d1b8990332af18f1c5159a6061ca889bcbb28432" datatype="html">
<source>Permission</source>
<target state="new">Permission</target>
<target state="translated">Yetki</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
<context context-type="linenumber">18</context>
@ -6240,7 +6216,7 @@
</trans-unit>
<trans-unit id="97bad3b5e318e5c7c755cd99062f2973efcf17e5" datatype="html">
<source>Restricted view</source>
<target state="new">Restricted view</target>
<target state="translated">Kısıtlı görünüm</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
<context context-type="linenumber">26</context>
@ -6252,7 +6228,7 @@
</trans-unit>
<trans-unit id="2570446216260149991" datatype="html">
<source>Oops! Could not grant access.</source>
<target state="new">Oops! Could not grant access.</target>
<target state="translated">Hay Allah! Erişim izni verilemedi.</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.component.ts</context>
<context context-type="linenumber">91</context>
@ -6260,7 +6236,7 @@
</trans-unit>
<trans-unit id="ddd8a4986d2d1717a274a5a0fbed04988a819e69" datatype="html">
<source>Private</source>
<target state="new">Private</target>
<target state="translated">Özel</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">24</context>
@ -6268,7 +6244,7 @@
</trans-unit>
<trans-unit id="5570511897986600686" datatype="html">
<source>Job Queue</source>
<target state="new">Job Queue</target>
<target state="translated">İş Kuyruğu</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/admin/admin-page-routing.module.ts</context>
<context context-type="linenumber">25</context>
@ -6288,14 +6264,14 @@
</trans-unit>
<trans-unit id="8580549503047096056" datatype="html">
<source>Investment</source>
<target state="new">Investment</target>
<target state="translated">Yatırım</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6304,10 +6280,10 @@
</trans-unit>
<trans-unit id="e19955db970092b9cde70be2cea163ab6adfac97" datatype="html">
<source>Absolute Asset Performance</source>
<target state="new">Absolute Asset Performance</target>
<target state="translated">Mutlak Varlık Performansı</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -6315,7 +6291,7 @@
<target state="new"> Asset Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -6323,7 +6299,7 @@
<target state="new">Absolute Currency Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6331,7 +6307,7 @@
<target state="new"> Currency Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6339,7 +6315,7 @@
<target state="new"> Absolute Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6347,7 +6323,7 @@
<target state="new"> Net Performance </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="3105754554141014845" datatype="html">
@ -6455,7 +6431,7 @@
<target state="new">Data Gathering</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6627,7 +6603,7 @@
<target state="new">Do you really want to close your Ghostfolio account?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6664,7 +6640,7 @@
</trans-unit>
<trans-unit id="8289b77182a57fbf7ebe3bfd506b85e3fdd9e537" datatype="html">
<source> Join now <x id="START_BLOCK_IF" equiv-text="@if (hasPermissionForDemo) {"/> or check out the example account <x id="CLOSE_BLOCK_IF" equiv-text="}"/></source>
<target state="new"> Join now <x id="START_BLOCK_IF" equiv-text="@if (hasPermissionForDemo) {"/> or check out the example account <x id="CLOSE_BLOCK_IF" equiv-text="}"/></target>
<target state="translated"> Hemen katıl <x id="START_BLOCK_IF" equiv-text="@if (hasPermissionForDemo) {"/> ya da örnek hesabı incele <x id="CLOSE_BLOCK_IF" equiv-text="}"/></target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">434</context>
@ -6675,7 +6651,7 @@
<target state="new">Oops! There was an error setting up biometric authentication.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6995,7 +6971,7 @@
<target state="new">United States</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7152,7 +7128,7 @@
</trans-unit>
<trans-unit id="f7ed8f2e1ac78c5a63741ae684779bcf7a99ab16" datatype="html">
<source>Oops! Invalid currency.</source>
<target state="new">Oops! Invalid currency.</target>
<target state="translated">Hay Allah! Geçersiz para birimi.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html</context>
<context context-type="linenumber">49</context>
@ -7160,7 +7136,7 @@
</trans-unit>
<trans-unit id="f1cc4a59110dd72517210565f76118df74336fec" datatype="html">
<source>This page has been archived.</source>
<target state="new">This page has been archived.</target>
<target state="translated">Bu sayfa arşivlendi.</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">14</context>
@ -7168,7 +7144,7 @@
</trans-unit>
<trans-unit id="ea66ce0bb1cb1dcee2bcb86a8876c5f2c2fa65f6" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is Open Source Software</target>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/>, Açık Kaynak Kodlu Yazılımdır</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">139</context>
@ -7176,7 +7152,7 @@
</trans-unit>
<trans-unit id="aa945d3772281b66851cc8b86d6de9726e65db70" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is not Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is not Open Source Software</target>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/>, Açık Kaynak Kodlu Yazılımdır</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">146</context>
@ -7184,7 +7160,7 @@
</trans-unit>
<trans-unit id="942e46b94b9d9662c3c3b7b5e7f9005c7b9feab7" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is Open Source Software</target>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/>, Açık Kaynak Kodlu Yazılımdır</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">156</context>
@ -7192,7 +7168,7 @@
</trans-unit>
<trans-unit id="08beed5100360c242c0aec92e8706d92f0cb70f3" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is not Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is not Open Source Software</target>
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/>, Açık Kaynak Kodlu Yazılım değildir</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">163</context>
@ -7602,7 +7578,7 @@
</trans-unit>
<trans-unit id="4068738931505527681" datatype="html">
<source>Please enter your Ghostfolio API key.</source>
<target state="new">Please enter your Ghostfolio API key.</target>
<target state="translated">Lütfen Ghostfolio API anahtarınızı girin.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts</context>
<context context-type="linenumber">57</context>
@ -7610,15 +7586,15 @@
</trans-unit>
<trans-unit id="7826234236931647519" datatype="html">
<source>AI prompt has been copied to the clipboard</source>
<target state="new">AI prompt has been copied to the clipboard</target>
<target state="translated">Yapay zeka istemi panoya kopyalandı</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
<source>Link has been copied to the clipboard</source>
<target state="new">Link has been copied to the clipboard</target>
<target state="translated">Bağlantı panoya kopyalandı</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.ts</context>
<context context-type="linenumber">65</context>
@ -7626,7 +7602,7 @@
</trans-unit>
<trans-unit id="4499ce8c46ad55564b23a42ed752e72984c0248f" datatype="html">
<source>Early Access</source>
<target state="new">Early Access</target>
<target state="translated">Erken Erişim</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context>
<context context-type="linenumber">16</context>
@ -7690,7 +7666,7 @@
</trans-unit>
<trans-unit id="8635324470284879211" datatype="html">
<source>end of day</source>
<target state="new">end of day</target>
<target state="translated">gün sonu</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">93</context>
@ -7698,7 +7674,7 @@
</trans-unit>
<trans-unit id="4547068148181074902" datatype="html">
<source>real-time</source>
<target state="new">real-time</target>
<target state="translated">gerçek zamanlı</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">97</context>
@ -7706,15 +7682,15 @@
</trans-unit>
<trans-unit id="7109040016560023658" datatype="html">
<source>Open Duck.ai</source>
<target state="new">Open Duck.ai</target>
<target state="translated">Duck.ai’yi aç</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
<source>Create</source>
<target state="new">Create</target>
<target state="translated">Oluştur</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/tags-selector/tags-selector.component.html</context>
<context context-type="linenumber">50</context>
@ -7722,7 +7698,7 @@
</trans-unit>
<trans-unit id="cdcd7c871f3bc0326ee77e5aea82af1ef26f46f2" datatype="html">
<source>Market Data</source>
<target state="new">Market Data</target>
<target state="translated">Piyasa Verileri</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">374</context>
@ -7730,7 +7706,7 @@
</trans-unit>
<trans-unit id="1230154438678955604" datatype="html">
<source>Change</source>
<target state="new">Change</target>
<target state="translated">Değişim</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/treemap-chart/treemap-chart.component.ts</context>
<context context-type="linenumber">365</context>
@ -7738,7 +7714,7 @@
</trans-unit>
<trans-unit id="1322586333669103999" datatype="html">
<source>Performance</source>
<target state="new">Performance</target>
<target state="translated">Performans</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/treemap-chart/treemap-chart.component.ts</context>
<context context-type="linenumber">365</context>
@ -7748,25 +7724,25 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<target state="translated">Yapay zeka istemi için portföy verilerini panoya kopyalayın</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
<source>Copy AI prompt to clipboard for analysis</source>
<target state="new">Copy AI prompt to clipboard for analysis</target>
<target state="translated">Yapay zeka istemini analiz için panoya kopyala</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
<source>Armenia</source>
<target state="new">Armenia</target>
<target state="translated">Ermenistan</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">73</context>
@ -7774,7 +7750,7 @@
</trans-unit>
<trans-unit id="7899437916897426237" datatype="html">
<source>British Virgin Islands</source>
<target state="new">British Virgin Islands</target>
<target state="translated">Britanya Virjin Adaları</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">77</context>
@ -7782,7 +7758,7 @@
</trans-unit>
<trans-unit id="4830118002486243553" datatype="html">
<source>Singapore</source>
<target state="new">Singapore</target>
<target state="translated">Singapur</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">91</context>
@ -7790,7 +7766,7 @@
</trans-unit>
<trans-unit id="e9048704780ed5bb3fc1af4f94d4fc5fdeb72cab" datatype="html">
<source>Terms and Conditions</source>
<target state="new">Terms and Conditions</target>
<target state="translated">Hükümler ve Koşullar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html</context>
<context context-type="linenumber">10</context>
@ -7798,7 +7774,7 @@
</trans-unit>
<trans-unit id="4051385e7211aebdb652666927a0564de3e74fd0" datatype="html">
<source>Please keep your security token safe. If you lose it, you will not be able to recover your account.</source>
<target state="new">Please keep your security token safe. If you lose it, you will not be able to recover your account.</target>
<target state="translated">Lütfen güvenlik tokenınızı güvende tutun. Kaybetmeniz halinde hesabınızı kurtarmanız mümkün olmayacaktır.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html</context>
<context context-type="linenumber">13</context>
@ -7806,7 +7782,7 @@
</trans-unit>
<trans-unit id="0c165378eae03c8bd376d2819d94b108d9929c64" datatype="html">
<source>I understand that if I lose my security token, I cannot recover my account.</source>
<target state="new">I understand that if I lose my security token, I cannot recover my account.</target>
<target state="translated">Güvenlik belirtecimi kaybedersem hesabımı kurtaramayacağımı anlıyorum.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html</context>
<context context-type="linenumber">23</context>
@ -7814,7 +7790,7 @@
</trans-unit>
<trans-unit id="ac10a3d9b59575640797c1a8e6aea642cf5d5e77" datatype="html">
<source>Continue</source>
<target state="new">Continue</target>
<target state="translated">Devam et</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html</context>
<context context-type="linenumber">38</context>
@ -7822,12 +7798,44 @@
</trans-unit>
<trans-unit id="43a04e6b986ac8b5184330fdcc4235867d48bcf7" datatype="html">
<source>Here is your security token. It is only visible once, please store and keep it in a safe place.</source>
<target state="new">Here is your security token. It is only visible once, please store and keep it in a safe place.</target>
<target state="translated">İşte güvenlik belirteciniz. Yalnızca bir kez görülebilir, lütfen saklayın ve güvenli bir yerde muhafaza edin.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html</context>
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

162
apps/client/src/locales/messages.uk.xlf

@ -1201,10 +1201,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -1235,11 +1231,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -1963,15 +1955,7 @@
<target state="translated">Ви дійсно хочете видалити цей купон?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">Ви дійсно хочете видалити цю валюту?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="297546430113071258" datatype="html">
@ -1979,7 +1963,7 @@
<target state="translated">Ви дійсно хочете видалити це системне повідомлення?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -1987,7 +1971,7 @@
<target state="translated">Ви дійсно хочете очистити кеш?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -1995,7 +1979,7 @@
<target state="translated">Будь ласка, встановіть ваше системне повідомлення:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="8fe73a4787b8068b2ba61f54ab7e0f9af2ea1fc9" datatype="html">
@ -2030,20 +2014,12 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<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">34</context>
</context-group>
</trans-unit>
<trans-unit id="62f17fd50522539fd4c85854828db9d2e1c5330f" datatype="html">
<source>User Signup</source>
<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">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -2051,7 +2027,7 @@
<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">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="4f986b5ab20fe31ca54d7345a73b6b2402ddd350" datatype="html">
@ -2059,7 +2035,7 @@
<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">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -2067,7 +2043,7 @@
<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">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -2075,7 +2051,7 @@
<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">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -2083,7 +2059,7 @@
<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">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -2091,7 +2067,7 @@
<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">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -2103,7 +2079,7 @@
<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">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -2111,7 +2087,7 @@
<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">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="e587f3aaad8881a0b7732fb3e86df8a4c91f25d2" datatype="html">
@ -2371,7 +2347,7 @@
<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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="a3db2898b85fed425f03294b839a98cef247a2dc" datatype="html">
@ -2427,7 +2403,7 @@
<target state="translated">Видалити користувача</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
@ -2619,7 +2595,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="76897e07c5670ce3b7710cc10c5e1c08b5f6a83a" datatype="html">
@ -2803,7 +2779,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2815,7 +2791,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -3116,7 +3092,7 @@
</trans-unit>
<trans-unit id="0b1e2c97e139808a34bd77b7da3504ece6c570cb" datatype="html">
<source>Liabilities</source>
<target state="translated">Зобов&apos;язання</target>
<target state="translated">Зобовязання</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">255</context>
@ -3615,7 +3591,7 @@
<target state="translated">Автоматичний</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="4941836956820527118" datatype="html">
@ -3623,7 +3599,7 @@
<target state="translated">Ви дійсно хочете закрити ваш обліковий запис Ghostfolio?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -3631,7 +3607,7 @@
<target state="translated">Ви дійсно хочете вилучити цей спосіб входу?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="5724720497710437101" datatype="html">
@ -3639,7 +3615,7 @@
<target state="translated">Упс! Виникла помилка під час налаштування біометричної автентифікації.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="121cc5391cd2a5115bc2b3160379ee5b36cd7716" datatype="html">
@ -5339,7 +5315,7 @@
<target state="translated">Дивіденди</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -5351,11 +5327,11 @@
<target state="translated">Інвестиції</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -5367,7 +5343,7 @@
<target state="translated">Щомісячно</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8036977202721714375" datatype="html">
@ -5375,7 +5351,7 @@
<target state="translated">Щорічно</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -5391,7 +5367,7 @@
<target state="translated">Абсолютна прибутковість активів</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="c726a56ba67c6c788e3759983dd8a1671d8cc886" datatype="html">
@ -5399,7 +5375,7 @@
<target state="translated"> Прибутковість активів </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="8ce52b52483f502dd23ed290357a17307c60280c" datatype="html">
@ -5407,7 +5383,7 @@
<target state="translated">Абсолютна прибутковість валюти</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -5415,7 +5391,7 @@
<target state="translated"> Прибутковість валюти </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -5423,7 +5399,7 @@
<target state="translated"> Абсолютна чиста прибутковість </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -5431,7 +5407,7 @@
<target state="translated"> Чиста прибутковість </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -5439,7 +5415,7 @@
<target state="translated">Топ</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -5447,7 +5423,7 @@
<target state="translated">Низ</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -5455,7 +5431,7 @@
<target state="translated">Еволюція портфеля</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
@ -5463,7 +5439,7 @@
<target state="translated">Інвестиційний графік</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -5471,7 +5447,7 @@
<target state="translated">Поточна серія</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -5479,7 +5455,7 @@
<target state="translated">Найдовша серія</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="6410cffb96159fcff46d91effc26df0e240bc0e3" datatype="html">
@ -5487,7 +5463,7 @@
<target state="translated">Графік дивідендів</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -6466,7 +6442,7 @@
</trans-unit>
<trans-unit id="986ed5a2e3edee8d10d65a7c087b226879ebaecc" datatype="html">
<source> Please note that the information provided in the Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table is based on our independent research and analysis. This website is not affiliated with <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot;&gt;"/>GitHub<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. </source>
<target state="translated"> Зазначаємо, що інформація, надана в порівняльній таблиці Ghostfolio проти <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> базується на нашому незалежному дослідженні та аналізі. Цей веб-сайт не пов&apos;язаний з <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> або будь-яким іншим продуктом, згаданим у порівнянні. Оскільки ландшафт інструментів особистих фінансів еволюціонує, важливо перевіряти будь-які конкретні деталі або зміни безпосередньо на сторінці відповідного продукту. Потрібно оновити дані? Допоможіть нам підтримувати точні дані на <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot;&gt;"/> GitHub<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. </target>
<target state="translated"> Зазначаємо, що інформація, надана в порівняльній таблиці Ghostfolio проти <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> базується на нашому незалежному дослідженні та аналізі. Цей веб-сайт не повязаний з <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> або будь-яким іншим продуктом, згаданим у порівнянні. Оскільки ландшафт інструментів особистих фінансів еволюціонує, важливо перевіряти будь-які конкретні деталі або зміни безпосередньо на сторінці відповідного продукту. Потрібно оновити дані? Допоможіть нам підтримувати точні дані на <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://github.com/ghostfolio/ghostfolio&quot;&gt;"/> GitHub<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/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">311</context>
@ -7206,7 +7182,7 @@
</trans-unit>
<trans-unit id="4230401090765872563" datatype="html">
<source>Liability</source>
<target state="translated">Зобов&apos;язання</target>
<target state="translated">Зобовязання</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">40</context>
@ -7529,7 +7505,7 @@
<target state="translated">Сполучені Штати</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1189482335778578193" datatype="html">
@ -7537,7 +7513,7 @@
<target state="translated">Екстремальний страх</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -7545,7 +7521,7 @@
<target state="translated">Екстремальна жадібність</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -7553,7 +7529,7 @@
<target state="translated">Нейтрально</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="258c041e93862316871096965e2d70579282fb1a" datatype="html">
@ -7621,7 +7597,7 @@
<target state="translated">Запит AI скопійовано в буфер обміну</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="4499ce8c46ad55564b23a42ed752e72984c0248f" datatype="html">
@ -7709,7 +7685,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7748,12 +7724,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7761,7 +7737,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7828,6 +7804,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

150
apps/client/src/locales/messages.xlf

@ -1081,10 +1081,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -1114,11 +1110,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -1708,35 +1700,28 @@
<source>Do you really want to delete this coupon?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="297546430113071258" datatype="html">
<source>Do you really want to delete this system message?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
<source>Do you really want to flush the cache?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
<source>Please set your system message:</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="8fe73a4787b8068b2ba61f54ab7e0f9af2ea1fc9" datatype="html">
@ -1767,13 +1752,6 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<context-group purpose="location">
@ -1785,42 +1763,42 @@
<source>User Signup</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
<source>Read-only Mode</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
<source>System Message</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
<source>Set Message</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
<source>Coupons</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
<source>Add</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -1831,14 +1809,14 @@
<source>Housekeeping</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
<source>Flush Cache</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="e587f3aaad8881a0b7732fb3e86df8a4c91f25d2" datatype="html">
@ -1969,7 +1947,7 @@
<source>Do you really want to delete this user?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.component.ts</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="a3db2898b85fed425f03294b839a98cef247a2dc" datatype="html">
@ -2011,7 +1989,7 @@
<source>Delete User</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
@ -2174,7 +2152,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -2192,7 +2170,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2203,7 +2181,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -2886,14 +2864,14 @@
<source>Auto</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
<source>Do you really want to remove this sign in method?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="121cc5391cd2a5115bc2b3160379ee5b36cd7716" datatype="html">
@ -4284,7 +4262,7 @@
<source>Dividend</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -4302,14 +4280,14 @@
<source>Monthly</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8036977202721714375" datatype="html">
<source>Yearly</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -4323,49 +4301,49 @@
<source>Top</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
<source>Bottom</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
<source>Portfolio Evolution</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
<source>Investment Timeline</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
<source>Current Streak</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
<source>Longest Streak</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="6410cffb96159fcff46d91effc26df0e240bc0e3" datatype="html">
<source>Dividend Timeline</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -5588,21 +5566,21 @@
<source>Extreme Fear</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
<source>Extreme Greed</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
<source>Neutral</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="3c33a66194384cf8c14e25170416767efa56fd98" datatype="html">
@ -5727,32 +5705,32 @@
<source>Absolute Currency Performance</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
<source> Absolute Net Performance </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="e19955db970092b9cde70be2cea163ab6adfac97" datatype="html">
<source>Absolute Asset Performance</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="8580549503047096056" datatype="html">
<source>Investment</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -5763,21 +5741,21 @@
<source> Asset Performance </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
<source> Net Performance </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
<source> Currency Performance </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="2593751087640318641" datatype="html">
@ -5901,7 +5879,7 @@
<source>Data Gathering</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6031,7 +6009,7 @@
<source>Do you really want to close your Ghostfolio account?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6066,7 +6044,7 @@
<source>Oops! There was an error setting up biometric authentication.</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6276,7 +6254,7 @@
<source>United States</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="647668541461749965" datatype="html">
@ -6889,7 +6867,7 @@
<source>AI prompt has been copied to the clipboard</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -6973,7 +6951,7 @@
<source>Open Duck.ai</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7012,7 +6990,7 @@
<source>Copy AI prompt to clipboard for analysis</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="4830118002486243553" datatype="html">
@ -7036,11 +7014,11 @@
<context context-type="linenumber">77</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="0c165378eae03c8bd376d2819d94b108d9929c64" datatype="html">
@ -7078,6 +7056,34 @@
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.component.ts</context>
<context context-type="linenumber">168</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.component.ts</context>
<context context-type="linenumber">163</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

156
apps/client/src/locales/messages.zh.xlf

@ -1122,10 +1122,6 @@
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.html</context>
<context context-type="linenumber">231</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
<context context-type="linenumber">92</context>
@ -1156,11 +1152,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">129</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-platform/admin-platform.component.html</context>
@ -1800,15 +1792,7 @@
<target state="translated">您确实要删除此优惠券吗?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1110981355132746478" datatype="html">
<source>Do you really want to delete this currency?</source>
<target state="translated">您真的要删除该货币吗?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">150</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="297546430113071258" datatype="html">
@ -1816,7 +1800,7 @@
<target state="translated">您真的要删除这条系统消息吗?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">163</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="6470890277760887814" datatype="html">
@ -1824,7 +1808,7 @@
<target state="translated">您真的要刷新缓存吗?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2712770700065625080" datatype="html">
@ -1832,7 +1816,7 @@
<target state="translated">请设置您的系统消息:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="8fe73a4787b8068b2ba61f54ab7e0f9af2ea1fc9" datatype="html">
@ -1867,14 +1851,6 @@
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<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">34</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<target state="translated">添加货币</target>
@ -1888,7 +1864,7 @@
<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">101</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -1896,7 +1872,7 @@
<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">115</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -1904,7 +1880,7 @@
<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">139</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -1912,7 +1888,7 @@
<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">161</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -1920,7 +1896,7 @@
<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">169</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -1928,7 +1904,7 @@
<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">229</context>
<context context-type="linenumber">162</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/account-balances/account-balances.component.html</context>
@ -1940,7 +1916,7 @@
<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">237</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -1948,7 +1924,7 @@
<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">241</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="e587f3aaad8881a0b7732fb3e86df8a4c91f25d2" datatype="html">
@ -2092,7 +2068,7 @@
<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">139</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="a3db2898b85fed425f03294b839a98cef247a2dc" datatype="html">
@ -2140,7 +2116,7 @@
<target state="translated">删除用户</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">260</context>
</context-group>
</trans-unit>
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
@ -2320,7 +2296,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">160</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="ec8b93e2ecc776c8dc2e43a791b6974612a90148" datatype="html">
@ -2340,7 +2316,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">101</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="6844699413925472826" datatype="html">
@ -2352,7 +2328,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit id="ce718ababbce63d776cf8b1f91412beb4c0a6e04" datatype="html">
@ -3108,7 +3084,7 @@
<target state="translated">自动</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -3116,7 +3092,7 @@
<target state="translated">您确实要删除此登录方法吗?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="121cc5391cd2a5115bc2b3160379ee5b36cd7716" datatype="html">
@ -4672,7 +4648,7 @@
<target state="translated">股息</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
@ -4692,7 +4668,7 @@
<target state="translated">每月</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="8036977202721714375" datatype="html">
@ -4700,7 +4676,7 @@
<target state="translated">每年</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">56</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="f6413089f93ac0756a20f8e74ef1ab78c81ef13c" datatype="html">
@ -4716,7 +4692,7 @@
<target state="translated">顶部</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">215</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -4724,7 +4700,7 @@
<target state="translated">底部</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">264</context>
<context context-type="linenumber">288</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -4732,7 +4708,7 @@
<target state="translated">投资组合演变</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">317</context>
<context context-type="linenumber">341</context>
</context-group>
</trans-unit>
<trans-unit id="658bfe96ba9d3a3a2ada478c8c855286b841f92a" datatype="html">
@ -4740,7 +4716,7 @@
<target state="translated">投资时间表</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">344</context>
<context context-type="linenumber">368</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -4748,7 +4724,7 @@
<target state="translated">当前连胜</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">365</context>
<context context-type="linenumber">389</context>
</context-group>
</trans-unit>
<trans-unit id="eabb7b2ede5498042bc9fbb565981a780bf340dc" datatype="html">
@ -4756,7 +4732,7 @@
<target state="translated">最长连续纪录</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">398</context>
</context-group>
</trans-unit>
<trans-unit id="6410cffb96159fcff46d91effc26df0e240bc0e3" datatype="html">
@ -4764,7 +4740,7 @@
<target state="translated">股息时间表</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">401</context>
<context context-type="linenumber">425</context>
</context-group>
</trans-unit>
<trans-unit id="6382f0e408575450219d3a10f8883a8f6c67e7d7" datatype="html">
@ -6136,7 +6112,7 @@
<target state="translated">极度恐惧</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="2634398159221205491" datatype="html">
@ -6144,7 +6120,7 @@
<target state="translated">极度贪婪</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
</trans-unit>
<trans-unit id="3511545370905854666" datatype="html">
@ -6152,7 +6128,7 @@
<target state="translated">中性的</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">103</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="3c33a66194384cf8c14e25170416767efa56fd98" datatype="html">
@ -6292,7 +6268,7 @@
<target state="translated">绝对货币表现</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">145</context>
</context-group>
</trans-unit>
<trans-unit id="5584854134b3049db7dfb7bf4d87a0b9b9b4b149" datatype="html">
@ -6300,7 +6276,7 @@
<target state="translated">绝对净性能</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="e19955db970092b9cde70be2cea163ab6adfac97" datatype="html">
@ -6308,7 +6284,7 @@
<target state="translated">绝对资产绩效</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">102</context>
</context-group>
</trans-unit>
<trans-unit id="8580549503047096056" datatype="html">
@ -6316,11 +6292,11 @@
<target state="translated">投资</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">47</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
@ -6332,7 +6308,7 @@
<target state="translated">资产绩效</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">99</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="d88d656d93dd2029b9d35712789d2567d2c0d739" datatype="html">
@ -6340,7 +6316,7 @@
<target state="translated">净绩效</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="e4da628796a8880899b986c2af0559a55d6a700c" datatype="html">
@ -6348,7 +6324,7 @@
<target state="translated">货币表现</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="2593751087640318641" datatype="html">
@ -6488,7 +6464,7 @@
<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">127</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="6439365426343089851" datatype="html">
@ -6628,7 +6604,7 @@
<target state="new">Do you really want to close your Ghostfolio account?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">175</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="85614ebfd89fe16873dfcf593a05f18b7468daac" datatype="html">
@ -6676,7 +6652,7 @@
<target state="new">Oops! There was an error setting up biometric authentication.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-settings/user-account-settings.component.ts</context>
<context context-type="linenumber">303</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="f0c5f6f270e70cbe063b5368fcf48f9afc1abd9b" datatype="html">
@ -6996,7 +6972,7 @@
<target state="new">United States</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit id="1519954996184640001" datatype="html">
@ -7614,7 +7590,7 @@
<target state="new">AI prompt has been copied to the clipboard</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">153</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="1616747898909934803" datatype="html">
@ -7710,7 +7686,7 @@
<target state="new">Open Duck.ai</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">174</context>
</context-group>
</trans-unit>
<trans-unit id="70a67e04629f6d412db0a12d51820b480788d795" datatype="html">
@ -7749,12 +7725,12 @@
<context context-type="linenumber">378</context>
</context-group>
</trans-unit>
<trans-unit id="cae42456a8243d5fb59733667bda1d3e15860d44" datatype="html">
<trans-unit id="afd6e2886f0bb7db3b54bef42bced4e7c67cc40c" datatype="html">
<source>Copy portfolio data to clipboard for AI prompt</source>
<target state="new">Copy portfolio data to clipboard for AI prompt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="187b68f90f45d63f0d3b1e830ac92f98d2447313" datatype="html">
@ -7762,7 +7738,7 @@
<target state="new">Copy AI prompt to clipboard for analysis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5004849258025239958" datatype="html">
@ -7829,6 +7805,38 @@
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="8944214829054650479" datatype="html">
<source>Security token</source>
<target state="new">Security token</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">163</context>
</context-group>
</trans-unit>
<trans-unit id="6751986162338860240" datatype="html">
<source>Do you really want to generate a new security token for this user?</source>
<target state="new">Do you really want to generate a new security token for this user?</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">168</context>
</context-group>
</trans-unit>
<trans-unit id="bb9188e6fbfd19db7f6ba5433592beaff50da35d" datatype="html">
<source>Generate Security Token</source>
<target state="new">Generate Security Token</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-users/admin-users.html</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7303091661854783304" datatype="html">
<source>United Kingdom</source>
<target state="new">United Kingdom</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">96</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

2
apps/client/src/styles.scss

@ -451,7 +451,7 @@ ngx-skeleton-loader {
}
.mat-mdc-menu-panel {
&.assistant {
&.no-max-width {
max-width: unset !important;
.mat-mdc-menu-content {

5
libs/common/src/lib/config.ts

@ -48,13 +48,14 @@ export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW =
export const DEFAULT_CURRENCY = 'USD';
export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy';
export const DEFAULT_HOST = '0.0.0.0';
export const DEFAULT_LANGUAGE_CODE = 'en';
export const DEFAULT_PAGE_SIZE = 50;
export const DEFAULT_PORT = 3333;
export const DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY = 1;
export const DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY = 1;
export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY = 1;
export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000;
export const DEFAULT_ROOT_URL = 'https://localhost:4200';
// USX is handled separately
export const DERIVED_CURRENCIES = [
@ -153,6 +154,8 @@ export const REPLACE_NAME_PARTS = [
'Xtrackers (IE) Plc -'
];
export const STORYBOOK_PATH = '/development/storybook';
export const SUPPORTED_LANGUAGE_CODES = [
'ca',
'de',

4
libs/common/src/lib/interfaces/account-balance.interface.ts

@ -0,0 +1,4 @@
export interface AccountBalance {
date: string;
value: number;
}

7
libs/common/src/lib/interfaces/admin-data.interface.ts

@ -1,11 +1,4 @@
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
export interface AdminData {
exchangeRates: ({
label1: string;
label2: string;
value: number;
} & AssetProfileIdentifier)[];
settings: { [key: string]: boolean | object | string | string[] };
transactionCount: number;
userCount: number;

4
libs/common/src/lib/interfaces/export.interface.ts

@ -1,8 +1,10 @@
import { Account, Order, Platform, Tag } from '@prisma/client';
import { AccountBalance } from './account-balance.interface';
export interface Export {
accounts: (Omit<Account, 'createdAt' | 'updatedAt' | 'userId'> & {
balances: { date: string; value: number }[];
balances: AccountBalance[];
})[];
activities: (Omit<
Order,

4
libs/common/src/lib/interfaces/index.ts

@ -1,4 +1,5 @@
import type { Access } from './access.interface';
import type { AccountBalance } from './account-balance.interface';
import type { Accounts } from './accounts.interface';
import type { AdminData } from './admin-data.interface';
import type { AdminJobs } from './admin-jobs.interface';
@ -37,6 +38,7 @@ import type { PortfolioReportRule } from './portfolio-report-rule.interface';
import type { PortfolioSummary } from './portfolio-summary.interface';
import type { Position } from './position.interface';
import type { Product } from './product';
import type { AccessTokenResponse } from './responses/access-token-response.interface';
import type { AccountBalancesResponse } from './responses/account-balances-response.interface';
import type { AiPromptResponse } from './responses/ai-prompt-response.interface';
import type { ApiKeyResponse } from './responses/api-key-response.interface';
@ -68,6 +70,8 @@ import type { XRayRulesSettings } from './x-ray-rules-settings.interface';
export {
Access,
AccessTokenResponse,
AccountBalance,
AccountBalancesResponse,
Accounts,
AdminData,

1
libs/common/src/lib/interfaces/portfolio-summary.interface.ts

@ -16,7 +16,6 @@ export interface PortfolioSummary extends PortfolioPerformance {
filteredValueInBaseCurrency?: number;
filteredValueInPercentage?: number;
fireWealth: number;
firstOrderDate: Date;
grossPerformance: number;
grossPerformanceWithCurrencyEffect: number;
interest: number;

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save