App Router : i18n and Supabase
Unanswered
California pilchard posted this in #help-forum
California pilchardOP
Okay its maybe a dummy question but how can we manage i18n in web app without slug (like spotify, instagram,...) ? I use Supabase for backend so I can save the language preference for each user. But how set the language of the user in the nextjs app ? And how manage the fact that user can be not logged ? Im new with i18n so I have no idea. My first idea is to use React Context, but I guess I need cookies to store the preference of the user (logged and unlogged) ?
36 Replies
Spotify handles content by fetching all of the text through GQL on the client, but best practice with next would be to use domain and/or subpath routing so it's cached on the route segment for better performance
California pilchardOP
Yeah Im gonna use subpath like [lang]in the doc but in the middlesware make something like, if the user is connected take is favorite language, if not connected, take the one from the Accept-Language header, is a good practice ?
Yes, next does this automatically based on the Accept-Language header sent by the browser (their system default)
https://nextjs.org/docs/pages/building-your-application/routing/internationalization#automatic-locale-detection
https://nextjs.org/docs/pages/building-your-application/routing/internationalization#automatic-locale-detection
California pilchardOP
Because im already use middleware to catch user session with Supabase :
So I guess I can have something with the language
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextRequest, NextResponse } from 'next/server'
export async function middleware(req: NextRequest) {
const res = NextResponse.next()
const supabase = createMiddlewareClient({ req, res })
await supabase.auth.getSession()
return res
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)']
}
So I guess I can have something with the language
You could overwrite that in middleware based on user settings
California pilchardOP
ChatGPT help me to just think about the way of doing and show me this example :
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextRequest, NextResponse } from 'next/server'
export async function middleware(req: NextRequest) {
const res = NextResponse.next()
const supabase = createMiddlewareClient({ req, res })
const session = await supabase.auth.getSession()
if (session) {
const userLanguage = await getUserLanguageFromSupabase(session.user.id) // Obtenez la langue de l'utilisateur depuis Supabase
setLanguageCookie(res, userLanguage)
} else {
const acceptLanguage = req.headers.get('Accept-Language')
const userLanguage = determineUserLanguage(acceptLanguage) // Déterminez la langue préférée en fonction de l'en-tête Accept-Language
setLanguageCookie(res, userLanguage)
}
return res
}
function setLanguageCookie(res, language) {
res.setHeader('Set-Cookie', `rcmd_locale=${language}; Path=/; HttpOnly; Secure; SameSite=Strict`)
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)']
}
Ive check the cookie from Spotify and they store the
sp_locale
value for the localeI don't use supabase, but this looks right in theory
California pilchardOP
But for now I have an error in the dictionaries.ts file :
import 'server-only'
const dictionaries = {
en: () => import('./dictionaries/en.json').then((module) => module.default),
nl: () => import('./dictionaries/fr.json').then((module) => module.default),
}
export const getDictionary = async (locale: string | number) => dictionaries[locale]() => ERROR HERE WITH dictionaries[locale] =>
Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{ en: () => Promise<{ products: { cart: string; }; }>; nl: () => Promise<{ products: { cart: string; }; }>; }'.
No index signature with a parameter of type 'string' was found on type '{ en: () => Promise<{ products: { cart: string; }; }>; nl: () => Promise<{ products: { cart: string; }; }>; }
Ive try adding interface like that but not working as well :
interface Dictionary {
[key: string]: () => Promise<{ [key: string]: string }>
}
actually, you can override this with the NEXT_LOCALE cookie
https://nextjs.org/docs/pages/building-your-application/routing/internationalization#leveraging-the-next_locale-cookie
https://nextjs.org/docs/pages/building-your-application/routing/internationalization#leveraging-the-next_locale-cookie
The locale gets passed as a param to each page.jsx, it might be easier to just have a content.json in the closest route segment that can be used to manage all the content there
California pilchardOP
Ohh ! I was thinking about create a new cookies
rcmd_locale
but if I can override the NEXT_LOCALE its even betterIts the Pages Router, isnt a problem ?
Actually, maybe? I don't see it in the /app docs
it'd be worth a try
same difference either way, just a little bit extra in middleware if it's not automatic
California pilchardOP
And when u say override NEXT_LOCALE, is only for a specific website right ? Like isnt gonna chance the lang of all the website ?
NEXT_LOCALE probably uses the same method as doing it manually in middleware. It would be just for your site, because the cookie is from your domain
it might also just be missing from app docs, in which case I'd be interested if it works so I can add it
California pilchardOP
Im gonna try this tomorrow, im gonna sleep rn so i'll keep u informed !
THx again for ur help and sry for my dummy questions 😄
no such thing as a dumb question, next is a 100% different arch pattern so things happen in different places than you might expect lol
California pilchardOP
ahah yeah probably
Btw to use "server-only" we have to enable experimental feature no ? Because in the /app docs they use server-only for
dictionaries.ts
or its maybe
"user-server"
'use server'
, it was server-only at one point California pilchardOP
Well maybe I can use the plugin
next-intl
no ? Because I have some difficulties to setup the middleware ahahCalifornia pilchardOP
Okay Ive setup the
next-intl
plugin with server component with this middleware :import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextRequest, NextResponse } from 'next/server'
import createIntlMiddleware from 'next-intl/middleware'
const locales = ['en', 'fr'];
const intlMiddleware = createIntlMiddleware({
locales,
defaultLocale: 'en'
})
export async function middleware(req: NextRequest) {
const res = NextResponse.next()
const supabase = createMiddlewareClient({ req, res })
await supabase.auth.getSession()
return intlMiddleware(req)
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)']
}
California pilchardOP
Well no I have to setup my middleware if my user is connected to change the NEXT_LOCALE value
California pilchardOP
Ive try this :
But in the cookies tabs nothing is change. Ive tried to create a new cookie with differente name and isnt working too
export async function middleware(req: NextRequest) {
const res = NextResponse.next()
const supabase = createMiddlewareClient({ req, res })
const { data: { session } } = await supabase.auth.getSession();
const { data: user } = await supabase.from('user').select('*').eq('id', session?.user.id).single() as { data: User }
if (user) {
console.log('user', user)
// Mettre à jour le cookie NEXT_LOCALE avec la langue préférée de l'utilisateur
res.cookies.set(
{
name: 'NEXT_LOCALE',
value: user.language,
maxAge: 365 * 24 * 60 * 60, // Durée de validité du cookie (1 an)
path: '/', // Le chemin du cookie
sameSite: 'strict',
priority: 'medium'
});
}
return intlMiddleware(req)
}
But in the cookies tabs nothing is change. Ive tried to create a new cookie with differente name and isnt working too
Okay the problem come from the `return intMiddleware(req)`` because if I do that :
I can override cookies. The problem is intMiddleware use req
return (res)
// return intlMiddleware(req)
I can override cookies. The problem is intMiddleware use req
California pilchardOP
I really dont understand with the cookies isnt set with my actual middleware... Because if I change manually the
NEXT_LOCALE
cookie value in the app tabs the lang changeCalifornia pilchardOP
Il gonna try this https://youtu.be/fmFYH_Xu3d0?si=TWAWOxx9XEUB-dzf
California pilchardOP
arrhh doesnt work either
California pilchardOP
So maybe I have to create a custom intlMiddleware to use the same
res
variable ?