Skip to content

Commit 4578412

Browse files
committed
refactor: react-intl to locale provider
1 parent 56616b9 commit 4578412

7 files changed

Lines changed: 108 additions & 116 deletions

File tree

components/Layout/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import NavBar from '../Navigation';
77
import MetaBar from '../Metabar';
88
import SideBar from '../Sidebar';
99
import Footer from '../Footer';
10-
import LocaleProvider from '../../providers/LocaleProvider';
10+
import LocaleProvider from '../providers/LocaleProvider';
1111

1212
/**
1313
* @typedef {Object} Props

components/Navigation/index.jsx

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,22 @@ import GitHubIcon from '@node-core/ui-components/Icons/Social/GitHub';
55
import SearchBox from '@node-core/doc-kit/src/generators/web/ui/components/SearchBox';
66
import { useTheme } from '@node-core/doc-kit/src/generators/web/ui/hooks/useTheme.mjs';
77

8-
import { useEffect, useState } from 'preact/hooks';
9-
import { useIntl } from 'react-intl';
10-
11-
import { localizeLink } from '../../util/link';
128
import { navigation } from '../../site.json' with { type: 'json' };
13-
149
import Logo from '#theme/Logo';
10+
import { useLocale } from '../providers/LocaleProvider';
11+
import { useMemo } from 'preact/hooks';
1512

1613
/**
1714
* NavBar component that displays the headings, search, etc.
1815
*/
1916
export default ({ metadata }) => {
2017
const [themePreference, setThemePreference] = useTheme();
21-
const [navigationItems, setNavigationItems] = useState(navigation);
22-
const { locale } = useIntl();
18+
const { localizeLink } = useLocale();
2319

24-
useEffect(() => {
25-
const items = navigation.map(item => ({
26-
...item,
27-
link: localizeLink(item.link, locale),
28-
}));
29-
30-
setNavigationItems(items);
31-
}, [locale]);
20+
const navigationItems = useMemo(
21+
() => navigation.map(item => ({ ...item, link: localizeLink(item.link) })),
22+
[localizeLink]
23+
);
3224

3325
return (
3426
<NavBar
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { createContext } from 'preact';
2+
import { useContext, useState, useEffect } from 'preact/hooks';
3+
4+
import { defaultLocale } from '../../site.json' with { type: 'json' };
5+
6+
const LOCALE_COOKIE = 'NEXT_LOCALE';
7+
8+
/**
9+
* Replaces the default locale prefix in a link with the given locale.
10+
*
11+
* @param {string} link
12+
* @param {string} locale
13+
* @returns {string}
14+
*/
15+
const localizeLink = (link, locale) =>
16+
link.replace(new RegExp(`^/${defaultLocale}(?=/|$)`), `/${locale}`);
17+
18+
/**
19+
* Detects the locale from the NEXT_LOCALE cookie.
20+
* Falls back to the default locale when the cookie is missing.
21+
*
22+
* @returns {string}
23+
*/
24+
export const detectLocaleFromCookies = () => {
25+
if (typeof document === 'undefined') {
26+
return defaultLocale;
27+
}
28+
29+
const match = document.cookie
30+
.split(';')
31+
.map(cookie => cookie.trim())
32+
.find(cookie => cookie.startsWith(`${LOCALE_COOKIE}=`));
33+
34+
return match
35+
? decodeURIComponent(match.slice(LOCALE_COOKIE.length + 1))
36+
: defaultLocale;
37+
};
38+
39+
const LocaleContext = createContext({
40+
locale: defaultLocale,
41+
localizeLink: link => link,
42+
});
43+
44+
export const useLocale = () => useContext(LocaleContext);
45+
46+
/**
47+
* Provides locale and a pre-bound localizeLink fn to the component tree.
48+
*
49+
* @param {{ locale?: string, children: import('preact').ComponentChildren }} props
50+
*/
51+
export default function LocaleProvider({ locale, children }) {
52+
const [detectedLocale, setDetectedLocale] = useState(defaultLocale);
53+
54+
useEffect(() => {
55+
setDetectedLocale(locale ?? detectLocaleFromCookies());
56+
}, [locale]);
57+
58+
const value = {
59+
locale: detectedLocale,
60+
localizeLink: link => localizeLink(link, detectedLocale),
61+
};
62+
63+
return (
64+
<LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
65+
);
66+
}

package-lock.json

Lines changed: 1 addition & 59 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
"dependencies": {
2424
"@node-core/ui-components": "^1.6.3",
2525
"@vercel/analytics": "^2.0.1",
26-
"@vercel/speed-insights": "^2.0.0",
27-
"react-intl": "^10.1.2"
26+
"@vercel/speed-insights": "^2.0.0"
2827
},
2928
"engines": {
3029
"node": "24.x"

providers/LocaleProvider.jsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
1-
import { IntlProvider } from 'react-intl';
1+
import { createContext } from 'preact';
2+
import { useContext } from 'preact/hooks';
23

3-
import { defaultLocale } from '../site.json' with { type: 'json' };
4+
import { defaultLocale } from '../../site.json' with { type: 'json' };
45

56
const LOCALE_COOKIE = 'NEXT_LOCALE';
67

78
/**
8-
* Detects the locale from the cookie.
9+
* Replaces the default locale prefix in a link with the given locale.
10+
*
11+
* @param {string} link
12+
* @param {string} locale
13+
* @returns {string}
14+
*/
15+
const localizeLink = (link, locale) =>
16+
link.replace(new RegExp(`^/${defaultLocale}(?=/|$)`), `/${locale}`);
17+
18+
/**
19+
* Detects the locale from the NEXT_LOCALE cookie.
920
* Falls back to the default locale when the cookie is missing.
1021
*
1122
* @returns {string}
@@ -15,29 +26,37 @@ export const detectLocaleFromCookies = () => {
1526
return defaultLocale;
1627
}
1728

18-
const localeCookie = document.cookie
29+
const match = document.cookie
1930
.split(';')
2031
.map(cookie => cookie.trim())
2132
.find(cookie => cookie.startsWith(`${LOCALE_COOKIE}=`));
2233

23-
if (!localeCookie) {
24-
return defaultLocale;
25-
}
26-
27-
return decodeURIComponent(localeCookie.slice(LOCALE_COOKIE.length + 1));
34+
return match
35+
? decodeURIComponent(match.slice(LOCALE_COOKIE.length + 1))
36+
: defaultLocale;
2837
};
2938

39+
const LocaleContext = createContext({
40+
locale: defaultLocale,
41+
localizeLink: link => link,
42+
});
43+
44+
export const useLocale = () => useContext(LocaleContext);
45+
3046
/**
31-
* LocaleProvider component that provides the locale context to its children.
47+
* Provides locale and a pre-bound localizeLink fn to the component tree.
3248
*
3349
* @param {{ locale?: string, children: import('preact').ComponentChildren }} props
3450
*/
3551
export default function LocaleProvider({ locale, children }) {
3652
const detectedLocale = locale ?? detectLocaleFromCookies();
3753

54+
const value = {
55+
locale: detectedLocale,
56+
localizeLink: link => localizeLink(link, detectedLocale),
57+
};
58+
3859
return (
39-
<IntlProvider locale={detectedLocale} messages={{}}>
40-
{children}
41-
</IntlProvider>
60+
<LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
4261
);
4362
}

util/link.js

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)