Next.js Discord

Discord Forum

Need to set a cookie on the client and read it in the middleware

Unanswered
Black Caiman posted this in #help-forum
Open in Discord
Black CaimanOP
Hey! I am trying to add a button that changes the language when clicking on the desired lang.
I cloned this example for i18n https://github.com/anthonyshew/i18n-demo and build on top of it.
So now I want to add a button that changes the language after clicking. I need to set a cookie on the client and read it in the middleware.

First I created a language switcher component that includes buttons for English and Spanish. When a user clicks on one of the buttons, you'll set a cookie to store their language preference.

import { cookies } from 'next/headers';

function LanguageSwitcher() {
  const setLanguageCookie = (lang) => {
    cookies().set('language', lang, { path: '/' });
    // Reload the page to reflect the new language preference
    window.location.reload();
  };

  return (
    <div>
      <button onClick={() => setLanguageCookie('en')}>English</button>
      <button onClick={() => setLanguageCookie('es')}>Spanish</button>
    </div>
  );
}

export default LanguageSwitcher;

1 Reply

Black CaimanOP
Then I read the language cookie and use it to determine the language set by the user:

import { NextRequest, NextResponse } from 'next/server';
import { match } from '@formatjs/intl-localematcher';
import Negotiator from 'negotiator';

let locales = ['en', 'es'];
export let defaultLocale = 'en';

function getLocale(request: Request): string {
  const headers = new Headers(request.headers);
  const acceptLanguage = headers.get('accept-language');

  if (acceptLanguage) {
    headers.set('accept-language', acceptLanguage.replaceAll('_', '-'));
  }

  const headersObject = Object.fromEntries(headers.entries());
  const languages = new Negotiator({ headers: headersObject }).languages();

  // Read the language preference from the cookie if it exists
  const langFromCookie = cookies().get('language');

  return langFromCookie || match(languages, locales, defaultLocale);
}

export function middleware(request: NextRequest) {
  let locale = getLocale(request) ?? defaultLocale;
  const pathname = request.nextUrl.pathname;

  const newUrl = new URL(`/${locale}${pathname}`, request.nextUrl);

  // e.g., incoming request is /products
  // The new URL is now /en/products
  return NextResponse.rewrite(newUrl);
}

export const config = {
  matcher: [
    // Skip all internal paths (_next)
    '/((?!_next|api|favicon.ico).*)',
    // Optional: only run on root (/) URL
    // '/'
  ],
};


When I want to import the language switcher into my page.tsx and try if it works I get the error that I use a button with onclick and for interactivity I need use client. But when I add use client I get the error that I am importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.
Not sure how to implement the functionality at this point.