Need to set a cookie on the client and read it in the middleware
Unanswered
Black Caiman posted this in #help-forum
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.
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:
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.
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.