Setting Up Internationalization
This guide walks you through the process of setting up internationalization in your Next.js application using the @repo/internationalization
package.
Prerequisites
Before you begin, make sure you have:
- A Next.js application using the App Router
- Access to the
@repo/internationalization
package
Installation
Add the internationalization package to your application’s dependencies:
// package.json
{
"dependencies": {
"@repo/internationalization": "workspace:*"
}
}
Then run:
Configuration Steps
1. Set Up Middleware
Create or update your middleware.ts
file to include the internationalization middleware:
// middleware.ts
import { internationalizationMiddleware } from '@repo/internationalization/middleware';
import { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
return internationalizationMiddleware(request);
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
The matcher pattern excludes static assets and API routes from the internationalization middleware.
2. Create Locale-Based Routes
Structure your application routes to include the locale parameter:
app/
├── [locale]/
│ ├── page.tsx
│ ├── about/
│ │ └── page.tsx
│ ├── contact/
│ │ └── page.tsx
│ └── layout.tsx
└── ...
3. Create a Root Layout
In your app/[locale]/layout.tsx
file, set up the root layout with internationalization support:
// app/[locale]/layout.tsx
import { getDictionary } from '@repo/internationalization';
import type { ReactNode } from 'react';
type RootLayoutProperties = {
readonly children: ReactNode;
readonly params: {
locale: string;
};
};
const RootLayout = async ({ children, params }: RootLayoutProperties) => {
const { locale } = params;
const dictionary = await getDictionary(locale);
return (
<html lang={locale}>
<body>
<header>
{/* Use dictionary entries for navigation */}
<nav>
<a href={`/${locale}`}>{dictionary.web.header.home}</a>
<a href={`/${locale}/about`}>{dictionary.web.header.about}</a>
<a href={`/${locale}/contact`}>{dictionary.web.header.contact}</a>
</nav>
</header>
<main>{children}</main>
<footer>
{/* Footer content */}
</footer>
</body>
</html>
);
};
export default RootLayout;
4. Set Up Pages with Translations
Create your pages with internationalization support:
// app/[locale]/page.tsx
import { getDictionary } from '@repo/internationalization';
export default async function HomePage({ params }: { params: { locale: string } }) {
const dictionary = await getDictionary(params.locale);
return (
<div>
<h1>{dictionary.web.home.meta.title}</h1>
<p>{dictionary.web.home.meta.description}</p>
{/* More content using dictionary entries */}
</div>
);
}
5. Set Up Client Components (Optional)
If you need translations in client components, create a wrapper for the client component:
// app/[locale]/contact/page.tsx
import { getDictionary } from '@repo/internationalization';
import { TranslationProvider } from '@repo/internationalization/TranslationProvider';
import ContactForm from '@/components/ContactForm'; // Client component
export default async function ContactPage({ params }: { params: { locale: string } }) {
const dictionary = await getDictionary(params.locale);
return (
<div>
<h1>{dictionary.web.contact.title}</h1>
<TranslationProvider locale={params.locale} messages={dictionary}>
<ContactForm />
</TranslationProvider>
</div>
);
}
Then in your client component:
// components/ContactForm.tsx
'use client';
import { useTranslation } from '@repo/internationalization/useTranslation';
export default function ContactForm() {
const { t } = useTranslation('web.contact.form');
return (
<form>
<label>{t('name')}</label>
<input type="text" />
<label>{t('email')}</label>
<input type="email" />
<button type="submit">{t('submit')}</button>
</form>
);
}
Verification
To verify that internationalization is working correctly:
-
Start your development server:
-
Visit your application with different locale paths:
http://localhost:3000/en
for English
http://localhost:3000/tr
for Turkish
http://localhost:3000/es
for Spanish
http://localhost:3000/de
for German
-
Check that the content is displayed in the correct language based on the URL path.
Troubleshooting
Missing Translations
If you see untranslated content or errors related to missing translations:
- Check that the locale in the URL matches one of the supported locales.
- Verify that the translation key exists in the dictionary file for the current locale.
- Check the browser console for any error messages related to translations.
Middleware Not Working
If the internationalization middleware is not working:
- Make sure the matcher pattern in your middleware configuration is correct.
- Check that the middleware is being applied to the correct routes.
- Verify that the middleware is being exported correctly from your
middleware.ts
file.
Next Steps