Skip to content

Commit

Permalink
code: kept working on adoption of i18n
Browse files Browse the repository at this point in the history
  • Loading branch information
ovflowd committed Nov 3, 2023
1 parent 8eee549 commit 4c94c55
Show file tree
Hide file tree
Showing 75 changed files with 3,489 additions and 2,510 deletions.
18 changes: 7 additions & 11 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import NextImage from 'next/image';
import classNames from 'classnames';
import { withThemeByDataAttribute } from '@storybook/addon-themes';
import { SiteProvider } from '../providers/siteProvider';
import { NextIntlClientProvider } from 'next-intl';
import { NotificationProvider } from '../providers/notificationProvider';
import * as constants from './constants';
Expand Down Expand Up @@ -29,15 +27,13 @@ const preview: Preview = {
// and all the App's Providers (Site, Theme, Locale)
decorators: [
Story => (
<SiteProvider>
<NextIntlClientProvider locale="en">
<NotificationProvider viewportClassName="absolute top-0 left-0 list-none">
<div className={rootClasses}>
<Story />
</div>
</NotificationProvider>
</NextIntlClientProvider>
</SiteProvider>
<NextIntlClientProvider locale="en">
<NotificationProvider viewportClassName="absolute top-0 left-0 list-none">
<div className={rootClasses}>
<Story />
</div>
</NotificationProvider>
</NextIntlClientProvider>
),
withThemeByDataAttribute<ReactRenderer>({
themes: {
Expand Down
77 changes: 77 additions & 0 deletions app/[locale]/[...path]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { notFound } from 'next/navigation';
import type { FC } from 'react';

import getDynamicRouter from '@/next.dynamic.mjs';
import {
availableLocaleCodes,
availableLocales,
defaultLocale,
} from '@/next.locales.mjs';
import Theme from '@/theme';

type DynamicStaticPaths = { path: string[]; locale: string };

const dynamicRouter = await getDynamicRouter();

// This method is used to retrieve all native statically supported pages (SCR) that
// we want to provide during build-time + allow fallback for dynamic pages during (ISR)
export const generateStaticParams = async () => {
const paths: DynamicStaticPaths[] = [];

for (const locale of availableLocales) {
const routesForLanguage = await dynamicRouter.getRoutesByLanguage(
locale.code
);

const mappedRoutesWithLocale = routesForLanguage.map(pathname =>
dynamicRouter.mapPathToRoute(locale.code, pathname)
);

paths.push(...mappedRoutesWithLocale);
}

return paths.sort();
};

const DynamicPage: FC<{ params: DynamicStaticPaths }> = async ({ params }) => {
const { path = [], locale = defaultLocale.code } = params;

console.log(locale);

if (!availableLocaleCodes.includes(locale)) {
return notFound();
}

const pathname = dynamicRouter.getPathname(path);

if (dynamicRouter.shouldIgnoreRoute(pathname)) {
return notFound();
}

// Retrieves and rewriting rule if the pathname matches any rule
const [, rewriteRule] = dynamicRouter.getRouteRewrite(pathname);

// We retrieve the source of the Markdown file by doing an educated guess
// of what possible files could be the source of the page, since the extension
// context is lost from `getStaticProps` as a limitation of Next.js itself
const { source, filename } = dynamicRouter.getMarkdownFile(
locale,
rewriteRule ? rewriteRule(pathname) : pathname
);

if (source.length && filename.length) {
// This parses the actual Markdown content and returns a full set of props
// to be passed to the base page (`DynamicPage`) which will render the Markdown
const mdxProps = await dynamicRouter.getMDXProps(source, filename);

// This retrieves the locale-specific props for the page, which are used
// to render translations and locale data
const localeProps = await dynamicRouter.getLocaleProps(locale);

return <Theme {...mdxProps} {...localeProps} />;
}

return notFound();
};

export default DynamicPage;
36 changes: 36 additions & 0 deletions app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Analytics } from '@vercel/analytics/react';
import { Source_Sans_3 } from 'next/font/google';
import { NextIntlClientProvider, useMessages } from 'next-intl';
import type { FC, PropsWithChildren } from 'react';

import { VERCEL_ENV } from '@/next.constants.mjs';

import '@/styles/old/index.css';

const sourceSans = Source_Sans_3({
weight: ['400', '600'],
display: 'fallback',
subsets: ['latin'],
});

type LocaleLayout = PropsWithChildren<{ params: { locale: string } }>;

const LocaleLayout: FC<LocaleLayout> = ({ children, params: { locale } }) => {
const messages = useMessages();

return (
<html lang={locale} className={sourceSans.className}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>

{VERCEL_ENV && <Analytics />}

<a rel="me" href="https://social.lfx.dev/@nodejs" />
</body>
</html>
);
};

export default LocaleLayout;
30 changes: 14 additions & 16 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
import type { MetadataRoute } from 'next';

import {
STATIC_ROUTES_IGNORES,
DYNAMIC_GENERATED_ROUTES,
BASE_PATH,
BASE_URL,
EXTERNAL_LINKS_SITEMAP,
} from '@/next.constants.mjs';
import { allPaths } from '@/next.dynamic.mjs';
import { defaultLocale } from '@/next.locales.mjs';
import getDynamicRouter from '@/next.dynamic.mjs';
import { availableLocales } from '@/next.locales.mjs';

// This is the combination of the Application Base URL and Base PATH
const baseUrlAndPath = `${BASE_URL}${BASE_PATH}`;

const dynamicRouter = await getDynamicRouter();

// This allows us to generate a `sitemap.xml` file dynamically based on the needs of the Node.js Website
// Next.js Sitemap Generation doesn't support `alternate` refs yet
// @see https://github.com/vercel/next.js/discussions/55646
const sitemap = (): MetadataRoute.Sitemap => {
// Retrieves all the dynamic generated paths
const dynamicRoutes = DYNAMIC_GENERATED_ROUTES();
const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
const paths: string[] = [];

for (const locale of availableLocales) {
const routesForLanguage = await dynamicRouter.getRoutesByLanguage(
locale.code
);

// Retrieves all the static paths for the default locale (English)
// and filter out the routes that should be ignored
const staticPaths = [...allPaths.get(defaultLocale.code)!]
.filter(route => STATIC_ROUTES_IGNORES.every(e => !e(route)))
.map(route => route.routeWithLocale);
paths.push(...routesForLanguage);
}

// The current date of this request
const currentDate = new Date().toISOString();

const appRoutes = [...dynamicRoutes, ...staticPaths]
.sort()
.map(route => `${baseUrlAndPath}/${route}`);
const appRoutes = paths.sort().map(route => `${baseUrlAndPath}/${route}`);

return [...appRoutes, ...EXTERNAL_LINKS_SITEMAP].map(route => ({
url: route,
Expand Down
40 changes: 18 additions & 22 deletions components/Common/ActiveLocalizedLink/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
'use client';

import classNames from 'classnames';
import type Link from 'next/link';
import { useRouter } from 'next/router';
import { useState, useEffect } from 'react';
import type { ComponentProps, FC } from 'react';

import LocalizedLink from '@/components/LocalizedLink';
import { Link, usePathname } from '@/navigation';

type ActiveLocalizedLinkProps = ComponentProps<typeof Link> & {
activeClassName: string;
Expand All @@ -16,33 +16,29 @@ const ActiveLocalizedLink: FC<ActiveLocalizedLinkProps> = ({
className,
...props
}) => {
const { asPath, isReady } = useRouter();
const pathname = usePathname();

const [computedClassName, setComputedClassName] = useState(className);

useEffect(() => {
// Check if the router fields are updated client-side
if (isReady) {
const currentHref = (props.as || props.href).toString();
const currentHref = (props.as || props.href).toString();

// Dynamic route will be matched via props.as
// Static route will be matched via props.href
const linkURL = new URL(currentHref, location.href);
// Dynamic route will be matched via props.as
// Static route will be matched via props.href
const linkURL = new URL(currentHref, location.href);

// Using URL().pathname to get rid of query and hash
const currentPathName = new URL(asPath, location.href).pathname;
// Using URL().pathname to get rid of query and hash
const currentPathName = new URL(pathname, location.href).pathname;

const newClassName = classNames(className, {
[activeClassName]: linkURL.pathname === currentPathName,
});
const newClassName = classNames(className, {
[activeClassName]: linkURL.pathname === currentPathName,
});

if (newClassName !== computedClassName) {
setComputedClassName(newClassName);
}
if (newClassName !== computedClassName) {
setComputedClassName(newClassName);
}
}, [
asPath,
isReady,
pathname,
props.as,
props.href,
activeClassName,
Expand All @@ -51,9 +47,9 @@ const ActiveLocalizedLink: FC<ActiveLocalizedLinkProps> = ({
]);

return (
<LocalizedLink className={computedClassName} {...props}>
<Link className={computedClassName} {...props}>
{children}
</LocalizedLink>
</Link>
);
};

Expand Down
7 changes: 3 additions & 4 deletions components/Common/Badge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import ArrowRightIcon from '@heroicons/react/24/solid/ArrowRightIcon';
import type Link from 'next/link';
import type { ComponentProps, FC, PropsWithChildren } from 'react';

import LocalizedLink from '@/components/LocalizedLink';
import { Link } from '@/navigation';

import styles from './index.module.css';

Expand All @@ -17,11 +16,11 @@ const Badge: FC<PropsWithChildren<BadgeProps>> = ({
children,
...args
}) => (
<LocalizedLink className={`${styles.wrapper} ${styles[kind]}`} {...args}>
<Link className={`${styles.wrapper} ${styles[kind]}`} {...args}>
{badgeText && <span className={styles.badge}>{badgeText}</span>}
<span className={styles.message}>{children}</span>
<ArrowRightIcon className={styles.icon} />
</LocalizedLink>
</Link>
);

export default Badge;
5 changes: 2 additions & 3 deletions components/Common/Banner/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ArrowUpRightIcon } from '@heroicons/react/24/outline';
import type { FC } from 'react';

import LocalizedLink from '@/components/LocalizedLink';
import { Link } from '@/navigation';

import styles from './index.module.css';

Expand All @@ -13,8 +13,7 @@ type BannerProps = {

const Banner: FC<BannerProps> = ({ type, text, url = '' }) => (
<div className={`${styles.banner} ${styles[type] || styles.default}`}>
{(url.length > 0 && <LocalizedLink href={url}>{text}</LocalizedLink>) ||
text}
{(url.length > 0 && <Link href={url}>{text}</Link>) || text}
{url.length > 0 && <ArrowUpRightIcon />}
</div>
);
Expand Down
8 changes: 4 additions & 4 deletions components/Common/Breadcrumbs/BreadcrumbLink/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import classNames from 'classnames';
import type { ComponentProps, FC } from 'react';

import LocalizedLink from '@/components/LocalizedLink';
import { Link } from '@/navigation';

import styles from './index.module.css';

type BreadcrumbLinkProps = {
active?: boolean;
} & ComponentProps<typeof LocalizedLink>;
} & ComponentProps<typeof Link>;

const BreadcrumbLink: FC<BreadcrumbLinkProps> = ({
href,
active,
...props
}) => (
<LocalizedLink
<Link
itemScope
itemType="http://schema.org/Thing"
itemProp="item"
Expand All @@ -29,7 +29,7 @@ const BreadcrumbLink: FC<BreadcrumbLinkProps> = ({
{...props}
>
<span itemProp="name">{props.children}</span>
</LocalizedLink>
</Link>
);

export default BreadcrumbLink;
6 changes: 3 additions & 3 deletions components/Common/CrossLink/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useTranslations } from 'next-intl';
import type { FC } from 'react';

import PrevNextArrow from '@/components/Common/PrevNextArrow';
import LocalizedLink from '@/components/LocalizedLink';
import { Link } from '@/navigation';

import styles from './index.module.css';

Expand All @@ -17,7 +17,7 @@ const CrossLink: FC<CrossLinkProps> = ({ type, text, url }) => {
const t = useTranslations();

return (
<LocalizedLink className={styles.crossLink} href={url}>
<Link className={styles.crossLink} href={url}>
<span
className={classNames(styles.header, {
[styles.reverse]: type === 'next',
Expand All @@ -34,7 +34,7 @@ const CrossLink: FC<CrossLinkProps> = ({ type, text, url }) => {
>
{text}
</span>
</LocalizedLink>
</Link>
);
};

Expand Down
6 changes: 3 additions & 3 deletions components/Common/MetaBar/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Image from 'next/image';

import AvatarGroup from '@/components/Common/AvatarGroup';
import MetaBar from '@/components/Common/MetaBar';
import LocalizedLink from '@/components/LocalizedLink';
import { Link } from '@/navigation';

type Story = StoryObj<typeof MetaBar>;
type Meta = MetaObj<typeof MetaBar>;
Expand Down Expand Up @@ -52,13 +52,13 @@ export const Default: Story = {
height={16}
data-on-dark
/>
<LocalizedLink href="/contribute">Edit this page</LocalizedLink>
<Link href="/contribute">Edit this page</Link>
</>
),
'components.metabar.viewAs': (
<>
<CodeBracketIcon />
<LocalizedLink href="/json">JSON</LocalizedLink>
<Link href="/json">JSON</Link>
</>
),
},
Expand Down
Loading

0 comments on commit 4c94c55

Please sign in to comment.