diff --git a/website/src/app/[lang]/layout.tsx b/website/src/app/layout.tsx similarity index 72% rename from website/src/app/[lang]/layout.tsx rename to website/src/app/layout.tsx index 02d8677..6e6f110 100644 --- a/website/src/app/[lang]/layout.tsx +++ b/website/src/app/layout.tsx @@ -1,4 +1,11 @@ +import { match } from '@formatjs/intl-localematcher'; +import { + AVAILABLE_LOCALES, + type AvailableLocale, + DEFAULT_LOCALE, +} from '@i18n/locales'; import { Nunito_Sans } from 'next/font/google'; +import { headers } from 'next/headers'; const nunitoSans = Nunito_Sans({ display: 'swap', @@ -13,7 +20,6 @@ import '@styles/main.scss'; import { ApolloWrapper } from '@app/apollo-wrapper'; import Footer from '@components/footer'; import Header from '@components/header'; -import { AVAILABLE_LOCALES } from '@i18n/locales'; import type { PagePropsWithLocale } from '@shared/types/page-with-locale-params'; export const metadata = { @@ -39,7 +45,19 @@ interface RootLayoutProps extends PagePropsWithLocale { } const RootLayout: React.FC = async ({ children, params }) => { - const { lang } = await params; + let { lang } = await params; + + if (!lang) { + const headersList = await headers(); + const acceptLanguagesHeader = headersList.get('accept-language'); + + lang = match( + (acceptLanguagesHeader ?? '').split(', '), + AVAILABLE_LOCALES, + DEFAULT_LOCALE, + ) as AvailableLocale; + } + return ( diff --git a/website/src/app/not-found.module.scss b/website/src/app/not-found.module.scss new file mode 100644 index 0000000..434d70c --- /dev/null +++ b/website/src/app/not-found.module.scss @@ -0,0 +1,38 @@ +@use '@styles/text-styles'; +@use '@styles/layout'; +@use '@styles/buttons'; +@use '@styles/breakpoints'; + +.notfound { + &__content_wrapper { + @include layout.content-max-width-7xl; + padding: var(--spacing-20) var(--spacing-16) var(--spacing-24); + + @include breakpoints.medium-screen { + padding: var(--spacing-6) var(--spacing-12) var(--spacing-12); + } + + @include breakpoints.small-screen { + padding: var(--spacing-6) var(--spacing-6) var(--spacing-8); + } + } + + h1 { + @include text-styles.header-1; + margin: 0; + margin-block-end: var(--spacing-6); + @include breakpoints.from-small-to-medium-screen { + @include text-styles.header-1--mobile; + } + } + + p { + @include text-styles.text-base; + margin: 0; + margin-block-end: var(--spacing-4); + + & > span { + @include text-styles.header-4; + } + } +} diff --git a/website/src/app/not-found.tsx b/website/src/app/not-found.tsx new file mode 100644 index 0000000..7746c7a --- /dev/null +++ b/website/src/app/not-found.tsx @@ -0,0 +1,42 @@ +import styles from './not-found.module.scss'; + +import SupportBanner from '@components/support-banner'; +import { match } from '@formatjs/intl-localematcher'; +import { + AVAILABLE_LOCALES, + type AvailableLocale, + DEFAULT_LOCALE, +} from '@i18n/locales'; +import { headers } from 'next/headers'; +import Link from 'next/link'; + +export default async function NotFound() { + const headersList = await headers(); + const acceptLanguagesHeader = headersList.get('accept-language'); + + const lang = match( + (acceptLanguagesHeader ?? '').split(', '), + AVAILABLE_LOCALES, + DEFAULT_LOCALE, + ) as AvailableLocale; + + return ( +
+
+
+

Sorry, this page isn’t available

+ +

+ 404 error: The link you followed may be broken, or the + page may have been removed. +

+ + + Back to homepage + +
+
+ +
+ ); +}