From b72f4c71e3370eca0ca8cb895cbecafb1d71348f Mon Sep 17 00:00:00 2001 From: "emma.zettervall" Date: Fri, 26 Sep 2025 08:00:25 +0000 Subject: [PATCH] Merged in feat/book-245-preferred-lang-redirect (pull request #2861) Feat/book 245 preferred lang redirect * added cookie to save preferredLang and middleware to route accordingly * Cleaned up code, added noValidLang.ts middleware * cleaned a little more * Added headers in languageRedirect and set language cookie maxAge to 1 year Approved-by: Linus Flood --- .../components/LanguageSwitcher/index.tsx | 2 ++ .../LanguageSwitcher/setLanguageCookie.ts | 9 ++++++ apps/scandic-web/middleware.ts | 25 +++------------- .../middlewares/languageRedirect.ts | 26 +++++++++++++++++ apps/scandic-web/middlewares/noValidLang.ts | 29 +++++++++++++++++++ 5 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 apps/scandic-web/components/LanguageSwitcher/setLanguageCookie.ts create mode 100644 apps/scandic-web/middlewares/languageRedirect.ts create mode 100644 apps/scandic-web/middlewares/noValidLang.ts diff --git a/apps/scandic-web/components/LanguageSwitcher/index.tsx b/apps/scandic-web/components/LanguageSwitcher/index.tsx index 43771a06b..850b7f864 100644 --- a/apps/scandic-web/components/LanguageSwitcher/index.tsx +++ b/apps/scandic-web/components/LanguageSwitcher/index.tsx @@ -20,6 +20,7 @@ import useLang from "@/hooks/useLang" import LanguageSwitcherContainer from "./LanguageSwitcherContainer" import LanguageSwitcherContent from "./LanguageSwitcherContent" +import { setLanguageCookie } from "./setLanguageCookie" import { languageSwitcherVariants } from "./variants" import styles from "./languageSwitcher.module.css" @@ -97,6 +98,7 @@ export default function LanguageSwitcher({ type }: LanguageSwitcherProps) { function onLanguageSwitch(toLang: string) { trackLanguageSwitchClick(currentLanguage, toLang) + setLanguageCookie(toLang) toggleDropdown(dropdownType) } diff --git a/apps/scandic-web/components/LanguageSwitcher/setLanguageCookie.ts b/apps/scandic-web/components/LanguageSwitcher/setLanguageCookie.ts new file mode 100644 index 000000000..ae4bdf2bb --- /dev/null +++ b/apps/scandic-web/components/LanguageSwitcher/setLanguageCookie.ts @@ -0,0 +1,9 @@ +"use server" +import { cookies } from "next/headers" + +export async function setLanguageCookie(preferredLang: string) { + const cookieStore = await cookies() + cookieStore.set("preferredLang", preferredLang, { + maxAge: 60 * 60 * 24 * 365, // 1 year + }) +} diff --git a/apps/scandic-web/middleware.ts b/apps/scandic-web/middleware.ts index be8930342..c320e2c69 100644 --- a/apps/scandic-web/middleware.ts +++ b/apps/scandic-web/middleware.ts @@ -1,7 +1,6 @@ import * as Sentry from "@sentry/nextjs" import { type NextMiddleware, NextResponse } from "next/server" -import { Lang } from "@scandic-hotels/common/constants/language" import { logger } from "@scandic-hotels/common/logger" import { findLang } from "@scandic-hotels/common/utils/languages" @@ -17,8 +16,10 @@ import * as familyAndFriends from "@/middlewares/familyAndFriends" import * as handleAuth from "@/middlewares/handleAuth" import * as handleDTMC from "@/middlewares/handleDTMC" import * as invalidUrl from "@/middlewares/invalidUrl" +import * as languageRedirect from "@/middlewares/languageRedirect" import * as legacySearchParams from "@/middlewares/legacySearchParams" import * as myPages from "@/middlewares/myPages" +import * as noValidLang from "@/middlewares/noValidLang" import * as redirect from "@/middlewares/redirect" import * as sasXScandic from "@/middlewares/sasXScandic" import * as trailingSlash from "@/middlewares/trailingSlash" @@ -33,28 +34,10 @@ export const middleware: NextMiddleware = async (request, event) => { const headers = getDefaultRequestHeaders(request) const lang = findLang(request.nextUrl.pathname) - if (!lang) { - // Lang is required for all our middleware. - // Without it we shortcircuit early. - // We use middleware-error route because notFound() requires a root layout - // which we do not want. We can move to that once all Current stuff is gone. - - // Default to English if no lang is found. - headers.set("x-lang", Lang.en) - return NextResponse.rewrite( - new URL(`/${Lang.en}/middleware-error/404`, request.nextUrl), - { - request: { - headers, - }, - status: 404, - statusText: "Not found", - } - ) - } - // Note that the order of middlewares is important since that is the order they are matched by. const middlewares = [ + languageRedirect, + noValidLang, invalidUrl, trailingSlash, currentWebLogin, diff --git a/apps/scandic-web/middlewares/languageRedirect.ts b/apps/scandic-web/middlewares/languageRedirect.ts new file mode 100644 index 000000000..c381b25ec --- /dev/null +++ b/apps/scandic-web/middlewares/languageRedirect.ts @@ -0,0 +1,26 @@ +import { type NextMiddleware, NextResponse } from "next/server" + +import { Lang } from "@scandic-hotels/common/constants/language" + +import { getDefaultRequestHeaders } from "./utils" + +import type { MiddlewareMatcher } from "@/types/middleware" + +export const middleware: NextMiddleware = (request) => { + const headers = getDefaultRequestHeaders(request) + const preferredLang = request.cookies.get("preferredLang")?.value ?? Lang.en + + // Set x-lang header + headers.set("x-lang", preferredLang) + + // Redirect to new URL if no lang in URL + const newUrl = new URL(`/${preferredLang}`, request.url) + return NextResponse.redirect(newUrl, { + headers, + }) +} + +export const matcher: MiddlewareMatcher = (request) => { + // if ULR is empty + return request.nextUrl.pathname.length <= 1 +} diff --git a/apps/scandic-web/middlewares/noValidLang.ts b/apps/scandic-web/middlewares/noValidLang.ts new file mode 100644 index 000000000..88a6cf1ce --- /dev/null +++ b/apps/scandic-web/middlewares/noValidLang.ts @@ -0,0 +1,29 @@ +import { type NextMiddleware, NextResponse } from "next/server" + +import { Lang } from "@scandic-hotels/common/constants/language" +import { findLang } from "@scandic-hotels/common/utils/languages" + +import { getDefaultRequestHeaders } from "./utils" + +import type { MiddlewareMatcher } from "@/types/middleware" + +export const middleware: NextMiddleware = (request) => { + const headers = getDefaultRequestHeaders(request) + + headers.set("x-lang", Lang.en) + return NextResponse.rewrite( + new URL(`/${Lang.en}/middleware-error/404`, request.nextUrl), + { + request: { + headers, + }, + status: 404, + statusText: "Not found", + } + ) +} + +export const matcher: MiddlewareMatcher = (request) => { + const lang = findLang(request.nextUrl.pathname) + return !lang +}