Files
biblical-guide.com/middleware.ts
Andrei 4346112766 feat: add Italian language support
Added complete Italian (it) translation for the Biblical Guide application:
- Created messages/it.json with full Italian translations
- Updated i18n.ts to include Italian locale
- Updated middleware.ts to handle Italian routes
- Added Italian to language options in all locale files (en, ro, es)

Users can now access the app in Italian at /it/* routes and select Italian from the language settings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-10 18:06:33 +00:00

89 lines
3.0 KiB
TypeScript

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import createIntlMiddleware from 'next-intl/middleware'
import { locales } from './i18n'
// Internationalization configuration
const intlMiddleware = createIntlMiddleware({
locales: [...locales],
defaultLocale: 'en',
localePrefix: 'always'
})
// Note: Avoid using Prisma or any Node-only APIs in Middleware.
// Middleware runs on the Edge runtime, where Prisma is not supported.
// If rate limiting is needed, implement it inside API route handlers
// (Node.js runtime) or via an external service (e.g., Upstash Redis).
export async function middleware(request: NextRequest) {
// Skip admin routes from internationalization
if (request.nextUrl.pathname.startsWith('/admin')) {
return NextResponse.next()
}
// Handle internationalization for non-API routes
if (!request.nextUrl.pathname.startsWith('/api')) {
return intlMiddleware(request)
}
// Skip API rate limiting here to stay Edge-safe
// Security headers for all responses
const response = NextResponse.next()
// Security headers
response.headers.set('X-Content-Type-Options', 'nosniff')
response.headers.set('X-Frame-Options', 'DENY')
response.headers.set('X-XSS-Protection', '1; mode=block')
response.headers.set('Referrer-Policy', 'origin-when-cross-origin')
response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()')
// CSRF protection for state-changing operations
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(request.method)) {
const origin = request.headers.get('origin')
const host = request.headers.get('host')
if (origin && host && !origin.endsWith(host)) {
return new NextResponse('Forbidden', { status: 403 })
}
}
// Authentication: perform only lightweight checks in Middleware (Edge).
// Defer full JWT verification to API route handlers (Node runtime).
const protectedPaths = ['/dashboard', '/profile', '/settings']
const isProtectedPath = protectedPaths.some(path =>
request.nextUrl.pathname.startsWith(path)
)
if (isProtectedPath) {
const token = request.cookies.get('authToken')?.value ||
request.headers.get('authorization')?.replace('Bearer ', '')
if (!token) {
// Extract locale from pathname for redirect
const locale = request.nextUrl.pathname.split('/')[1]
const isValidLocale = ['ro', 'en', 'es', 'it'].includes(locale)
const redirectLocale = isValidLocale ? locale : 'en'
return NextResponse.redirect(new URL(`/${redirectLocale}/auth/login`, request.url))
}
}
return response
}
export const config = {
matcher: [
// Match all pathnames except for
// - api routes
// - admin routes
// - _next (Next.js internals)
// - _vercel
// - static files (images, etc.)
// - favicon.ico, robots.txt, sitemap.xml
'/((?!api|admin|_next|_vercel|.*\\..*|favicon.ico|robots.txt|sitemap.xml).*)',
// Match internationalized pathnames
'/(ro|en|es|it)/:path*'
],
}