* move setLang() to a root layout
* fix: findLang only returns acceptable languages * fix: fallback to use header x-lang if we haven't setLang yet * fix: languageSchema, allow uppercase Approved-by: Linus Flood
This commit is contained in:
@@ -2,14 +2,11 @@ import { Suspense } from "react"
|
||||
|
||||
import Breadcrumbs from "@/components/Breadcrumbs"
|
||||
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import { PageContentTypeEnum } from "@/types/requests/contentType"
|
||||
|
||||
export default function AllBreadcrumbs({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
export default function AllBreadcrumbs({}: PageArgs<LangParams>) {
|
||||
return (
|
||||
<Suspense fallback={<BreadcrumbsSkeleton />}>
|
||||
<Breadcrumbs variant={PageContentTypeEnum.accountPage} />
|
||||
|
||||
@@ -6,7 +6,6 @@ import Blocks from "@/components/Blocks"
|
||||
import SectionHeader from "@/components/Section/Header"
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
@@ -14,11 +13,9 @@ import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export { generateMetadata } from "@/utils/generateMetadata"
|
||||
|
||||
export default async function MyPages({
|
||||
params,
|
||||
}: PageArgs<LangParams & { path: string[] }>) {
|
||||
setLang(params.lang)
|
||||
|
||||
export default async function MyPages({}: PageArgs<
|
||||
LangParams & { path: string[] }
|
||||
>) {
|
||||
const accountPageRes = await serverClient().contentstack.accountPage.get()
|
||||
const intl = await getIntl()
|
||||
|
||||
|
||||
@@ -2,17 +2,12 @@ import ManagePreferencesButton from "@/components/Profile/ManagePreferencesButto
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function CommunicationSlot({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
export default async function CommunicationSlot({}: PageArgs<LangParams>) {
|
||||
const intl = await getIntl()
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
|
||||
@@ -5,14 +5,12 @@ import CreditCardList from "@/components/Profile/CreditCardList"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function CreditCardSlot({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
export default async function CreditCardSlot({}: PageArgs<LangParams>) {
|
||||
const intl = await getIntl()
|
||||
const creditCards = await serverClient().user.creditCards()
|
||||
|
||||
|
||||
@@ -5,16 +5,12 @@ import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function MembershipCardSlot({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
export default async function MembershipCardSlot({}: PageArgs<LangParams>) {
|
||||
const intl = await getIntl()
|
||||
const membershipCards = await getMembershipCards()
|
||||
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import { getProfile } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import Form from "@/components/Forms/Edit/Profile"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function EditProfileSlot({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
export default async function EditProfileSlot({}: PageArgs<LangParams>) {
|
||||
const user = await getProfile()
|
||||
if (!user || "error" in user) {
|
||||
return null
|
||||
|
||||
@@ -16,14 +16,12 @@ import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function Profile({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
const intl = await getIntl()
|
||||
const user = await getProfile()
|
||||
if (!user || "error" in user) {
|
||||
|
||||
@@ -3,14 +3,12 @@ import "./profileLayout.css"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export { generateMetadata } from "@/utils/generateMetadata"
|
||||
|
||||
export default async function ProfilePage({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
export default async function ProfilePage({}: PageArgs<LangParams>) {
|
||||
const accountPage = await serverClient().contentstack.accountPage.get()
|
||||
|
||||
if (!accountPage) {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Suspense } from "react"
|
||||
|
||||
import Breadcrumbs from "@/components/Breadcrumbs"
|
||||
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { ContentTypeParams, LangParams, PageArgs } from "@/types/params"
|
||||
import { PageContentTypeEnum } from "@/types/requests/contentType"
|
||||
@@ -16,8 +15,6 @@ const IGNORED_CONTENT_TYPES = [
|
||||
export default function PageBreadcrumbs({
|
||||
params,
|
||||
}: PageArgs<LangParams & ContentTypeParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
if (IGNORED_CONTENT_TYPES.includes(params.contentType)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import LoyaltyPage from "@/components/ContentType/LoyaltyPage"
|
||||
import StartPage from "@/components/ContentType/StartPage"
|
||||
import CollectionPage from "@/components/ContentType/StaticPages/CollectionPage"
|
||||
import ContentPage from "@/components/ContentType/StaticPages/ContentPage"
|
||||
import { getLang, setLang } from "@/i18n/serverContext"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
import { isValidSession } from "@/utils/session"
|
||||
|
||||
import type {
|
||||
@@ -33,8 +33,6 @@ export default async function ContentTypePage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams & ContentTypeParams & UIDParams, { subpage?: string }>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const pathname = headers().get("x-pathname") || ""
|
||||
|
||||
switch (params.contentType) {
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import BookingConfirmation from "@/components/HotelReservation/BookingConfirmation"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function BookingConfirmationPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams, { confirmationNumber: string }>) {
|
||||
setLang(params.lang)
|
||||
void getBookingConfirmation(searchParams.confirmationNumber)
|
||||
return (
|
||||
<BookingConfirmation confirmationNumber={searchParams.confirmationNumber} />
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Suspense } from "react"
|
||||
import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer"
|
||||
import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton"
|
||||
import { MapContainer } from "@/components/MapContainer"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
@@ -11,11 +10,8 @@ import type { AlternativeHotelsSearchParams } from "@/types/components/hotelRese
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SelectHotelMapPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams, AlternativeHotelsSearchParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
return (
|
||||
<div className={styles.main}>
|
||||
<MapContainer>
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Suspense } from "react"
|
||||
|
||||
import SelectHotel from "@/components/HotelReservation/SelectHotel"
|
||||
import { SelectHotelSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelSkeleton"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { AlternativeHotelsSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
@@ -11,8 +10,6 @@ export default async function AlternativeHotelsPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams, AlternativeHotelsSearchParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const roomKey = Object.keys(searchParams)
|
||||
.filter((key) => key.startsWith("room["))
|
||||
.map((key) => searchParams[key])
|
||||
|
||||
@@ -21,7 +21,6 @@ import MobileSummary from "@/components/HotelReservation/EnterDetails/Summary/Mo
|
||||
import { generateChildrenString } from "@/components/HotelReservation/utils"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
import EnterDetailsProvider from "@/providers/EnterDetailsProvider"
|
||||
import { convertSearchParamsToObj } from "@/utils/url"
|
||||
|
||||
@@ -49,8 +48,6 @@ export default async function DetailsPage({
|
||||
params: { lang },
|
||||
searchParams,
|
||||
}: PageArgs<LangParams, SelectRateSearchParams>) {
|
||||
setLang(lang)
|
||||
|
||||
const intl = await getIntl()
|
||||
const selectRoomParams = new URLSearchParams(searchParams)
|
||||
const booking = convertSearchParamsToObj<SelectRateSearchParams>(searchParams)
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Suspense } from "react"
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
@@ -14,8 +13,6 @@ import {
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default function HotelReservationPage({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
if (!env.ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Suspense } from "react"
|
||||
import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer"
|
||||
import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton"
|
||||
import { MapContainer } from "@/components/MapContainer"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
@@ -12,11 +11,8 @@ import type { SelectHotelSearchParams } from "@/types/components/hotelReservatio
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SelectHotelMapPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams, SelectHotelSearchParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const suspenseKey = stringify(searchParams)
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Suspense } from "react"
|
||||
|
||||
import SelectHotel from "@/components/HotelReservation/SelectHotel"
|
||||
import { SelectHotelSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelSkeleton"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
@@ -12,8 +11,6 @@ export default async function SelectHotelPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams, SelectHotelSearchParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const suspenseKey = stringify(searchParams)
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Suspense } from "react"
|
||||
import SelectRate from "@/components/HotelReservation/SelectRate"
|
||||
import { HotelInfoCardSkeleton } from "@/components/HotelReservation/SelectRate/HotelInfoCard"
|
||||
import { RoomsContainerSkeleton } from "@/components/HotelReservation/SelectRate/RoomsContainer/RoomsContainerSkeleton"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
@@ -13,8 +12,6 @@ export default async function SelectRatePage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams & { section: string }, SelectRateSearchParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
const suspenseKey = stringify(searchParams)
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,15 +2,12 @@ import { Suspense } from "react"
|
||||
|
||||
import { MyStay } from "@/components/HotelReservation/MyStay"
|
||||
import { MyStaySkeleton } from "@/components/HotelReservation/MyStay/myStaySkeleton"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function MyStayPage({
|
||||
params,
|
||||
}: PageArgs<LangParams & { refId: string }>) {
|
||||
setLang(params.lang)
|
||||
|
||||
return (
|
||||
<Suspense fallback={<MyStaySkeleton />}>
|
||||
<MyStay reservationId={params.refId} />
|
||||
|
||||
22
app/[lang]/(live)/@footer/error.tsx
Normal file
22
app/[lang]/(live)/@footer/error.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
"use client"
|
||||
|
||||
import { env } from "@/env/client"
|
||||
|
||||
export default function Error({
|
||||
error,
|
||||
}: {
|
||||
error: Error & { digest?: string }
|
||||
reset: () => void
|
||||
}) {
|
||||
return (
|
||||
<section>
|
||||
<pre>Unable to render footer</pre>
|
||||
{env.NEXT_PUBLIC_NODE_ENV === "development" && (
|
||||
<div>
|
||||
<div>{error.message}</div>
|
||||
<pre>{error.stack}</pre>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
16
app/[lang]/(live)/@footer/page.tsx
Normal file
16
app/[lang]/(live)/@footer/page.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import CurrentFooter from "@/components/Current/Footer"
|
||||
import Footer, { preload } from "@/components/Footer"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default function FooterSlot({}: PageArgs<LangParams>) {
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
return <CurrentFooter />
|
||||
}
|
||||
|
||||
preload()
|
||||
|
||||
return <Footer />
|
||||
}
|
||||
22
app/[lang]/(live)/@header/error.tsx
Normal file
22
app/[lang]/(live)/@header/error.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
"use client"
|
||||
|
||||
import { env } from "@/env/client"
|
||||
|
||||
export default function Error({
|
||||
error,
|
||||
}: {
|
||||
error: Error & { digest?: string }
|
||||
reset: () => void
|
||||
}) {
|
||||
return (
|
||||
<section>
|
||||
<pre>Unable to render header</pre>
|
||||
{env.NEXT_PUBLIC_NODE_ENV === "development" && (
|
||||
<div>
|
||||
<div>{error.message}</div>
|
||||
<pre>{error.stack}</pre>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
21
app/[lang]/(live)/@header/page.tsx
Normal file
21
app/[lang]/(live)/@header/page.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import CurrentHeader from "@/components/Current/Header"
|
||||
import HeaderFallback from "@/components/Current/Header/HeaderFallback"
|
||||
import Header from "@/components/Header"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default function HeaderPage({}: PageArgs<LangParams>) {
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
return (
|
||||
<Suspense fallback={<HeaderFallback />}>
|
||||
<CurrentHeader />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
return <Header />
|
||||
}
|
||||
@@ -20,25 +20,22 @@ import GTMScript from "@/components/TrackingSDK/GTMScript"
|
||||
import RouterTracking from "@/components/TrackingSDK/RouterTracking"
|
||||
import { getIntl } from "@/i18n"
|
||||
import ServerIntlProvider from "@/i18n/Provider"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, LayoutArgs } from "@/types/params"
|
||||
|
||||
export default async function RootLayout({
|
||||
bookingwidget,
|
||||
children,
|
||||
params,
|
||||
}: React.PropsWithChildren<
|
||||
LayoutArgs<LangParams> & {
|
||||
bookingwidget: React.ReactNode
|
||||
}
|
||||
>) {
|
||||
setLang(params.lang)
|
||||
preloadUserTracking()
|
||||
const { defaultLocale, locale, messages } = await getIntl()
|
||||
|
||||
return (
|
||||
<html lang={params.lang}>
|
||||
<>
|
||||
<head>
|
||||
<AdobeSDKScript />
|
||||
<GTMScript />
|
||||
@@ -73,6 +70,6 @@ export default async function RootLayout({
|
||||
</ServerIntlProvider>
|
||||
</SessionProvider>
|
||||
</body>
|
||||
</html>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import NotFound from "@/components/Current/NotFound"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default function NotFoundPage({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
export default function NotFoundPage({}: PageArgs<LangParams>) {
|
||||
return <NotFound />
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { LangParams, LayoutArgs, StatusParams } from "@/types/params"
|
||||
@@ -7,8 +5,6 @@ import type { LangParams, LayoutArgs, StatusParams } from "@/types/params"
|
||||
export default async function MiddlewareError({
|
||||
params,
|
||||
}: LayoutArgs<LangParams & StatusParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
return (
|
||||
<div className={styles.layout}>
|
||||
Middleware error {params.lang}: {params.status}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import Header from "@/components/Current/Header"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function HeaderPage({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
export default async function HeaderPage({}: PageArgs<LangParams>) {
|
||||
return <Header />
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import { request } from "@/lib/graphql/request"
|
||||
|
||||
import ContentPage from "@/components/Current/ContentPage"
|
||||
import Tracking from "@/components/Current/Tracking"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, PageArgs, UriParams } from "@/types/params"
|
||||
import type { GetCurrentBlockPageData } from "@/types/requests/currentBlockPage"
|
||||
@@ -16,8 +15,6 @@ export default async function CurrentContentPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: PageArgs<LangParams, UriParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
try {
|
||||
if (!searchParams.uri) {
|
||||
throw new Error("Bad URI")
|
||||
|
||||
@@ -12,7 +12,6 @@ import SkipToMainContent from "@/components/SkipToMainContent"
|
||||
import RouterTracking from "@/components/TrackingSDK/RouterTracking"
|
||||
import { getIntl } from "@/i18n"
|
||||
import ServerIntlProvider from "@/i18n/Provider"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { Metadata } from "next"
|
||||
|
||||
@@ -31,7 +30,6 @@ export default async function RootLayout({
|
||||
}: React.PropsWithChildren<
|
||||
LayoutArgs<LangParams> & { header: React.ReactNode }
|
||||
>) {
|
||||
setLang(params.lang)
|
||||
const { defaultLocale, locale, messages } = await getIntl()
|
||||
|
||||
return (
|
||||
|
||||
@@ -17,7 +17,6 @@ import GTMScript from "@/components/TrackingSDK/GTMScript"
|
||||
import RouterTracking from "@/components/TrackingSDK/RouterTracking"
|
||||
import { getIntl } from "@/i18n"
|
||||
import ServerIntlProvider from "@/i18n/Provider"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { LangParams, LayoutArgs } from "@/types/params"
|
||||
|
||||
@@ -29,7 +28,6 @@ export default async function RootLayout({
|
||||
return null
|
||||
}
|
||||
|
||||
setLang(params.lang)
|
||||
preloadUserTracking()
|
||||
const { defaultLocale, locale, messages } = await getIntl()
|
||||
|
||||
|
||||
16
app/[lang]/layout.tsx
Normal file
16
app/[lang]/layout.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { getLang, setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type { Lang } from "@/constants/languages"
|
||||
|
||||
export default function Layout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
params: { lang: Lang }
|
||||
}) {
|
||||
setLang(params.lang)
|
||||
const lang = getLang()
|
||||
|
||||
return <html lang={lang}>{children}</html>
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import { getProfile } from "@/lib/trpc/memoizedRequests"
|
||||
import AccountPage from "@/components/Webviews/AccountPage"
|
||||
import LoyaltyPage from "@/components/Webviews/LoyaltyPage"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import type {
|
||||
ContentTypeWebviewParams,
|
||||
@@ -18,7 +17,6 @@ import type {
|
||||
export default async function ContentTypePage({
|
||||
params,
|
||||
}: PageArgs<LangParams & ContentTypeWebviewParams & UIDParams, {}>) {
|
||||
setLang(params.lang)
|
||||
const intl = await getIntl()
|
||||
const user = await getProfile()
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import GTMScript from "@/components/TrackingSDK/GTMScript"
|
||||
import RouterTracking from "@/components/TrackingSDK/RouterTracking"
|
||||
import { getIntl } from "@/i18n"
|
||||
import ServerIntlProvider from "@/i18n/Provider"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./layout.module.css"
|
||||
|
||||
@@ -26,7 +25,6 @@ export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
}: React.PropsWithChildren<LayoutArgs<LangParams>>) {
|
||||
setLang(params.lang)
|
||||
const { defaultLocale, locale, messages } = await getIntl()
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default function Refresh({ params }: PageArgs<LangParams>) {
|
||||
setLang(params.lang)
|
||||
|
||||
export default function Refresh({}: PageArgs<LangParams>) {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<LoadingSpinner />
|
||||
|
||||
@@ -5,7 +5,9 @@ import { texts } from "./Texts"
|
||||
import styles from "./notFound.module.css"
|
||||
|
||||
export default function NotFound() {
|
||||
const infoTexts = texts[getLang()]
|
||||
const lang = getLang()
|
||||
const infoTexts = texts[lang]
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
transform-origin: bottom;
|
||||
}
|
||||
|
||||
.roomPanel>* {
|
||||
.roomPanel > * {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -52,4 +52,4 @@ div.roomContainer p.subtitle {
|
||||
.roomContainer {
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
"use client"
|
||||
import { useParams } from "next/navigation"
|
||||
|
||||
import { LangParams } from "@/types/params"
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
import { languageSchema } from "@/utils/languages"
|
||||
|
||||
import type { LangParams } from "@/types/params"
|
||||
|
||||
/**
|
||||
* A hook to get the current lang from the URL
|
||||
*/
|
||||
export default function useLang() {
|
||||
const { lang } = useParams<LangParams>()
|
||||
return lang
|
||||
|
||||
const parsedLang = languageSchema.safeParse(lang)
|
||||
return parsedLang.success ? parsedLang.data : Lang.en
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ We have a hook called `useLang` that directly returns the `lang` parameter from
|
||||
|
||||
In order to not prop drill that all the way from a page we use React's `cache` in a way that resembles React`s context, but on the server side.
|
||||
|
||||
For this to work we must set the language with `setLang` on all root layouts and pages, including pages in parallel routes. Then we can use `getLang` in the components where we need the language.
|
||||
For this to work we must set the language with `setLang` on the topmost layout
|
||||
|
||||
This was inspired by [server-only-context](https://github.com/manvalls/server-only-context)
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import "server-only"
|
||||
|
||||
import { headers } from "next/headers"
|
||||
import { cache } from "react"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
const getRef = cache(() => ({ current: Lang.en }))
|
||||
import { languageSchema } from "@/utils/languages"
|
||||
|
||||
const getRef = cache(() => ({ current: undefined as Lang | undefined }))
|
||||
|
||||
/**
|
||||
* Set the language for the current request
|
||||
@@ -13,12 +18,17 @@ const getRef = cache(() => ({ current: Lang.en }))
|
||||
* @param newLang
|
||||
*/
|
||||
export function setLang(newLang: Lang) {
|
||||
getRef().current = newLang
|
||||
const parseResult = languageSchema.safeParse(newLang)
|
||||
getRef().current = parseResult.success ? parseResult.data : Lang.en
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global language set for the current request
|
||||
*/
|
||||
export function getLang() {
|
||||
return getRef().current
|
||||
export function getLang(): Lang {
|
||||
const contextLang = getRef().current
|
||||
const headerLang = headers().get("x-lang") as Lang
|
||||
|
||||
const l = contextLang || headerLang || Lang.en
|
||||
return l
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type NextMiddleware,NextResponse } from "next/server"
|
||||
import { type NextMiddleware, NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
myPages,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { MembershipLevelEnum } from "@/constants/membershipLevels"
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { MembershipLevelEnum } from "@/constants/membershipLevels"
|
||||
|
||||
export const loyaltyLevelInput = z.object({
|
||||
level: z.nativeEnum(MembershipLevelEnum),
|
||||
|
||||
@@ -33,7 +33,7 @@ const outputSchema = z.object({
|
||||
export const verifyOtp = protectedProcedure
|
||||
.input(inputSchema)
|
||||
.output(outputSchema)
|
||||
.mutation(async function ({ ctx, input }) {
|
||||
.mutation(async function ({ input }) {
|
||||
const sasAuthToken = getSasToken()
|
||||
|
||||
if (!sasAuthToken) {
|
||||
|
||||
@@ -57,6 +57,7 @@ export const contentstackBaseProcedure = baseProcedure.use(
|
||||
if (!opts.ctx.lang) {
|
||||
// When fetching data client side with TRPC we don't pass through middlewares and therefore do not get the lang through headers
|
||||
// We can then pass lang as an input in the request and set it to the context in the procedure
|
||||
|
||||
const input = await opts.getRawInput()
|
||||
const parsedInput = langInput.safeParse(input)
|
||||
if (!parsedInput.success) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher"
|
||||
import type { Header } from "@/types/trpc/routers/contentstack/header"
|
||||
|
||||
export interface MobileMenuProps {
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
export function findLang(pathname: string) {
|
||||
return Object.values(Lang).find(
|
||||
const langFromPath = Object.values(Lang).find(
|
||||
(l) => pathname.startsWith(`/${l}/`) || pathname === `/${l}`
|
||||
)
|
||||
|
||||
const parsedLang = languageSchema.safeParse(langFromPath)
|
||||
if (!parsedLang.success) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return parsedLang.data
|
||||
}
|
||||
|
||||
export const languageSchema = z.preprocess(
|
||||
(arg) => (typeof arg === "string" ? arg.toLowerCase() : arg),
|
||||
z.nativeEnum(Lang)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user