Skip to content

Commit 9c26580

Browse files
committed
feat: preserve locale with cookie
1 parent 6cd8967 commit 9c26580

3 files changed

Lines changed: 87 additions & 1 deletion

File tree

components/Navigation/index.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,24 @@ import SearchBox from '@node-core/doc-kit/src/generators/web/ui/components/Searc
77
import { useTheme } from '@node-core/doc-kit/src/generators/web/ui/hooks/useTheme.mjs';
88
import { navigation } from '../../site.json' with { type: 'json' };
99
import Logo from '#theme/Logo';
10+
import useLocalizedLink from '../../hooks/useLocalizedLink';
1011

1112
/**
1213
* NavBar component that displays the headings, search, etc.
1314
*/
1415
export default ({ metadata }) => {
1516
const [themePreference, setThemePreference] = useTheme();
17+
const getLocalizedLink = useLocalizedLink();
18+
const navItems = navigation.map((item) => ({
19+
...item,
20+
link: getLocalizedLink(item.link),
21+
}));
1622

1723
return (
1824
<NavBar
1925
Logo={Logo}
2026
sidebarItemTogglerAriaLabel="Toggle navigation menu"
21-
navItems={navigation}
27+
navItems={navItems}
2228
>
2329
<SearchBox pathname={metadata.path} />
2430
<ThemeToggle

hooks/useLocalizedLink.jsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { useEffect, useState } from 'preact/hooks';
2+
3+
import { defaultLocale } from '../site.json' with { type: 'json' };
4+
5+
const LOCALE_COOKIE = 'NEXT_LOCALE';
6+
7+
/**
8+
* Retrieves the locale from the NEXT_LOCALE cookie.
9+
*
10+
* @returns {string|null} The locale from the NEXT_LOCALE cookie, or null if not found.
11+
*/
12+
const getNextLocaleFromCookie = () => {
13+
if (typeof document === 'undefined') {
14+
return null;
15+
}
16+
17+
const localeCookie = document.cookie
18+
.split(';')
19+
.map((cookie) => cookie.trim())
20+
.find((cookie) => cookie.startsWith(`${LOCALE_COOKIE}=`));
21+
22+
if (!localeCookie) {
23+
return null;
24+
}
25+
26+
return decodeURIComponent(localeCookie.slice(LOCALE_COOKIE.length + 1));
27+
};
28+
29+
/**
30+
* Replaces the default locale in a link with the provided locale.
31+
*
32+
* @param {string} link - The link to be localized.
33+
* @param {string|null} nextLocale - The locale to apply to the link.
34+
* @returns {string} - The localized link.
35+
*/
36+
const replaceLocaleInLink = (link, nextLocale) => {
37+
if (!link.startsWith('/') || !link.startsWith(`/${defaultLocale}`)) {
38+
return link;
39+
}
40+
41+
const localizedPrefix = nextLocale ? `/${nextLocale}` : '';
42+
43+
if (link === `/${defaultLocale}`) {
44+
return localizedPrefix || '/';
45+
}
46+
47+
return link.replace(`/${defaultLocale}/`, `${localizedPrefix}/`);
48+
};
49+
50+
/**
51+
* Localizes a given link based on the provided locale.
52+
*
53+
* @param {string} link - The link to be localized.
54+
* @param {string|null} nextLocale - The locale to apply to the link.
55+
* @returns {string} - The localized link.
56+
*/
57+
const localizeLink = (link, nextLocale) => {
58+
if (nextLocale === null) {
59+
return link;
60+
}
61+
62+
return replaceLocaleInLink(link, nextLocale);
63+
};
64+
65+
/**
66+
* Custom hook to get a function that localizes links based on the NEXT_LOCALE cookie.
67+
* @returns {function(string): string} A function that takes a link and returns the localized version of that link.
68+
*/
69+
const useLocalizedLink = () => {
70+
const [nextLocale, setNextLocale] = useState(null);
71+
72+
useEffect(() => {
73+
setNextLocale(getNextLocaleFromCookie());
74+
}, []);
75+
76+
return (link) => localizeLink(link, nextLocale);
77+
};
78+
79+
export default useLocalizedLink;

site.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"defaultLocale": "en",
23
"navigation": [
34
{
45
"link": "/learn",

0 commit comments

Comments
 (0)