2 Commits

Author SHA1 Message Date
3ac3262e77 Merge remote-tracking branch 'origin/dev' into dev
All checks were successful
Build and Deploy / test-backend (push) Successful in 28s
Build and Deploy / test-frontend (push) Successful in 1m3s
Build and Deploy / build-and-push (push) Successful in 27s
Build and Deploy / deploy (push) Successful in 20s
# Conflicts:
#	frontend/src/app/app.config.ts
2026-03-11 17:10:06 +01:00
18ecc07240 feat(front-end): ssr i18n fix 2026-03-11 17:09:51 +01:00
2 changed files with 69 additions and 1 deletions

View File

@@ -21,6 +21,7 @@ import {
provideClientHydration,
withEventReplay,
} from '@angular/platform-browser';
import { serverOriginInterceptor } from './core/interceptors/server-origin.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
@@ -33,7 +34,9 @@ export const appConfig: ApplicationConfig = {
scrollPositionRestoration: 'top',
}),
),
provideHttpClient(withInterceptors([adminAuthInterceptor])),
provideHttpClient(
withInterceptors([serverOriginInterceptor, adminAuthInterceptor]),
),
provideTranslateHttpLoader({
prefix: './assets/i18n/',
suffix: '.json',

View File

@@ -0,0 +1,65 @@
import { HttpInterceptorFn } from '@angular/common/http';
import { inject, REQUEST } from '@angular/core';
type RequestLike = {
protocol?: string;
get?: (name: string) => string | undefined;
headers?: Record<string, string | string[] | undefined>;
};
function isAbsoluteUrl(url: string): boolean {
return /^[a-z][a-z\d+\-.]*:/i.test(url) || url.startsWith('//');
}
function firstHeaderValue(
value: string | string[] | undefined,
): string | null {
if (Array.isArray(value)) {
return value[0] ?? null;
}
return typeof value === 'string' ? value : null;
}
function resolveOrigin(request: RequestLike | null): string | null {
if (!request) {
return null;
}
const host =
request.get?.('host') ??
firstHeaderValue(request.headers?.['host']) ??
firstHeaderValue(request.headers?.['x-forwarded-host']);
if (!host) {
return null;
}
const forwardedProtoRaw = firstHeaderValue(
request.headers?.['x-forwarded-proto'],
);
const forwardedProto = forwardedProtoRaw
?.split(',')
.map((part) => part.trim().toLowerCase())
.find(Boolean);
const protocol = forwardedProto || request.protocol || 'http';
return `${protocol}://${host}`;
}
function normalizeRelativePath(url: string): string {
const withoutDot = url.replace(/^\.\//, '');
return withoutDot.startsWith('/') ? withoutDot : `/${withoutDot}`;
}
export const serverOriginInterceptor: HttpInterceptorFn = (req, next) => {
if (isAbsoluteUrl(req.url)) {
return next(req);
}
const request = inject(REQUEST, { optional: true }) as RequestLike | null;
const origin = resolveOrigin(request);
if (!origin) {
return next(req);
}
const absoluteUrl = `${origin}${normalizeRelativePath(req.url)}`;
return next(req.clone({ url: absoluteUrl }));
};