Files
print-calculator/frontend/src/server-routing.ts

106 lines
2.7 KiB
TypeScript

const SUPPORTED_LANG_LIST = ['it', 'en', 'de', 'fr'] as const;
export const SUPPORTED_LANGS = new Set<string>(SUPPORTED_LANG_LIST);
export const DEFAULT_LANG = 'it';
export function resolvePublicRedirectTarget(pathname: string): string | null {
const normalizedPath = normalizePathname(pathname);
if (shouldBypassRedirect(normalizedPath)) {
return null;
}
const trimmedPath =
normalizedPath === '/' ? '/' : normalizedPath.replace(/\/+$/, '');
const segments = splitSegments(trimmedPath);
if (segments.length === 0) {
return `/${DEFAULT_LANG}`;
}
const firstSegment = segments[0].toLowerCase();
if (SUPPORTED_LANGS.has(firstSegment)) {
const canonicalSegments = [firstSegment, ...segments.slice(1)];
const canonicalPath = `/${canonicalSegments.join('/')}`;
const directRedirect = resolveCanonicalRedirect(canonicalSegments);
if (directRedirect) {
return directRedirect;
}
return canonicalPath === normalizedPath ? null : canonicalPath;
}
const effectiveSegments = looksLikeLangToken(firstSegment)
? segments.slice(1)
: segments;
if (effectiveSegments.length === 0) {
return `/${DEFAULT_LANG}`;
}
const directRedirect = resolveCanonicalRedirect([
DEFAULT_LANG,
...effectiveSegments,
]);
if (directRedirect) {
return directRedirect;
}
return `/${[DEFAULT_LANG, ...effectiveSegments].join('/')}`;
}
function resolveCanonicalRedirect(segments: string[]): string | null {
const [lang, section, thirdSegment, fourthSegment] = segments;
if (section?.toLowerCase() === 'calculator' && segments.length === 2) {
return `/${lang}/calculator/basic`;
}
if (
section?.toLowerCase() === 'shop' &&
segments.length === 4 &&
thirdSegment?.toLowerCase() !== 'p' &&
fourthSegment
) {
return `/${lang}/shop/p/${fourthSegment}`;
}
return null;
}
function normalizePathname(pathname: string): string {
const rawValue = String(pathname || '/').trim();
if (!rawValue) {
return '/';
}
return rawValue.startsWith('/') ? rawValue : `/${rawValue}`;
}
function shouldBypassRedirect(pathname: string): boolean {
if (
pathname.startsWith('/api/') ||
pathname.startsWith('/assets/') ||
pathname.startsWith('/media/')
) {
return true;
}
if (
pathname === '/robots.txt' ||
pathname === '/sitemap.xml' ||
pathname === '/sitemap-static.xml' ||
pathname === '/favicon.ico'
) {
return true;
}
return /\.[^/]+$/.test(pathname);
}
function splitSegments(pathname: string): string[] {
return pathname.split('/').filter(Boolean);
}
function looksLikeLangToken(segment: string | null | undefined): boolean {
return (
typeof segment === 'string' && /^[a-z]{2}(?:-[a-z]{2})?$/i.test(segment)
);
}