From f7c992bcdf01e4afc0d8e76ba95b8a6db2cdfe80 Mon Sep 17 00:00:00 2001 From: kinou-p Date: Sun, 5 May 2024 05:55:19 +0200 Subject: [PATCH] add choose language --- my-app/package-lock.json | 71 +++++++++++++++++++++++++++++ my-app/package.json | 3 ++ my-app/src/App.tsx | 5 +- my-app/src/components/button.tsx | 4 +- my-app/src/components/header.tsx | 67 +++++++++++++++------------ my-app/src/css/mine.css | 49 ++------------------ my-app/src/index.tsx | 2 +- my-app/src/pages/home.tsx | 13 ++++-- my-app/src/utils/i18n.tsx | 52 +++++++++++++++++++++ my-app/src/utils/language_index.tsx | 5 ++ 10 files changed, 188 insertions(+), 83 deletions(-) create mode 100644 my-app/src/utils/i18n.tsx create mode 100644 my-app/src/utils/language_index.tsx diff --git a/my-app/package-lock.json b/my-app/package-lock.json index 06ca03e..40d6d6a 100644 --- a/my-app/package-lock.json +++ b/my-app/package-lock.json @@ -23,10 +23,13 @@ "bootstrap": "^4.6.0", "country-flag-icons": "^1.5.11", "framer-motion": "^11.1.7", + "i18next": "^23.11.3", + "i18next-xhr-backend": "^3.2.2", "react": "^18.3.1", "react-bootstrap": "^2.10.2", "react-country-flag": "^3.1.0", "react-dom": "^18.3.1", + "react-i18next": "^14.1.1", "react-icons": "^5.2.0", "react-router-dom": "^6.23.0", "react-scripts": "^5.0.1", @@ -9675,6 +9678,14 @@ "node": ">=12" } }, + "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==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", @@ -9818,6 +9829,37 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "23.11.3", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.3.tgz", + "integrity": "sha512-Pq/aSKowir7JM0rj+Wa23Kb6KKDUGno/HjG+wRQu0PxoTbpQ4N89MAT0rFGvXmLkRLNMb1BbBOKGozl01dabzg==", + "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" + } + ], + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-xhr-backend": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-3.2.2.tgz", + "integrity": "sha512-OtRf2Vo3IqAxsttQbpjYnmMML12IMB5e0fc5B7qKJFLScitYaXa1OhMX0n0X/3vrfFlpHL9Ro/H+ps4Ej2j7QQ==", + "deprecated": "replaced by i18next-http-backend", + "dependencies": { + "@babel/runtime": "^7.5.5" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -15542,6 +15584,27 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-i18next": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.1.tgz", + "integrity": "sha512-QSiKw+ihzJ/CIeIYWrarCmXJUySHDwQr5y8uaNIkbxoGRm/5DukkxZs+RPla79IKyyDPzC/DRlgQCABHtrQuQQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-icons": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.0.tgz", @@ -17923,6 +17986,14 @@ "node": ">= 0.8" } }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/my-app/package.json b/my-app/package.json index 5aa4488..b9a466e 100644 --- a/my-app/package.json +++ b/my-app/package.json @@ -18,10 +18,13 @@ "bootstrap": "^4.6.0", "country-flag-icons": "^1.5.11", "framer-motion": "^11.1.7", + "i18next": "^23.11.3", + "i18next-xhr-backend": "^3.2.2", "react": "^18.3.1", "react-bootstrap": "^2.10.2", "react-country-flag": "^3.1.0", "react-dom": "^18.3.1", + "react-i18next": "^14.1.1", "react-icons": "^5.2.0", "react-router-dom": "^6.23.0", "react-scripts": "^5.0.1", diff --git a/my-app/src/App.tsx b/my-app/src/App.tsx index 3d74de4..e3744ce 100644 --- a/my-app/src/App.tsx +++ b/my-app/src/App.tsx @@ -11,8 +11,9 @@ import React, { useState } from "react"; import CssBaseline from '@mui/material/CssBaseline'; import Header from './components/header'; import { ColorModeContext } from './utils/color-toggle'; +import { useTranslation } from 'react-i18next'; - +import "./utils/i18n"; function App() { @@ -37,6 +38,8 @@ function App() }, }); + const { i18n, t } = useTranslation(); + return ( diff --git a/my-app/src/components/button.tsx b/my-app/src/components/button.tsx index 29723a9..8aa431c 100644 --- a/my-app/src/components/button.tsx +++ b/my-app/src/components/button.tsx @@ -2,11 +2,13 @@ import * as React from 'react'; import { Button as BaseButton } from '@mui/base/Button'; import { styled } from '@mui/system'; import Stack from '@mui/material/Stack'; +import { useTranslation } from 'react-i18next'; export default function ButtonSimple() { + const { i18n, t } = useTranslation(); return ( // - + ); } diff --git a/my-app/src/components/header.tsx b/my-app/src/components/header.tsx index ed11feb..33fe059 100644 --- a/my-app/src/components/header.tsx +++ b/my-app/src/components/header.tsx @@ -1,63 +1,70 @@ import MenuSimple from './language'; import MaterialUISwitch from './switch' import { useTheme, ThemeProvider, createTheme } from '@mui/material/styles'; -// import { ThemeProvider, createTheme } from '@mui/material/styles'; import React, { useState, useContext } from "react"; - import logo from '../img/first.jpg'; -// import { ColorModeContext } from '../utils/color-toggle' - -// const theme = useTheme() -// const colorMode = React.useContext(ColorModeContext); - import { ColorModeContext } from '../utils/color-toggle'; +import { useTranslation } from 'react-i18next'; -// const { ColorMode, setColorMode } = useColorMode(); - +import ReactCountryFlag from "react-country-flag" +import { FormControl } from 'react-bootstrap'; +import { Box, InputLabel, MenuItem} from '@mui/material'; +import Select, { SelectChangeEvent } from '@mui/material/Select'; function Header() { - + const { i18n, t } = useTranslation(); const { changeMode } = useContext(ColorModeContext); - // const { colorMode, setColorMode } = changeMode(); + const [language, setLanguage] = useState(1); + + function handleChange() { + // i18n.language + i18n.changeLanguage(language ? 'en' : 'fr') + setLanguage(language ? 0 : 1) + } - // const toggleColorMode = () => { - // // Call setColorMode and pass the new color mode value - // setColorMode(colorMode === 'light' ? 'dark' : 'light'); - // }; return ( - //
-
- {/*

A.P

*/} -
+
+ Logo -
- +
- Contact + {t("page1")}
- Projets + {t("page2")}
- CV + {t("page3")}
- Competences + {t("page4")}
- -
- + {/* */} + + {/* */} + {/* Age */} + + {/* */} + + - {/* */}
- //
) } diff --git a/my-app/src/css/mine.css b/my-app/src/css/mine.css index d5040b0..e4fab15 100644 --- a/my-app/src/css/mine.css +++ b/my-app/src/css/mine.css @@ -8,28 +8,19 @@ } body { - /* overflow: hidden; */ - /* color:black; */ + overflow: hidden; max-width: 100vw; font-family: "Fira Sans", Arial, sans-serif; - /* height: 100vh; */ width: 100vw; margin: 0; padding: 0; font-family: Arial, sans-serif; - /* border: 1vh solide white; */ } header { width: 100%; - /* background-color: #a4a4a4; */ - /* padding: 20px 0; */ text-align: center; height: 15vh; - - /* border-bottom-width: 5px; */ - /* border-bottom: 1cm; */ - /* border-color: rgb(207, 0, 0); */ } .header-content { @@ -37,39 +28,29 @@ body { width: 100vw; height: 100%; display: flex; - /* align-items: center; */ justify-content: space-between; - /* padding-left: 0px; */ } .logo img{ height: 100%; /* Adjust the size as needed */ - /* margin-right: 32.5vw; */ margin-left: 3vw; margin-right: 20vw; margin-bottom: 1vh; - /* margin-left: 20px; */ } .pages { margin-left: 5vw; font-weight: 800; - /* width: 5vw; */ - /* margin-top: 5vh; */ align-self: center; - /* height: 5vh; */ - transition-property: transform; - /* transition-duration: 200ms; */ transition: all 200ms ease; &:hover { transform: scale(1.1); - border-bottom: 4px solid; + border-bottom: 2px solid; } } - .title { color:black; font-weight: 800; @@ -93,15 +74,11 @@ body { margin-right: 0vw; } - /* .css-15bhy65 { - /* margin-right: 20px; */ - Button{ font-weight: 800; } .dark_mode { - /* font-weight: 800; */ margin-right: 2vw; width: 8vw; } @@ -128,10 +105,6 @@ body { width: 50vh; height: 50%; align-self: start; - /* margin-left: 30%; */ - /* margin-left: 10%; */ - /* margin-top: 15%; */ - /* max-width: 60%; */ } .presentation { @@ -142,9 +115,7 @@ body { .home { position: absolute; - /* top: 50%; */ right: -100vw; - /* height: 50%; */ animation: slideRight 2s ease forwards; display: flex; flex-direction: row; @@ -173,25 +144,17 @@ body { margin-left: 70%; } - - /* .css-cg7pzv { - width: 20vw; - } */ .project_group { font-size: 1vw; display: flex; flex-direction: row; - /* width: 100vw; */ - /* justify-content: center; */ - /* align-self: left; */ align-items: center; } .project_list { vertical-align: baseline; margin-right: 2vw; - /* justify-content: space-between; */ transition-property: transform; transition-duration: 500ms; &:hover { @@ -210,15 +173,9 @@ body { transition: all 700ms ease; transform: scale(1.15); color: rgb(0, 127, 255); - /* transition-property: transform; */ - /* transition-duration: 700ms; */ - /* padding-right: 10vh; */ opacity: 0; } .project_list:hover + .arrow { - /* color: rgb(0, 127, 255); */ - /* transition-property: transform; */ - /* transition-duration: 700ms; */ opacity: 1; - } + } \ No newline at end of file diff --git a/my-app/src/index.tsx b/my-app/src/index.tsx index 11a3f35..52f79ae 100644 --- a/my-app/src/index.tsx +++ b/my-app/src/index.tsx @@ -5,7 +5,7 @@ import App from './App'; // import ColorModeProvider from './utils/color-toggle'; import reportWebVitals from './reportWebVitals'; - +import "./utils/i18n"; import { ColorModeProvider } from "./utils/color-toggle" const root = ReactDOM.createRoot( diff --git a/my-app/src/pages/home.tsx b/my-app/src/pages/home.tsx index 487a869..ed18fae 100644 --- a/my-app/src/pages/home.tsx +++ b/my-app/src/pages/home.tsx @@ -2,26 +2,31 @@ import Header from '../components/header' import ButtonSimple from '../components/button' import { FaArrowRightLong } from "react-icons/fa6"; +import { useTranslation } from 'react-i18next'; function Home() { + + const { i18n, t } = useTranslation(); + return(
{/*
*/}
-
Bienvenue.
-
Étudiant a 42 en informatique, je cherche un emploi afin de compléter +
{t("welcome")}
+ {/*
Étudiant a 42 en informatique, je cherche un emploi afin de compléter ma formation académique par une expérience professionnelle qui a du sens. Je suis ouvert à de nombreuses propositions en rapport avec mes études - et suis prêt à discuter de mon parcours plus amplement lors d’un entretien.
+ et suis prêt à discuter de mon parcours plus amplement lors d’un entretien.
*/} +
{t("description")}
-
Projects
+
{t("project")}

- Ft_Transcendence

diff --git a/my-app/src/utils/i18n.tsx b/my-app/src/utils/i18n.tsx new file mode 100644 index 0000000..5ee02f6 --- /dev/null +++ b/my-app/src/utils/i18n.tsx @@ -0,0 +1,52 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; + +// import i18n from "i18next"; +// import LanguageDetector from "i18next-browser-languagedetector"; +import Backend from "i18next-xhr-backend"; +// import { initReactI18next } from "react-i18next"; + +// const fallbackLng = ["en"]; + + +i18n + .use(Backend) // used to load data from othe directory +// .use(LanguageDetector) // detects the current language + .use(initReactI18next) // passes i18n down to react-i18next + .init({ + fallbackLng: "fr", + // lng: getCurrentLang(), + interpolation: { + escapeValue: false, + }, + resources: { + en: { + translation: { + page1: "Contact", + page2: "Projects", + page3: "Resume", + page4: "Skills", + page5: "", + description:"Student majoring in computer science at 42, I am seeking employment to complement my academic training with meaningful professional experience. I am open to various job opportunities related to my studies and am ready to discuss my background further during an interview.", + project:"Projects", + welcome:"Welcome.", + resume:"My Resume", + }, + }, + fr: { + translation: { + page1: "Contact", + page2: "Projets", + page3: "CV", + page4: "Competences", + page5: "", + description:"Étudiant a 42 en informatique, je cherche un emploi afin de compléter ma formation académique par une expérience professionnelle qui a du sens. Je suis ouvert à de nombreuses propositions en rapport avec mes études et suis prêt à discuter de mon parcours plus amplement lors d’un entretien.", + project:"Projets", + welcome:"Bienvenue.", + resume:"Mon CV", + }, + }, + }, + }); + +export default i18n; \ No newline at end of file diff --git a/my-app/src/utils/language_index.tsx b/my-app/src/utils/language_index.tsx new file mode 100644 index 0000000..c675e43 --- /dev/null +++ b/my-app/src/utils/language_index.tsx @@ -0,0 +1,5 @@ +export const LANGUAGES = [ + { label: "Spanish", code: "es" }, + { label: "English", code: "en" }, + { label: "French", code: "fr" }, + ]; \ No newline at end of file