From ec84f31bc71fcb5dfda093f849c9b8feb680f05d Mon Sep 17 00:00:00 2001
From: Cyril
Date: Thu, 31 Jul 2025 11:19:34 +0200
Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F(frontend)=20set=20html=20lan?=
=?UTF-8?q?g=20attribute=20dynamically=20based=20on=20current=20loc?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ensures proper language tag is set for accessibility and SEO compliance
Signed-off-by: Cyril
---
CHANGELOG.md | 4 +-
.../__tests__/app-impress/language.spec.ts | 6 +++
src/frontend/apps/impress/src/i18n/config.ts | 1 +
.../apps/impress/src/i18n/initI18n.ts | 14 +++++-
.../apps/impress/src/pages/_document.tsx | 44 ++++++++++++++-----
5 files changed, 55 insertions(+), 14 deletions(-)
create mode 100644 src/frontend/apps/impress/src/i18n/config.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 876698384..92b65a9d6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,7 +25,9 @@ and this project adheres to
- ♻️(frontend) redirect to doc after duplicate #1175
- 🔧(project) change env.d system by using local files #1200
- ⚡️(frontend) improve tree stability #1207
-- ⚡️(frontend) improve accessibility #1232
+- ⚡️(frontend) improve accessibility
+ - #1232
+ - #1248
- 🛂(frontend) block drag n drop when not desktop #1239
### Fixed
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/language.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/language.spec.ts
index 1d616cc49..166ac6537 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/language.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/language.spec.ts
@@ -26,6 +26,8 @@ test.describe.serial('Language', () => {
test('checks language switching', async ({ page }) => {
const header = page.locator('header').first();
+ await expect(page.locator('html')).toHaveAttribute('lang', 'en-us');
+
// initial language should be english
await expect(
page.getByRole('button', {
@@ -36,6 +38,8 @@ test.describe.serial('Language', () => {
// switch to french
await waitForLanguageSwitch(page, TestLanguage.French);
+ await expect(page.locator('html')).toHaveAttribute('lang', 'fr');
+
await expect(
header.getByRole('button').getByText('Français'),
).toBeVisible();
@@ -47,6 +51,8 @@ test.describe.serial('Language', () => {
await expect(header.getByRole('button').getByText('Deutsch')).toBeVisible();
await expect(page.getByLabel('Abmelden')).toBeVisible();
+
+ await expect(page.locator('html')).toHaveAttribute('lang', 'de');
});
test('checks that backend uses the same language as the frontend', async ({
diff --git a/src/frontend/apps/impress/src/i18n/config.ts b/src/frontend/apps/impress/src/i18n/config.ts
new file mode 100644
index 000000000..99250a452
--- /dev/null
+++ b/src/frontend/apps/impress/src/i18n/config.ts
@@ -0,0 +1 @@
+export const fallbackLng = 'en';
diff --git a/src/frontend/apps/impress/src/i18n/initI18n.ts b/src/frontend/apps/impress/src/i18n/initI18n.ts
index 090226407..15d97c0bf 100644
--- a/src/frontend/apps/impress/src/i18n/initI18n.ts
+++ b/src/frontend/apps/impress/src/i18n/initI18n.ts
@@ -2,6 +2,7 @@ import i18next from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
+import { fallbackLng } from './config';
import resources from './translations.json';
// Add an initialization guard
@@ -16,7 +17,7 @@ if (!isInitialized && !i18next.isInitialized) {
.use(initReactI18next)
.init({
resources,
- fallbackLng: 'en',
+ fallbackLng,
debug: false,
detection: {
order: ['cookie', 'navigator'],
@@ -35,6 +36,17 @@ if (!isInitialized && !i18next.isInitialized) {
nsSeparator: false,
keySeparator: false,
})
+ .then(() => {
+ if (typeof document !== 'undefined') {
+ document.documentElement.setAttribute(
+ 'lang',
+ i18next.language || fallbackLng,
+ );
+ i18next.on('languageChanged', (lang) => {
+ document.documentElement.setAttribute('lang', lang);
+ });
+ }
+ })
.catch((e) => console.error('i18n initialization failed:', e));
}
diff --git a/src/frontend/apps/impress/src/pages/_document.tsx b/src/frontend/apps/impress/src/pages/_document.tsx
index 9f81db4d9..27a0f30e8 100644
--- a/src/frontend/apps/impress/src/pages/_document.tsx
+++ b/src/frontend/apps/impress/src/pages/_document.tsx
@@ -1,13 +1,33 @@
-import { Head, Html, Main, NextScript } from 'next/document';
-
-export default function RootLayout() {
- return (
-
-
-
-
-
-
-
- );
+import Document, {
+ DocumentContext,
+ Head,
+ Html,
+ Main,
+ NextScript,
+} from 'next/document';
+
+import { fallbackLng } from '../i18n/config';
+
+class MyDocument extends Document<{ locale: string }> {
+ static async getInitialProps(ctx: DocumentContext) {
+ const initialProps = await Document.getInitialProps(ctx);
+ return {
+ ...initialProps,
+ locale: ctx.locale || fallbackLng,
+ };
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
}
+
+export default MyDocument;