From c47042e7ff9713e2a42d60b1fb35d08864dfe7b7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 27 Aug 2026 11:15:21 +0200 Subject: [PATCH] Improve language localization of asset classes --- apps/api/src/app/endpoints/ai/ai.service.ts | 50 ++++++++++++++++----- apps/api/src/services/i18n/i18n.service.ts | 10 ++++- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/apps/api/src/app/endpoints/ai/ai.service.ts b/apps/api/src/app/endpoints/ai/ai.service.ts index 123c71c3e..4c6e096b8 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.ts +++ b/apps/api/src/app/endpoints/ai/ai.service.ts @@ -12,6 +12,7 @@ import type { AiPromptMode } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; +import { AssetClass, AssetSubClass } from '@prisma/client'; import { generateText } from 'ai'; import { format } from 'date-fns'; import type { ColumnDescriptor } from 'tablemark'; @@ -105,6 +106,18 @@ export class AiService { return { name, align: align ?? 'left' }; }); + const assetClassTranslations = this.getEnumTranslations({ + languageCode, + id: 'assetClass', + values: Object.values(AssetClass) + }); + + const assetSubClassTranslations = this.getEnumTranslations({ + languageCode, + id: 'assetSubClass', + values: Object.values(AssetSubClass) + }); + const holdingsTableRows = Object.values(holdings) .sort((a, b) => { return b.allocationInPercentage - a.allocationInPercentage; @@ -134,21 +147,11 @@ export class AiService { break; case 'ASSET_CLASS': - row[name] = assetClass - ? this.i18nService.getTranslation({ - languageCode, - id: `assetClass.${assetClass}` - }) || assetClass - : ''; + row[name] = assetClassTranslations[assetClass] ?? ''; break; case 'ASSET_SUB_CLASS': - row[name] = assetSubClass - ? this.i18nService.getTranslation({ - languageCode, - id: `assetSubClass.${assetSubClass}` - }) || assetSubClass - : ''; + row[name] = assetSubClassTranslations[assetSubClass] ?? ''; break; case 'CURRENCY': @@ -214,4 +217,27 @@ export class AiService { `Provide your answer in the following language: ${languageCode}.` ].join('\n'); } + + private getEnumTranslations({ + id, + languageCode, + values + }: { + id: string; + languageCode: string; + values: T[]; + }) { + return values.reduce( + (translations, value) => { + translations[value] = + this.i18nService.getTranslation({ + languageCode, + id: `${id}.${value}` + }) || value; + + return translations; + }, + {} as Record + ); + } } diff --git a/apps/api/src/services/i18n/i18n.service.ts b/apps/api/src/services/i18n/i18n.service.ts index 83eb3a3ac..cd8f85369 100644 --- a/apps/api/src/services/i18n/i18n.service.ts +++ b/apps/api/src/services/i18n/i18n.service.ts @@ -25,15 +25,21 @@ export class I18nService implements OnModuleInit { languageCode: string; placeholders?: Record; }): string { - const $ = this.translations[languageCode]; + const languageCodeToUse = this.translations[languageCode] + ? languageCode + : DEFAULT_LANGUAGE_CODE; + + const $ = this.translations[languageCodeToUse]; if (!$) { this.logger.warn(`Translation not found for locale '${languageCode}'`); + + return ''; } let translatedText = $( `trans-unit[id="${id}"] > ${ - languageCode === DEFAULT_LANGUAGE_CODE ? 'source' : 'target' + languageCodeToUse === DEFAULT_LANGUAGE_CODE ? 'source' : 'target' }` ).text();