Skip to content

Commit

Permalink
feat: add i18n with next-intl
Browse files Browse the repository at this point in the history
  • Loading branch information
ixartz committed Dec 1, 2023
1 parent 48c12c4 commit 1f43eb2
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 19 deletions.
5 changes: 5 additions & 0 deletions messages/en.json
@@ -0,0 +1,5 @@
{
"Index": {
"title": "Hello world!"
}
}
5 changes: 5 additions & 0 deletions messages/fr.json
@@ -0,0 +1,5 @@
{
"Index": {
"title": "Bonjour monde!"
}
}
39 changes: 22 additions & 17 deletions next.config.mjs
@@ -1,27 +1,32 @@
/* eslint-disable import/no-extraneous-dependencies, import/extensions */
import './src/libs/Env.mjs';
import withBundleAnalyzer from '@next/bundle-analyzer';
import withNextIntl from 'next-intl/plugin';

const withNextIntlConfig = withNextIntl();

const bundleAnalyzer = withBundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
});

/** @type {import('next').NextConfig} */
export default bundleAnalyzer({
eslint: {
dirs: ['.'],
},
poweredByHeader: false,
reactStrictMode: true,
webpack: (config) => {
// config.externals is needed to resolve the following errors:
// Module not found: Can't resolve 'bufferutil'
// Module not found: Can't resolve 'utf-8-validate'
config.externals.push({
bufferutil: 'bufferutil',
'utf-8-validate': 'utf-8-validate',
});
export default bundleAnalyzer(
withNextIntlConfig({
eslint: {
dirs: ['.'],
},
poweredByHeader: false,
reactStrictMode: true,
webpack: (config) => {
// config.externals is needed to resolve the following errors:
// Module not found: Can't resolve 'bufferutil'
// Module not found: Can't resolve 'utf-8-validate'
config.externals.push({
bufferutil: 'bufferutil',
'utf-8-validate': 'utf-8-validate',
});

return config;
},
});
return config;
},
}),
);
142 changes: 141 additions & 1 deletion package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -32,6 +32,7 @@
"checkly": "^4.4.0",
"drizzle-orm": "^0.29.1",
"next": "^14.0.3",
"next-intl": "^3.2.1",
"next-seo": "^6.4.0",
"next-sitemap": "^4.2.3",
"react": "^18.2.0",
Expand Down
10 changes: 9 additions & 1 deletion src/app/layout.tsx → src/app/[locale]/layout.tsx
@@ -1,6 +1,9 @@
import '@/styles/global.css';

import type { Metadata } from 'next';
import { notFound } from 'next/navigation';

import { AppConfig } from '@/utils/AppConfig';

export const metadata: Metadata = {
icons: [
Expand Down Expand Up @@ -31,11 +34,16 @@ export default function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children,
params: { locale },
}: {
children: React.ReactNode;
params: { locale: string };
}) {
// Validate that the incoming `locale` parameter is valid
if (!AppConfig.locales.includes(locale)) notFound();

return (
<html lang="en">
<html lang={locale}>
<body>{children}</body>
</html>
);
Expand Down
6 changes: 6 additions & 0 deletions src/app/[locale]/page.tsx
@@ -0,0 +1,6 @@
import { useTranslations } from 'next-intl';

export default function Index() {
const t = useTranslations('Index');
return <h1>{t('title')}</h1>;
}
6 changes: 6 additions & 0 deletions src/app/[locale]/translation/page.tsx
@@ -0,0 +1,6 @@
import { useTranslations } from 'next-intl';

export default function Index() {
const t = useTranslations('Index');
return <h1>{t('title')}</h1>;
}
5 changes: 5 additions & 0 deletions src/i18n.ts
@@ -0,0 +1,5 @@
import { getRequestConfig } from 'next-intl/server';

export default getRequestConfig(async ({ locale }) => ({
messages: (await import(`../messages/${locale}.json`)).default,
}));
14 changes: 14 additions & 0 deletions src/middleware.ts
@@ -1,5 +1,14 @@
import { authMiddleware, redirectToSignIn } from '@clerk/nextjs';
import type { NextRequest } from 'next/server';
import createMiddleware from 'next-intl/middleware';

import { AppConfig } from './utils/AppConfig';

const intlMiddleware = createMiddleware({
locales: AppConfig.locales,
localePrefix: 'as-needed',
defaultLocale: AppConfig.defaultLocale,
});

export default authMiddleware({
publicRoutes: (req: NextRequest) =>
Expand All @@ -8,6 +17,11 @@ export default authMiddleware({
// By default, the middleware will return a 401 response for all routes `/api/*` when the user is signed out.
// But, for `/api/guestbook`, we want unauthenticated users to be able to access it.

beforeAuth: (req) => {
// Execute next-intl middleware before Clerk's auth middleware
return intlMiddleware(req);
},

// eslint-disable-next-line consistent-return
afterAuth(auth, req) {
// Handle users who aren't authenticated
Expand Down
3 changes: 3 additions & 0 deletions src/utils/AppConfig.ts
Expand Up @@ -4,4 +4,7 @@ export const AppConfig = {
title: 'Nextjs Starter',
description: 'Starter code for your Nextjs Boilerplate with Tailwind CSS',
locale: 'en',

locales: ['en', 'fr'],
defaultLocale: 'en',
};

0 comments on commit 1f43eb2

Please sign in to comment.