Skip to content

Commit 4c84518

Browse files
committed
⚡️(frontend) set html lang attribute dynamically based on current loc
ensures proper language tag is set for accessibility and SEO compliance Signed-off-by: Cyril <[email protected]>
1 parent 30dfea7 commit 4c84518

File tree

5 files changed

+62
-14
lines changed

5 files changed

+62
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ and this project adheres to
2222
- ♻️(frontend) redirect to doc after duplicate #1175
2323
- 🔧(project) change env.d system by using local files #1200
2424
- ⚡️(frontend) improve tree stability #1207
25-
- ⚡️(frontend) improve accessibility #1232
25+
- ⚡️(frontend) improve accessibility
26+
- #1232
27+
- #1248
2628
- 🛂(frontend) block drag n drop when not desktop #1239
2729

2830
### Fixed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { useEffect } from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
4+
export function HtmlLangUpdater() {
5+
const { i18n } = useTranslation();
6+
7+
useEffect(() => {
8+
const lang = i18n.language?.split('-')[0] || 'fr';
9+
document.documentElement.setAttribute('lang', lang);
10+
}, [i18n.language]);
11+
12+
return null;
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const fallbackLng = 'en';

src/frontend/apps/impress/src/i18n/initI18n.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import i18next from 'i18next';
22
import LanguageDetector from 'i18next-browser-languagedetector';
33
import { initReactI18next } from 'react-i18next';
44

5+
import { fallbackLng } from './config';
56
import resources from './translations.json';
67

78
// Add an initialization guard
@@ -16,7 +17,7 @@ if (!isInitialized && !i18next.isInitialized) {
1617
.use(initReactI18next)
1718
.init({
1819
resources,
19-
fallbackLng: 'en',
20+
fallbackLng,
2021
debug: false,
2122
detection: {
2223
order: ['cookie', 'navigator'],
@@ -35,6 +36,17 @@ if (!isInitialized && !i18next.isInitialized) {
3536
nsSeparator: false,
3637
keySeparator: false,
3738
})
39+
.then(() => {
40+
if (typeof document !== 'undefined') {
41+
document.documentElement.setAttribute(
42+
'lang',
43+
i18next.language || fallbackLng,
44+
);
45+
i18next.on('languageChanged', (lang) => {
46+
document.documentElement.setAttribute('lang', lang);
47+
});
48+
}
49+
})
3850
.catch((e) => console.error('i18n initialization failed:', e));
3951
}
4052

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
1-
import { Head, Html, Main, NextScript } from 'next/document';
2-
3-
export default function RootLayout() {
4-
return (
5-
<Html>
6-
<Head />
7-
<body suppressHydrationWarning={process.env.NODE_ENV === 'development'}>
8-
<Main />
9-
<NextScript />
10-
</body>
11-
</Html>
12-
);
1+
import Document, {
2+
DocumentContext,
3+
Head,
4+
Html,
5+
Main,
6+
NextScript,
7+
} from 'next/document';
8+
9+
import { fallbackLng } from '../i18n/config';
10+
11+
class MyDocument extends Document<{ locale: string }> {
12+
static async getInitialProps(ctx: DocumentContext) {
13+
const initialProps = await Document.getInitialProps(ctx);
14+
return {
15+
...initialProps,
16+
locale: ctx.locale || fallbackLng,
17+
};
18+
}
19+
20+
render() {
21+
return (
22+
<Html lang={this.props.locale}>
23+
<Head />
24+
<body>
25+
<Main />
26+
<NextScript />
27+
</body>
28+
</Html>
29+
);
30+
}
1331
}
32+
33+
export default MyDocument;

0 commit comments

Comments
 (0)