Browse Source

Merge pull request #19 from dandevaud/MR-Main-dockerpush

Mr main dockerpush
pull/5027/head
dandevaud 2 years ago
committed by GitHub
parent
commit
f30ea1c3dd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/build-code.yml
  2. 84
      CHANGELOG.md
  3. 4
      Dockerfile
  4. 5
      README.md
  5. 2
      apps/api/project.json
  6. 7
      apps/api/src/app/admin/admin.controller.ts
  7. 43
      apps/api/src/app/app.module.ts
  8. 33
      apps/api/src/app/frontend.middleware.ts
  9. 199
      apps/api/src/app/import/import.service.ts
  10. 17
      apps/api/src/app/order/order.controller.ts
  11. 29
      apps/api/src/app/order/order.service.ts
  12. 119
      apps/api/src/app/portfolio/portfolio.service.ts
  13. 7
      apps/api/src/app/redis-cache/interfaces/redis-cache.interface.ts
  14. 8
      apps/api/src/app/redis-cache/interfaces/redis-store.interface.ts
  15. 6
      apps/api/src/app/redis-cache/redis-cache.module.ts
  16. 27
      apps/api/src/app/redis-cache/redis-cache.service.ts
  17. 36
      apps/api/src/app/sitemap/sitemap.controller.ts
  18. 24
      apps/api/src/app/sitemap/sitemap.module.ts
  19. 26
      apps/api/src/app/user/user.service.ts
  20. 250
      apps/api/src/assets/sitemap.xml
  21. 3
      apps/api/src/main.ts
  22. 3
      apps/api/src/services/cron.service.ts
  23. 2
      apps/api/src/services/data-gathering/data-gathering.module.ts
  24. 41
      apps/api/src/services/data-gathering/data-gathering.service.ts
  25. 45
      apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts
  26. 9
      apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts
  27. 2
      apps/api/tsconfig.app.json
  28. 96
      apps/client/project.json
  29. 1
      apps/client/src/app/app.component.html
  30. 145
      apps/client/src/app/components/home-overview/home-overview.html
  31. 2
      apps/client/src/app/components/home-overview/home-overview.module.ts
  32. 4
      apps/client/src/app/components/home-overview/home-overview.scss
  33. 2
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts
  34. 3
      apps/client/src/app/core/auth.guard.ts
  35. 9
      apps/client/src/app/pages/about/about-page.scss
  36. 7
      apps/client/src/app/pages/account/account-page.component.ts
  37. 7
      apps/client/src/app/pages/account/account-page.html
  38. 11
      apps/client/src/app/pages/admin/admin-page.scss
  39. 10
      apps/client/src/app/pages/home/home-page.scss
  40. 12
      apps/client/src/app/pages/open/open-page.html
  41. 44
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  42. 18
      apps/client/src/app/pages/portfolio/allocations/allocations-page.html
  43. 1
      apps/client/src/app/pages/portfolio/allocations/allocations-page.scss
  44. 11
      apps/client/src/app/pages/portfolio/portfolio-page.scss
  45. 13
      apps/client/src/app/pages/public/public-page.component.ts
  46. 18
      apps/client/src/app/pages/public/public-page.html
  47. 8
      apps/client/src/app/pages/zen/zen-page.scss
  48. 0
      apps/client/src/assets/.well-known/assetlinks.json
  49. 0
      apps/client/src/assets/index.html
  50. 232
      apps/client/src/locales/messages.de.xlf
  51. 230
      apps/client/src/locales/messages.es.xlf
  52. 230
      apps/client/src/locales/messages.fr.xlf
  53. 230
      apps/client/src/locales/messages.it.xlf
  54. 230
      apps/client/src/locales/messages.nl.xlf
  55. 230
      apps/client/src/locales/messages.pt.xlf
  56. 209
      apps/client/src/locales/messages.xlf
  57. 3
      apps/client/src/styles.scss
  58. 2
      apps/client/tsconfig.app.json
  59. 11
      libs/common/src/lib/config.ts
  60. 16
      libs/common/src/lib/helper.ts
  61. 3
      libs/common/src/lib/types/market-advanced.type.ts
  62. 6
      libs/common/src/lib/types/market.type.ts
  63. 13
      libs/ui/src/lib/activities-table/activities-table.component.ts
  64. 4
      libs/ui/src/lib/holdings-table/holdings-table.component.html
  65. 2
      libs/ui/src/lib/holdings-table/holdings-table.component.ts
  66. 7
      nx.json
  67. 124
      package.json
  68. 2
      test/import/invalid-currency.csv
  69. 19
      test/import/unavailable-exchange-rate.json
  70. 9644
      yarn.lock

2
.github/workflows/build-code.yml

@ -33,4 +33,4 @@ jobs:
run: yarn test
- name: Build application
run: yarn build:all
run: yarn build:production

84
CHANGELOG.md

@ -5,6 +5,90 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.299.1 - 2023-08-10
### Changed
- Optimized the activities import by allowing a different currency than the asset's official one
- Added a timeout to the _EOD Historical Data_ requests
- Migrated the requests from `bent` to `got` in the _EOD Historical Data_ service
### Fixed
- Fixed the editing of the emergency fund
- Fixed the historical data gathering interval for asset profiles used as benchmarks having activities
## 1.298.0 - 2023-08-06
### Changed
- Improved the language localization for German (`de`)
- Upgraded `ng-extract-i18n-merge` from version `2.6.0` to `2.7.0`
- Upgraded `Nx` from version `16.5.5` to `16.6.0`
### Fixed
- Fixed the styles of various components (card, progress, tab) after the upgrade to `@angular/material` `16`
## 1.297.4 - 2023-08-05
### Added
- Added the footer to the public page
- Added a `copy-assets` `Nx` target to the client build
### Changed
- Improved the alignment of the region percentages on the allocations page
- Improved the alignment of the region percentages on the public page
- Improved the redirection of the home page to the localized home page
- Improved the language localization for German (`de`)
- Upgraded `angular` from version `15.2.5` to `16.1.8`
- Upgraded `nestjs` from version `9.1.4` to `10.1.3`
- Upgraded `Nx` from version `16.0.3` to `16.5.5`
## 1.296.0 - 2023-08-01
### Changed
- Optimized the validation in the activities import by reducing the list to unique asset profiles
- Optimized the data gathering in the activities import
## 1.295.0 - 2023-07-30
### Added
- Added a step by step introduction for new users
### Fixed
- Removed the _Stay signed in_ setting on _Sign in with fingerprint_ activation
## 1.294.0 - 2023-07-29
### Changed
- Extended the allocations by market chart on the allocations page by unavailable data
### Fixed
- Considered liabilities in the total account value calculation
## 1.293.0 - 2023-07-26
### Added
- Added error handling for the _Redis_ connections to keep the app running if the connection fails
### Changed
- Set the `lastmod` dates of `sitemap.xml` dynamically
### Fixed
- Fixed the missing values in the holdings table
- Fixed the `no such file or directory` error caused by the missing `favicon.ico` file
## 1.292.0 - 2023-07-24
### Added

4
Dockerfile

@ -33,7 +33,7 @@ COPY ./tsconfig.base.json tsconfig.base.json
COPY ./libs libs
COPY ./apps apps
RUN yarn build:all
RUN yarn build:production
# Prepare the dist image with additional node_modules
WORKDIR /ghostfolio/dist/apps/api
@ -58,4 +58,4 @@ RUN apt update && apt install -y \
COPY --from=builder /ghostfolio/dist/apps /ghostfolio/apps
WORKDIR /ghostfolio/apps/api
EXPOSE ${PORT:-3333}
CMD [ "yarn", "start:prod" ]
CMD [ "yarn", "start:production" ]

5
README.md

@ -153,7 +153,6 @@ Please follow the instructions of the Ghostfolio [Unraid Community App](https://
### Setup
1. Run `yarn install`
1. Run `yarn build:dev` to build the source code including the assets
1. Run `docker-compose --env-file ./.env -f docker/docker-compose.dev.yml up -d` to start [PostgreSQL](https://www.postgresql.org) and [Redis](https://redis.io)
1. Run `yarn database:setup` to initialize the database schema
1. Start the server and the client (see [_Development_](#Development))
@ -263,7 +262,9 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous/<INSERT_SECURITY_TO
## Community Projects
- [ghostfolio-cli](https://github.com/DerAndereJohannes/ghostfolio-cli): Command-line interface to access your portfolio
Discover a variety of community projects for Ghostfolio: https://github.com/topics/ghostfolio
Are you building your own project? Add the `ghostfolio` topic to your _GitHub_ repository to get listed as well. [Learn more →](https://docs.github.com/en/articles/classifying-your-repository-with-topics)
## Contributing

2
apps/api/project.json

@ -33,7 +33,7 @@
"outputs": ["{options.outputPath}"]
},
"serve": {
"executor": "@nx/node:node",
"executor": "@nx/js:node",
"options": {
"buildTarget": "api:build"
}

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

@ -7,6 +7,7 @@ import {
GATHER_ASSET_PROFILE_PROCESS,
GATHER_ASSET_PROFILE_PROCESS_OPTIONS
} from '@ghostfolio/common/config';
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import {
AdminData,
AdminMarketData,
@ -116,7 +117,7 @@ export class AdminController {
name: GATHER_ASSET_PROFILE_PROCESS,
opts: {
...GATHER_ASSET_PROFILE_PROCESS_OPTIONS,
jobId: `${dataSource}-${symbol}`
jobId: getAssetProfileIdentifier({ dataSource, symbol })
}
};
})
@ -152,7 +153,7 @@ export class AdminController {
name: GATHER_ASSET_PROFILE_PROCESS,
opts: {
...GATHER_ASSET_PROFILE_PROCESS_OPTIONS,
jobId: `${dataSource}-${symbol}`
jobId: getAssetProfileIdentifier({ dataSource, symbol })
}
};
})
@ -185,7 +186,7 @@ export class AdminController {
name: GATHER_ASSET_PROFILE_PROCESS,
opts: {
...GATHER_ASSET_PROFILE_PROCESS_OPTIONS,
jobId: `${dataSource}-${symbol}`
jobId: getAssetProfileIdentifier({ dataSource, symbol })
}
});
}

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

@ -7,11 +7,16 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { TwitterBotModule } from '@ghostfolio/api/services/twitter-bot/twitter-bot.module';
import {
DEFAULT_LANGUAGE_CODE,
SUPPORTED_LANGUAGE_CODES
} from '@ghostfolio/common/config';
import { BullModule } from '@nestjs/bull';
import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ScheduleModule } from '@nestjs/schedule';
import { ServeStaticModule } from '@nestjs/serve-static';
import { StatusCodes } from 'http-status-codes';
import { AccessModule } from './access/access.module';
import { AccountModule } from './account/account.module';
@ -32,6 +37,7 @@ import { OrderModule } from './order/order.module';
import { PlatformModule } from './platform/platform.module';
import { PortfolioModule } from './portfolio/portfolio.module';
import { RedisCacheModule } from './redis-cache/redis-cache.module';
import { SitemapModule } from './sitemap/sitemap.module';
import { SubscriptionModule } from './subscription/subscription.module';
import { SymbolModule } from './symbol/symbol.module';
import { UserModule } from './user/user.module';
@ -69,20 +75,37 @@ import { UserModule } from './user/user.module';
PrismaModule,
RedisCacheModule,
ScheduleModule.forRoot(),
...SUPPORTED_LANGUAGE_CODES.map((languageCode) => {
return ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'client', languageCode),
serveRoot: `/${languageCode}`
});
}),
ServeStaticModule.forRoot({
exclude: ['/api*', '/sitemap.xml'],
rootPath: join(__dirname, '..', 'client'),
serveStaticOptions: {
/*etag: false // Disable etag header to fix PWA
setHeaders: (res, path) => {
if (path.includes('ngsw.json')) {
// Disable cache (https://stackoverflow.com/questions/22632593/how-to-disable-webpage-caching-in-expressjs-nodejs/39775595)
// https://gertjans.home.xs4all.nl/javascript/cache-control.html#no-cache
res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
setHeaders: (res) => {
if (res.req?.path === '/') {
let languageCode = DEFAULT_LANGUAGE_CODE;
try {
const code = res.req.headers['accept-language']
.split(',')[0]
.split('-')[0];
if (SUPPORTED_LANGUAGE_CODES.includes(code)) {
languageCode = code;
}
} catch {}
res.set('Location', `/${languageCode}`);
res.statusCode = StatusCodes.MOVED_PERMANENTLY;
}
}*/
},
rootPath: join(__dirname, '..', 'client'),
exclude: ['/api*']
}
}
}),
SitemapModule,
SubscriptionModule,
SymbolModule,
TwitterBotModule,

33
apps/api/src/app/frontend.middleware.ts

