diff --git a/package.json b/package.json index 58f0f35..1dccd3c 100644 --- a/package.json +++ b/package.json @@ -66,8 +66,6 @@ "@apollo/client": "^3.12.2", "@apollo/experimental-nextjs-app-support": "^0.11.7", "@contentful/rich-text-react-renderer": "^16.0.0", - "@formatjs/intl-getcanonicallocales": "^2.5.4", - "@formatjs/intl-locale": "^4.2.9", "@formatjs/intl-localematcher": "^0.5.10", "@mui/base": "5.0.0-beta.64", "formik": "^2.4.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c8771e3..d9db19f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,12 +17,6 @@ importers: '@contentful/rich-text-react-renderer': specifier: ^16.0.0 version: 16.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@formatjs/intl-getcanonicallocales': - specifier: ^2.5.4 - version: 2.5.4 - '@formatjs/intl-locale': - specifier: ^4.2.9 - version: 4.2.9 '@formatjs/intl-localematcher': specifier: ^0.5.10 version: 0.5.10 @@ -1397,21 +1391,6 @@ packages: '@floating-ui/utils@0.2.8': resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} - '@formatjs/ecma402-abstract@2.3.2': - resolution: {integrity: sha512-6sE5nyvDloULiyOMbOTJEEgWL32w+VHkZQs8S02Lnn8Y/O5aQhjOEXwWzvR7SsBE/exxlSpY2EsWZgqHbtLatg==} - - '@formatjs/fast-memoize@2.2.6': - resolution: {integrity: sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw==} - - '@formatjs/intl-enumerator@1.8.8': - resolution: {integrity: sha512-U/1FGFNObuWWy0N+DwRiDDZvH8cjKixjDDbgr1I1RJ66jOLSVDUApdOsGd8hSmFFAiNXT5s4tM9WfL4QT5VoSw==} - - '@formatjs/intl-getcanonicallocales@2.5.4': - resolution: {integrity: sha512-vSDOsAcc3U+Kl/0b3de8wCQkb3W30H8LUuslyz67wTAHOPSQhPimZyquhwxXpJR+K5yy9CkzTgk5YE5kFT+PFg==} - - '@formatjs/intl-locale@4.2.9': - resolution: {integrity: sha512-zX3Y06SmZ3sAGymzTFNTpWCx4yfdHmuODpGBPbyMfA5Z7Frc17VKEW+D7FIJOVdBZD1918d97vKxu7UAlAxwaw==} - '@formatjs/intl-localematcher@0.5.10': resolution: {integrity: sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==} @@ -8823,33 +8802,6 @@ snapshots: '@floating-ui/utils@0.2.8': {} - '@formatjs/ecma402-abstract@2.3.2': - dependencies: - '@formatjs/fast-memoize': 2.2.6 - '@formatjs/intl-localematcher': 0.5.10 - decimal.js: 10.4.3 - tslib: 2.8.1 - - '@formatjs/fast-memoize@2.2.6': - dependencies: - tslib: 2.8.1 - - '@formatjs/intl-enumerator@1.8.8': - dependencies: - '@formatjs/ecma402-abstract': 2.3.2 - tslib: 2.8.1 - - '@formatjs/intl-getcanonicallocales@2.5.4': - dependencies: - tslib: 2.8.1 - - '@formatjs/intl-locale@4.2.9': - dependencies: - '@formatjs/ecma402-abstract': 2.3.2 - '@formatjs/intl-enumerator': 1.8.8 - '@formatjs/intl-getcanonicallocales': 2.5.4 - tslib: 2.8.1 - '@formatjs/intl-localematcher@0.5.10': dependencies: tslib: 2.8.1 diff --git a/website/src/app/layout.tsx b/website/src/app/layout.tsx index 6e6f110..cd2153a 100644 --- a/website/src/app/layout.tsx +++ b/website/src/app/layout.tsx @@ -1,11 +1,12 @@ -import { match } from '@formatjs/intl-localematcher'; -import { - AVAILABLE_LOCALES, - type AvailableLocale, - DEFAULT_LOCALE, -} from '@i18n/locales'; +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'; +import { getLocale } from '@shared/utils/get-locale'; import { Nunito_Sans } from 'next/font/google'; -import { headers } from 'next/headers'; const nunitoSans = Nunito_Sans({ display: 'swap', @@ -15,13 +16,6 @@ const nunitoSans = Nunito_Sans({ preload: true, }); -import '@styles/main.scss'; - -import { ApolloWrapper } from '@app/apollo-wrapper'; -import Footer from '@components/footer'; -import Header from '@components/header'; -import type { PagePropsWithLocale } from '@shared/types/page-with-locale-params'; - export const metadata = { title: 'NR2F1 Foundation', metadataBase: new URL('https://website-nr2f1.vercel.app'), // TODO: update this once we migrate @@ -48,14 +42,7 @@ const RootLayout: React.FC = async ({ children, 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; + lang = await getLocale(); } return ( diff --git a/website/src/app/not-found.tsx b/website/src/app/not-found.tsx index 488abd6..270f707 100644 --- a/website/src/app/not-found.tsx +++ b/website/src/app/not-found.tsx @@ -1,13 +1,8 @@ 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 type { AvailableLocale } from '@i18n/locales'; +import { getLocale } from '@shared/utils/get-locale'; import Link from 'next/link'; const translations: Record> = { @@ -38,14 +33,7 @@ const translations: Record> = { }; 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; + const lang = await getLocale(); return (
diff --git a/website/src/i18n/locales.ts b/website/src/i18n/locales.ts index 66e2c5f..3e83aed 100644 --- a/website/src/i18n/locales.ts +++ b/website/src/i18n/locales.ts @@ -44,3 +44,5 @@ export interface LocaleParamsPath { } export type LocalisedString = Record; + +export const changeLocaleFormat = (locale: string) => locale.replace('_', '-'); diff --git a/website/src/middleware.ts b/website/src/middleware.ts index daaf683..b7112f5 100644 --- a/website/src/middleware.ts +++ b/website/src/middleware.ts @@ -1,7 +1,9 @@ -import '@formatjs/intl-getcanonicallocales/polyfill'; -import '@formatjs/intl-locale/polyfill'; import { match } from '@formatjs/intl-localematcher'; -import { AVAILABLE_LOCALES, DEFAULT_LOCALE } from '@i18n/locales'; +import { + AVAILABLE_LOCALES, + DEFAULT_LOCALE, + changeLocaleFormat, +} from '@i18n/locales'; import Negotiator from 'negotiator'; import { type NextRequest, NextResponse } from 'next/server'; @@ -12,7 +14,7 @@ const getLocale = (request: NextRequest) => { }, }); - const userLocales = negotiator.languages(); + const userLocales = negotiator.languages().map(changeLocaleFormat); return match(userLocales, AVAILABLE_LOCALES, DEFAULT_LOCALE); }; diff --git a/website/src/shared/utils/get-locale.ts b/website/src/shared/utils/get-locale.ts new file mode 100644 index 0000000..44b37dd --- /dev/null +++ b/website/src/shared/utils/get-locale.ts @@ -0,0 +1,34 @@ +'use server'; + +import { match } from '@formatjs/intl-localematcher'; +import { + AVAILABLE_LOCALES, + type AvailableLocale, + DEFAULT_LOCALE, + changeLocaleFormat, +} from '@i18n/locales'; +import Negotiator from 'negotiator'; +import { headers } from 'next/headers'; + +export const getUserLocales = async () => { + const headersList = await headers(); + + const negotiator = new Negotiator({ + headers: { + 'accept-language': headersList.get('accept-language') ?? '', + }, + }); + + return negotiator.languages().map(changeLocaleFormat); +}; + +export const getLocale = async () => { + const userLocales = await getUserLocales(); + const lang = match( + userLocales, + AVAILABLE_LOCALES, + DEFAULT_LOCALE, + ) as AvailableLocale; + + return lang; +};