diff --git a/src/app.js b/src/app.js index 3d8dbc1..472715d 100644 --- a/src/app.js +++ b/src/app.js @@ -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) => { diff --git a/test/staticServing.test.js b/test/staticServing.test.js index d3be775..b2cb439 100644 --- a/test/staticServing.test.js +++ b/test/staticServing.test.js @@ -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/');