From 6054173b032d734716ff10114a840543f4656132 Mon Sep 17 00:00:00 2001 From: Theis Gaedigk Date: Sun, 26 Oct 2025 12:52:58 +0100 Subject: [PATCH] implemented i18n translation technology --- FrontendV2/package-lock.json | 87 ++++++++++++++++++++++++++++++ FrontendV2/package.json | 2 + FrontendV2/src/main.tsx | 1 + FrontendV2/src/utils/i18n/index.ts | 33 ++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 FrontendV2/src/utils/i18n/index.ts diff --git a/FrontendV2/package-lock.json b/FrontendV2/package-lock.json index 3d49f35..9386253 100644 --- a/FrontendV2/package-lock.json +++ b/FrontendV2/package-lock.json @@ -12,6 +12,7 @@ "@emotion/react": "^11.14.0", "@tailwindcss/vite": "^4.1.11", "@tanstack/react-query": "^5.85.5", + "i18next": "^25.6.0", "jotai": "^2.15.0", "js-cookie": "^3.0.5", "lucide-react": "^0.539.0", @@ -20,6 +21,7 @@ "primereact": "^10.9.6", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-i18next": "^16.2.0", "react-icons": "^5.5.0", "react-router-dom": "^7.8.0", "react-toastify": "^11.0.5", @@ -4313,6 +4315,46 @@ "react-is": "^16.7.0" } }, + "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": "25.6.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.6.0.tgz", + "integrity": "sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5264,6 +5306,33 @@ "react": "^19.2.0" } }, + "node_modules/react-i18next": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.2.0.tgz", + "integrity": "sha512-giCEDa6NtQYvuLGW9xaBo4HCVxT0Y8jrOpX/uSnd+lZ3Dmm/2BNrGNEgRZzWDkSobmE6IWPJ+/Ow9Rhi/gP6+g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "html-parse-stringify": "^3.0.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "i18next": ">= 25.5.2", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-icons": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", @@ -5845,6 +5914,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": "7.1.12", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", @@ -5982,6 +6060,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "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/FrontendV2/package.json b/FrontendV2/package.json index 67f75e7..4b9241b 100644 --- a/FrontendV2/package.json +++ b/FrontendV2/package.json @@ -14,6 +14,7 @@ "@emotion/react": "^11.14.0", "@tailwindcss/vite": "^4.1.11", "@tanstack/react-query": "^5.85.5", + "i18next": "^25.6.0", "jotai": "^2.15.0", "js-cookie": "^3.0.5", "lucide-react": "^0.539.0", @@ -22,6 +23,7 @@ "primereact": "^10.9.6", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-i18next": "^16.2.0", "react-icons": "^5.5.0", "react-router-dom": "^7.8.0", "react-toastify": "^11.0.5", diff --git a/FrontendV2/src/main.tsx b/FrontendV2/src/main.tsx index c7e7446..a2ca89e 100644 --- a/FrontendV2/src/main.tsx +++ b/FrontendV2/src/main.tsx @@ -3,6 +3,7 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import "./index.css"; import App from "./App.tsx"; +import i18n from "./utils/i18n"; // import i18n configuration DO NOT REMOVE createRoot(document.getElementById("root")!).render( diff --git a/FrontendV2/src/utils/i18n/index.ts b/FrontendV2/src/utils/i18n/index.ts new file mode 100644 index 0000000..62c824d --- /dev/null +++ b/FrontendV2/src/utils/i18n/index.ts @@ -0,0 +1,33 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; + +import enLang from "./locales/en/en.json"; +import deLang from "./locales/de/de.json"; + +// the translations +// (tip move them in a JSON file and import them, +// or even better, manage them separated from your code: https://react.i18next.com/guides/multiple-translation-files) +const resources = { + en: { + translation: enLang, + }, + de: { + translation: deLang, + }, +}; + +i18n + .use(initReactI18next) // passes i18n down to react-i18next + .init({ + resources, + fallbackLng: "en", // use en if detected lng is not available + lng: "de", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources + // you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage + // if you're using a language detector, do not define the lng option + + interpolation: { + escapeValue: false, // react already safes from xss + }, + }); + +export default i18n;