feat(SW-1842): Making the language switcher links render in the initial HTML for SEO purposes, should also fix SW-1991 and SW-1742.

Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-03-24 14:12:48 +00:00
parent f633ad7fcc
commit 34bc877092
6 changed files with 83 additions and 70 deletions

View File

@@ -1,6 +1,6 @@
"use client"
import { FocusTrap } from "focus-trap-react"
import FocusLock from "react-focus-lock"
import { useIntl } from "react-intl"
import { logout } from "@/constants/routes/handleAuth"
@@ -42,7 +42,7 @@ export default function MyPagesMenuContent({
}
return (
<FocusTrap focusTrapOptions={{ clickOutsideDeactivates: true }}>
<FocusLock returnFocus={true}>
<nav className={styles.myPagesMenuContent}>
<div className={introClassName}>
<Subtitle type="two" className={styles.userName}>
@@ -75,7 +75,7 @@ export default function MyPagesMenuContent({
</li>
</ul>
</nav>
</FocusTrap>
</FocusLock>
)
}

View File

@@ -1,6 +1,6 @@
"use client"
import { FocusTrap } from "focus-trap-react"
import FocusLock from "react-focus-lock"
import useDropdownStore from "@/stores/main-menu"
@@ -34,10 +34,7 @@ export default function MegaMenu({
}
return (
<FocusTrap
active={isOpen}
focusTrapOptions={{ clickOutsideDeactivates: true }}
>
<FocusLock disabled={!isOpen} returnFocus={true}>
<nav className={`${styles.megaMenu} ${isOpen ? styles.active : ""}`}>
{isMobile ? (
<div className={styles.backWrapper}>
@@ -122,6 +119,6 @@ export default function MegaMenu({
) : null}
</div>
</nav>
</FocusTrap>
</FocusLock>
)
}

View File

@@ -1,6 +1,5 @@
"use client"
import { FocusTrap } from "focus-trap-react"
import { usePathname } from "next/navigation"
import { useIntl } from "react-intl"
@@ -29,33 +28,31 @@ export default function LanguageSwitcherContent({
const pathname = usePathname()
return (
<FocusTrap focusTrapOptions={{ clickOutsideDeactivates: true }}>
<div className={styles.languageWrapper}>
<Subtitle className={styles.subtitle} type="two">
{intl.formatMessage({ id: "Select your language" })}
</Subtitle>
<ul className={styles.list}>
{urlKeys.map((key) => {
const url = urls[key]?.url
const isActive = currentLanguage === key
if (url) {
return (
<li key={key}>
<Link
className={`${styles.link} ${isActive ? styles.active : ""}`}
href={replaceUrlPart(pathname, url)}
onClick={onLanguageSwitch}
keepSearchParams
>
{languages[key]}
{isActive ? <CheckIcon color="burgundy" /> : null}
</Link>
</li>
)
}
})}
</ul>
</div>
</FocusTrap>
<div className={styles.languageWrapper}>
<Subtitle className={styles.subtitle} type="two">
{intl.formatMessage({ id: "Select your language" })}
</Subtitle>
<ul className={styles.list}>
{urlKeys.map((key) => {
const url = urls[key]?.url
const isActive = currentLanguage === key
if (url) {
return (
<li key={key}>
<Link
className={`${styles.link} ${isActive ? styles.active : ""}`}
href={replaceUrlPart(pathname, url)}
onClick={onLanguageSwitch}
keepSearchParams
>
{languages[key]}
{isActive ? <CheckIcon color="burgundy" /> : null}
</Link>
</li>
)
}
})}
</ul>
</div>
)
}

View File

@@ -2,6 +2,7 @@
import { usePathname } from "next/navigation"
import { useRef } from "react"
import FocusLock from "react-focus-lock"
import { useIntl } from "react-intl"
import { languages } from "@/constants/languages"
@@ -118,14 +119,14 @@ export default function LanguageSwitcher({ type }: LanguageSwitcherProps) {
<div
className={`${styles.dropdown} ${isLanguageSwitcherOpen ? styles.isExpanded : ""}`}
>
{isLanguageSwitcherOpen ? (
<FocusLock returnFocus={true} disabled={!isLanguageSwitcherOpen}>
<LanguageSwitcherContainer type={type}>
<LanguageSwitcherContent
urls={languagesResponse.urls}
onLanguageSwitch={() => toggleDropdown(dropdownType)}
/>
</LanguageSwitcherContainer>
) : null}
</FocusLock>
</div>
</div>
)

View File

@@ -68,7 +68,6 @@
"embla-carousel-react": "^8.5.2",
"fast-deep-equal": "^3.1.3",
"fetch-retry": "^6.0.0",
"focus-trap-react": "^11.0.3",
"framer-motion": "^11.3.28",
"graphql": "^16.8.1",
"graphql-request": "^6.1.0",
@@ -88,6 +87,7 @@
"react-day-picker": "^9.0.8",
"react-dom": "^18",
"react-feather": "^2.0.10",
"react-focus-lock": "^2.13.6",
"react-hook-form": "^7.51.2",
"react-international-phone": "^4.2.6",
"react-intl": "^6.6.8",

View File

@@ -1597,6 +1597,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.13":
version: 7.26.10
resolution: "@babel/runtime@npm:7.26.10"
dependencies:
regenerator-runtime: "npm:^0.14.0"
checksum: 10c0/6dc6d88c7908f505c4f7770fb4677dfa61f68f659b943c2be1f2a99cb6680343462867abf2d49822adc435932919b36c77ac60125793e719ea8745f2073d3745
languageName: node
linkType: hard
"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.24.5, @babel/runtime@npm:^7.8.4":
version: 7.26.9
resolution: "@babel/runtime@npm:7.26.9"
@@ -6282,7 +6291,6 @@ __metadata:
eslint-plugin-simple-import-sort: "npm:^12.1.0"
fast-deep-equal: "npm:^3.1.3"
fetch-retry: "npm:^6.0.0"
focus-trap-react: "npm:^11.0.3"
framer-motion: "npm:^11.3.28"
graphql: "npm:^16.8.1"
graphql-request: "npm:^6.1.0"
@@ -6309,6 +6317,7 @@ __metadata:
react-day-picker: "npm:^9.0.8"
react-dom: "npm:^18"
react-feather: "npm:^2.0.10"
react-focus-lock: "npm:^2.13.6"
react-hook-form: "npm:^7.51.2"
react-international-phone: "npm:^4.2.6"
react-intl: "npm:^6.6.8"
@@ -12497,27 +12506,12 @@ __metadata:
languageName: node
linkType: hard
"focus-trap-react@npm:^11.0.3":
version: 11.0.3
resolution: "focus-trap-react@npm:11.0.3"
"focus-lock@npm:^1.3.6":
version: 1.3.6
resolution: "focus-lock@npm:1.3.6"
dependencies:
focus-trap: "npm:^7.6.4"
tabbable: "npm:^6.2.0"
peerDependencies:
"@types/react": ^18.0.0 || ^19.0.0
"@types/react-dom": ^18.0.0 || ^19.0.0
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
checksum: 10c0/5a4829720901e32ef8cb0783a91e06262e079ab4a0537ffa21d866b1b70d6d383a4ee14baa19e84d952a304b4b08814a1c1fbdb2307d79a2995977735376ae45
languageName: node
linkType: hard
"focus-trap@npm:^7.6.4":
version: 7.6.4
resolution: "focus-trap@npm:7.6.4"
dependencies:
tabbable: "npm:^6.2.0"
checksum: 10c0/ed810d47fd904a5e0269e822d98e634c6cbdd7222046c712ef299bdd26a422db754e3cec04e6517065b12be4b47f65c21f6244e0c07a308b1060985463d518cb
tslib: "npm:^2.0.3"
checksum: 10c0/9fc9aee762d9fc41a339cbee328b6fa9d8fdaea545aac10c7ce77358ba7800c47918a583613174d059dedc909d7a6ddd550895caf3449ca995bd66644368ec8f
languageName: node
linkType: hard
@@ -17723,7 +17717,7 @@ __metadata:
languageName: node
linkType: hard
"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@@ -18024,6 +18018,17 @@ __metadata:
languageName: node
linkType: hard
"react-clientside-effect@npm:^1.2.7":
version: 1.2.7
resolution: "react-clientside-effect@npm:1.2.7"
dependencies:
"@babel/runtime": "npm:^7.12.13"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
checksum: 10c0/8d50ef578daa6bfbd970c85a22bf3179a8b237dfad2abffd866241c3fea9d0e1996bc016dca9fe616da4bfe39484836901a70230ac924671ed1fb8ee6ec40e71
languageName: node
linkType: hard
"react-day-picker@npm:^9.0.8":
version: 9.5.1
resolution: "react-day-picker@npm:9.5.1"
@@ -18098,6 +18103,26 @@ __metadata:
languageName: node
linkType: hard
"react-focus-lock@npm:^2.13.6":
version: 2.13.6
resolution: "react-focus-lock@npm:2.13.6"
dependencies:
"@babel/runtime": "npm:^7.0.0"
focus-lock: "npm:^1.3.6"
prop-types: "npm:^15.6.2"
react-clientside-effect: "npm:^1.2.7"
use-callback-ref: "npm:^1.3.3"
use-sidecar: "npm:^1.1.3"
peerDependencies:
"@types/react": "*"
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 10c0/5a3e92fb0025042ab613c54b8ff0aa6c3a45a4d4785c51c024758b02ff83a89295b458ba609c48d11f1c6bbcab6a6b032c5c17d1f3d168a2835cbbec3dea6a46
languageName: node
linkType: hard
"react-hook-form@npm:^7.51.2":
version: 7.54.2
resolution: "react-hook-form@npm:7.54.2"
@@ -20112,13 +20137,6 @@ __metadata:
languageName: node
linkType: hard
"tabbable@npm:^6.2.0":
version: 6.2.0
resolution: "tabbable@npm:6.2.0"
checksum: 10c0/ced8b38f05f2de62cd46836d77c2646c42b8c9713f5bd265daf0e78ff5ac73d3ba48a7ca45f348bafeef29b23da7187c72250742d37627883ef89cbd7fa76898
languageName: node
linkType: hard
"table-layout@npm:^1.0.2, table-layout@npm:~1.0.0":
version: 1.0.2
resolution: "table-layout@npm:1.0.2"