Language Detection Middleware
Automatic language detection and URL routing based on user preferences
Middleware automatically detects users’ language preferences and redirects them to the appropriate localised version of your site. It uses browser settings, geolocation, and user preferences to serve the right language before any content loads.
File location: Place middleware.ts in your project root, at the same level as your app/ directory — not inside it.
Set-up
Step 1: Create a Dynamic Route
Create a [locale] directory in your app/ folder and move all pages into it:
Step 2: Add middleware
Create middleware.ts in your project root:
import { createNextMiddleware } from 'gt-next/middleware';
export default createNextMiddleware();
export const config = {
// Match all paths except API routes, static files, and Next.js internals
matcher: ['/((?!api|static|.*\\..*|_next).*)']
};This enables automatic language detection and URL routing with locale prefixes such as /en/about, /es/about.
Language detection
The middleware detects users’ language preferences in this order:
- URL locale —
/es/about→ Spanish - User cookie — previous language selection
- Browser headers —
Accept-Languageheader - Default locale — configured fallback language
The middleware automatically handles browser language detection and cookie persistence without additional configuration.
Localised Paths
Customise URL paths for different languages:
export default createNextMiddleware({
pathConfig: {
// English: /en/products, Chinese: /zh/产品
"/products": {
"zh": "/产品"
},
// Dynamic routes: /en/product/123, /zh/产品/123
"/product/[id]": {
"zh": "/产品/[id]"
}
}
});URL structure
By default, your default locale will not be prefixed with a locale code:
/about → /about (default locale: English)
/about → /es/about (Spanish)
/about → /fr/about (French)Add a prefix to the default locale
To prefix all locales, including the default:
export default createNextMiddleware({
prefixDefaultLocale: true
});Result:
/about → /en/about (English, with prefix)
/about → /es/about (Spanish, with prefix)
/about → /fr/about (French, with prefix)Common issues
Missing Dynamic Route
All pages must be within [locale]/:
❌ Incorrect:
app/
├── page.tsx
└── about/page.tsx
✅ Correct:
app/
└── [locale]/
├── page.tsx
└── about/page.tsxMatcher Configuration
Exclude API routes and static files:
export const config = {
matcher: ['/((?!api|static|.*\\..*|_next).*)']
};Test your middleware configuration thoroughly — incorrect matchers can cause infinite redirects or break static assets.
Next steps
- SSG Guide - Static generation with locale routing
- RTL Support - Right-to-left languages
- API references:
How is this guide?