Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions components/Layout/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import NavBar from '../Navigation';
import MetaBar from '../Metabar';
import SideBar from '../Sidebar';
import Footer from '../Footer';
import LocaleProvider from '../../providers/LocaleProvider';
Comment thread
canerakdas marked this conversation as resolved.
Outdated

/**
* @typedef {Object} Props
Expand All @@ -20,7 +21,7 @@ import Footer from '../Footer';
* @param {Props} props
*/
export default ({ metadata, headings, readingTime, children }) => (
<>
<LocaleProvider>
<Analytics basePath="/learn/_vercel" />
<SpeedInsights basePath="/learn/_vercel" />
<NavBar metadata={metadata} />
Expand All @@ -40,5 +41,5 @@ export default ({ metadata, headings, readingTime, children }) => (
</div>
</Article>
<Footer metadata={metadata} />
</>
</LocaleProvider>
);
20 changes: 18 additions & 2 deletions components/Navigation/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,39 @@ import ThemeToggle from '@node-core/ui-components/Common/ThemeToggle';
import NavBar from '@node-core/ui-components/Containers/NavBar';
import styles from '@node-core/ui-components/Containers/NavBar/index.module.css';
import GitHubIcon from '@node-core/ui-components/Icons/Social/GitHub';

import SearchBox from '@node-core/doc-kit/src/generators/web/ui/components/SearchBox';
import { useTheme } from '@node-core/doc-kit/src/generators/web/ui/hooks/useTheme.mjs';

import { useEffect, useState } from 'preact/hooks';
import { useIntl } from 'react-intl';

import { localizeLink } from '../../util/link';
import { navigation } from '../../site.json' with { type: 'json' };

import Logo from '#theme/Logo';

/**
* NavBar component that displays the headings, search, etc.
*/
export default ({ metadata }) => {
const [themePreference, setThemePreference] = useTheme();
const [navigationItems, setNavigationItems] = useState(navigation);
const { locale } = useIntl();

useEffect(() => {
Comment thread
canerakdas marked this conversation as resolved.
Outdated
const items = navigation.map(item => ({
...item,
link: localizeLink(item.link, locale),
}));

setNavigationItems(items);
}, [locale]);

return (
<NavBar
Logo={Logo}
sidebarItemTogglerAriaLabel="Toggle navigation menu"
navItems={navigation}
navItems={navigationItems}
>
<SearchBox pathname={metadata.path} />
<ThemeToggle
Expand Down
60 changes: 59 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"dependencies": {
"@node-core/ui-components": "^1.6.3",
"@vercel/analytics": "^2.0.1",
"@vercel/speed-insights": "^2.0.0"
"@vercel/speed-insights": "^2.0.0",
"react-intl": "^10.1.2"
},
"engines": {
"node": "24.x"
Expand Down
43 changes: 43 additions & 0 deletions providers/LocaleProvider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { IntlProvider } from 'react-intl';

import { defaultLocale } from '../site.json' with { type: 'json' };

const LOCALE_COOKIE = 'NEXT_LOCALE';

/**
* Detects the locale from the cookie.
* Falls back to the default locale when the cookie is missing.
*
* @returns {string}
*/
export const detectLocaleFromCookies = () => {
if (typeof document === 'undefined') {
return defaultLocale;
}

const localeCookie = document.cookie
.split(';')
.map(cookie => cookie.trim())
.find(cookie => cookie.startsWith(`${LOCALE_COOKIE}=`));

if (!localeCookie) {
return defaultLocale;
}

return decodeURIComponent(localeCookie.slice(LOCALE_COOKIE.length + 1));
Comment thread
canerakdas marked this conversation as resolved.
Outdated
};

/**
* LocaleProvider component that provides the locale context to its children.
*
* @param {{ locale?: string, children: import('preact').ComponentChildren }} props
*/
export default function LocaleProvider({ locale, children }) {
const detectedLocale = locale ?? detectLocaleFromCookies();

return (
<IntlProvider locale={detectedLocale} messages={{}}>
{children}
</IntlProvider>
);
}
5 changes: 3 additions & 2 deletions site.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
{
"defaultLocale": "en",
"navigation": [
{
"link": "/learn",
"text": "Learn"
},
{
"link": "/about",
"link": "/en/about",
"text": "About"
},
{
"link": "/en/download",
"text": "Download"
},
{
"link": "/blog",
"link": "/en/blog",
"text": "Blog"
},
{
Expand Down
26 changes: 26 additions & 0 deletions util/link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { defaultLocale } from '../site.json' with { type: 'json' };

/**
* Replaces the default locale in a link with the provided locale.
*
* @param {string} link - The link to be localized.
* @param {string|null} locale - The locale to apply to the link.
* @returns {string} - The localized link.
*/
export const localizeLink = (link, locale) => {
Comment thread
canerakdas marked this conversation as resolved.
Outdated
if (
typeof document === 'undefined' ||
!link.startsWith('/') ||
!link.startsWith(`/${defaultLocale}`)
) {
return link;
Comment thread
canerakdas marked this conversation as resolved.
Outdated
}

const localizedPrefix = locale ? `/${locale}` : '';
const localizedLink = link.replace(
`/${defaultLocale}/`,
`${localizedPrefix}/`
);

Comment thread
canerakdas marked this conversation as resolved.
Outdated
return localizedLink;
};