diff --git a/web/client/index.html b/web/client/index.html index 6e56e6e..644d232 100644 --- a/web/client/index.html +++ b/web/client/index.html @@ -4,9 +4,11 @@ - client + + BIS SP‑21 Standards + Skip to main content
diff --git a/web/client/package-lock.json b/web/client/package-lock.json index 8284d98..74a2983 100644 --- a/web/client/package-lock.json +++ b/web/client/package-lock.json @@ -8,8 +8,11 @@ "name": "client", "version": "0.0.0", "dependencies": { + "i18next": "^26.0.8", + "i18next-browser-languagedetector": "^8.2.1", "react": "^19.2.5", "react-dom": "^19.2.5", + "react-i18next": "^17.0.6", "react-router-dom": "^7.14.2" }, "devDependencies": { @@ -216,6 +219,15 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", @@ -664,9 +676,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -684,9 +693,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -704,9 +710,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -724,9 +727,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -744,9 +744,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -764,9 +761,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1509,6 +1503,52 @@ "hermes-estree": "0.25.1" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/i18next": { + "version": "26.0.8", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.0.8.tgz", + "integrity": "sha512-BRzLom0mhDhV9v0QhgUUHWQJuwFmnr1194xEcNLYD6ym8y8s542n4jXUvRLnhNTbh9PmpU6kGZamyuGHQMsGjw==", + "funding": [ + { + "type": "individual", + "url": "https://www.locize.com/i18next" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + }, + { + "type": "individual", + "url": "https://www.locize.com" + } + ], + "license": "MIT", + "peerDependencies": { + "typescript": "^5 || ^6" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.1.tgz", + "integrity": "sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1780,9 +1820,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1804,9 +1841,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1828,9 +1862,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1852,9 +1883,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2152,6 +2180,33 @@ "react": "^19.2.5" } }, + "node_modules/react-i18next": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.6.tgz", + "integrity": "sha512-WzJ6SMKF+GTD7JZZqxSR1AKKmXjaSu39sClUrNlwxS4Tl7a99O+ltFy6yhPMO+wgZuxpQjJ2PZkfrQKmAqrLhw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "html-parse-stringify": "^3.0.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "i18next": ">= 26.0.1", + "react": ">= 16.8.0", + "typescript": "^5 || ^6" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-router": { "version": "7.14.2", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.2.tgz", @@ -2365,6 +2420,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/vite": { "version": "8.0.10", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", @@ -2443,6 +2507,15 @@ } } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/web/client/package.json b/web/client/package.json index 2b94c6d..43dfff3 100644 --- a/web/client/package.json +++ b/web/client/package.json @@ -10,8 +10,11 @@ "preview": "vite preview" }, "dependencies": { + "i18next": "^26.0.8", + "i18next-browser-languagedetector": "^8.2.1", "react": "^19.2.5", "react-dom": "^19.2.5", + "react-i18next": "^17.0.6", "react-router-dom": "^7.14.2" }, "devDependencies": { diff --git a/web/client/src/App.jsx b/web/client/src/App.jsx index 67e1407..12674e8 100644 --- a/web/client/src/App.jsx +++ b/web/client/src/App.jsx @@ -1,4 +1,6 @@ +import { useEffect } from "react"; import { Routes, Route, Navigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import Navbar from "./components/Navbar"; import Footer from "./components/Footer"; import Home from "./pages/Home"; @@ -7,22 +9,26 @@ import Categories from "./pages/Categories"; import About from "./pages/About"; import Recommend from "./pages/Recommend"; -/** - * Main application router. - * Renders layout with Navbar/Footer and routes to pages. - */ export default function App() { + const { i18n } = useTranslation(); + + useEffect(() => { + document.documentElement.lang = i18n.language; + }, [i18n.language]); + return ( <> - - } /> - } /> - } /> - } /> - } /> - } /> - +
+ + } /> + } /> + } /> + } /> + } /> + } /> + +