Skip to content

Commit

Permalink
add i18n
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMelior committed Jul 12, 2024
1 parent 13c4a03 commit 887417f
Show file tree
Hide file tree
Showing 29 changed files with 420 additions and 293 deletions.
27 changes: 19 additions & 8 deletions app/layout.tsx → app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ClientProviders } from '@/app/providers/client-providers';
import '@/app/styles/index.scss';
import { getDictionary, i18n, Locale } from '@/shared/config';
import { PageLoader } from '@/shared/ui';
import { Footer, Light, Navbar, Sidebar } from '@/widgets';
import type { Metadata } from 'next';
Expand All @@ -13,13 +14,23 @@ export const metadata: Metadata = {
description: `Small and modern pet-projects. Hi, I'am Mark Melior - Frontend developer.`,
};

export default function RootLayout({
children,
}: Readonly<{
export async function generateStaticParams() {
return i18n.locales.map((locale) => ({ lang: locale }));
}

type Props = {
children: React.ReactNode;
}>) {
params: { lang: Locale };
};

export default async function RootLayout({
children,
params,
}: Readonly<Props>) {
const dict = await getDictionary(params.lang);

return (
<html lang='en'>
<html lang={params.lang}>
<body className={inter.className}>
<ClientProviders>
<Suspense
Expand All @@ -31,14 +42,14 @@ export default function RootLayout({
}
>
<Light />
<Navbar />
<Navbar dict={dict.ui} />
<div className='overflow-hidden'>
<div className='max-w-8xl mx-auto px-4 sm:px-6 md:px-8 relative z-20'>
<Sidebar />
<Sidebar dict={dict.ui} />
<div className='lg:pl-[19.5rem]'>
<div className='max-w-3xl mx-auto pt-10 xl:max-w-none xl:ml-0'>
{children}
<Footer />
<Footer dict={dict.ui} />
</div>
</div>
</div>
Expand Down
11 changes: 11 additions & 0 deletions app/[lang]/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default async function NotFound() {
// {
// params: { lang },
// }: {
// params: { lang: Locale };
// }
// const dictionary = await getDictionary(lang);

return <>Not fount page.</>;
// return <>{dictionary['ui']['page-not-found']}</>;
}
18 changes: 18 additions & 0 deletions app/[lang]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Locale } from '@/shared/config';
import { Header } from '@/widgets';
import { getDictionary } from '../../src/shared/config/i18n/dictionaries';

export default async function Home({
params: { lang },
}: {
params: { lang: Locale };
}) {
const dictionary = await getDictionary(lang);
const { description, note, title } = dictionary['home-page'];

return (
<>
<Header note={note} title={title} description={description} />
</>
);
}
File renamed without changes.
File renamed without changes.
3 changes: 0 additions & 3 deletions app/not-found.tsx

This file was deleted.

15 changes: 0 additions & 15 deletions app/page.tsx

This file was deleted.

69 changes: 69 additions & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { i18n, Locale } from '@/shared/config';
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;

// `/_next/` and `/api/` are ignored by the watcher, but we need to ignore files in `public` manually
if (
[
'/images/light.avif',
'/images/noise.png',
'/images/light-dark.avif',
'/favicon.ico',
].includes(pathname)
) {
return;
}

if (
pathname.startsWith(`/${i18n.defaultLocale}/`) ||
pathname === `/${i18n.defaultLocale}`
) {
// The incoming request is for /en/whatever, so we'll reDIRECT to /whatever
return NextResponse.redirect(
new URL(
pathname.replace(
`/${i18n.defaultLocale}`,
pathname === `/${i18n.defaultLocale}` ? '/' : '',
),
request.url,
),
);
}

const pathnameIsMissingLocale = i18n.locales.every(
(locale) =>
!pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`,
);

if (pathnameIsMissingLocale) {
// Now for EITHER /en or /nl (for example) we're going to tell Next.js that the request is for /en/whatever
// or /nl/whatever, and then reWRITE the request to that it is handled properly.
return NextResponse.rewrite(
new URL(
`/${i18n.defaultLocale}${pathname}${request.nextUrl.search}`,
request.nextUrl.href,
),
);
}

const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-url', request.url);

const segments = request.url.split('/')[3];
const lang = i18n.locales.includes(segments as Locale)
? segments
: i18n.defaultLocale;
requestHeaders.set('x-lang', lang);

return NextResponse.next({
request: {
headers: requestHeaders,
},
});
}

export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
3 changes: 3 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import remarkGfm from 'remark-gfm';
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
experimental: {
mdxRs: true,
},
};

const withMDX = createMDX({
Expand Down
Loading

0 comments on commit 887417f

Please sign in to comment.