Next.js Discord

Discord Forum

How handle next-intl and middleware ?

Unanswered
California pilchard posted this in #help-forum
Open in Discord
California pilchardOP
Okay I have a lot of problem with my middleware and next-intl. I dont know how can I handle locale rooting, with static file (in public folder), and with robots.ts and sitemap.ts. My current middleware is like this :
import { NextRequest, NextResponse } from 'next/server';
import createIntlMiddleware from 'next-intl/middleware';
import { createMiddlewareClient } from './lib/supabase/middleware';
import { routing } from './lib/i18n/routing';

const intlMiddleware = createIntlMiddleware(routing);

export async function middleware(request: NextRequest) {
  let response = intlMiddleware(request);

  const url = request.nextUrl.clone();
  const localeMatch = url.pathname.split('/')[1];
  const hasLocale = routing.locales.includes(localeMatch as any);
  if (hasLocale) url.pathname = url.pathname.replace(`/${localeMatch}`, '');
  // IMPORTANT: Avoid writing any logic between createServerClient and
  // supabase.auth.getUser(). A simple mistake could make it very hard to debug
  // issues with users being randomly logged out.
  const supabase = createMiddlewareClient({ request, response });
  const {
    data: { user },
  } = await supabase.auth.getUser();

  /**
   * Check locale if user is logged in
   */
  const localeHeader = response.headers.get('x-middleware-request-x-next-intl-locale');
  const { data: config } = await supabase.rpc('get_config', {
    user_id: user?.id,
  }).single();

  if (user && config?.user_language && routing.locales.includes(config.user_language)) {
    const wrongLocale =
      (hasLocale && localeMatch !== config.user_language) ||
      (localeHeader && localeHeader !== config.user_language);
    if (wrongLocale) {
      url.pathname = `/${config.user_language}${url.pathname}`;
      return (NextResponse.redirect(url));
    }
  }

  /**
   * Check maintenance mode
   * 
   * If the app is in maintenance mode, redirect all users to the maintenance page
   * If the app is not in maintenance mode, redirect all users to the home page
   * 
   */
  if (config?.maintenance_mode && url.pathname !== '/maintenance' && process.env.NODE_ENV !== 'development') {
    url.pathname = `/maintenance`;
    return (NextResponse.redirect(url));
  } else if (url.pathname === '/maintenance' && !config?.maintenance_mode) {
    url.pathname = '/';
    return (NextResponse.redirect(url));
  }

  /**
   * Redirect user if not logged in
   */
  const anonUserOnly = [
    '/auth'
  ];
  if (user && anonUserOnly.some((path) => url.pathname.startsWith(path))) {
    // if /auth/login and there is redirect query param, go to redirect
    if (url.pathname === '/auth/login' && url.searchParams.has('redirect'))
      return (NextResponse.redirect(new URL(url.searchParams.get('redirect')!, request.url)));
    url.pathname = '/';
    url.search = '';
    return (NextResponse.redirect(url));
  }

  /**
   * Redirect user if logged in
   */
  const authentifiedUserOnly = [
    '/collection',
    '/feed',
    '/settings',
  ];
  if (!user && authentifiedUserOnly.some((path) => url.pathname.startsWith(path))) {
    url.pathname = '/auth/login';
    url.searchParams.set('redirect', request.nextUrl.pathname);
    return (NextResponse.redirect(url));
  }

  /**
   * Redirect user if not premium
   */
  const premiumUserOnly = [
    '/feed/cast-crew',
  ];
  if (user && !config?.user_premium && premiumUserOnly.some((path) => url.pathname.startsWith(path))) {
    url.pathname = '/upgrade';
    return (NextResponse.redirect(url));
  }
  
  return (response);
}

export const config = {
  matcher: [
    '/((?!api|_next|_vercel|.*\\..*).*)',
    // User pages
    '/@:username/:path*',
  ],
};

Btw I have a rewrite in next.config.ts :
async rewrites() {
    return [
      {
        source: '/:lang/@:username/:path*',
        destination: '/:lang/user/:username/:path*',
      },
    ];
  },

2 Replies

California pilchardOP
So my folder are :
tree -L 2 src/app
src/app
├── [lang]
│   ├── (app)
│   ├── (maintenance)
│   └── layout.tsx
├── api
│   ├── revalidate
│   └── stripe
├── robots.ts
└── sitemaps
    └── sitemap.ts

robots.txt is working on /robots.txt, but /sitemaps/sitemap.yml go to /[lang]/(app)/layout.ts
California pilchardOP
Ive change my matcher by :
matcher: [   `/((?!api|_next|_vercel|favicon\\.ico|manifest\\.webmanifest|robots\\.txt|sitemaps/|opensearch\\.xml|assets/|.*\\.(?:json|xml|js)$).*)`,
  ],