@ -4,7 +4,7 @@ import * as path from 'path';
import { environment } from '@ghostfolio/api/environments/environment';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper';
import { Injectable, NestMiddleware } from '@nestjs/common';
import { format } from 'date-fns';
import { NextFunction, Request, Response } from 'express';
@ -120,7 +120,7 @@ export class FrontendMiddleware implements NestMiddleware {
next();
} else if (request.path === '/de' || request.path.startsWith('/de/')) {
response.send(
this.interpolate(this.indexHtmlDe, {
interpolate(this.indexHtmlDe, {
currentDate,
featureGraphicPath,
title,
@ -133,7 +133,7 @@ export class FrontendMiddleware implements NestMiddleware {
);
} else if (request.path === '/es' || request.path.startsWith('/es/')) {
response.send(
this.interpolate(this.indexHtmlEs, {
interpolate(this.indexHtmlEs, {
currentDate,
featureGraphicPath,
title,
@ -146,7 +146,7 @@ export class FrontendMiddleware implements NestMiddleware {
);
} else if (request.path === '/fr' || request.path.startsWith('/fr/')) {
response.send(
this.interpolate(this.indexHtmlFr, {
interpolate(this.indexHtmlFr, {
currentDate,
featureGraphicPath,
title,
@ -159,7 +159,7 @@ export class FrontendMiddleware implements NestMiddleware {
);
} else if (request.path === '/it' || request.path.startsWith('/it/')) {
response.send(
this.interpolate(this.indexHtmlIt, {
interpolate(this.indexHtmlIt, {
currentDate,
featureGraphicPath,
title,
@ -172,7 +172,7 @@ export class FrontendMiddleware implements NestMiddleware {
);
} else if (request.path === '/nl' || request.path.startsWith('/nl/')) {
response.send(
this.interpolate(this.indexHtmlNl, {
interpolate(this.indexHtmlNl, {
currentDate,
featureGraphicPath,
title,
@ -185,7 +185,7 @@ export class FrontendMiddleware implements NestMiddleware {
);
} else if (request.path === '/pt' || request.path.startsWith('/pt/')) {
response.send(
this.interpolate(this.indexHtmlPt, {
interpolate(this.indexHtmlPt, {
currentDate,
featureGraphicPath,
title,
@ -198,7 +198,7 @@ export class FrontendMiddleware implements NestMiddleware {
);
} else {
response.send(
this.interpolate(this.indexHtmlEn, {
interpolate(this.indexHtmlEn, {
currentDate,
featureGraphicPath,
title,
@ -215,20 +215,15 @@ export class FrontendMiddleware implements NestMiddleware {
return path.join(__dirname, '..', 'client', aLocale, 'index.html');
}
private interpolate(template: string, context: any) {
return template.replace(/[$]{([^}]+)}/g, (_, objectPath) => {
const properties = objectPath.split('.');
return properties.reduce(
(previous, current) => previous?.[current],
context
);
});
}
private isFileRequest(filename: string) {
if (filename === '/assets/LICENSE') {
return true;
} else if (filename.includes('auth/ey')) {
} else if (
filename.includes('auth/ey') ||
filename.includes(
'personal-finance-tools/open-source-alternative-to-markets.sh'
)
) {
return false;
}

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

@ -8,10 +8,15 @@ import {
import { OrderService } from '@ghostfolio/api/app/order/order.service';
import { PlatformService } from '@ghostfolio/api/app/platform/platform.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { parseDate } from '@ghostfolio/common/helper';
import {
DATE_FORMAT,
getAssetProfileIdentifier,
parseDate
} from '@ghostfolio/common/helper';
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import {
AccountWithPlatform,
@ -20,13 +25,15 @@ import {
import { Injectable } from '@nestjs/common';
import { DataSource, Prisma, SymbolProfile } from '@prisma/client';
import Big from 'big.js';
import { endOfToday, isAfter, isSameDay, parseISO } from 'date-fns';
import { endOfToday, format, isAfter, isSameDay, parseISO } from 'date-fns';
import { uniqBy } from 'lodash';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class ImportService {
public constructor(
private readonly accountService: AccountService,
private readonly dataGatheringService: DataGatheringService,
private readonly dataProviderService: DataProviderService,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly orderService: OrderService,
@ -220,8 +227,7 @@ export class ImportService {
const assetProfiles = await this.validateActivities({
activitiesDto,
maxActivitiesToImport,
userId
maxActivitiesToImport
});
const activitiesExtendedWithErrors = await this.extendActivitiesWithErrors({
@ -243,17 +249,47 @@ export class ImportService {
const activities: Activity[] = [];
for (const {
accountId,
comment,
date,
error,
fee,
quantity,
SymbolProfile: assetProfile,
type,
unitPrice
} of activitiesExtendedWithErrors) {
for (let [
index,
{
accountId,
comment,
date,
error,
fee,
quantity,
SymbolProfile,
type,
unitPrice
}
] of activitiesExtendedWithErrors.entries()) {
const assetProfile = assetProfiles[
getAssetProfileIdentifier({
dataSource: SymbolProfile.dataSource,
symbol: SymbolProfile.symbol
})
] ?? {
currency: SymbolProfile.currency,
dataSource: SymbolProfile.dataSource,
symbol: SymbolProfile.symbol
};
const {
assetClass,
assetSubClass,
countries,
createdAt,
currency,
dataSource,
id,
isin,
name,
scraperConfiguration,
sectors,
symbol,
symbolMapping,
url,
updatedAt
} = assetProfile;
const validatedAccount = accounts.find(({ id }) => {
return id === accountId;
});
@ -264,6 +300,35 @@ export class ImportService {
Account?: { id: string; name: string };
});
if (SymbolProfile.currency !== assetProfile.currency) {
// Convert the unit price and fee to the asset currency if the imported
// activity is in a different currency
unitPrice = await this.exchangeRateDataService.toCurrencyAtDate(
unitPrice,
SymbolProfile.currency,
assetProfile.currency,
date
);
if (!unitPrice) {
throw new Error(
`activities.${index} historical exchange rate at ${format(
date,
DATE_FORMAT
)} is not available from "${SymbolProfile.currency}" to "${
assetProfile.currency
}"`
);
}
fee = await this.exchangeRateDataService.toCurrencyAtDate(
fee,
SymbolProfile.currency,
assetProfile.currency,
date
);
}
if (isDryRun) {
order = {
comment,
@ -279,23 +344,22 @@ export class ImportService {
id: uuidv4(),
isDraft: isAfter(date, endOfToday()),
SymbolProfile: {
assetClass: assetProfile.assetClass,
assetSubClass: assetProfile.assetSubClass,
comment: assetProfile.comment,
countries: assetProfile.countries,
createdAt: assetProfile.createdAt,
currency: assetProfile.currency,
dataSource: assetProfile.dataSource,
id: assetProfile.id,
isin: assetProfile.isin,
name: assetProfile.name,
scraperConfiguration: assetProfile.scraperConfiguration,
sectors: assetProfile.sectors,
symbol: assetProfile.currency,
symbolMapping: assetProfile.symbolMapping,
updatedAt: assetProfile.updatedAt,
url: assetProfile.url,
...assetProfiles[assetProfile.symbol]
assetClass,
assetSubClass,
countries,
createdAt,
currency,
dataSource,
id,
isin,
name,
scraperConfiguration,
sectors,
symbol,
symbolMapping,
updatedAt,
url,
comment: assetProfile.comment
},
Account: validatedAccount,
symbolProfileId: undefined,
@ -318,14 +382,14 @@ export class ImportService {
SymbolProfile: {
connectOrCreate: {
create: {
currency: assetProfile.currency,
dataSource: assetProfile.dataSource,
symbol: assetProfile.symbol
currency,
dataSource,
symbol
},
where: {
dataSource_symbol: {
dataSource: assetProfile.dataSource,
symbol: assetProfile.symbol
dataSource,
symbol
}
}
}
@ -337,24 +401,49 @@ export class ImportService {
const value = new Big(quantity).mul(unitPrice).toNumber();
//@ts-ignore
activities.push({
...order,
error,
value,
feeInBaseCurrency: this.exchangeRateDataService.toCurrency(
fee,
assetProfile.currency,
currency,
userCurrency
),
//@ts-ignore
SymbolProfile: assetProfile,
valueInBaseCurrency: this.exchangeRateDataService.toCurrency(
value,
assetProfile.currency,
currency,
userCurrency
)
});
}
activities.sort((activity1, activity2) => {
return Number(activity1.date) - Number(activity2.date);
});
if (!isDryRun) {
// Gather symbol data in the background, if not dry run
const uniqueActivities = uniqBy(activities, ({ SymbolProfile }) => {
return getAssetProfileIdentifier({
dataSource: SymbolProfile.dataSource,
symbol: SymbolProfile.symbol
});
});
this.dataGatheringService.gatherSymbols(
uniqueActivities.map(({ date, SymbolProfile }) => {
return {
date,
dataSource: SymbolProfile.dataSource,
symbol: SymbolProfile.symbol
};
})
);
}
return activities;
}
@ -446,25 +535,30 @@ export class ImportService {
private async validateActivities({
activitiesDto,
maxActivitiesToImport,
userId
maxActivitiesToImport
}: {
activitiesDto: Partial<CreateOrderDto>[];
maxActivitiesToImport: number;
userId: string;
}) {
if (activitiesDto?.length > maxActivitiesToImport) {
throw new Error(`Too many activities (${maxActivitiesToImport} at most)`);
}
const assetProfiles: {
[symbol: string]: Partial<SymbolProfile>;
[assetProfileIdentifier: string]: Partial<SymbolProfile>;
} = {};
const uniqueActivitiesDto = uniqBy(
activitiesDto,
({ dataSource, symbol }) => {
return getAssetProfileIdentifier({ dataSource, symbol });
}
);
for (const [
index,
{ currency, dataSource, symbol }
] of activitiesDto.entries()) {
] of uniqueActivitiesDto.entries()) {
if (dataSource !== 'MANUAL') {
const assetProfile = (
await this.dataProviderService.getAssetProfiles([
@ -472,19 +566,26 @@ export class ImportService {
])
)?.[symbol];
if (assetProfile === undefined) {
if (!assetProfile) {
throw new Error(
`activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")`
);
}
if (assetProfile.currency !== currency) {
if (
assetProfile.currency !== currency &&
!this.exchangeRateDataService.hasCurrencyPair(
currency,
assetProfile.currency
)
) {
throw new Error(
`activities.${index}.currency ("${currency}") does not match with "${assetProfile.currency}"`
`activities.${index}.currency ("${currency}") does not match with "${assetProfile.currency}" and no exchange rate is available from "${currency}" to "${assetProfile.currency}"`
);
}
assetProfiles[symbol] = assetProfile;
assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })] =
assetProfile;
}
}

17
apps/api/src/app/order/order.controller.ts

@ -2,6 +2,7 @@ import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor';
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor';
import { ApiService } from '@ghostfolio/api/services/api/api.service';
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service';
import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service';
import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -36,6 +37,7 @@ import { UpdateOrderDto } from './update-order.dto';
export class OrderController {
public constructor(
private readonly apiService: ApiService,
private readonly dataGatheringService: DataGatheringService,
private readonly impersonationService: ImpersonationService,
private readonly orderService: OrderService,
@Inject(REQUEST) private readonly request: RequestWithUser
@ -123,7 +125,7 @@ export class OrderController {
);
}
return this.orderService.createOrder({
const order = await this.orderService.createOrder({
...data,
date: parseISO(data.date),
SymbolProfile: {
@ -144,6 +146,19 @@ export class OrderController {
User: { connect: { id: this.request.user.id } },
userId: this.request.user.id
});
if (!order.isDraft) {
// Gather symbol data in the background, if not draft
this.dataGatheringService.gatherSymbols([
{
dataSource: data.dataSource,
date: order.date,
symbol: data.symbol
}
]);
}
return order;
}
@Put(':id')

29
apps/api/src/app/order/order.service.ts

@ -7,6 +7,7 @@ import {
GATHER_ASSET_PROFILE_PROCESS,
GATHER_ASSET_PROFILE_PROCESS_OPTIONS
} from '@ghostfolio/common/config';
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import { Filter } from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
@ -117,7 +118,7 @@ export class OrderService {
};
}
await this.dataGatheringService.addJobToQueue({
this.dataGatheringService.addJobToQueue({
data: {
dataSource: data.SymbolProfile.connectOrCreate.create.dataSource,
symbol: data.SymbolProfile.connectOrCreate.create.symbol
@ -125,25 +126,12 @@ export class OrderService {
name: GATHER_ASSET_PROFILE_PROCESS,
opts: {
...GATHER_ASSET_PROFILE_PROCESS_OPTIONS,
jobId: `${data.SymbolProfile.connectOrCreate.create.dataSource}-${data.SymbolProfile.connectOrCreate.create.symbol}`
}
});
const isDraft =
data.type === 'LIABILITY'
? false
: isAfter(data.date as Date, endOfToday());
if (!isDraft) {
// Gather symbol data of order in the background, if not draft
this.dataGatheringService.gatherSymbols([
{
jobId: getAssetProfileIdentifier({
dataSource: data.SymbolProfile.connectOrCreate.create.dataSource,
date: <Date>data.date,
symbol: data.SymbolProfile.connectOrCreate.create.symbol
}
]);
}
})
}
});
delete data.accountId;
delete data.assetClass;
@ -162,6 +150,11 @@ export class OrderService {
const orderData: Prisma.OrderCreateInput = data;
const isDraft =
data.type === 'LIABILITY'
? false
: isAfter(data.date as Date, endOfToday());
const order = await this.prismaService.order.create({
data: {
...orderData,

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

@ -538,11 +538,13 @@ export class PortfolioService {
const dataProviderResponse = dataProviderResponses[item.symbol];
const markets: PortfolioPosition['markets'] = {
[UNKNOWN_KEY]: 0,
developedMarkets: 0,
emergingMarkets: 0,
otherMarkets: 0
};
const marketsAdvanced: PortfolioPosition['marketsAdvanced'] = {
[UNKNOWN_KEY]: 0,
asiaPacific: 0,
emergingMarkets: 0,
europe: 0,
@ -551,7 +553,12 @@ export class PortfolioService {
otherMarkets: 0
};
this.calculateMarketsAllocation(symbolProfile, markets, marketsAdvanced);
this.calculateMarketsAllocation(
symbolProfile,
markets,
marketsAdvanced,
value
);
holdings[item.symbol] = {
markets,
@ -732,50 +739,61 @@ export class PortfolioService {
japan: number;
northAmerica: number;
otherMarkets: number;
}
},
value: Big
) {
for (const country of symbolProfile.countries) {
if (developedMarkets.includes(country.code)) {
markets.developedMarkets = new Big(markets.developedMarkets)
.plus(country.weight)
.toNumber();
} else if (emergingMarkets.includes(country.code)) {
markets.emergingMarkets = new Big(markets.emergingMarkets)
.plus(country.weight)
.toNumber();
} else {
markets.otherMarkets = new Big(markets.otherMarkets)
.plus(country.weight)
.toNumber();
}
if (symbolProfile.countries.length > 0) {
for (const country of symbolProfile.countries) {
if (developedMarkets.includes(country.code)) {
markets.developedMarkets = new Big(markets.developedMarkets)
.plus(country.weight)
.toNumber();
} else if (emergingMarkets.includes(country.code)) {
markets.emergingMarkets = new Big(markets.emergingMarkets)
.plus(country.weight)
.toNumber();
} else {
markets.otherMarkets = new Big(markets.otherMarkets)
.plus(country.weight)
.toNumber();
}
if (country.code === 'JP') {
marketsAdvanced.japan = new Big(marketsAdvanced.japan)
.plus(country.weight)
.toNumber();
} else if (country.code === 'CA' || country.code === 'US') {
marketsAdvanced.northAmerica = new Big(marketsAdvanced.northAmerica)
.plus(country.weight)
.toNumber();
} else if (asiaPacificMarkets.includes(country.code)) {
marketsAdvanced.asiaPacific = new Big(marketsAdvanced.asiaPacific)
.plus(country.weight)
.toNumber();
} else if (emergingMarkets.includes(country.code)) {
marketsAdvanced.emergingMarkets = new Big(
marketsAdvanced.emergingMarkets
)
.plus(country.weight)
.toNumber();
} else if (europeMarkets.includes(country.code)) {
marketsAdvanced.europe = new Big(marketsAdvanced.europe)
.plus(country.weight)
.toNumber();
} else {
marketsAdvanced.otherMarkets = new Big(marketsAdvanced.otherMarkets)
.plus(country.weight)
.toNumber();
if (country.code === 'JP') {
marketsAdvanced.japan = new Big(marketsAdvanced.japan)
.plus(country.weight)
.toNumber();
} else if (country.code === 'CA' || country.code === 'US') {
marketsAdvanced.northAmerica = new Big(marketsAdvanced.northAmerica)
.plus(country.weight)
.toNumber();
} else if (asiaPacificMarkets.includes(country.code)) {
marketsAdvanced.asiaPacific = new Big(marketsAdvanced.asiaPacific)
.plus(country.weight)
.toNumber();
} else if (emergingMarkets.includes(country.code)) {
marketsAdvanced.emergingMarkets = new Big(
marketsAdvanced.emergingMarkets
)
.plus(country.weight)
.toNumber();
} else if (europeMarkets.includes(country.code)) {
marketsAdvanced.europe = new Big(marketsAdvanced.europe)
.plus(country.weight)
.toNumber();
} else {
marketsAdvanced.otherMarkets = new Big(marketsAdvanced.otherMarkets)
.plus(country.weight)
.toNumber();
}
}
} else {
markets[UNKNOWN_KEY] = new Big(markets[UNKNOWN_KEY])
.plus(value)
.toNumber();
marketsAdvanced[UNKNOWN_KEY] = new Big(marketsAdvanced[UNKNOWN_KEY])
.plus(value)
.toNumber();
}
}
@ -1935,12 +1953,12 @@ export class PortfolioService {
userId: string;
withExcludedAccounts?: boolean;
}) {
const ordersOfTypeItem = await this.orderService.getOrders({
const ordersOfTypeItemOrLiability = await this.orderService.getOrders({
filters,
userCurrency,
userId,
withExcludedAccounts,
types: ['ITEM']
types: ['ITEM', 'LIABILITY']
});
const accounts: PortfolioDetails['accounts'] = {};
@ -1980,13 +1998,14 @@ export class PortfolioService {
return accountId === account.id;
});
const ordersOfTypeItemByAccount = ordersOfTypeItem.filter(
({ accountId }) => {
const ordersOfTypeItemOrLiabilityByAccount =
ordersOfTypeItemOrLiability.filter(({ accountId }) => {
return accountId === account.id;
}
);
});
ordersByAccount = ordersByAccount.concat(ordersOfTypeItemByAccount);
ordersByAccount = ordersByAccount.concat(
ordersOfTypeItemOrLiabilityByAccount
);
accounts[account.id] = {
balance: account.balance,
@ -2026,7 +2045,7 @@ export class PortfolioService {
order.unitPrice ??
0);
if (order.type === 'SELL') {
if (order.type === 'LIABILITY' || order.type === 'SELL') {
currentValueOfSymbolInBaseCurrency *= -1;
}

7
apps/api/src/app/redis-cache/interfaces/redis-cache.interface.ts

@ -0,0 +1,7 @@
import { Cache } from 'cache-manager';
import type { RedisStore } from './redis-store.interface';
export interface RedisCache extends Cache {
store: RedisStore;
}

8
apps/api/src/app/redis-cache/interfaces/redis-store.interface.ts

@ -0,0 +1,8 @@
import { Store } from 'cache-manager';
import { createClient } from 'redis';
export interface RedisStore extends Store {
getClient: () => ReturnType<typeof createClient>;
isCacheableValue: (value: any) => boolean;
name: 'redis';
}

6
apps/api/src/app/redis-cache/redis-cache.module.ts

@ -1,7 +1,9 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { CacheManagerOptions, CacheModule, Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { Module } from '@nestjs/common';
import * as redisStore from 'cache-manager-redis-store';
import type { RedisClientOptions } from 'redis';
import { RedisCacheService } from './redis-cache.service';
@ -11,7 +13,7 @@ import { RedisCacheService } from './redis-cache.service';
imports: [ConfigurationModule],
inject: [ConfigurationService],
useFactory: async (configurationService: ConfigurationService) => {
return <CacheManagerOptions>{
return <RedisClientOptions>{
host: configurationService.get('REDIS_HOST'),
max: configurationService.get('MAX_ITEM_IN_CACHE'),
password: configurationService.get('REDIS_PASSWORD'),

27
apps/api/src/app/redis-cache/redis-cache.service.ts

@ -1,21 +1,30 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { CACHE_MANAGER, Inject, Injectable } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable, Logger } from '@nestjs/common';
import type { RedisCache } from './interfaces/redis-cache.interface';
@Injectable()
export class RedisCacheService {
public constructor(
@Inject(CACHE_MANAGER) private readonly cache: Cache,
@Inject(CACHE_MANAGER) private readonly cache: RedisCache,
private readonly configurationService: ConfigurationService
) {}
) {
const client = cache.store.getClient();
client.on('error', (error) => {
Logger.error(error, 'RedisCacheService');
});
}
public async get(key: string): Promise<string> {
return await this.cache.get(key);
}
public getQuoteKey({ dataSource, symbol }: UniqueAsset) {
return `quote-${dataSource}-${symbol}`;
return `quote-${getAssetProfileIdentifier({ dataSource, symbol })}`;
}
public async remove(key: string) {
@ -27,8 +36,10 @@ export class RedisCacheService {
}
public async set(key: string, value: string, ttlInSeconds?: number) {
await this.cache.set(key, value, {
ttl: ttlInSeconds ?? this.configurationService.get('CACHE_TTL')
});
await this.cache.set(
key,
value,
ttlInSeconds ?? this.configurationService.get('CACHE_TTL')
);
}
}

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

@ -0,0 +1,36 @@
import * as fs from 'fs';
import * as path from 'path';
import {
DATE_FORMAT,
getYesterday,
interpolate
} from '@ghostfolio/common/helper';
import { Controller, Get, Res, VERSION_NEUTRAL, Version } from '@nestjs/common';
import { format } from 'date-fns';
import { Response } from 'express';
@Controller('sitemap.xml')
export class SitemapController {
public sitemapXml = '';
public constructor() {
try {
this.sitemapXml = fs.readFileSync(
path.join(__dirname, 'assets', 'sitemap.xml'),
'utf8'
);
} catch {}
}
@Get()
@Version(VERSION_NEUTRAL)
public async flushCache(@Res() response: Response): Promise<void> {
response.setHeader('content-type', 'application/xml');
response.send(
interpolate(this.sitemapXml, {
currentDate: format(getYesterday(), DATE_FORMAT)
})
);
}
}

24
apps/api/src/app/sitemap/sitemap.module.ts

@ -0,0 +1,24 @@
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.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';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { Module } from '@nestjs/common';
import { SitemapController } from './sitemap.controller';
@Module({
controllers: [SitemapController],
imports: [
ConfigurationModule,
DataGatheringModule,
DataProviderModule,
ExchangeRateDataModule,
PrismaModule,
RedisCacheModule,
SymbolProfileModule
]
})
export class SitemapModule {}

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

@ -14,6 +14,7 @@ import {
import { UserWithSettings } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common';
import { Prisma, Role, User } from '@prisma/client';
import { differenceInDays } from 'date-fns';
import { sortBy } from 'lodash';
const crypto = require('crypto');
@ -165,11 +166,26 @@ export class UserService {
user.subscription =
this.subscriptionService.getSubscription(Subscription);
if (
Analytics?.activityCount % 5 === 0 &&
user.subscription?.type === 'Basic'
) {
currentPermissions.push(permissions.enableSubscriptionInterstitial);
if (user.subscription?.type === 'Basic') {
const daysSinceRegistration = differenceInDays(
new Date(),
user.createdAt
);
let frequency = 20;
if (daysSinceRegistration > 180) {
frequency = 3;
} else if (daysSinceRegistration > 60) {
frequency = 5;
} else if (daysSinceRegistration > 30) {
frequency = 10;
} else if (daysSinceRegistration > 15) {
frequency = 15;
}
if (Analytics?.activityCount % frequency === 1) {
currentPermissions.push(permissions.enableSubscriptionInterstitial);
}
}
if (user.subscription?.type === 'Premium') {

250
apps/client/src/assets/sitemap.xml → apps/api/src/assets/sitemap.xml

@ -6,514 +6,514 @@
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://ghostfol.io/de</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/blog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/blog/2021/07/hallo-ghostfolio</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/features</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/haeufig-gestellte-fragen</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/maerkte</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/open</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/preise</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/registrierung</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/ressourcen</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/ueber-uns</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/ueber-uns/changelog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/ueber-uns/datenschutzbestimmungen</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/ueber-uns/lizenz</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about/changelog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about/license</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2021/07/hello-ghostfolio</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/01/ghostfolio-first-months-in-open-source</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/ghostfolio-meets-internet-identity</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/how-do-i-get-my-finances-in-order</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/08/500-stars-on-github</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/10/hacktoberfest-2022</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/11/black-friday-2022</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/12/the-importance-of-tracking-your-personal-finances</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2023/02/ghostfolio-meets-umbrel</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2023/03/ghostfolio-reaches-1000-stars-on-github</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2023/05/unlock-your-financial-potential-with-ghostfolio</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2023/07/exploring-the-path-to-fire</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/faq</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/features</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/markets</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/open</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/pricing</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/register</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-altoo</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-copilot-money</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-delta</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-divvydiary</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-exirio</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-folishare</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-getquin</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-gospatz</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-justetf</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-kubera</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-markets.sh</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-maybe-finance</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-monse</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-parqet</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-plannix</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-portfolio-dividend-tracker</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-portseido</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-projectionlab</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-seeking-alpha</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-sharesight</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-simple-portfolio</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-snowball-analytics</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-sumio</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-utluna</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-yeekatee</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/funcionalidades</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/mercados</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/open</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/precios</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/preguntas-mas-frecuentes</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/recursos</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/registro</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/sobre</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/sobre/changelog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/sobre/licencia</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/es/sobre/politica-de-privacidad</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/a-propos</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/a-propos/changelog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/a-propos/licence</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/a-propos/politique-de-confidentialite</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/enregistrement</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/fonctionnalites</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/foire-aux-questions</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/marches</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/open</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/prix</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/fr/ressources</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/domande-piu-frequenti</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/funzionalita</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/informazioni-su</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/informazioni-su/changelog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/informazioni-su/licenza</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/informazioni-su/informativa-sulla-privacy</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/iscrizione</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/mercati</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/open</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/prezzi</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/it/risorse</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/bronnen</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/kenmerken</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/markten</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/open</loc>
<changefreq>daily</changefreq>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/over</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/over/changelog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/over/licentie</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/over/privacybeleid</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/prijzen</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/registratie</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/nl/vaak-gestelde-vragen</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/blog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/funcionalidades</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/mercados</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/open</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/perguntas-mais-frequentes</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/precos</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/recursos</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/registo</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/sobre</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/sobre/changelog</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/sobre/licenca</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/pt/sobre/politica-de-privacidade</loc>
<lastmod>2023-07-10T00:00:00+00:00</lastmod>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
</urlset>

3
apps/api/src/main.ts

@ -23,7 +23,7 @@ async function bootstrap() {
defaultVersion: '1',
type: VersioningType.URI
});
app.setGlobalPrefix('api');
app.setGlobalPrefix('api', { exclude: ['sitemap.xml'] });
app.useGlobalPipes(
new ValidationPipe({
forbidNonWhitelisted: true,
@ -40,6 +40,7 @@ async function bootstrap() {
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

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

@ -2,6 +2,7 @@ import {
GATHER_ASSET_PROFILE_PROCESS,
GATHER_ASSET_PROFILE_PROCESS_OPTIONS
} from '@ghostfolio/common/config';
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import { Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
@ -48,7 +49,7 @@ export class CronService {
name: GATHER_ASSET_PROFILE_PROCESS,
opts: {
...GATHER_ASSET_PROFILE_PROCESS_OPTIONS,
jobId: `${dataSource}-${symbol}`
jobId: getAssetProfileIdentifier({ dataSource, symbol })
}
};
})

2
apps/api/src/services/data-gathering/data-gathering.module.ts

@ -5,6 +5,7 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
import { DATA_GATHERING_QUEUE } from '@ghostfolio/common/config';
import { BullModule } from '@nestjs/bull';
@ -28,6 +29,7 @@ import { DataGatheringProcessor } from './data-gathering.processor';
ExchangeRateDataModule,
MarketDataModule,
PrismaModule,
PropertyModule,
SymbolProfileModule
],
providers: [DataGatheringProcessor, DataGatheringService],

41
apps/api/src/services/data-gathering/data-gathering.service.ts

@ -4,14 +4,20 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
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 {
DATA_GATHERING_QUEUE,
GATHER_HISTORICAL_MARKET_DATA_PROCESS,
GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS
GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS,
PROPERTY_BENCHMARKS
} from '@ghostfolio/common/config';
import { DATE_FORMAT, resetHours } from '@ghostfolio/common/helper';
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import {
DATE_FORMAT,
getAssetProfileIdentifier,
resetHours
} from '@ghostfolio/common/helper';
import { BenchmarkProperty, UniqueAsset } from '@ghostfolio/common/interfaces';
import { InjectQueue } from '@nestjs/bull';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { DataSource } from '@prisma/client';
@ -30,6 +36,7 @@ export class DataGatheringService {
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly marketDataService: MarketDataService,
private readonly prismaService: PrismaService,
private readonly propertyService: PropertyService,
private readonly symbolProfileService: SymbolProfileService
) {}
@ -221,7 +228,10 @@ export class DataGatheringService {
name: GATHER_HISTORICAL_MARKET_DATA_PROCESS,
opts: {
...GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS,
jobId: `${dataSource}-${symbol}-${format(date, DATE_FORMAT)}`
jobId: `${getAssetProfileIdentifier({
dataSource,
symbol
})}-${format(date, DATE_FORMAT)}`
}
};
})
@ -248,6 +258,10 @@ export class DataGatheringService {
});
}
private getEarliestDate(aStartDate: Date) {
return min([aStartDate, subYears(new Date(), 10)]);
}
private async getSymbols7D(): Promise<IDataGatheringItem[]> {
const startDate = subDays(resetHours(new Date()), 7);
@ -314,6 +328,14 @@ export class DataGatheringService {
}
private async getSymbolsMax(): Promise<IDataGatheringItem[]> {
const benchmarkAssetProfileIdMap: { [key: string]: boolean } = {};
(
((await this.propertyService.getByKey(
PROPERTY_BENCHMARKS
)) as BenchmarkProperty[]) ?? []
).forEach(({ symbolProfileId }) => {
benchmarkAssetProfileIdMap[symbolProfileId] = true;
});
const startDate =
(
await this.prismaService.order.findFirst({
@ -327,7 +349,7 @@ export class DataGatheringService {
return {
dataSource,
symbol,
date: min([startDate, subYears(new Date(), 10)])
date: this.getEarliestDate(startDate)
};
});
@ -336,6 +358,7 @@ export class DataGatheringService {
orderBy: [{ symbol: 'asc' }],
select: {
dataSource: true,
id: true,
Order: {
orderBy: [{ date: 'asc' }],
select: { date: true },
@ -357,9 +380,15 @@ export class DataGatheringService {
);
})
.map((symbolProfile) => {
let date = symbolProfile.Order?.[0]?.date ?? startDate;
if (benchmarkAssetProfileIdMap[symbolProfile.id]) {
date = this.getEarliestDate(startDate);
}
return {
...symbolProfile,
date: symbolProfile.Order?.[0]?.date ?? startDate
date
};
});

45
apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts

@ -5,6 +5,7 @@ import {
IDataProviderHistoricalResponse,
IDataProviderResponse
} from '@ghostfolio/api/services/interfaces/interfaces';
import { DEFAULT_REQUEST_TIMEOUT } from '@ghostfolio/common/config';
import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper';
import { Granularity } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
@ -14,9 +15,10 @@ import {
DataSource,
SymbolProfile
} from '@prisma/client';
import bent from 'bent';
import Big from 'big.js';
import { format, isToday } from 'date-fns';
import got from 'got';
import ms from 'ms';
@Injectable()
export class EodHistoricalDataService implements DataProviderInterface {
@ -76,19 +78,19 @@ export class EodHistoricalDataService implements DataProviderInterface {
const symbol = this.convertToEodSymbol(aSymbol);
try {
const get = bent(
const response = await got(
`${this.URL}/eod/${symbol}?api_token=${
this.apiKey
}&fmt=json&from=${format(from, DATE_FORMAT)}&to=${format(
to,
DATE_FORMAT
)}&period={aGranularity}`,
'GET',
'json',
200
);
const response = await get();
{
timeout: {
request: DEFAULT_REQUEST_TIMEOUT
}
}
).json<any>();
return response.reduce(
(result, historicalItem, index, array) => {
@ -136,16 +138,16 @@ export class EodHistoricalDataService implements DataProviderInterface {
}
try {
const get = bent(
const realTimeResponse = await got(
`${this.URL}/real-time/${symbols[0]}?api_token=${
this.apiKey
}&fmt=json&s=${symbols.join(',')}`,
'GET',
'json',
200
);
const realTimeResponse = await get();
{
timeout: {
request: DEFAULT_REQUEST_TIMEOUT
}
}
).json<any>();
const quotes =
symbols.length === 1 ? [realTimeResponse] : realTimeResponse;
@ -329,13 +331,14 @@ export class EodHistoricalDataService implements DataProviderInterface {
let searchResult = [];
try {
const get = bent(
const response = await got(
`${this.URL}/search/${aQuery}?api_token=${this.apiKey}`,
'GET',
'json',
200
);
const response = await get();
{
timeout: {
request: DEFAULT_REQUEST_TIMEOUT
}
}
).json<any>();
searchResult = response.map(
({ Code, Currency, Exchange, ISIN: isin, Name: name, Type }) => {

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

@ -33,6 +33,15 @@ export class ExchangeRateDataService {
return this.currencyPairs;
}
public hasCurrencyPair(currency1: string, currency2: string) {
return this.currencyPairs.some(({ symbol }) => {
return (
symbol === `${currency1}${currency2}` ||
symbol === `${currency2}${currency1}`
);
});
}
public async initialize() {
this.baseCurrency = this.configurationService.get('BASE_CURRENCY');
this.currencies = await this.prepareCurrencies();

2
apps/api/tsconfig.app.json

@ -4,7 +4,7 @@
"outDir": "../../dist/out-tsc",
"types": ["node"],
"emitDecoratorMetadata": true,
"target": "es2015"
"target": "es2021"
},
"exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"],
"include": ["**/*.ts"]

96
apps/client/project.json

@ -11,60 +11,15 @@
"prefix": "gf",
"targets": {
"build": {
"executor": "@angular-devkit/build-angular:browser",
"executor": "@nx/angular:webpack-browser",
"options": {
"localize": true,
"outputPath": "dist/apps/client",
"index": "apps/client/src/index.html",
"main": "apps/client/src/main.ts",
"polyfills": "apps/client/src/polyfills.ts",
"tsConfig": "apps/client/tsconfig.app.json",
"assets": [
{
"glob": "assetlinks.json",
"input": "apps/client/src/assets",
"output": "./../.well-known"
},
{
"glob": "CHANGELOG.md",
"input": "",
"output": "./../assets"
},
{
"glob": "LICENSE",
"input": "",
"output": "./../assets"
},
{
"glob": "robots.txt",
"input": "apps/client/src/assets",
"output": "./../"
},
{
"glob": "sitemap.xml",
"input": "apps/client/src/assets",
"output": "./../"
},
{
"glob": "site.webmanifest",
"input": "apps/client/src/assets",
"output": "./../"
},
{
"glob": "**/*",
"input": "node_modules/ionicons/dist/ionicons",
"output": "./../ionicons"
},
{
"glob": "**/*.js",
"input": "node_modules/ionicons/dist/",
"output": "./../"
},
{
"glob": "**/*",
"input": "apps/client/src/assets",
"output": "./../assets/"
}
],
"assets": [],
"styles": [
"apps/client/src/styles/theme.scss",
"apps/client/src/styles.scss"
@ -139,8 +94,51 @@
"outputs": ["{options.outputPath}"],
"defaultConfiguration": ""
},
"copy-assets": {
"executor": "nx:run-commands",
"options": {
"commands": [
{
"command": "mkdir -p dist/apps/client"
},
{
"command": "cp -r apps/client/src/assets dist/apps/client"
},
{
"command": "cp -r apps/client/src/assets/.well-known dist/apps/client"
},
{
"command": "cp apps/client/src/assets/favicon.ico dist/apps/client"
},
{
"command": "cp apps/client/src/assets/index.html dist/apps/client"
},
{
"command": "cp apps/client/src/assets/robots.txt dist/apps/client"
},
{
"command": "cp apps/client/src/assets/site.webmanifest dist/apps/client"
},
{
"command": "cp node_modules/ionicons/dist/index.js dist/apps/client"
},
{
"command": "cp node_modules/ionicons/dist/ionicons.js dist/apps/client"
},
{
"command": "cp -r node_modules/ionicons/dist/ionicons dist/apps/client/ionicons"
},
{
"command": "cp CHANGELOG.md dist/apps/client/assets"
},
{
"command": "cp LICENSE dist/apps/client/assets"
}
]
}
},
"serve": {
"executor": "@angular-devkit/build-angular:dev-server",
"executor": "@nx/angular:webpack-dev-server",
"options": {
"browserTarget": "client:build",
"proxyConfig": "apps/client/proxy.conf.json"

1
apps/client/src/app/app.component.html

@ -50,6 +50,7 @@
currentRoute === 'features' ||
currentRoute === 'markets' ||
currentRoute === 'open' ||
currentRoute === 'p' ||
currentRoute === 'pricing' ||
currentRoute === 'resources' ||
currentRoute === 'register' ||

145
apps/client/src/app/components/home-overview/home-overview.html

@ -1,57 +1,110 @@
<div
class="align-items-center container d-flex flex-column h-100 justify-content-center overview p-0 position-relative"
>
<div class="row w-100">
<div class="col p-0">
<div class="chart-container mx-auto position-relative">
<div
*ngIf="hasPermissionToCreateOrder && historicalDataItems?.length === 0"
class="align-items-center d-flex h-100 justify-content-center w-100"
<div
*ngIf="hasPermissionToCreateOrder && historicalDataItems?.length === 0; else isUserActive"
class="justify-content-center row w-100"
>
<div class="col introduction">
<h4 i18n>Welcome to Ghostfolio</h4>
<p i18n>Ready to take control of your personal finances?</p>
<ol class="font-weight-bold">
<li
class="mb-2"
[ngClass]="{ 'text-muted': user?.accounts?.length > 1 }"
>
<div class="d-flex justify-content-center">
<gf-no-transactions-info-indicator></gf-no-transactions-info-indicator>
</div>
</div>
<gf-line-chart
class="position-absolute"
symbol="Performance"
unit="%"
[colorScheme]="user?.settings?.colorScheme"
[hidden]="historicalDataItems?.length === 0"
[historicalDataItems]="historicalDataItems"
[isAnimated]="user?.settings?.dateRange === '1d' ? false : true"
[locale]="user?.settings?.locale"
[ngClass]="{ 'pr-3': deviceType === 'mobile' }"
[showGradient]="true"
[showLoader]="false"
[showXAxis]="false"
[showYAxis]="false"
></gf-line-chart>
<a class="d-block" [routerLink]="['/accounts']"
><span i18n>Setup your accounts</span><br />
<span class="font-weight-normal" i18n
>Get a comprehensive financial overview by adding your bank and
brokerage accounts.</span
></a
>
</li>
<li class="mb-2">
<a class="d-block" [routerLink]="['/portfolio', 'activities']">
<span i18n>Capture your activities</span><br />
<span class="font-weight-normal" i18n
>Record your investment activities to keep your portfolio up to
date.</span
></a
>
</li>
<li class="mb-2">
<a class="d-block" [routerLink]="['/portfolio']">
<span i18n>Monitor and analyze your portfolio</span><br />
<span class="font-weight-normal" i18n
>Track your progress in real-time with comprehensive analysis and
insights.</span
>
</a>
</li>
</ol>
<div class="d-flex justify-content-center">
<a
*ngIf="user?.accounts?.length === 1"
color="primary"
mat-flat-button
[routerLink]="['/accounts']"
>
<ng-container i18n>Setup accounts</ng-container>
</a>
<a
*ngIf="user?.accounts?.length > 1"
color="primary"
mat-flat-button
[routerLink]="['/portfolio', 'activities']"
>
<ng-container i18n>Add activity</ng-container>
</a>
</div>
</div>
</div>
<div class="overview-container row mt-1">
<div class="col">
<gf-portfolio-performance
class="pb-4"
[baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="deviceType"
[errors]="errors"
[isAllTimeHigh]="isAllTimeHigh"
[isAllTimeLow]="isAllTimeLow"
[isLoading]="isLoadingPerformance"
[locale]="user?.settings?.locale"
[performance]="performance"
[showDetails]="showDetails"
></gf-portfolio-performance>
<div *ngIf="showDetails" class="text-center">
<gf-toggle
[defaultValue]="user?.settings?.dateRange"
<ng-template #isUserActive>
<div class="row w-100">
<div class="col p-0">
<div class="chart-container mx-auto position-relative">
<gf-line-chart
class="position-absolute"
symbol="Performance"
unit="%"
[colorScheme]="user?.settings?.colorScheme"
[hidden]="historicalDataItems?.length === 0"
[historicalDataItems]="historicalDataItems"
[isAnimated]="user?.settings?.dateRange === '1d' ? false : true"
[locale]="user?.settings?.locale"
[ngClass]="{ 'pr-3': deviceType === 'mobile' }"
[showGradient]="true"
[showLoader]="false"
[showXAxis]="false"
[showYAxis]="false"
></gf-line-chart>
</div>
</div>
</div>
<div class="overview-container row mt-1">
<div class="col">
<gf-portfolio-performance
class="pb-4"
[baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="deviceType"
[errors]="errors"
[isAllTimeHigh]="isAllTimeHigh"
[isAllTimeLow]="isAllTimeLow"
[isLoading]="isLoadingPerformance"
[options]="dateRangeOptions"
(change)="onChangeDateRange($event.value)"
></gf-toggle>
[locale]="user?.settings?.locale"
[performance]="performance"
[showDetails]="showDetails"
></gf-portfolio-performance>
<div *ngIf="showDetails" class="text-center">
<gf-toggle
[defaultValue]="user?.settings?.dateRange"
[isLoading]="isLoadingPerformance"
[options]="dateRangeOptions"
(change)="onChangeDateRange($event.value)"
></gf-toggle>
</div>
</div>
</div>
</div>
</ng-template>
</div>

2
apps/client/src/app/components/home-overview/home-overview.module.ts

@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
import { GfPortfolioPerformanceModule } from '@ghostfolio/client/components/portfolio-performance/portfolio-performance.module';
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
@ -16,6 +17,7 @@ import { HomeOverviewComponent } from './home-overview.component';
GfNoTransactionsInfoModule,
GfPortfolioPerformanceModule,
GfToggleModule,
MatButtonModule,
RouterModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]

4
apps/client/src/app/components/home-overview/home-overview.scss

@ -31,4 +31,8 @@
top: 0;
}
}
.introduction {
max-width: 50rem;
}
}

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

@ -50,7 +50,7 @@ export class PortfolioSummaryComponent implements OnChanges, OnInit {
public onEditEmergencyFund() {
const emergencyFundInput = prompt(
$localize`Please enter the amount of your emergency fund:`,
this.summary.emergencyFund?.toString() ?? '0'
this.summary.emergencyFund?.total?.toString() ?? '0'
);
const emergencyFund = parseFloat(emergencyFundInput?.trim());

3
apps/client/src/app/core/auth.guard.ts

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Router,
RouterStateSnapshot
} from '@angular/router';
@ -12,7 +11,7 @@ import { EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
export class AuthGuard {
private static PUBLIC_PAGE_ROUTES = [
'/about',
'/about/changelog',

9
apps/client/src/app/pages/about/about-page.scss

@ -11,14 +11,9 @@
padding-bottom: constant(safe-area-inset-bottom);
::ng-deep {
gf-about-page,
gf-changelog-page,
gf-privacy-policy-page {
flex: 1 1 auto;
overflow-y: auto;
}
.mat-mdc-tab-link-container {
--mat-tab-header-active-focus-indicator-color: transparent;
--mat-tab-header-active-hover-indicator-color: transparent;
--mdc-tab-indicator-active-indicator-color: transparent;
.mat-mdc-tab-link {

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

@ -15,6 +15,10 @@ import {
import { ActivatedRoute, Router } from '@angular/router';
import { CreateAccessDto } from '@ghostfolio/api/app/access/create-access.dto';
import { DataService } from '@ghostfolio/client/services/data.service';
import {
STAY_SIGNED_IN,
SettingsStorageService
} from '@ghostfolio/client/services/settings-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service';
import { getDateFormatString } from '@ghostfolio/common/helper';
@ -80,6 +84,7 @@ export class AccountPageComponent implements OnDestroy, OnInit {
private snackBar: MatSnackBar,
private route: ActivatedRoute,
private router: Router,
private settingsStorageService: SettingsStorageService,
private stripeService: StripeService,
private userService: UserService,
public webAuthnService: WebAuthnService
@ -397,6 +402,8 @@ export class AccountPageComponent implements OnDestroy, OnInit {
})
)
.subscribe(() => {
this.settingsStorageService.removeSetting(STAY_SIGNED_IN);
this.update();
});
}

7
apps/client/src/app/pages/account/account-page.html

@ -235,7 +235,12 @@
</div>
</div>
<div class="align-items-center d-flex mt-4 py-1">
<div class="pr-1 w-50" i18n>Sign in with fingerprint</div>
<div class="pr-1 w-50">
<div i18n>Biometric Authentication</div>
<div class="hint-text text-muted" i18n>
Sign in with fingerprint
</div>
</div>
<div class="pl-1 w-50">
<mat-checkbox
#toggleSignInWithFingerprintEnabledElement

11
apps/client/src/app/pages/admin/admin-page.scss

@ -11,16 +11,9 @@
padding-bottom: constant(safe-area-inset-bottom);
::ng-deep {
gf-admin-jobs,
gf-admin-market-data,
gf-admin-overview,
gf-admin-settings,
gf-admin-users {
flex: 1 1 auto;
overflow-y: auto;
}
.mat-mdc-tab-link-container {
--mat-tab-header-active-focus-indicator-color: transparent;
--mat-tab-header-active-hover-indicator-color: transparent;
--mdc-tab-indicator-active-indicator-color: transparent;
.mat-mdc-tab-link {

10
apps/client/src/app/pages/home/home-page.scss

@ -11,15 +11,9 @@
padding-bottom: constant(safe-area-inset-bottom);
::ng-deep {
gf-home-holdings,
gf-home-market,
gf-home-overview,
gf-home-summary {
flex: 1 1 auto;
overflow-y: auto;
}
.mat-mdc-tab-link-container {
--mat-tab-header-active-focus-indicator-color: transparent;
--mat-tab-header-active-hover-indicator-color: transparent;
--mdc-tab-indicator-active-indicator-color: transparent;
.mat-mdc-tab-link {

12
apps/client/src/app/pages/open/open-page.html

@ -3,7 +3,7 @@
<div class="col">
<h3 class="d-none d-sm-block mb-3 text-center">Open Startup</h3>
<div class="intro-container">
<p>
<p i18n>
At Ghostfolio, transparency is at the core of our values. We publish
the source code as
<a
@ -18,7 +18,7 @@
>AGPL-3.0 license</a
>
and we openly share aggregated key metrics of the platform’s
performance.
operational status.
</p>
</div>
</div>
@ -31,6 +31,7 @@
<div class="row">
<div class="col-xs-12 col-md-4 my-2">
<gf-value
i18n
size="large"
subLabel="(Last 24 hours)"
[locale]="user?.settings?.locale"
@ -40,6 +41,7 @@
</div>
<div class="col-xs-12 col-md-4 my-2">
<gf-value
i18n
size="large"
subLabel="(Last 30 days)"
[locale]="user?.settings?.locale"
@ -49,6 +51,7 @@
</div>
<div class="col-xs-12 col-md-4 my-2">
<gf-value
i18n
size="large"
subLabel="(Last 30 days)"
[locale]="user?.settings?.locale"
@ -62,6 +65,7 @@
href="https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg"
>
<gf-value
i18n
size="large"
[locale]="user?.settings?.locale"
[value]="statistics?.slackCommunityUsers ?? '-'"
@ -75,6 +79,7 @@
href="https://github.com/ghostfolio/ghostfolio/graphs/contributors"
>
<gf-value
i18n
size="large"
[locale]="user?.settings?.locale"
[value]="statistics?.gitHubContributors ?? '-'"
@ -88,6 +93,7 @@
href="https://github.com/ghostfolio/ghostfolio/stargazers"
>
<gf-value
i18n
size="large"
[locale]="user?.settings?.locale"
[value]="statistics?.gitHubStargazers ?? '-'"
@ -101,6 +107,7 @@
href="https://hub.docker.com/r/ghostfolio/ghostfolio"
>
<gf-value
i18n
size="large"
[locale]="user?.settings?.locale"
[value]="statistics?.dockerHubPulls ?? '-'"
@ -111,6 +118,7 @@
<div class="col-xs-12 col-md-4 my-2">
<a class="d-block" href="https://status.ghostfol.io">
<gf-value
i18n
size="large"
subLabel="(Last 90 days)"
[isPercent]="true"

44
apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts

@ -86,7 +86,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
value: number;
};
};
public UNKNOWN_KEY = UNKNOWN_KEY;
public user: User;
public worldMapChartFormat: string;
@ -229,20 +229,29 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
}
};
this.markets = {
[UNKNOWN_KEY]: {
name: UNKNOWN_KEY,
value: 0
},
developedMarkets: {
name: 'developedMarkets',
value: undefined
value: 0
},
emergingMarkets: {
name: 'emergingMarkets',
value: undefined
value: 0
},
otherMarkets: {
name: 'otherMarkets',
value: undefined
value: 0
}
};
this.marketsAdvanced = {
[UNKNOWN_KEY]: {
id: UNKNOWN_KEY,
name: UNKNOWN_KEY,
value: 0
},
asiaPacific: {
id: 'asiaPacific',
name: translate('Asia-Pacific'),
@ -346,16 +355,6 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
// Prepare analysis data by continents, countries and sectors except for cash
if (position.countries.length > 0) {
if (!this.markets.developedMarkets.value) {
this.markets.developedMarkets.value = 0;
}
if (!this.markets.emergingMarkets.value) {
this.markets.emergingMarkets.value = 0;
}
if (!this.markets.otherMarkets.value) {
this.markets.otherMarkets.value = 0;
}
this.markets.developedMarkets.value +=
position.markets.developedMarkets *
(isNumber(position.valueInBaseCurrency)
@ -447,6 +446,18 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
)
? this.portfolioDetails.holdings[symbol].valueInBaseCurrency
: this.portfolioDetails.holdings[symbol].valueInPercentage;
this.markets[UNKNOWN_KEY].value += isNumber(
position.valueInBaseCurrency
)
? this.portfolioDetails.holdings[symbol].valueInBaseCurrency
: this.portfolioDetails.holdings[symbol].valueInPercentage;
this.marketsAdvanced[UNKNOWN_KEY].value += isNumber(
position.valueInBaseCurrency
)
? this.portfolioDetails.holdings[symbol].valueInBaseCurrency
: this.portfolioDetails.holdings[symbol].valueInPercentage;
}
if (position.sectors.length > 0) {
@ -511,7 +522,8 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
const marketsTotal =
this.markets.developedMarkets.value +
this.markets.emergingMarkets.value +
this.markets.otherMarkets.value;
this.markets.otherMarkets.value +
this.markets[UNKNOWN_KEY].value;
this.markets.developedMarkets.value =
this.markets.developedMarkets.value / marketsTotal;
@ -519,6 +531,8 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
this.markets.emergingMarkets.value / marketsTotal;
this.markets.otherMarkets.value =
this.markets.otherMarkets.value / marketsTotal;
this.markets[UNKNOWN_KEY].value =
this.markets[UNKNOWN_KEY].value / marketsTotal;
}
public onAccountChartClicked({ symbol }: UniqueAsset) {

18
apps/client/src/app/pages/portfolio/allocations/allocations-page.html

@ -215,7 +215,7 @@
></gf-world-map-chart>
</div>
<div class="row">
<div class="col-xs-12 col-md-4 my-2">
<div class="col-xs-12 col-md my-2">
<gf-value
i18n
size="large"
@ -224,7 +224,7 @@
>Developed Markets</gf-value
>
</div>
<div class="col-xs-12 col-md-4 my-2">
<div class="col-xs-12 col-md my-2">
<gf-value
i18n
size="large"
@ -233,7 +233,7 @@
>Emerging Markets</gf-value
>
</div>
<div class="col-xs-12 col-md-4 my-2">
<div class="col-xs-12 col-md my-2">
<gf-value
i18n
size="large"
@ -242,6 +242,18 @@
>Other Markets</gf-value
>
</div>
<div
*ngIf="markets?.[UNKNOWN_KEY]?.value > 0"
class="col-xs-12 col-md my-2"
>
<gf-value
i18n
size="large"
[isPercent]="true"
[value]="markets?.[UNKNOWN_KEY]?.value"
>No data available</gf-value
>
</div>
</div>
</mat-card-content>
</mat-card>

1
apps/client/src/app/pages/portfolio/allocations/allocations-page.scss

@ -31,6 +31,7 @@
}
.mat-mdc-progress-bar {
--mdc-linear-progress-active-indicator-height: 0.5rem;
--mdc-linear-progress-track-height: 0.5rem;
border-radius: 0.25rem;

11
apps/client/src/app/pages/portfolio/portfolio-page.scss

@ -11,16 +11,9 @@
padding-bottom: constant(safe-area-inset-bottom);
::ng-deep {
gf-activities-page,
gf-allocations-page,
gf-analysis-page,
gf-holdings-page,
gf-fire-page {
flex: 1 1 auto;
overflow-y: auto;
}
.mat-mdc-tab-link-container {
--mat-tab-header-active-focus-indicator-color: transparent;
--mat-tab-header-active-hover-indicator-color: transparent;
--mdc-tab-indicator-active-indicator-color: transparent;
.mat-mdc-tab-link {

13
apps/client/src/app/pages/public/public-page.component.ts

@ -44,6 +44,7 @@ export class PublicPageComponent implements OnInit {
public symbols: {
[name: string]: { name: string; symbol: string; value: number };
};
public UNKNOWN_KEY = UNKNOWN_KEY;
private id: string;
private unsubscribeSubject = new Subject<void>();
@ -99,6 +100,10 @@ export class PublicPageComponent implements OnInit {
}
};
this.markets = {
[UNKNOWN_KEY]: {
name: UNKNOWN_KEY,
value: 0
},
developedMarkets: {
name: 'developedMarkets',
value: 0
@ -180,6 +185,9 @@ export class PublicPageComponent implements OnInit {
this.countries[UNKNOWN_KEY].value +=
this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency;
this.markets[UNKNOWN_KEY].value +=
this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency;
}
if (position.sectors.length > 0) {
@ -214,7 +222,8 @@ export class PublicPageComponent implements OnInit {
const marketsTotal =
this.markets.developedMarkets.value +
this.markets.emergingMarkets.value +
this.markets.otherMarkets.value;
this.markets.otherMarkets.value +
this.markets[UNKNOWN_KEY].value;
this.markets.developedMarkets.value =
this.markets.developedMarkets.value / marketsTotal;
@ -222,6 +231,8 @@ export class PublicPageComponent implements OnInit {
this.markets.emergingMarkets.value / marketsTotal;
this.markets.otherMarkets.value =
this.markets.otherMarkets.value / marketsTotal;
this.markets[UNKNOWN_KEY].value =
this.markets[UNKNOWN_KEY].value / marketsTotal;
}
public ngOnDestroy() {

18
apps/client/src/app/pages/public/public-page.html

@ -84,7 +84,7 @@
></gf-world-map-chart>
</div>
<div class="row">
<div class="col-xs-12 col-md-4 my-2">
<div class="col-xs-12 col-md my-2">
<gf-value
i18n
size="large"
@ -93,7 +93,7 @@
>Developed Markets</gf-value
>
</div>
<div class="col-xs-12 col-md-4 my-2">
<div class="col-xs-12 col-md my-2">
<gf-value
i18n
size="large"
@ -102,7 +102,7 @@
>Emerging Markets</gf-value
>
</div>
<div class="col-xs-12 col-md-4 my-2">
<div class="col-xs-12 col-md my-2">
<gf-value
i18n
size="large"
@ -111,6 +111,18 @@
>Other Markets</gf-value
>
</div>
<div
*ngIf="markets?.[UNKNOWN_KEY]?.value > 0"
class="col-xs-12 col-md my-2"
>
<gf-value
i18n
size="large"
[isPercent]="true"
[value]="markets?.[UNKNOWN_KEY]?.value"
>No data available</gf-value
>
</div>
</div>
</mat-card-content>
</mat-card>

8
apps/client/src/app/pages/zen/zen-page.scss

@ -11,13 +11,9 @@
padding-bottom: constant(safe-area-inset-bottom);
::ng-deep {
gf-home-holdings,
gf-home-overview {
flex: 1 1 auto;
overflow-y: auto;
}
.mat-mdc-tab-link-container {
--mat-tab-header-active-focus-indicator-color: transparent;
--mat-tab-header-active-hover-indicator-color: transparent;
--mdc-tab-indicator-active-indicator-color: transparent;
.mat-mdc-tab-link {

0
apps/client/src/assets/assetlinks.json → apps/client/src/assets/.well-known/assetlinks.json

0
apps/client/src/assets/index.html

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

@ -18,7 +18,7 @@
<target state="translated">Das Ausfallrisiko beim Börsenhandel kann erheblich sein. Es ist nicht ratsam, Geld zu investieren, welches du kurzfristig benötigst.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">180,181</context>
<context context-type="linenumber">181,182</context>
</context-group>
</trans-unit>
<trans-unit id="b6192ee60a5e0e40874f4d02fbaaa584a0f1541e" datatype="html">
@ -758,7 +758,7 @@
<target state="translated">Ressourcen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">72</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -778,7 +778,7 @@
<target state="translated">Preise</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -898,7 +898,7 @@
<target state="translated">Über</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -938,7 +938,7 @@
<target state="translated">Features</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">85</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -954,7 +954,7 @@
<target state="translated">Märkte</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">70</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -978,7 +978,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">152</context>
</context-group>
</trans-unit>
<trans-unit id="5207635742003539443" datatype="html">
@ -1446,7 +1446,7 @@
<target state="translated">Datenschutzbestimmungen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html</context>
@ -1458,7 +1458,7 @@
<target state="translated">Blog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html</context>
@ -1526,7 +1526,7 @@
<target state="translated">Changelog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/changelog/changelog-page.html</context>
@ -1538,7 +1538,7 @@
<target state="translated">Lizenz</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">90</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/license/license-page.html</context>
@ -1570,7 +1570,7 @@
<target state="translated">Bitte gebe deinen Gutscheincode ein:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">236</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1578,7 +1578,7 @@
<target state="translated">Gutscheincode konnte nicht eingelöst werden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">246</context>
<context context-type="linenumber">251</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1586,7 +1586,7 @@
<target state="translated">Gutscheincode wurde eingelöst</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">258</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1594,7 +1594,7 @@
<target state="translated">Neu laden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">264</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1602,7 +1602,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/pages/account/account-page.component.ts</context>
<context context-type="linenumber">305</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1705,12 +1705,12 @@
<context context-type="linenumber">193</context>
</context-group>
</trans-unit>
<trans-unit id="9ae348ee3a7319c2fc4794fa8bc425999d355f8f" datatype="html">
<source>Sign in with fingerprint</source>
<target state="translated">Einloggen mit Fingerabdruck</target>
<trans-unit id="78cf1b9b94e0e93e65d1d522001a5c54304e9f25" datatype="html">
<source> Sign in with fingerprint </source>
<target state="translated"> Einloggen mit Fingerabdruck </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">238</context>
<context context-type="linenumber">240,242</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1718,7 +1718,7 @@
<target state="translated">Benutzer ID</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">268</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1726,7 +1726,7 @@
<target state="translated">Zugangsberechtigung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">282</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1954,7 +1954,7 @@
<target state="translated">Nach Konto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">278</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
@ -2002,7 +2002,7 @@
<target state="translated">Nach Land</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2140,6 +2140,10 @@
<trans-unit id="49af37bcd0c34e88ab989641e52ef92f3fb56e06" datatype="html">
<source>Add activity</source>
<target state="translate">Aktivität hinzufügen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">58</context>
</context-group>
<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">8</context>
@ -2318,7 +2322,7 @@
<target state="translated">Ghostfolio verschafft Ihnen den Überblick über Ihr Vermögen.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">135,137</context>
<context context-type="linenumber">147,149</context>
</context-group>
</trans-unit>
<trans-unit id="8298333184054476827" datatype="html">
@ -2671,7 +2675,7 @@
</trans-unit>
<trans-unit id="7233cd3a1ef8913fa5c6db7a29c88044646ceacc" datatype="html">
<source>Other Markets</source>
<target state="translated">Andere Länder</target>
<target state="translated">Übrige Länder</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">242</context>
@ -2798,7 +2802,7 @@
<target state="translated">Filtern nach Konto, Währung, Symbol oder Typ...</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
<context context-type="linenumber">418</context>
<context context-type="linenumber">419</context>
</context-group>
</trans-unit>
<trans-unit id="fbaaeb297e70b9a800acf841b9d26c19d60651ef" datatype="html">
@ -2826,7 +2830,7 @@
<target state="translated">Experimentelle Funktionen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">253</context>
<context context-type="linenumber">258</context>
</context-group>
</trans-unit>
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
@ -2874,7 +2878,7 @@
<target state="translated">Automatisch</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -3174,7 +3178,7 @@
<target state="translated">Community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
@ -3446,7 +3450,7 @@
<target state="translated"> Vorschau auf kommende Funktionalität </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">254,256</context>
<context context-type="linenumber">259,261</context>
</context-group>
</trans-unit>
<trans-unit id="280c5b1f5b5b748fbbb37bf7a12c37f41539c1ff" datatype="html">
@ -3870,7 +3874,7 @@
<target state="translated">Nach ETF-Anbieter</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">298</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="e0c92dc95e1e0fc33d21b5e2df5ea28a86439d56" datatype="html">
@ -4070,7 +4074,7 @@
<target state="translated">Private Finanzen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">68</context>
</context-group>
</trans-unit>
<trans-unit id="6992d42edf46c12a4a9ecb3b7a46761a967c8ee1" datatype="html">
@ -4078,7 +4082,7 @@
<target state="translated">Häufig gestellte Fragen (FAQ)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -7085,6 +7089,166 @@
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="6fafe6662f57e08bca1f26bc2d2c9631a106ba29" datatype="html">
<source>Welcome to Ghostfolio</source>
<target state="translated">Herzlich willkommen bei Ghostfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="71c2ec88fc3953a1db6cfca218173fcf489fa803" datatype="html">
<source>Setup your accounts</source>
<target state="translated">Konten einrichten</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="43cc09795191db2dc5925aed2b8f920e1822e13f" datatype="html">
<source>Get a comprehensive financial overview by adding your bank and brokerage accounts.</source>
<target state="translated">Verschaffe dir einen umfassenden Überblick, indem du deine Bank- und Wertpapierkonten hinzufügst.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">19,20</context>
</context-group>
</trans-unit>
<trans-unit id="4747213591a189a98d5aface48f2755f863025a4" datatype="html">
<source>Capture your activities</source>
<target state="translated">Aktivitäten erfassen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="804b8810cfbf317424a9fd6387ad57ec5bec972c" datatype="html">
<source>Record your investment activities to keep your portfolio up to date.</source>
<target state="translated">Erfasse deine Investitionsaktivitäten, um dein Portfolio auf dem neuesten Stand zu halten.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">28,29</context>
</context-group>
</trans-unit>
<trans-unit id="3d0333063dd1cd5062db56f859be74bdfb25a7f3" datatype="html">
<source>Monitor and analyze your portfolio</source>
<target state="translated">Portfolio überwachen und analysieren</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="8bcb7e0eac9c406765fadda3238974f271facce6" datatype="html">
<source>Track your progress in real-time with comprehensive analysis and insights.</source>
<target state="translated">Verfolge die Entwicklung in Echtzeit mit umfassenden Analysen und Einblicken.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">37,38</context>
</context-group>
</trans-unit>
<trans-unit id="0038953528872613d2eff0ed3912b109d9e9b5cf" datatype="html">
<source>No data available</source>
<target state="translated">Keine Daten verfügbar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="06c1bcff740ab4b1d5283d937d22e9daf8b31933" datatype="html">
<source>Ready to take control of your personal finances?</source>
<target state="translated">Bist du bereit, die Kontrolle über deine Finanzen zu übernehmen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="1bdfdbf86e61060cf785b6bd53692b47c9afec63" datatype="html">
<source>Setup accounts</source>
<target state="translated">Konten einrichten</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="fa22693b23a8bed32d787023df105a7b40002f9c" datatype="html">
<source>Biometric Authentication</source>
<target state="translated">Biometrische Authentifizierung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">239</context>
</context-group>
</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"> Bei Ghostfolio gehört Transparenz zum zentralen Inhalt unserer Grundwerte. Wir publizieren den Quellcode als <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) unter der <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-Lizenz<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> und veröffentlichen aggregierte Kennzahlen über den Betriebsstatus der Plattform. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6,22</context>
</context-group>
</trans-unit>
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
<source>Active Users</source>
<target state="translated">Aktive Nutzer</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
<source>New Users</source>
<target state="translated">Neue Nutzer</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">49</context>
</context-group>
</trans-unit>
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
<source>Users in Slack community</source>
<target state="translated">Nutzer in der Slack Community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
<source>Contributors on GitHub</source>
<target state="translated">Contributors auf GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
<source>Stars on GitHub</source>
<target state="translated">Sterne auf GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="512b096f732f5e05dc1c451276b7a2b1a2509acd" datatype="html">
<source>Pulls on Docker Hub</source>
<target state="translated">Downloads auf Docker Hub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<target state="translated">Verfügbarkeit</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

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

@ -19,7 +19,7 @@
<target state="new">El riesgo de pérdida en trading puede ser importante. No es aconsejable invertir dinero que puedas necesitar a corto plazo.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">180,181</context>
<context context-type="linenumber">181,182</context>
</context-group>
</trans-unit>
<trans-unit id="b6192ee60a5e0e40874f4d02fbaaa584a0f1541e" datatype="html">
@ -759,7 +759,7 @@
<target state="translated">Recursos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">72</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -779,7 +779,7 @@
<target state="translated">Precios</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -899,7 +899,7 @@
<target state="translated">Sobre</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -939,7 +939,7 @@
<target state="translated">Funcionalidades</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">85</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -955,7 +955,7 @@
<target state="translated">Mercados</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">70</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -979,7 +979,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">152</context>
</context-group>
</trans-unit>
<trans-unit id="5207635742003539443" datatype="html">
@ -1447,7 +1447,7 @@
<target state="translated">Política de privacidad</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html</context>
@ -1459,7 +1459,7 @@
<target state="translated">Blog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html</context>
@ -1527,7 +1527,7 @@
<target state="translated">Registro de cambios</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/changelog/changelog-page.html</context>
@ -1539,7 +1539,7 @@
<target state="translated">Licencia de uso</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">90</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/license/license-page.html</context>
@ -1571,7 +1571,7 @@
<target state="translated">Por favor, ingresa tu código de cupón:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">236</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1579,7 +1579,7 @@
<target state="translated">No se puede canjear este código de cupón</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">246</context>
<context context-type="linenumber">251</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1587,7 +1587,7 @@
<target state="translated">El codigo de cupón ha sido canjeado</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">258</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1595,7 +1595,7 @@
<target state="translated">Refrescar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">264</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1603,7 +1603,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/pages/account/account-page.component.ts</context>
<context context-type="linenumber">305</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1706,12 +1706,12 @@
<context context-type="linenumber">193</context>
</context-group>
</trans-unit>
<trans-unit id="9ae348ee3a7319c2fc4794fa8bc425999d355f8f" datatype="html">
<source>Sign in with fingerprint</source>
<target state="translated">Accede con huella digital</target>
<trans-unit id="78cf1b9b94e0e93e65d1d522001a5c54304e9f25" datatype="html">
<source> Sign in with fingerprint </source>
<target state="translated"> Accede con huella digital </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">238</context>
<context context-type="linenumber">240,242</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1719,7 +1719,7 @@
<target state="translated">ID usuario</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">268</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1727,7 +1727,7 @@
<target state="translated">Acceso concedido</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">282</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1955,7 +1955,7 @@
<target state="translated">Por cuenta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">278</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
@ -2003,7 +2003,7 @@
<target state="translated">Por país</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2141,6 +2141,10 @@
<trans-unit id="49af37bcd0c34e88ab989641e52ef92f3fb56e06" datatype="html">
<source>Add activity</source>
<target state="translated">Añadir operación</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">58</context>
</context-group>
<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">8</context>
@ -2319,7 +2323,7 @@
<target state="translated">Ghostfolio te permite hacer un seguimiento de tu riqueza.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">135,137</context>
<context context-type="linenumber">147,149</context>
</context-group>
</trans-unit>
<trans-unit id="8298333184054476827" datatype="html">
@ -2799,7 +2803,7 @@
<target state="translated">Filtrar por cuenta, divisa, símbolo o tipo...</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
<context context-type="linenumber">418</context>
<context context-type="linenumber">419</context>
</context-group>
</trans-unit>
<trans-unit id="3d14940af7de691ac27efb67bef3e974cbe3281c" datatype="html">
@ -2827,7 +2831,7 @@
<target state="translated">Funcionalidades experimentales</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">253</context>
<context context-type="linenumber">258</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
@ -2875,7 +2879,7 @@
<target state="translated">Automático</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -3175,7 +3179,7 @@
<target state="translated">Comunidad</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
@ -3447,7 +3451,7 @@
<target state="new"> Sneak peek at upcoming functionality </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">254,256</context>
<context context-type="linenumber">259,261</context>
</context-group>
</trans-unit>
<trans-unit id="280c5b1f5b5b748fbbb37bf7a12c37f41539c1ff" datatype="html">
@ -3871,7 +3875,7 @@
<target state="new">By ETF Provider</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">298</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="e0c92dc95e1e0fc33d21b5e2df5ea28a86439d56" datatype="html">
@ -4071,7 +4075,7 @@
<target state="new">Personal Finance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">68</context>
</context-group>
</trans-unit>
<trans-unit id="6992d42edf46c12a4a9ecb3b7a46761a967c8ee1" datatype="html">
@ -4079,7 +4083,7 @@
<target state="new">Frequently Asked Questions (FAQ)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -7086,6 +7090,166 @@
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="6fafe6662f57e08bca1f26bc2d2c9631a106ba29" datatype="html">
<source>Welcome to Ghostfolio</source>
<target state="new">Welcome to Ghostfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="71c2ec88fc3953a1db6cfca218173fcf489fa803" datatype="html">
<source>Setup your accounts</source>
<target state="new">Setup your accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="43cc09795191db2dc5925aed2b8f920e1822e13f" datatype="html">
<source>Get a comprehensive financial overview by adding your bank and brokerage accounts.</source>
<target state="new">Get a comprehensive financial overview by adding your bank and brokerage accounts.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">19,20</context>
</context-group>
</trans-unit>
<trans-unit id="4747213591a189a98d5aface48f2755f863025a4" datatype="html">
<source>Capture your activities</source>
<target state="new">Capture your activities</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="804b8810cfbf317424a9fd6387ad57ec5bec972c" datatype="html">
<source>Record your investment activities to keep your portfolio up to date.</source>
<target state="new">Record your investment activities to keep your portfolio up to date.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">28,29</context>
</context-group>
</trans-unit>
<trans-unit id="3d0333063dd1cd5062db56f859be74bdfb25a7f3" datatype="html">
<source>Monitor and analyze your portfolio</source>
<target state="new">Monitor and analyze your portfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="8bcb7e0eac9c406765fadda3238974f271facce6" datatype="html">
<source>Track your progress in real-time with comprehensive analysis and insights.</source>
<target state="new">Track your progress in real-time with comprehensive analysis and insights.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">37,38</context>
</context-group>
</trans-unit>
<trans-unit id="0038953528872613d2eff0ed3912b109d9e9b5cf" datatype="html">
<source>No data available</source>
<target state="new">No data available</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="06c1bcff740ab4b1d5283d937d22e9daf8b31933" datatype="html">
<source>Ready to take control of your personal finances?</source>
<target state="new">Ready to take control of your personal finances?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="1bdfdbf86e61060cf785b6bd53692b47c9afec63" datatype="html">
<source>Setup accounts</source>
<target state="new">Setup accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="fa22693b23a8bed32d787023df105a7b40002f9c" datatype="html">
<source>Biometric Authentication</source>
<target state="new">Biometric Authentication</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">239</context>
</context-group>
</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="new"> 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. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6,22</context>
</context-group>
</trans-unit>
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
<source>Active Users</source>
<target state="new">Active Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
<source>New Users</source>
<target state="new">New Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">49</context>
</context-group>
</trans-unit>
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
<source>Users in Slack community</source>
<target state="new">Users in Slack community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
<source>Contributors on GitHub</source>
<target state="new">Contributors on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
<source>Stars on GitHub</source>
<target state="new">Stars on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="512b096f732f5e05dc1c451276b7a2b1a2509acd" datatype="html">
<source>Pulls on Docker Hub</source>
<target state="new">Pulls on Docker Hub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<target state="new">Uptime</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

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

@ -6,7 +6,7 @@
<target state="translated">Le risque de perte en investissant peut être important. Il est déconseillé d&apos;investir de l&apos;argent dont vous pourriez avoir besoin à court terme.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">180,181</context>
<context context-type="linenumber">181,182</context>
</context-group>
</trans-unit>
<trans-unit id="fbaaeb297e70b9a800acf841b9d26c19d60651ef" datatype="html">
@ -1050,7 +1050,7 @@
<target state="translated">Ressources</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">72</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1070,7 +1070,7 @@
<target state="translated">Prix</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1190,7 +1190,7 @@
<target state="translated">À propos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1230,7 +1230,7 @@
<target state="translated">Fonctionnalités</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">85</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1246,7 +1246,7 @@
<target state="translated">Marchés</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">70</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1798,7 +1798,7 @@
<target state="translated">Historique des modifications</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/changelog/changelog-page.html</context>
@ -1810,7 +1810,7 @@
<target state="Politique de Vie Privée">License</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">90</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/license/license-page.html</context>
@ -1834,7 +1834,7 @@
<target state="translated">Politique de Vie Privée</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html</context>
@ -1854,7 +1854,7 @@
<target state="translated">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="5196970976032945030" datatype="html">
@ -1862,7 +1862,7 @@
<target state="translated">Veuillez entrer votre code promotionnel :</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">236</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1870,7 +1870,7 @@
<target state="translated">Le code promotionnel n&apos;a pas pu être appliqué</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">246</context>
<context context-type="linenumber">251</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1878,7 +1878,7 @@
<target state="translated">Le code promotionnel a été appliqué</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">258</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1886,7 +1886,7 @@
<target state="translated">Rafraîchir</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">264</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1894,7 +1894,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/pages/account/account-page.component.ts</context>
<context context-type="linenumber">305</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1982,7 +1982,7 @@
<target state="translated">Communauté</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
@ -2069,12 +2069,12 @@
<context context-type="linenumber">193</context>
</context-group>
</trans-unit>
<trans-unit id="9ae348ee3a7319c2fc4794fa8bc425999d355f8f" datatype="html">
<source>Sign in with fingerprint</source>
<target state="translated">Se connecter avec empreinte</target>
<trans-unit id="78cf1b9b94e0e93e65d1d522001a5c54304e9f25" datatype="html">
<source> Sign in with fingerprint </source>
<target state="translated"> Se connecter avec empreinte </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">238</context>
<context context-type="linenumber">240,242</context>
</context-group>
</trans-unit>
<trans-unit id="03b120b05e0922e5e830c3466fda9ee0bfbf59e9" datatype="html">
@ -2082,7 +2082,7 @@
<target state="translated">Fonctionnalités expérimentales</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">253</context>
<context context-type="linenumber">258</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -2090,7 +2090,7 @@
<target state="translated">ID d&apos;utilisateur</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">268</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -2098,7 +2098,7 @@
<target state="translated">Accès donné</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">282</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -2226,7 +2226,7 @@
<target state="translated">Blog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html</context>
@ -2388,6 +2388,10 @@
<trans-unit id="49af37bcd0c34e88ab989641e52ef92f3fb56e06" datatype="html">
<source>Add activity</source>
<target state="translated">Ajouter Activité</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">58</context>
</context-group>
<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">8</context>
@ -2558,7 +2562,7 @@
<target state="translated">Par Compte</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">278</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
@ -2606,7 +2610,7 @@
<target state="translated">Par Pays</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2834,7 +2838,7 @@
<target state="translated"> Ghostfolio vous aide à garder un aperçu de votre patrimoine. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">135,137</context>
<context context-type="linenumber">147,149</context>
</context-group>
</trans-unit>
<trans-unit id="802222cb4754d74846b18f651b1f94e21576185d" datatype="html">
@ -2846,7 +2850,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">152</context>
</context-group>
</trans-unit>
<trans-unit id="8298333184054476827" datatype="html">
@ -3030,7 +3034,7 @@
<target state="translated">Filtrer par compte, devise, symbole, ou type...</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
<context context-type="linenumber">418</context>
<context context-type="linenumber">419</context>
</context-group>
</trans-unit>
<trans-unit id="170f7de02b14690fb9c1999a16926c0044bfd5c1" datatype="html">
@ -3446,7 +3450,7 @@
<target state="translated"> Avant-première de fonctionnalités futures </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">254,256</context>
<context context-type="linenumber">259,261</context>
</context-group>
</trans-unit>
<trans-unit id="280c5b1f5b5b748fbbb37bf7a12c37f41539c1ff" datatype="html">
@ -3870,7 +3874,7 @@
<target state="translated">Par Émetteur d&apos;ETF</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">298</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="e0c92dc95e1e0fc33d21b5e2df5ea28a86439d56" datatype="html">
@ -4070,7 +4074,7 @@
<target state="translated">Finance Personnelle</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">68</context>
</context-group>
</trans-unit>
<trans-unit id="6992d42edf46c12a4a9ecb3b7a46761a967c8ee1" datatype="html">
@ -4078,7 +4082,7 @@
<target state="translated">Questions Fréquentes (FAQ)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -7085,6 +7089,166 @@
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="6fafe6662f57e08bca1f26bc2d2c9631a106ba29" datatype="html">
<source>Welcome to Ghostfolio</source>
<target state="new">Welcome to Ghostfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="71c2ec88fc3953a1db6cfca218173fcf489fa803" datatype="html">
<source>Setup your accounts</source>
<target state="new">Setup your accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="43cc09795191db2dc5925aed2b8f920e1822e13f" datatype="html">
<source>Get a comprehensive financial overview by adding your bank and brokerage accounts.</source>
<target state="new">Get a comprehensive financial overview by adding your bank and brokerage accounts.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">19,20</context>
</context-group>
</trans-unit>
<trans-unit id="4747213591a189a98d5aface48f2755f863025a4" datatype="html">
<source>Capture your activities</source>
<target state="new">Capture your activities</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="804b8810cfbf317424a9fd6387ad57ec5bec972c" datatype="html">
<source>Record your investment activities to keep your portfolio up to date.</source>
<target state="new">Record your investment activities to keep your portfolio up to date.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">28,29</context>
</context-group>
</trans-unit>
<trans-unit id="3d0333063dd1cd5062db56f859be74bdfb25a7f3" datatype="html">
<source>Monitor and analyze your portfolio</source>
<target state="new">Monitor and analyze your portfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="8bcb7e0eac9c406765fadda3238974f271facce6" datatype="html">
<source>Track your progress in real-time with comprehensive analysis and insights.</source>
<target state="new">Track your progress in real-time with comprehensive analysis and insights.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">37,38</context>
</context-group>
</trans-unit>
<trans-unit id="0038953528872613d2eff0ed3912b109d9e9b5cf" datatype="html">
<source>No data available</source>
<target state="new">No data available</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="06c1bcff740ab4b1d5283d937d22e9daf8b31933" datatype="html">
<source>Ready to take control of your personal finances?</source>
<target state="new">Ready to take control of your personal finances?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="1bdfdbf86e61060cf785b6bd53692b47c9afec63" datatype="html">
<source>Setup accounts</source>
<target state="new">Setup accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="fa22693b23a8bed32d787023df105a7b40002f9c" datatype="html">
<source>Biometric Authentication</source>
<target state="new">Biometric Authentication</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">239</context>
</context-group>
</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="new"> 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. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6,22</context>
</context-group>
</trans-unit>
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
<source>Active Users</source>
<target state="new">Active Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
<source>New Users</source>
<target state="new">New Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">49</context>
</context-group>
</trans-unit>
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
<source>Users in Slack community</source>
<target state="new">Users in Slack community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
<source>Contributors on GitHub</source>
<target state="new">Contributors on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
<source>Stars on GitHub</source>
<target state="new">Stars on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="512b096f732f5e05dc1c451276b7a2b1a2509acd" datatype="html">
<source>Pulls on Docker Hub</source>
<target state="new">Pulls on Docker Hub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<target state="new">Uptime</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

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

@ -19,7 +19,7 @@
<target state="new">Il rischio di perdita nel trading può essere notevole. Non è consigliabile investire denaro di cui potresti avere bisogno a breve termine.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">180,181</context>
<context context-type="linenumber">181,182</context>
</context-group>
</trans-unit>
<trans-unit id="b6192ee60a5e0e40874f4d02fbaaa584a0f1541e" datatype="html">
@ -759,7 +759,7 @@
<target state="translated">Risorse</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">72</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -779,7 +779,7 @@
<target state="translated">Prezzi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -899,7 +899,7 @@
<target state="translated">Informazioni su</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -939,7 +939,7 @@
<target state="translated">Funzionalità</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">85</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -955,7 +955,7 @@
<target state="translated">Mercati</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">70</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -979,7 +979,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">152</context>
</context-group>
</trans-unit>
<trans-unit id="5207635742003539443" datatype="html">
@ -1447,7 +1447,7 @@
<target state="translated">Informativa sulla privacy</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html</context>
@ -1459,7 +1459,7 @@
<target state="translated">Blog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html</context>
@ -1527,7 +1527,7 @@
<target state="translated">Registro delle modifiche</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/changelog/changelog-page.html</context>
@ -1539,7 +1539,7 @@
<target state="translated">Licenza d&apos;uso</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">90</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/license/license-page.html</context>
@ -1571,7 +1571,7 @@
<target state="translated">Inserisci il tuo codice del buono:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">236</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1579,7 +1579,7 @@
<target state="translated">Impossibile riscattare il codice del buono</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">246</context>
<context context-type="linenumber">251</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1587,7 +1587,7 @@
<target state="translated">Il codice del buono è stato riscattato</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">258</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1595,7 +1595,7 @@
<target state="translated">Ricarica</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">264</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1603,7 +1603,7 @@
<target state="translated">Vuoi davvero rimuovere questo metodo di accesso?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">305</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1706,12 +1706,12 @@
<context context-type="linenumber">193</context>
</context-group>
</trans-unit>
<trans-unit id="9ae348ee3a7319c2fc4794fa8bc425999d355f8f" datatype="html">
<source>Sign in with fingerprint</source>
<target state="translated">Accesso con impronta digitale</target>
<trans-unit id="78cf1b9b94e0e93e65d1d522001a5c54304e9f25" datatype="html">
<source> Sign in with fingerprint </source>
<target state="translated"> Accesso con impronta digitale </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">238</context>
<context context-type="linenumber">240,242</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1719,7 +1719,7 @@
<target state="translated">ID utente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">268</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1727,7 +1727,7 @@
<target state="translated">Accesso concesso</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">282</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1955,7 +1955,7 @@
<target state="translated">Per account</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">278</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
@ -2003,7 +2003,7 @@
<target state="translated">Per paese</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2141,6 +2141,10 @@
<trans-unit id="49af37bcd0c34e88ab989641e52ef92f3fb56e06" datatype="html">
<source>Add activity</source>
<target state="translated">Aggiungi un&apos;attività</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">58</context>
</context-group>
<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">8</context>
@ -2319,7 +2323,7 @@
<target state="translated">Ghostfolio ti permette di tenere traccia della tua ricchezza. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">135,137</context>
<context context-type="linenumber">147,149</context>
</context-group>
</trans-unit>
<trans-unit id="8298333184054476827" datatype="html">
@ -2799,7 +2803,7 @@
<target state="translated">Filtra per account, valuta, simbolo o tipo...</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
<context context-type="linenumber">418</context>
<context context-type="linenumber">419</context>
</context-group>
</trans-unit>
<trans-unit id="3d14940af7de691ac27efb67bef3e974cbe3281c" datatype="html">
@ -2827,7 +2831,7 @@
<target state="translated">Funzionalità sperimentali</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">253</context>
<context context-type="linenumber">258</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
@ -2875,7 +2879,7 @@
<target state="new">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -3175,7 +3179,7 @@
<target state="new">Community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
@ -3447,7 +3451,7 @@
<target state="new"> Sneak peek at upcoming functionality </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">254,256</context>
<context context-type="linenumber">259,261</context>
</context-group>
</trans-unit>
<trans-unit id="280c5b1f5b5b748fbbb37bf7a12c37f41539c1ff" datatype="html">
@ -3871,7 +3875,7 @@
<target state="new">By ETF Provider</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">298</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="e0c92dc95e1e0fc33d21b5e2df5ea28a86439d56" datatype="html">
@ -4071,7 +4075,7 @@
<target state="new">Personal Finance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">68</context>
</context-group>
</trans-unit>
<trans-unit id="6992d42edf46c12a4a9ecb3b7a46761a967c8ee1" datatype="html">
@ -4079,7 +4083,7 @@
<target state="new">Frequently Asked Questions (FAQ)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -7086,6 +7090,166 @@
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="6fafe6662f57e08bca1f26bc2d2c9631a106ba29" datatype="html">
<source>Welcome to Ghostfolio</source>
<target state="new">Welcome to Ghostfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="71c2ec88fc3953a1db6cfca218173fcf489fa803" datatype="html">
<source>Setup your accounts</source>
<target state="new">Setup your accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="43cc09795191db2dc5925aed2b8f920e1822e13f" datatype="html">
<source>Get a comprehensive financial overview by adding your bank and brokerage accounts.</source>
<target state="new">Get a comprehensive financial overview by adding your bank and brokerage accounts.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">19,20</context>
</context-group>
</trans-unit>
<trans-unit id="4747213591a189a98d5aface48f2755f863025a4" datatype="html">
<source>Capture your activities</source>
<target state="new">Capture your activities</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="804b8810cfbf317424a9fd6387ad57ec5bec972c" datatype="html">
<source>Record your investment activities to keep your portfolio up to date.</source>
<target state="new">Record your investment activities to keep your portfolio up to date.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">28,29</context>
</context-group>
</trans-unit>
<trans-unit id="3d0333063dd1cd5062db56f859be74bdfb25a7f3" datatype="html">
<source>Monitor and analyze your portfolio</source>
<target state="new">Monitor and analyze your portfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="8bcb7e0eac9c406765fadda3238974f271facce6" datatype="html">
<source>Track your progress in real-time with comprehensive analysis and insights.</source>
<target state="new">Track your progress in real-time with comprehensive analysis and insights.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">37,38</context>
</context-group>
</trans-unit>
<trans-unit id="0038953528872613d2eff0ed3912b109d9e9b5cf" datatype="html">
<source>No data available</source>
<target state="new">No data available</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="06c1bcff740ab4b1d5283d937d22e9daf8b31933" datatype="html">
<source>Ready to take control of your personal finances?</source>
<target state="new">Ready to take control of your personal finances?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="1bdfdbf86e61060cf785b6bd53692b47c9afec63" datatype="html">
<source>Setup accounts</source>
<target state="new">Setup accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="fa22693b23a8bed32d787023df105a7b40002f9c" datatype="html">
<source>Biometric Authentication</source>
<target state="new">Biometric Authentication</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">239</context>
</context-group>
</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="new"> 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. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6,22</context>
</context-group>
</trans-unit>
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
<source>Active Users</source>
<target state="new">Active Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
<source>New Users</source>
<target state="new">New Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">49</context>
</context-group>
</trans-unit>
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
<source>Users in Slack community</source>
<target state="new">Users in Slack community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
<source>Contributors on GitHub</source>
<target state="new">Contributors on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
<source>Stars on GitHub</source>
<target state="new">Stars on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="512b096f732f5e05dc1c451276b7a2b1a2509acd" datatype="html">
<source>Pulls on Docker Hub</source>
<target state="new">Pulls on Docker Hub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<target state="new">Uptime</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

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

@ -18,7 +18,7 @@
<target state="new">Het risico van verlies in de handel kan aanzienlijk zijn. Het is niet raadzaam om geld te beleggen dat u op korte termijn nodig kunt hebben.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">180,181</context>
<context context-type="linenumber">181,182</context>
</context-group>
</trans-unit>
<trans-unit id="b6192ee60a5e0e40874f4d02fbaaa584a0f1541e" datatype="html">
@ -758,7 +758,7 @@
<target state="translated">Middelen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">72</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -778,7 +778,7 @@
<target state="translated">Prijzen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -898,7 +898,7 @@
<target state="translated">Over</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -938,7 +938,7 @@
<target state="translated">Kenmerken</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">85</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -954,7 +954,7 @@
<target state="translated">Markten</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">70</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -978,7 +978,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">152</context>
</context-group>
</trans-unit>
<trans-unit id="5207635742003539443" datatype="html">
@ -1446,7 +1446,7 @@
<target state="translated">Privacybeleid</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html</context>
@ -1458,7 +1458,7 @@
<target state="translated">Blog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html</context>
@ -1526,7 +1526,7 @@
<target state="translated">Changelog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/changelog/changelog-page.html</context>
@ -1538,7 +1538,7 @@
<target state="translated">Licentie</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">90</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/license/license-page.html</context>
@ -1570,7 +1570,7 @@
<target state="translated">Voer uw couponcode in:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">236</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1578,7 +1578,7 @@
<target state="translated">Kon kortingscode niet inwisselen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">246</context>
<context context-type="linenumber">251</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1586,7 +1586,7 @@
<target state="translated">Couponcode is ingewisseld</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">258</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1594,7 +1594,7 @@
<target state="translated">Herladen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">264</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1602,7 +1602,7 @@
<target state="translated">Wilt u deze aanmeldingsmethode echt verwijderen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">305</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1705,12 +1705,12 @@
<context context-type="linenumber">193</context>
</context-group>
</trans-unit>
<trans-unit id="9ae348ee3a7319c2fc4794fa8bc425999d355f8f" datatype="html">
<source>Sign in with fingerprint</source>
<target state="translated">Aanmelden met vingerafdruk</target>
<trans-unit id="78cf1b9b94e0e93e65d1d522001a5c54304e9f25" datatype="html">
<source> Sign in with fingerprint </source>
<target state="translated"> Aanmelden met vingerafdruk </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">238</context>
<context context-type="linenumber">240,242</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1718,7 +1718,7 @@
<target state="translated">Gebruikers-ID</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">268</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1726,7 +1726,7 @@
<target state="translated">Verleende toegang</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">282</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1954,7 +1954,7 @@
<target state="translated">Per rekening</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">278</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
@ -2002,7 +2002,7 @@
<target state="translated">Per land</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2140,6 +2140,10 @@
<trans-unit id="49af37bcd0c34e88ab989641e52ef92f3fb56e06" datatype="html">
<source>Add activity</source>
<target state="translated">Activiteit toevoegen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">58</context>
</context-group>
<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">8</context>
@ -2318,7 +2322,7 @@
<target state="translated">Ghostfolio stelt u in staat om uw vermogen bij te houden. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">135,137</context>
<context context-type="linenumber">147,149</context>
</context-group>
</trans-unit>
<trans-unit id="8298333184054476827" datatype="html">
@ -2798,7 +2802,7 @@
<target state="translated">Filter op rekening, valuta, symbool of type...</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
<context context-type="linenumber">418</context>
<context context-type="linenumber">419</context>
</context-group>
</trans-unit>
<trans-unit id="3d14940af7de691ac27efb67bef3e974cbe3281c" datatype="html">
@ -2826,7 +2830,7 @@
<target state="translated">Experimentele functies</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">253</context>
<context context-type="linenumber">258</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
@ -2874,7 +2878,7 @@
<target state="translated">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
@ -3174,7 +3178,7 @@
<target state="translated">Gemeenschap</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
@ -3446,7 +3450,7 @@
<target state="new"> Sneak peek at upcoming functionality </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">254,256</context>
<context context-type="linenumber">259,261</context>
</context-group>
</trans-unit>
<trans-unit id="280c5b1f5b5b748fbbb37bf7a12c37f41539c1ff" datatype="html">
@ -3870,7 +3874,7 @@
<target state="new">By ETF Provider</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">298</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="e0c92dc95e1e0fc33d21b5e2df5ea28a86439d56" datatype="html">
@ -4070,7 +4074,7 @@
<target state="new">Personal Finance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">68</context>
</context-group>
</trans-unit>
<trans-unit id="6992d42edf46c12a4a9ecb3b7a46761a967c8ee1" datatype="html">
@ -4078,7 +4082,7 @@
<target state="new">Frequently Asked Questions (FAQ)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -7085,6 +7089,166 @@
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="6fafe6662f57e08bca1f26bc2d2c9631a106ba29" datatype="html">
<source>Welcome to Ghostfolio</source>
<target state="new">Welcome to Ghostfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="71c2ec88fc3953a1db6cfca218173fcf489fa803" datatype="html">
<source>Setup your accounts</source>
<target state="new">Setup your accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="43cc09795191db2dc5925aed2b8f920e1822e13f" datatype="html">
<source>Get a comprehensive financial overview by adding your bank and brokerage accounts.</source>
<target state="new">Get a comprehensive financial overview by adding your bank and brokerage accounts.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">19,20</context>
</context-group>
</trans-unit>
<trans-unit id="4747213591a189a98d5aface48f2755f863025a4" datatype="html">
<source>Capture your activities</source>
<target state="new">Capture your activities</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="804b8810cfbf317424a9fd6387ad57ec5bec972c" datatype="html">
<source>Record your investment activities to keep your portfolio up to date.</source>
<target state="new">Record your investment activities to keep your portfolio up to date.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">28,29</context>
</context-group>
</trans-unit>
<trans-unit id="3d0333063dd1cd5062db56f859be74bdfb25a7f3" datatype="html">
<source>Monitor and analyze your portfolio</source>
<target state="new">Monitor and analyze your portfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="8bcb7e0eac9c406765fadda3238974f271facce6" datatype="html">
<source>Track your progress in real-time with comprehensive analysis and insights.</source>
<target state="new">Track your progress in real-time with comprehensive analysis and insights.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">37,38</context>
</context-group>
</trans-unit>
<trans-unit id="0038953528872613d2eff0ed3912b109d9e9b5cf" datatype="html">
<source>No data available</source>
<target state="new">No data available</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="06c1bcff740ab4b1d5283d937d22e9daf8b31933" datatype="html">
<source>Ready to take control of your personal finances?</source>
<target state="new">Ready to take control of your personal finances?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="1bdfdbf86e61060cf785b6bd53692b47c9afec63" datatype="html">
<source>Setup accounts</source>
<target state="new">Setup accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="fa22693b23a8bed32d787023df105a7b40002f9c" datatype="html">
<source>Biometric Authentication</source>
<target state="new">Biometric Authentication</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">239</context>
</context-group>
</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="new"> 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. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6,22</context>
</context-group>
</trans-unit>
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
<source>Active Users</source>
<target state="new">Active Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
<source>New Users</source>
<target state="new">New Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">49</context>
</context-group>
</trans-unit>
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
<source>Users in Slack community</source>
<target state="new">Users in Slack community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
<source>Contributors on GitHub</source>
<target state="new">Contributors on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
<source>Stars on GitHub</source>
<target state="new">Stars on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="512b096f732f5e05dc1c451276b7a2b1a2509acd" datatype="html">
<source>Pulls on Docker Hub</source>
<target state="new">Pulls on Docker Hub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<target state="new">Uptime</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

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

@ -6,7 +6,7 @@
<target state="translated">O risco de perda em investimentos pode ser substancial. Não é aconselhável investir dinheiro que possa vir a precisar a curto prazo.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">180,181</context>
<context context-type="linenumber">181,182</context>
</context-group>
</trans-unit>
<trans-unit id="fbaaeb297e70b9a800acf841b9d26c19d60651ef" datatype="html">
@ -930,7 +930,7 @@
<target state="translated">Recursos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">72</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -950,7 +950,7 @@
<target state="translated">Preços</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1070,7 +1070,7 @@
<target state="translated">Sobre</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1110,7 +1110,7 @@
<target state="translated">Funcionalidades</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">85</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1126,7 +1126,7 @@
<target state="translated">Mercados</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">70</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -1782,7 +1782,7 @@
<target state="translated">Changelog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/changelog/changelog-page.html</context>
@ -1794,7 +1794,7 @@
<target state="translated">Licença</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">90</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/license/license-page.html</context>
@ -1818,7 +1818,7 @@
<target state="translated">Política de Privacidade</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html</context>
@ -1838,7 +1838,7 @@
<target state="translated">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="5196970976032945030" datatype="html">
@ -1846,7 +1846,7 @@
<target state="translated">Por favor, insira o seu código de cupão:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">236</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1854,7 +1854,7 @@
<target state="translated">Não foi possível resgatar o código de cupão</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">246</context>
<context context-type="linenumber">251</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1862,7 +1862,7 @@
<target state="translated">Código de cupão foi resgatado</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">258</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1870,7 +1870,7 @@
<target state="translated">Atualizar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">264</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1878,7 +1878,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/pages/account/account-page.component.ts</context>
<context context-type="linenumber">305</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -2033,12 +2033,12 @@
<context context-type="linenumber">214</context>
</context-group>
</trans-unit>
<trans-unit id="9ae348ee3a7319c2fc4794fa8bc425999d355f8f" datatype="html">
<source>Sign in with fingerprint</source>
<target state="translated">Iniciar sessão com impressão digital</target>
<trans-unit id="78cf1b9b94e0e93e65d1d522001a5c54304e9f25" datatype="html">
<source> Sign in with fingerprint </source>
<target state="translated"> Iniciar sessão com impressão digital </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">238</context>
<context context-type="linenumber">240,242</context>
</context-group>
</trans-unit>
<trans-unit id="03b120b05e0922e5e830c3466fda9ee0bfbf59e9" datatype="html">
@ -2046,7 +2046,7 @@
<target state="translated">Funcionalidades Experimentais</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">253</context>
<context context-type="linenumber">258</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -2054,7 +2054,7 @@
<target state="translated">ID do Utilizador</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">268</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -2062,7 +2062,7 @@
<target state="translated">Acesso Concedido</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">282</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -2154,7 +2154,7 @@
<target state="translated">Blog</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html</context>
@ -2300,6 +2300,10 @@
<trans-unit id="49af37bcd0c34e88ab989641e52ef92f3fb56e06" datatype="html">
<source>Add activity</source>
<target state="translated">Adicionar atividade</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">58</context>
</context-group>
<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">8</context>
@ -2478,7 +2482,7 @@
<target state="translated">Por Conta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">278</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
@ -2526,7 +2530,7 @@
<target state="translated">Por País</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2742,7 +2746,7 @@
<target state="translated"> O Ghostfolio permite-lhe estar a par e gerir a sua riqueza. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">135,137</context>
<context context-type="linenumber">147,149</context>
</context-group>
</trans-unit>
<trans-unit id="802222cb4754d74846b18f651b1f94e21576185d" datatype="html">
@ -2754,7 +2758,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">152</context>
</context-group>
</trans-unit>
<trans-unit id="8298333184054476827" datatype="html">
@ -2918,7 +2922,7 @@
<target state="translated">Filtrar por conta, moeda, símbolo ou tipo...</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
<context context-type="linenumber">418</context>
<context context-type="linenumber">419</context>
</context-group>
</trans-unit>
<trans-unit id="170f7de02b14690fb9c1999a16926c0044bfd5c1" datatype="html">
@ -3230,7 +3234,7 @@
<target state="translated">Comunidade</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
@ -3446,7 +3450,7 @@
<target state="translated"> Acesso antecipado a funcionalidades futuras </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">254,256</context>
<context context-type="linenumber">259,261</context>
</context-group>
</trans-unit>
<trans-unit id="280c5b1f5b5b748fbbb37bf7a12c37f41539c1ff" datatype="html">
@ -3870,7 +3874,7 @@
<target state="translated">Por Prestador de ETF</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">298</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="e0c92dc95e1e0fc33d21b5e2df5ea28a86439d56" datatype="html">
@ -4070,7 +4074,7 @@
<target state="translated">Finanças pessoais</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">68</context>
</context-group>
</trans-unit>
<trans-unit id="6992d42edf46c12a4a9ecb3b7a46761a967c8ee1" datatype="html">
@ -4078,7 +4082,7 @@
<target state="translated">Perguntas Frequentes (FAQ)</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -7085,6 +7089,166 @@
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="6fafe6662f57e08bca1f26bc2d2c9631a106ba29" datatype="html">
<source>Welcome to Ghostfolio</source>
<target state="new">Welcome to Ghostfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="71c2ec88fc3953a1db6cfca218173fcf489fa803" datatype="html">
<source>Setup your accounts</source>
<target state="new">Setup your accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="43cc09795191db2dc5925aed2b8f920e1822e13f" datatype="html">
<source>Get a comprehensive financial overview by adding your bank and brokerage accounts.</source>
<target state="new">Get a comprehensive financial overview by adding your bank and brokerage accounts.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">19,20</context>
</context-group>
</trans-unit>
<trans-unit id="4747213591a189a98d5aface48f2755f863025a4" datatype="html">
<source>Capture your activities</source>
<target state="new">Capture your activities</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="804b8810cfbf317424a9fd6387ad57ec5bec972c" datatype="html">
<source>Record your investment activities to keep your portfolio up to date.</source>
<target state="new">Record your investment activities to keep your portfolio up to date.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">28,29</context>
</context-group>
</trans-unit>
<trans-unit id="3d0333063dd1cd5062db56f859be74bdfb25a7f3" datatype="html">
<source>Monitor and analyze your portfolio</source>
<target state="new">Monitor and analyze your portfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="8bcb7e0eac9c406765fadda3238974f271facce6" datatype="html">
<source>Track your progress in real-time with comprehensive analysis and insights.</source>
<target state="new">Track your progress in real-time with comprehensive analysis and insights.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">37,38</context>
</context-group>
</trans-unit>
<trans-unit id="0038953528872613d2eff0ed3912b109d9e9b5cf" datatype="html">
<source>No data available</source>
<target state="new">No data available</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="06c1bcff740ab4b1d5283d937d22e9daf8b31933" datatype="html">
<source>Ready to take control of your personal finances?</source>
<target state="new">Ready to take control of your personal finances?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="1bdfdbf86e61060cf785b6bd53692b47c9afec63" datatype="html">
<source>Setup accounts</source>
<target state="new">Setup accounts</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="fa22693b23a8bed32d787023df105a7b40002f9c" datatype="html">
<source>Biometric Authentication</source>
<target state="new">Biometric Authentication</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">239</context>
</context-group>
</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="new"> 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. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6,22</context>
</context-group>
</trans-unit>
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
<source>Active Users</source>
<target state="new">Active Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
<source>New Users</source>
<target state="new">New Users</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">49</context>
</context-group>
</trans-unit>
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
<source>Users in Slack community</source>
<target state="new">Users in Slack community</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
<source>Contributors on GitHub</source>
<target state="new">Contributors on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
<source>Stars on GitHub</source>
<target state="new">Stars on GitHub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="512b096f732f5e05dc1c451276b7a2b1a2509acd" datatype="html">
<source>Pulls on Docker Hub</source>
<target state="new">Pulls on Docker Hub</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<target state="new">Uptime</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

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

@ -17,7 +17,7 @@
<source>The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term.</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">180,181</context>
<context context-type="linenumber">181,182</context>
</context-group>
</trans-unit>
<trans-unit id="b6192ee60a5e0e40874f4d02fbaaa584a0f1541e" datatype="html">
@ -695,7 +695,7 @@
<source>Resources</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">72</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -714,7 +714,7 @@
<source>Pricing</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -833,7 +833,7 @@
<source>About</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -869,7 +869,7 @@
<source>Features</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">85</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -884,7 +884,7 @@
<source>Markets</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">70</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/header/header.component.html</context>
@ -907,7 +907,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">140</context>
<context context-type="linenumber">152</context>
</context-group>
</trans-unit>
<trans-unit id="5207635742003539443" datatype="html">
@ -1329,7 +1329,7 @@
<source>Privacy Policy</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html</context>
@ -1340,7 +1340,7 @@
<source>Blog</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html</context>
@ -1407,7 +1407,7 @@
<source>Changelog</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">83</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/changelog/changelog-page.html</context>
@ -1418,7 +1418,7 @@
<source>License</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">90</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/about/license/license-page.html</context>
@ -1447,35 +1447,35 @@
<source>Please enter your coupon code:</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">236</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
<source>Could not redeem coupon code</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">246</context>
<context context-type="linenumber">251</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
<source>Coupon code has been redeemed</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">258</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
<source>Reload</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">264</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/pages/account/account-page.component.ts</context>
<context context-type="linenumber">305</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1567,25 +1567,25 @@
<context context-type="linenumber">193</context>
</context-group>
</trans-unit>
<trans-unit id="9ae348ee3a7319c2fc4794fa8bc425999d355f8f" datatype="html">
<source>Sign in with fingerprint</source>
<trans-unit id="78cf1b9b94e0e93e65d1d522001a5c54304e9f25" datatype="html">
<source> Sign in with fingerprint </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">238</context>
<context context-type="linenumber">240,242</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
<source>User ID</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">268</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
<source>Granted Access</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">282</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1792,7 +1792,7 @@
<source>By Account</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">278</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
@ -1834,7 +1834,7 @@
<source>By Country</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -1958,6 +1958,10 @@
</trans-unit>
<trans-unit id="49af37bcd0c34e88ab989641e52ef92f3fb56e06" datatype="html">
<source>Add activity</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">58</context>
</context-group>
<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">8</context>
@ -2121,7 +2125,7 @@
<source> Ghostfolio empowers you to keep track of your wealth. </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">135,137</context>
<context context-type="linenumber">147,149</context>
</context-group>
</trans-unit>
<trans-unit id="8298333184054476827" datatype="html">
@ -2550,7 +2554,7 @@
<source>Filter by account, currency, symbol or type...</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
<context context-type="linenumber">418</context>
<context context-type="linenumber">419</context>
</context-group>
</trans-unit>
<trans-unit id="3d14940af7de691ac27efb67bef3e974cbe3281c" datatype="html">
@ -2575,7 +2579,7 @@
<source>Experimental Features</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">253</context>
<context context-type="linenumber">258</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
@ -2624,7 +2628,7 @@
<source>Auto</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="693d14f486a25e86bc515dfcfc4462d5201217ef" datatype="html">
@ -2881,7 +2885,7 @@
<source>Community</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">115</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
@ -3125,7 +3129,7 @@
<source> Sneak peek at upcoming functionality </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">254,256</context>
<context context-type="linenumber">259,261</context>
</context-group>
</trans-unit>
<trans-unit id="280c5b1f5b5b748fbbb37bf7a12c37f41539c1ff" datatype="html">
@ -3487,7 +3491,7 @@
<source>By ETF Provider</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">298</context>
<context context-type="linenumber">310</context>
</context-group>
</trans-unit>
<trans-unit id="3c32a07710e402b2c056bd346e7c42f6015334a6" datatype="html">
@ -3685,14 +3689,14 @@
<source>Personal Finance</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">68</context>
</context-group>
</trans-unit>
<trans-unit id="6992d42edf46c12a4a9ecb3b7a46761a967c8ee1" datatype="html">
<source>Frequently Asked Questions (FAQ)</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">87</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="1c275927e7e22395d21a86e4ab459e428bcac27e" datatype="html">
@ -6644,6 +6648,147 @@
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="0038953528872613d2eff0ed3912b109d9e9b5cf" datatype="html">
<source>No data available</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="3d0333063dd1cd5062db56f859be74bdfb25a7f3" datatype="html">
<source>Monitor and analyze your portfolio</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="43cc09795191db2dc5925aed2b8f920e1822e13f" datatype="html">
<source>Get a comprehensive financial overview by adding your bank and brokerage accounts.</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">19,20</context>
</context-group>
</trans-unit>
<trans-unit id="4747213591a189a98d5aface48f2755f863025a4" datatype="html">
<source>Capture your activities</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="6fafe6662f57e08bca1f26bc2d2c9631a106ba29" datatype="html">
<source>Welcome to Ghostfolio</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="71c2ec88fc3953a1db6cfca218173fcf489fa803" datatype="html">
<source>Setup your accounts</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="804b8810cfbf317424a9fd6387ad57ec5bec972c" datatype="html">
<source>Record your investment activities to keep your portfolio up to date.</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">28,29</context>
</context-group>
</trans-unit>
<trans-unit id="8bcb7e0eac9c406765fadda3238974f271facce6" datatype="html">
<source>Track your progress in real-time with comprehensive analysis and insights.</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">37,38</context>
</context-group>
</trans-unit>
<trans-unit id="06c1bcff740ab4b1d5283d937d22e9daf8b31933" datatype="html">
<source>Ready to take control of your personal finances?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="1bdfdbf86e61060cf785b6bd53692b47c9afec63" datatype="html">
<source>Setup accounts</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/home-overview/home-overview.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="fa22693b23a8bed32d787023df105a7b40002f9c" datatype="html">
<source>Biometric Authentication</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
<source>Active Users</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="512b096f732f5e05dc1c451276b7a2b1a2509acd" datatype="html">
<source>Pulls on Docker Hub</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
<source>New Users</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">49</context>
</context-group>
</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>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">6,22</context>
</context-group>
</trans-unit>
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
<source>Stars on GitHub</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
<source>Contributors on GitHub</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
<source>Users in Slack community</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit id="ed1d16219cf7cc3ad92d2d49f0c55bbafe3768b2" datatype="html">
<source>Uptime</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/open/open-page.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

3
apps/client/src/styles.scss

@ -253,6 +253,7 @@ body {
.mat-mdc-card {
--mdc-elevated-card-container-color: var(--dark-background);
--mdc-outlined-card-container-color: var(--dark-background);
}
.mat-mdc-fab {
@ -262,7 +263,6 @@ body {
}
}
.mat-mdc-paginator,
.mat-mdc-paginator {
background-color: rgba(var(--palette-foreground-base-dark), 0.02);
}
@ -421,7 +421,6 @@ ngx-skeleton-loader {
}
}
.mat-mdc-paginator,
.mat-mdc-paginator {
background-color: rgba(var(--palette-foreground-base-light), 0.02);

2
apps/client/tsconfig.app.json

@ -3,7 +3,7 @@
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"],
"typeRoots": ["../node_modules/@types"],
"typeRoots": ["../../node_modules/@types"],
"target": "ES2022",
"useDefineForClassFields": false
},

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

@ -38,6 +38,7 @@ export const DATA_GATHERING_QUEUE_PRIORITY_HIGH = 1;
export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy';
export const DEFAULT_LANGUAGE_CODE = 'en';
export const DEFAULT_PAGE_SIZE = 50;
export const DEFAULT_REQUEST_TIMEOUT = ms('3 seconds');
export const EMERGENCY_FUND_TAG_ID = '4452656d-9fa4-4bd0-ba38-70492e31d180';
@ -91,4 +92,14 @@ export const QUEUE_JOB_STATUS_LIST = <JobStatus[]>[
'waiting'
];
export const SUPPORTED_LANGUAGE_CODES = [
'de',
'en',
'es',
'fr',
'it',
'nl',
'pt'
];
export const UNKNOWN_KEY = 'UNKNOWN';

16
libs/common/src/lib/helper.ts

@ -5,7 +5,7 @@ import { getDate, getMonth, getYear, parse, subDays } from 'date-fns';
import { de, es, fr, it, nl, pt } from 'date-fns/locale';
import { ghostfolioScraperApiSymbolPrefix, locale } from './config';
import { Benchmark } from './interfaces';
import { Benchmark, UniqueAsset } from './interfaces';
import { ColorScheme } from './types';
const NUMERIC_REGEXP = /[-]{0,1}[\d]*[.,]{0,1}[\d]+/g;
@ -64,6 +64,10 @@ export function extractNumberFromString(aString: string): number {
}
}
export function getAssetProfileIdentifier({ dataSource, symbol }: UniqueAsset) {
return `${dataSource}-${symbol}`;
}
export function getBackgroundColor(aColorScheme: ColorScheme) {
return getCssVariable(
aColorScheme === 'DARK' ||
@ -230,6 +234,16 @@ export function isCurrency(aSymbol = '') {
return currencies[aSymbol];
}
export function interpolate(template: string, context: any) {
return template.replace(/[$]{([^}]+)}/g, (_, objectPath) => {
const properties = objectPath.split('.');
return properties.reduce(
(previous, current) => previous?.[current],
context
);
});
}
export function resetHours(aDate: Date) {
const year = getYear(aDate);
const month = getMonth(aDate);

3
libs/common/src/lib/types/market-advanced.type.ts

@ -4,4 +4,5 @@ export type MarketAdvanced =
| 'europe'
| 'japan'
| 'northAmerica'
| 'otherMarkets';
| 'otherMarkets'
| 'UNKNOWN';

6
libs/common/src/lib/types/market.type.ts

@ -1 +1,5 @@
export type Market = 'developedMarkets' | 'emergingMarkets' | 'otherMarkets';
export type Market =
| 'developedMarkets'
| 'emergingMarkets'
| 'otherMarkets'
| 'UNKNOWN';

13
libs/ui/src/lib/activities-table/activities-table.component.ts

@ -383,13 +383,14 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy, OnInit {
}
private getTotalValue() {
let totalValue = new Big(0);
const paginatedData = this.getPaginatedData();
for (const activity of paginatedData) {
if (isNumber(activity.valueInBaseCurrency)) {
if (activity.type === 'BUY' || activity.type === 'ITEM') {
totalValue = totalValue.plus(activity.valueInBaseCurrency);
} else if (activity.type === 'SELL') {
let totalValue = new Big(0);
for (const { type, valueInBaseCurrency } of paginatedData) {
if (isNumber(valueInBaseCurrency)) {
if (type === 'BUY' || type === 'ITEM') {
totalValue = totalValue.plus(valueInBaseCurrency);
} else if (type === 'LIABILITY' || type === 'SELL') {
return null;
}
} else {

4
libs/ui/src/lib/holdings-table/holdings-table.component.html

@ -61,7 +61,7 @@
</td>
</ng-container>
<ng-container matColumnDef="value">
<ng-container matColumnDef="valueInBaseCurrency">
<th
*matHeaderCellDef
class="d-none d-lg-table-cell justify-content-end px-1"
@ -79,7 +79,7 @@
<gf-value
[isCurrency]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.value"
[value]="isLoading ? undefined : element.valueInBaseCurrency"
></gf-value>
</div>
</td>

2
libs/ui/src/lib/holdings-table/holdings-table.component.ts

@ -55,7 +55,7 @@ export class HoldingsTableComponent implements OnChanges, OnDestroy, OnInit {
this.displayedColumns = ['icon', 'nameWithSymbol', 'dateOfFirstActivity'];
if (this.hasPermissionToShowValues) {
this.displayedColumns.push('value');
this.displayedColumns.push('valueInBaseCurrency');
}
this.displayedColumns.push('allocationInPercentage');

7
nx.json

@ -50,7 +50,8 @@
"default",
"^production",
"{workspaceRoot}/.storybook/**/*",
"!{projectRoot}/.storybook/**/*"
"{projectRoot}/.storybook/**/*",
"{projectRoot}/tsconfig.storybook.json"
]
}
},
@ -67,7 +68,9 @@
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/.storybook/**/*",
"!{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)"
"!{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)",
"!{projectRoot}/tsconfig.storybook.json",
"!{projectRoot}/src/test-setup.[jt]s"
]
}
}

124
package.json

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "1.292.0",
"version": "1.299.1",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"scripts": {
@ -13,8 +13,8 @@
"affected:lint": "nx affected:lint",
"affected:test": "nx affected:test",
"angular": "node --max_old_space_size=32768 ./node_modules/@angular/cli/bin/ng",
"build:all": "nx run api:build:production && nx run client:build:production --localize && yarn replace-placeholders-in-build",
"build:dev": "nx run api:build && nx run client:build --localize && yarn replace-placeholders-in-build",
"build:dev": "nx run api:build && nx run client:build && nx run client:copy-assets && yarn replace-placeholders-in-build",
"build:production": "nx run api:build:production && nx run client:build:production && nx run client:copy-assets && yarn replace-placeholders-in-build",
"build:storybook": "nx run ui:build-storybook",
"database:format-schema": "prisma format",
"database:generate-typings": "prisma generate",
@ -36,11 +36,11 @@
"lint": "nx workspace-lint && ng lint",
"ng": "nx",
"nx": "nx",
"postinstall": "prisma generate && ngcc --properties es2020 browser module main",
"postinstall": "prisma generate",
"replace-placeholders-in-build": "node ./replace.build.js",
"start": "node dist/apps/api/main",
"start:client": "nx run client:serve --configuration=development-en --hmr -o",
"start:prod": "yarn database:migrate && yarn database:seed && node main",
"start:client": "nx run client:copy-assets && nx run client:serve --configuration=development-en --hmr -o",
"start:production": "yarn database:migrate && yarn database:seed && node main",
"start:server": "nx run api:serve --watch",
"start:storybook": "nx run ui:storybook",
"test": "npx dotenv-cli -e .env.example -- nx test",
@ -52,17 +52,17 @@
"workspace-generator": "nx workspace-generator"
},
"dependencies": {
"@angular/animations": "15.2.5",
"@angular/cdk": "15.2.6",
"@angular/common": "15.2.5",
"@angular/compiler": "15.2.5",
"@angular/core": "15.2.5",
"@angular/forms": "15.2.5",
"@angular/material": "15.2.6",
"@angular/platform-browser": "15.2.5",
"@angular/platform-browser-dynamic": "15.2.5",
"@angular/router": "15.2.5",
"@angular/service-worker": "15.2.5",
"@angular/animations": "16.1.8",
"@angular/cdk": "16.1.7",
"@angular/common": "16.1.8",
"@angular/compiler": "16.1.8",
"@angular/core": "16.1.8",
"@angular/forms": "16.1.8",
"@angular/material": "16.1.7",
"@angular/platform-browser": "16.1.8",
"@angular/platform-browser-dynamic": "16.1.8",
"@angular/router": "16.1.8",
"@angular/service-worker": "16.1.8",
"@codewithdan/observable-store": "2.2.15",
"@dfinity/agent": "0.15.7",
"@dfinity/auth-client": "0.15.7",
@ -70,15 +70,16 @@
"@dfinity/identity": "0.15.7",
"@dfinity/principal": "0.15.7",
"@dinero.js/currencies": "2.0.0-alpha.8",
"@nestjs/bull": "0.6.3",
"@nestjs/common": "9.1.4",
"@nestjs/config": "2.2.0",
"@nestjs/core": "9.1.4",
"@nestjs/jwt": "9.0.0",
"@nestjs/passport": "9.0.0",
"@nestjs/platform-express": "9.1.4",
"@nestjs/schedule": "2.1.0",
"@nestjs/serve-static": "3.0.0",
"@nestjs/bull": "10.0.1",
"@nestjs/cache-manager": "2.1.0",
"@nestjs/common": "10.1.3",
"@nestjs/config": "3.0.0",
"@nestjs/core": "10.1.3",
"@nestjs/jwt": "10.1.0",
"@nestjs/passport": "10.0.0",
"@nestjs/platform-express": "10.1.3",
"@nestjs/schedule": "3.0.2",
"@nestjs/serve-static": "4.0.0",
"@prisma/client": "4.16.2",
"@simplewebauthn/browser": "5.2.1",
"@simplewebauthn/server": "5.2.1",
@ -105,13 +106,14 @@
"date-fns": "2.29.3",
"envalid": "7.3.1",
"google-spreadsheet": "3.2.0",
"got": "11.8.6",
"helmet": "7.0.0",
"http-status-codes": "2.2.0",
"ionicons": "7.1.0",
"lodash": "4.17.21",
"marked": "4.2.12",
"ms": "3.0.0-canary.1",
"ng-extract-i18n-merge": "2.6.0",
"ng-extract-i18n-merge": "2.7.0",
"ngx-device-detector": "5.0.1",
"ngx-markdown": "15.1.0",
"ngx-skeleton-loader": "7.0.0",
@ -128,37 +130,37 @@
"twitter-api-v2": "1.14.2",
"uuid": "9.0.0",
"yahoo-finance2": "2.4.3",
"zone.js": "0.12.0"
"zone.js": "0.13.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "15.2.5",
"@angular-devkit/core": "15.2.5",
"@angular-devkit/schematics": "15.2.5",
"@angular-eslint/eslint-plugin": "15.2.0",
"@angular-eslint/eslint-plugin-template": "15.2.0",
"@angular-eslint/template-parser": "15.2.0",
"@angular/cli": "15.2.5",
"@angular/compiler-cli": "15.2.5",
"@angular/language-service": "15.2.5",
"@angular/localize": "15.2.5",
"@angular/pwa": "15.2.5",
"@nestjs/schematics": "9.1.0",
"@nestjs/testing": "9.4.0",
"@nx/angular": "16.0.3",
"@nx/cypress": "16.0.3",
"@nx/eslint-plugin": "16.0.3",
"@nx/jest": "16.0.3",
"@nx/js": "16.0.3",
"@nx/nest": "16.0.3",
"@nx/node": "16.0.3",
"@nx/storybook": "16.0.3",
"@nx/web": "16.0.3",
"@nx/workspace": "16.0.3",
"@schematics/angular": "15.2.5",
"@angular-devkit/build-angular": "16.1.8",
"@angular-devkit/core": "16.1.8",
"@angular-devkit/schematics": "16.1.8",
"@angular-eslint/eslint-plugin": "16.0.3",
"@angular-eslint/eslint-plugin-template": "16.0.3",
"@angular-eslint/template-parser": "16.0.3",
"@angular/cli": "16.1.8",
"@angular/compiler-cli": "16.1.8",
"@angular/language-service": "16.1.8",
"@angular/localize": "16.1.8",
"@angular/pwa": "16.1.8",
"@nestjs/schematics": "10.0.1",
"@nestjs/testing": "10.1.3",
"@nx/angular": "16.6.0",
"@nx/cypress": "16.6.0",
"@nx/eslint-plugin": "16.6.0",
"@nx/jest": "16.6.0",
"@nx/js": "16.6.0",
"@nx/nest": "16.6.0",
"@nx/node": "16.6.0",
"@nx/storybook": "16.6.0",
"@nx/web": "16.6.0",
"@nx/workspace": "16.6.0",
"@schematics/angular": "16.1.8",
"@simplewebauthn/typescript-types": "5.2.1",
"@storybook/addon-essentials": "7.0.9",
"@storybook/angular": "7.0.9",
"@storybook/core-server": "7.0.9",
"@storybook/addon-essentials": "7.2.1",
"@storybook/angular": "7.2.1",
"@storybook/core-server": "7.2.1",
"@types/big.js": "6.1.6",
"@types/body-parser": "1.19.2",
"@types/cache-manager": "3.4.2",
@ -167,7 +169,7 @@
"@types/jest": "29.4.4",
"@types/lodash": "4.14.195",
"@types/marked": "4.0.8",
"@types/node": "18.11.18",
"@types/node": "20.4.2",
"@types/papaparse": "5.3.7",
"@types/passport-google-oauth20": "2.0.11",
"@typescript-eslint/eslint-plugin": "5.51.0",
@ -184,9 +186,9 @@
"import-sort-style-module": "6.0.0",
"jest": "29.4.3",
"jest-environment-jsdom": "29.4.3",
"jest-preset-angular": "13.0.0",
"nx": "16.0.3",
"nx-cloud": "16.0.5",
"jest-preset-angular": "13.1.1",
"nx": "16.6.0",
"nx-cloud": "16.2.0",
"prettier": "2.8.4",
"prettier-plugin-organize-attributes": "0.0.5",
"react": "18.2.0",
@ -195,8 +197,8 @@
"storybook": "7.0.9",
"ts-jest": "29.1.0",
"ts-node": "10.9.1",
"tslib": "2.0.0",
"typescript": "4.9.5"
"tslib": "2.6.0",
"typescript": "5.1.6"
},
"engines": {
"node": ">=18"

2
test/import/invalid-currency.csv

@ -1,2 +1,2 @@
Date,Code,Currency,Price,Quantity,Action,Fee
12/12/2021,BTC,EUR,44558.42,1,buy,0
12/12/2021,BTC,<invalid>,44558.42,1,buy,0

1 Date Code Currency Price Quantity Action Fee
2 12/12/2021 BTC EUR <invalid> 44558.42 1 buy 0

19
test/import/unavailable-exchange-rate.json

@ -0,0 +1,19 @@
{
"meta": {
"date": "2023-02-05T00:00:00.000Z",
"version": "dev"
},
"activities": [
{
"comment": null,
"fee": 0,
"quantity": 0,
"type": "BUY",
"unitPrice": 0,
"currency": "EUR",
"dataSource": "YAHOO",
"date": "1990-01-01T22:00:00.000Z",
"symbol": "MSFT"
}
]
}

9644
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save