-
Notifications
You must be signed in to change notification settings - Fork 32
feat: Preserve locale with cookie & react-intl #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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' }; | ||
|
canerakdas marked this conversation as resolved.
|
||
|
|
||
| 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(() => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to use an useEffect here? Can't this be an useMemo? |
||
| 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 | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| 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)); | ||
|
canerakdas marked this conversation as resolved.
|
||
| }; | ||
|
|
||
| /** | ||
| * 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> | ||
| ); | ||
| } | ||
| 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) => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe react-intl has utils for localizing a link.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's one of the intentions behind using react-intl, is to have it localizing a link for you. Although I'm not seeing now within react-intl a way of doing so. 🤔
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think such a feature exists 🙈 It seems like we're currently only using a provider that stores the locale. To be honest, I'm not sure there’s much benefit to using it this way 🥲
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I chatted with @canerakdas in DMs he's going to pivot without react-intl. |
||
| if ( | ||
| typeof document === 'undefined' || | ||
| !link.startsWith('/') || | ||
| !link.startsWith(`/${defaultLocale}`) | ||
| ) { | ||
| return link; | ||
|
canerakdas marked this conversation as resolved.
|
||
| } | ||
|
|
||
| const localizedPrefix = locale ? `/${locale}` : ''; | ||
| const localizedLink = link.replace( | ||
| `/${defaultLocale}/`, | ||
| `${localizedPrefix}/` | ||
| ); | ||
|
|
||
|
canerakdas marked this conversation as resolved.
|
||
| return localizedLink; | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: providers folder inside components folder.