feat(seo): redirect / to /fr/ or /en/ server-side based on Accept-Language

This commit is contained in:
2026-08-02 10:21:38 +02:00
parent 5ff8a865e8
commit b2636e20cf
2 changed files with 27 additions and 0 deletions
+7
View File
@@ -68,6 +68,13 @@ export function createApp(config, prisma) {
app.set('trust proxy', '1');
app.use(compression());
app.get('/', (req, res) => {
const acceptLanguage = req.headers['accept-language'] ?? '';
const primaryTag = acceptLanguage.split(',')[0]?.split(';')[0]?.split('-')[0]?.trim().toLowerCase();
const lang = primaryTag === 'en' ? 'en' : 'fr';
res.redirect(301, `/${lang}/`);
});
const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, path.join(config.storageDir, 'uploads')),
filename: (req, file, cb) => {
+20
View File
@@ -39,6 +39,26 @@ afterAll(async () => {
await fs.rm(frontendDist, { recursive: true, force: true });
});
describe('root redirect', () => {
it('redirects to /en/ when Accept-Language prefers English', async () => {
const response = await request(app).get('/').set('Accept-Language', 'en-US,en;q=0.9');
expect(response.status).toBe(301);
expect(response.headers.location).toBe('/en/');
});
it('redirects to /fr/ when Accept-Language prefers French', async () => {
const response = await request(app).get('/').set('Accept-Language', 'fr-FR,fr;q=0.9,en;q=0.5');
expect(response.status).toBe(301);
expect(response.headers.location).toBe('/fr/');
});
it('defaults to /fr/ when Accept-Language is absent', async () => {
const response = await request(app).get('/');
expect(response.status).toBe(301);
expect(response.headers.location).toBe('/fr/');
});
});
describe('static asset serving', () => {
it('sends HTML pages with Cache-Control: no-cache', async () => {
const response = await request(app).get('/fr/');