From 44ea3cba8d243852c81f7c430d9ddbfa7412eab2 Mon Sep 17 00:00:00 2001 From: Tobias Kugel <78074722+tobikugel@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:00:27 -0300 Subject: [PATCH] Feature/set up localization for static portfolio analysis rules: Economic Market Cluster Risks (#5169) * Set up localization for static portfolio analysis rules: Economic Market Cluster Risks * Update changelog --- CHANGELOG.md | 5 ++ .../src/app/portfolio/portfolio.service.ts | 8 ++- apps/api/src/app/user/user.service.ts | 4 ++ .../developed-markets.ts | 58 ++++++++++++++----- .../emerging-markets.ts | 58 ++++++++++++++----- apps/client/src/app/pages/i18n/i18n-page.html | 36 ++++++++++++ 6 files changed, 139 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5efe62150..61c69f535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Set up the language localization for the static portfolio analysis rule: _Economic Market Cluster Risks_ (Developed Markets) +- Set up the language localization for the static portfolio analysis rule: _Economic Market Cluster Risks_ (Emerging Markets) + ### Changed - Improved the platform icon in the create or update platform dialog of the admin control diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index a343015c5..4d09edf8b 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1223,13 +1223,17 @@ export class PortfolioService { [ new EconomicMarketClusterRiskDevelopedMarkets( this.exchangeRateDataService, + this.i18nService, marketsTotalInBaseCurrency, - markets.developedMarkets.valueInBaseCurrency + markets.developedMarkets.valueInBaseCurrency, + userSettings.language ), new EconomicMarketClusterRiskEmergingMarkets( this.exchangeRateDataService, + this.i18nService, marketsTotalInBaseCurrency, - markets.emergingMarkets.valueInBaseCurrency + markets.emergingMarkets.valueInBaseCurrency, + userSettings.language ) ], userSettings diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 14da87208..a69167b3b 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -300,12 +300,16 @@ export class UserService { ).getSettings(user.settings.settings), EconomicMarketClusterRiskDevelopedMarkets: new EconomicMarketClusterRiskDevelopedMarkets( + undefined, + undefined, undefined, undefined, undefined ).getSettings(user.settings.settings), EconomicMarketClusterRiskEmergingMarkets: new EconomicMarketClusterRiskEmergingMarkets( + undefined, + undefined, undefined, undefined, undefined diff --git a/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts b/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts index d2c8fdae9..7ca7a2d76 100644 --- a/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts +++ b/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts @@ -1,6 +1,7 @@ import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { UserSettings } from '@ghostfolio/common/interfaces'; export class EconomicMarketClusterRiskDevelopedMarkets extends Rule { @@ -9,10 +10,13 @@ export class EconomicMarketClusterRiskDevelopedMarkets extends Rule { public constructor( protected exchangeRateDataService: ExchangeRateDataService, + private i18nService: I18nService, currentValueInBaseCurrency: number, - developedMarketsValueInBaseCurrency: number + developedMarketsValueInBaseCurrency: number, + languageCode: string ) { super(exchangeRateDataService, { + languageCode, key: EconomicMarketClusterRiskDevelopedMarkets.name }); @@ -29,32 +33,55 @@ export class EconomicMarketClusterRiskDevelopedMarkets extends Rule { if (developedMarketsValueRatio > ruleSettings.thresholdMax) { return { - evaluation: `The developed markets contribution of your current investment (${(developedMarketsValueRatio * 100).toPrecision(3)}%) exceeds ${( - ruleSettings.thresholdMax * 100 - ).toPrecision(3)}%`, + evaluation: this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskDevelopedMarkets.false.max', + languageCode: this.getLanguageCode(), + placeholders: { + developedMarketsValueRatio: ( + developedMarketsValueRatio * 100 + ).toPrecision(3), + thresholdMax: (ruleSettings.thresholdMax * 100).toPrecision(3) + } + }), value: false }; } else if (developedMarketsValueRatio < ruleSettings.thresholdMin) { return { - evaluation: `The developed markets contribution of your current investment (${(developedMarketsValueRatio * 100).toPrecision(3)}%) is below ${( - ruleSettings.thresholdMin * 100 - ).toPrecision(3)}%`, + evaluation: this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskDevelopedMarkets.false.min', + languageCode: this.getLanguageCode(), + placeholders: { + developedMarketsValueRatio: ( + developedMarketsValueRatio * 100 + ).toPrecision(3), + thresholdMin: (ruleSettings.thresholdMin * 100).toPrecision(3) + } + }), value: false }; } return { - evaluation: `The developed markets contribution of your current investment (${(developedMarketsValueRatio * 100).toPrecision(3)}%) is within the range of ${( - ruleSettings.thresholdMin * 100 - ).toPrecision( - 3 - )}% and ${(ruleSettings.thresholdMax * 100).toPrecision(3)}%`, + evaluation: this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskDevelopedMarkets.true', + languageCode: this.getLanguageCode(), + placeholders: { + developedMarketsValueRatio: ( + developedMarketsValueRatio * 100 + ).toPrecision(3), + thresholdMin: (ruleSettings.thresholdMin * 100).toPrecision(3), + thresholdMax: (ruleSettings.thresholdMax * 100).toPrecision(3) + } + }), value: true }; } public getCategoryName() { - return 'Economic Market Cluster Risk'; // TODO: Replace hardcoded text with i18n translation + return this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRisk.category', + languageCode: this.getLanguageCode() + }); } public getConfiguration() { @@ -71,7 +98,10 @@ export class EconomicMarketClusterRiskDevelopedMarkets extends Rule { } public getName() { - return 'Developed Markets'; + return this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskDevelopedMarkets', + languageCode: this.getLanguageCode() + }); } public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { diff --git a/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts b/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts index fd3c0ab67..cbf9f98b7 100644 --- a/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts +++ b/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts @@ -1,6 +1,7 @@ import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { UserSettings } from '@ghostfolio/common/interfaces'; export class EconomicMarketClusterRiskEmergingMarkets extends Rule { @@ -9,10 +10,13 @@ export class EconomicMarketClusterRiskEmergingMarkets extends Rule { public constructor( protected exchangeRateDataService: ExchangeRateDataService, + private i18nService: I18nService, currentValueInBaseCurrency: number, - emergingMarketsValueInBaseCurrency: number + emergingMarketsValueInBaseCurrency: number, + languageCode: string ) { super(exchangeRateDataService, { + languageCode, key: EconomicMarketClusterRiskEmergingMarkets.name }); @@ -29,32 +33,55 @@ export class EconomicMarketClusterRiskEmergingMarkets extends Rule { if (emergingMarketsValueRatio > ruleSettings.thresholdMax) { return { - evaluation: `The emerging markets contribution of your current investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%) exceeds ${( - ruleSettings.thresholdMax * 100 - ).toPrecision(3)}%`, + evaluation: this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskEmergingMarkets.false.max', + languageCode: this.getLanguageCode(), + placeholders: { + emergingMarketsValueRatio: ( + emergingMarketsValueRatio * 100 + ).toPrecision(3), + thresholdMax: (ruleSettings.thresholdMax * 100).toPrecision(3) + } + }), value: false }; } else if (emergingMarketsValueRatio < ruleSettings.thresholdMin) { return { - evaluation: `The emerging markets contribution of your current investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%) is below ${( - ruleSettings.thresholdMin * 100 - ).toPrecision(3)}%`, + evaluation: this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskEmergingMarkets.false.min', + languageCode: this.getLanguageCode(), + placeholders: { + emergingMarketsValueRatio: ( + emergingMarketsValueRatio * 100 + ).toPrecision(3), + thresholdMin: (ruleSettings.thresholdMin * 100).toPrecision(3) + } + }), value: false }; } return { - evaluation: `The emerging markets contribution of your current investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%) is within the range of ${( - ruleSettings.thresholdMin * 100 - ).toPrecision( - 3 - )}% and ${(ruleSettings.thresholdMax * 100).toPrecision(3)}%`, + evaluation: this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskEmergingMarkets.true', + languageCode: this.getLanguageCode(), + placeholders: { + emergingMarketsValueRatio: ( + emergingMarketsValueRatio * 100 + ).toPrecision(3), + thresholdMin: (ruleSettings.thresholdMin * 100).toPrecision(3), + thresholdMax: (ruleSettings.thresholdMax * 100).toPrecision(3) + } + }), value: true }; } public getCategoryName() { - return 'Economic Market Cluster Risk'; // TODO: Replace hardcoded text with i18n translation + return this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRisk.category', + languageCode: this.getLanguageCode() + }); } public getConfiguration() { @@ -71,7 +98,10 @@ export class EconomicMarketClusterRiskEmergingMarkets extends Rule { } public getName() { - return 'Emerging Markets'; + return this.i18nService.getTranslation({ + id: 'rule.economicMarketClusterRiskEmergingMarkets', + languageCode: this.getLanguageCode() + }); } public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { diff --git a/apps/client/src/app/pages/i18n/i18n-page.html b/apps/client/src/app/pages/i18n/i18n-page.html index 9f130f295..bb5a00cc0 100644 --- a/apps/client/src/app/pages/i18n/i18n-page.html +++ b/apps/client/src/app/pages/i18n/i18n-page.html @@ -86,6 +86,42 @@
  • Economic Market Cluster Risks
  • +
  • + Developed Markets +
  • +
  • + The developed markets contribution of your current investment + (${developedMarketsValueRatio}%) exceeds + ${thresholdMax}% +
  • +
  • + The developed markets contribution of your current investment + (${developedMarketsValueRatio}%) is below + ${thresholdMin}% +
  • +
  • + The developed markets contribution of your current investment + (${developedMarketsValueRatio}%) is within the range of + ${thresholdMin}% and ${thresholdMax}% +
  • +
  • + Emerging Markets +
  • +
  • + The emerging markets contribution of your current investment + (${emergingMarketsValueRatio}%) exceeds + ${thresholdMax}% +
  • +
  • + The emerging markets contribution of your current investment + (${emergingMarketsValueRatio}%) is below + ${thresholdMin}% +
  • +
  • + The emerging markets contribution of your current investment + (${emergingMarketsValueRatio}%) is within the range of + ${thresholdMin}% and ${thresholdMax}% +
  • Emergency Fund
  • Set up