diff --git a/apps/api/src/app/endpoints/sitemap/sitemap.service.ts b/apps/api/src/app/endpoints/sitemap/sitemap.service.ts index 9522351d5..62dac680b 100644 --- a/apps/api/src/app/endpoints/sitemap/sitemap.service.ts +++ b/apps/api/src/app/endpoints/sitemap/sitemap.service.ts @@ -7,6 +7,9 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { Injectable } from '@nestjs/common'; +const translationTaggedMessageRegex = + /:.*@@(?[a-zA-Z0-9.]+):(?.+)/; + @Injectable() export class SitemapService { public constructor( @@ -19,11 +22,9 @@ export class SitemapService { return SUPPORTED_LANGUAGE_CODES.flatMap((languageCode) => { return personalFinanceTools.map(({ alias, key }) => { - const pathSegments = [ - 'resources', - 'personalFinanceTools', - 'openSourceAlternativeTo' - ]; + const route = + publicRoutes.resources.subRoutes.personalFinanceTools.subRoutes + .product; const params = { rootUrl, languageCode, @@ -31,7 +32,7 @@ export class SitemapService { urlPostfix: alias ?? key }; - return this.createSitemapUrl(pathSegments, params); + return this.createRouteSitemapUrl({ route, ...params }); }); }).join('\n'); } @@ -40,7 +41,6 @@ export class SitemapService { const rootUrl = this.configurationService.get('ROOT_URL'); return SUPPORTED_LANGUAGE_CODES.flatMap((languageCode) => { - const pathSegments = []; const params = { rootUrl, languageCode, @@ -48,9 +48,9 @@ export class SitemapService { }; // add language specific root URL - const urls = [this.createSitemapUrl(pathSegments, params)]; + const urls = [this.createRouteSitemapUrl(params)]; - urls.push(...this.createSitemapUrls(publicRoutes, pathSegments, params)); + urls.push(...this.createSitemapUrls(publicRoutes, params)); return urls; }).join('\n'); @@ -58,57 +58,46 @@ export class SitemapService { private createSitemapUrls( routes: Record, - pathSegments: string[], params: { rootUrl: string; languageCode: string; currentDate: string } ): string[] { return Object.values(routes).flatMap((route) => { if (route.excludeFromSitemap) return []; - const currentPathSegments = [ - ...pathSegments, - this.kebabToCamel(route.path) - ]; - - const urls = [this.createSitemapUrl(currentPathSegments, params)]; + const urls = [this.createRouteSitemapUrl({ route, ...params })]; if (route.subRoutes) { - urls.push( - ...this.createSitemapUrls( - route.subRoutes, - currentPathSegments, - params - ) - ); + urls.push(...this.createSitemapUrls(route.subRoutes, params)); } return urls; }); } - private createSitemapUrl( - pathSegments: string[], - { - rootUrl, - languageCode, - currentDate, - urlPostfix - }: { - rootUrl: string; - languageCode: string; - currentDate: string; - urlPostfix?: string; - } - ): string { - const segments = pathSegments.map((_, index, segments) => { - const translationId = ['routes', ...segments.slice(0, index + 1)].join( - '.' - ); - - return this.i18nService.getTranslation({ - languageCode, - id: translationId - }); - }); + private createRouteSitemapUrl({ + route, + rootUrl, + languageCode, + currentDate, + urlPostfix + }: { + route?: PublicRoute; + rootUrl: string; + languageCode: string; + currentDate: string; + urlPostfix?: string; + }): string { + const segments = + route?.routerLink.map((link) => { + const match = link.match(translationTaggedMessageRegex); + const segment = match + ? (this.i18nService.getTranslation({ + languageCode, + id: match.groups.id + }) ?? match.groups.message) + : link; + + return segment.replace(/^\/+|\/+$/, ''); + }) ?? []; const location = [rootUrl, languageCode, ...segments].join('/') + (urlPostfix ? `-${urlPostfix}` : ''); @@ -120,8 +109,4 @@ export class SitemapService { ' ' ].join('\n'); } - - private kebabToCamel(str: string): string { - return str.replace(/-([a-z])/g, (_, char) => char.toUpperCase()); - } } diff --git a/libs/common/src/lib/routes/routes.ts b/libs/common/src/lib/routes/routes.ts index f2194ff18..f8a542bf3 100644 --- a/libs/common/src/lib/routes/routes.ts +++ b/libs/common/src/lib/routes/routes.ts @@ -1,11 +1,18 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import '@angular/localize/init'; - import { InternalRoute } from './interfaces/internal-route.interface'; import { PublicRoute } from './interfaces/public-route.interface'; +if (typeof window !== 'undefined') { + import('@angular/localize/init'); +} else { + (global as any).$localize = ( + messageParts: TemplateStringsArray, + ...expressions: any[] + ) => String.raw({ raw: messageParts }, ...expressions); +} + export const internalRoutes: Record = { account: { path: 'account',