add choose language

This commit is contained in:
kinou-p 2024-05-05 05:55:19 +02:00
parent 151c9d9dc5
commit f7c992bcdf
10 changed files with 188 additions and 83 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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 (
<BrowserRouter>
<CssBaseline />

View File

@ -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 (
// <Stack spacing={2} direction="row">
<Button>Mon CV</Button>
<Button>{t("resume")}</Button>
);
}

View File

@ -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 (
// <ThemeProvider theme={darkTheme}>
<header>
<div className="header-content">
{/* <h1 className="title">A.P</h1> */}
<div className="logo">
<div className="header-content">
<a className="logo" href="/">
<img src={logo} alt="Logo" />
</div>
</a>
<div className="pages">
Contact
{t("page1")}
</div>
<div className="pages">
Projets
{t("page2")}
</div>
<div className="pages">
CV
{t("page3")}
</div>
<div className="pages">
Competences
{t("page4")}
</div>
<div className="language">
<MenuSimple/>
{/* <MenuSimple/> */}
<Box sx={{ minWidth: 120 }}>
{/* <FormControl > */}
{/* <InputLabel id="demo-simple-select-label">Age</InputLabel> */}
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={language}
// label="Age"
onChange={handleChange}
>
<MenuItem value={0}><ReactCountryFlag countryCode="GB" svg/></MenuItem>
<MenuItem value={1}><ReactCountryFlag countryCode="FR" svg/></MenuItem>
</Select>
{/* </FormControl> */}
</Box>
<MaterialUISwitch onChange={changeMode}/>
{/* <Switch className="dark_mode" checked={toggleDarkMode} onChange={toggleDarkTheme} defaultChecked /> */}
</div>
</div>
</header>
// </ThemeProvider>
)
}

View File

@ -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;
@ -174,24 +145,16 @@ body {
}
/* .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;
}

View File

@ -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(

View File

@ -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(
<div>
<body>
{/* <Header/> */}
<div className='home'>
<div className="presentation">
<div className='hello'>Bienvenue.</div>
<div className="description">Étudiant a 42 en informatique, je cherche un emploi afin de compléter
<div className='hello'>{t("welcome")}</div>
{/* <div className="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 dun entretien.</div>
et suis prêt à discuter de mon parcours plus amplement lors dun entretien.</div> */}
<div>{t("description")}</div>
<div className="cv_button">
<ButtonSimple/>
</div>
</div>
<div className="project">
<div className='project_txt'>Projects</div>
<div className='project_txt'>{t("project")}</div>
<div className = "project_group">
<p className="project_list">- Ft_Transcendence</p>
<FaArrowRightLong className="arrow"/>

52
my-app/src/utils/i18n.tsx Normal file
View File

@ -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 dun entretien.",
project:"Projets",
welcome:"Bienvenue.",
resume:"Mon CV",
},
},
},
});
export default i18n;

View File

@ -0,0 +1,5 @@
export const LANGUAGES = [
{ label: "Spanish", code: "es" },
{ label: "English", code: "en" },
{ label: "French", code: "fr" },
];