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

@Marchy 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 ?

@California pilchard 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

@Marchy 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 locale
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 }>
}

@Marchy You could overwrite that in middleware based on user settings

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

@Marchy 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

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 ?

@California pilchard Its 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

@Marchy Actually, maybe? I don't see it in the /app docs <:meow_stare:763826437341839422>

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 ?

@California pilchard 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 😄

@California pilchard 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"

@California pilchard 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 ahah
California 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 change

California 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 ?