Merge pull request #1711 from Cihatata/i18n-support-client

feat: i18n support for client
This commit is contained in:
Alexander Holliday authored and GitHub committed 2025-02-08 18:25:36 -08:00
commit 36ce69d737
16 files changed
+683 -76

No files matched your search

+134
View File
@@ -0,0 +1,134 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Box, MenuItem, Select, Stack } from "@mui/material";
import { useTheme } from "@emotion/react";
import Flag from "react-world-flags";
const LanguageSelector = () => {
const { i18n } = useTranslation();
const theme = useTheme();
const [language, setLanguage] = useState(i18n.language || "gb");
const handleChange = (event) => {
const newLang = event.target.value;
setLanguage(newLang);
i18n.changeLanguage(newLang);
};
// i18n instance'ından mevcut dilleri al
const languages = Object.keys(i18n.options.resources || {});
return (
<Select
value={language}
onChange={handleChange}
size="small"
sx={{
height: 28,
width: 64,
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
borderRadius: theme.shape.borderRadius,
fontSize: 10,
"& .MuiOutlinedInput-notchedOutline": {
borderColor: theme.palette.primary.lowContrast,
borderRadius: theme.shape.borderRadius,
},
"&:hover .MuiOutlinedInput-notchedOutline": {
borderColor: theme.palette.primary.lowContrast,
},
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
borderColor: theme.palette.primary.lowContrast,
},
"& .MuiSvgIcon-root": {
color: theme.palette.primary.contrastText,
width: 16,
height: 16,
right: 4,
top: "calc(50% - 8px)",
},
"& .MuiSelect-select": {
padding: "2px 20px 2px 8px",
display: "flex",
alignItems: "center",
fontSize: 10,
},
}}
MenuProps={{
PaperProps: {
sx: {
backgroundColor: theme.palette.primary.main,
borderRadius: theme.shape.borderRadius,
marginTop: 1,
width: 64,
"& .MuiMenuItem-root": {
padding: "2px 8px",
minHeight: 28,
fontSize: 10,
},
},
},
anchorOrigin: {
vertical: "bottom",
horizontal: "left",
},
transformOrigin: {
vertical: "top",
horizontal: "left",
},
}}
>
{languages.map((lang) => (
<MenuItem
key={lang}
value={lang}
sx={{
color: theme.palette.primary.contrastText,
"&:hover": {
backgroundColor: theme.palette.primary.lowContrast,
},
"&.Mui-selected": {
backgroundColor: theme.palette.primary.lowContrast,
"&:hover": {
backgroundColor: theme.palette.primary.lowContrast,
},
},
}}
>
<Stack
direction="row"
spacing={2}
alignItems="center"
ml={0.5}
>
<Box
component="span"
sx={{
width: 16,
height: 12,
display: "flex",
alignItems: "center",
"& img": {
width: "100%",
height: "100%",
objectFit: "cover",
borderRadius: 0.5,
},
}}
>
<Flag code={lang.toUpperCase()} />
</Box>
<Box
component="span"
sx={{ textTransform: "uppercase", fontSize: 10 }}
>
{lang}
</Box>
</Stack>
</MenuItem>
))}
</Select>
);
};
export default LanguageSelector;
@@ -3,6 +3,7 @@ import { Box, Button, Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import TextInput from "../../../../Components/Inputs/TextInput";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
/**
* Renders the email step of the login process which includes an email field.
@@ -18,6 +19,7 @@ import PropTypes from "prop-types";
const EmailStep = ({ form, errors, onSubmit, onChange }) => {
const theme = useTheme();
const inputRef = useRef(null);
const { t } = useTranslation();
useEffect(() => {
if (inputRef.current) {
@@ -33,8 +35,8 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => {
position="relative"
>
<Box>
<Typography component="h1">Log In</Typography>
<Typography>Enter your email address</Typography>
<Typography component="h1">{t("authLoginTitle")}</Typography>
<Typography>{t("authLoginEnterEmail")}</Typography>
</Box>
<Box
textAlign="left"
@@ -48,7 +50,7 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => {
<TextInput
type="email"
id="login-email-input"
label="Email"
label={t("email")}
isRequired={true}
placeholder="jordan.ellis@domain.com"
autoComplete="email"
@@ -77,7 +79,7 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => {
},
}}
>
Continue
{t("continue")}
</Button>
</Stack>
</Box>
@@ -1,10 +1,12 @@
import { Box, Typography, useTheme } from "@mui/material";
import PropTypes from "prop-types";
import { useNavigate } from "react-router";
import { useTranslation } from "react-i18next";
const ForgotPasswordLabel = ({ email, errorEmail }) => {
const theme = useTheme();
const navigate = useNavigate();
const { t } = useTranslation();
const handleNavigate = () => {
if (email !== "" && !errorEmail) {
@@ -20,7 +22,7 @@ const ForgotPasswordLabel = ({ email, errorEmail }) => {
display="inline-block"
color={theme.palette.primary.main}
>
Forgot password?
{t("authForgotPasswordTitle")}
</Typography>
<Typography
component="span"
@@ -29,15 +31,15 @@ const ForgotPasswordLabel = ({ email, errorEmail }) => {
sx={{ userSelect: "none" }}
onClick={handleNavigate}
>
Reset password
{t("authForgotPasswordResetPassword")}
</Typography>
</Box>
);
};
ForgotPasswordLabel.proptype = {
ForgotPasswordLabel.propTypes = {
email: PropTypes.string.isRequired,
emailError: PropTypes.string.isRequired,
errorEmail: PropTypes.string.isRequired,
};
export default ForgotPasswordLabel;
@@ -7,7 +7,7 @@ import TextInput from "../../../../Components/Inputs/TextInput";
import { PasswordEndAdornment } from "../../../../Components/Inputs/TextInput/Adornments";
import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
/**
* Renders the password step of the login process, including a password input field.
*
@@ -23,6 +23,7 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
const theme = useTheme();
const inputRef = useRef(null);
const authState = useSelector((state) => state.auth);
const { t } = useTranslation();
useEffect(() => {
if (inputRef.current) {
@@ -38,8 +39,8 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
textAlign="center"
>
<Box>
<Typography component="h1">Log In</Typography>
<Typography>Enter your password</Typography>
<Typography component="h1">{t("authLoginTitle")}</Typography>
<Typography>{t("authLoginEnterPassword")}</Typography>
</Box>
<Box
component="form"
@@ -56,7 +57,7 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
<TextInput
type="password"
id="login-password-input"
label="Password"
label={t("password")}
isRequired={true}
placeholder="••••••••••"
autoComplete="current-password"
@@ -87,7 +88,7 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
}}
>
<ArrowBackRoundedIcon />
Back
{t("commonBack")}{" "}
</Button>
<LoadingButton
variant="contained"
@@ -104,7 +105,7 @@ const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => {
},
}}
>
Continue
{t("continue")}
</LoadingButton>
</Stack>
</Box>
+18 -5
View File
@@ -15,6 +15,7 @@ import EmailStep from "./Components/EmailStep";
import PasswordStep from "./Components/PasswordStep";
import ThemeSwitch from "../../../Components/ThemeSwitch";
import ForgotPasswordLabel from "./Components/ForgotPasswordLabel";
import LanguageSelector from "../../../Components/LanguageSelector";
const DEMO = import.meta.env.VITE_APP_DEMO;
@@ -163,11 +164,26 @@ const Login = () => {
<Stack
direction="row"
alignItems="center"
justifyContent="space-between"
px={theme.spacing(12)}
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>Checkmate</Typography>
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>Checkmate</Typography>
</Stack>
<Stack
direction="row"
spacing={2}
alignItems="center"
>
<LanguageSelector />
<ThemeSwitch />
</Stack>
</Stack>
<Stack
width="100%"
@@ -213,9 +229,6 @@ const Login = () => {
email={form.email}
errorEmail={errors.email}
/>
<Box marginX={"auto"}>
<ThemeSwitch />
</Box>
</Stack>
</Stack>
);
+13 -8
View File
@@ -15,7 +15,7 @@ import Background from "../../../assets/Images/background-grid.svg?react";
import Logo from "../../../assets/icons/checkmate-icon.svg?react";
import Mail from "../../../assets/icons/mail.svg?react";
import "../index.css";
import { useTranslation } from "react-i18next";
/**
* Displays the initial landing page.
*
@@ -26,7 +26,7 @@ import "../index.css";
*/
const LandingPage = ({ isSuperAdmin, onSignup }) => {
const theme = useTheme();
const { t } = useTranslation();
return (
<>
<Stack
@@ -37,7 +37,9 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
<Box>
<Typography component="h1">Sign Up</Typography>
<Typography>
Create your {isSuperAdmin ? "Super admin " : ""}account to get started.
{isSuperAdmin
? t("authRegisterCreateSuperAdminAccount")
: t("authRegisterCreateAccount")}
</Typography>
</Box>
<Box width="100%">
@@ -60,12 +62,12 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
}}
>
<Mail />
Sign up with Email
{t("authRegisterSignUpWithEmail")}
</Button>
</Box>
<Box maxWidth={400}>
<Typography className="tos-p">
By signing up, you agree to our{" "}
{t("authRegisterBySigningUp")}
<Typography
component="span"
onClick={() => {
@@ -118,6 +120,7 @@ const Register = ({ isSuperAdmin }) => {
const navigate = useNavigate();
const { token } = useParams();
const theme = useTheme();
const { t } = useTranslation();
// TODO If possible, change the IDs of these fields to match the backend
const idMap = {
"register-firstname-input": "firstName",
@@ -307,7 +310,7 @@ const Register = ({ isSuperAdmin }) => {
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>Checkmate</Typography>
<Typography sx={{ userSelect: "none" }}>{t("commonAppName")}</Typography>
</Stack>
<Stack
width="100%"
@@ -367,7 +370,9 @@ const Register = ({ isSuperAdmin }) => {
textAlign="center"
p={theme.spacing(12)}
>
<Typography display="inline-block">Already have an account? —</Typography>
<Typography display="inline-block">
{t("authRegisterAlreadyHaveAccount")} -
</Typography>
<Typography
component="span"
ml={theme.spacing(2)}
@@ -376,7 +381,7 @@ const Register = ({ isSuperAdmin }) => {
}}
sx={{ userSelect: "none", color: theme.palette.primary.main }}
>
Log In
{t("authLoginTitle")}
</Typography>
</Box>
</Stack>
@@ -6,7 +6,7 @@ import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
import TextInput from "../../../../Components/Inputs/TextInput";
import Check from "../../../../Components/Check/Check";
import { useValidatePassword } from "../../hooks/useValidatePassword";
import { useTranslation } from "react-i18next";
StepThree.propTypes = {
onSubmit: PropTypes.func,
onBack: PropTypes.func,
@@ -23,6 +23,7 @@ StepThree.propTypes = {
function StepThree({ onSubmit, onBack }) {
const theme = useTheme();
const inputRef = useRef(null);
const { t } = useTranslation();
useEffect(() => {
if (inputRef.current) {
@@ -38,8 +39,8 @@ function StepThree({ onSubmit, onBack }) {
textAlign="center"
>
<Box>
<Typography component="h1">Sign Up</Typography>
<Typography>Create your password</Typography>
<Typography component="h1">{t("signUp")}</Typography>
<Typography>{t("createPassword")}</Typography>
</Box>
<Box
component="form"
@@ -63,9 +64,9 @@ function StepThree({ onSubmit, onBack }) {
type="password"
id="register-password-input"
name="password"
label="Password"
label={t("commonPassword")}
isRequired={true}
placeholder="Create a password"
placeholder={t("createAPassword")}
autoComplete="current-password"
value={form.password}
onChange={handleChange}
@@ -76,9 +77,9 @@ function StepThree({ onSubmit, onBack }) {
type="password"
id="register-confirm-input"
name="confirm"
label="Confirm password"
label={t("authSetNewPasswordConfirmPassword")}
isRequired={true}
placeholder="Confirm your password"
placeholder={t("confirmPassword")}
autoComplete="current-password"
value={form.confirm}
onChange={handleChange}
@@ -90,33 +91,33 @@ function StepThree({ onSubmit, onBack }) {
mb={{ xs: theme.spacing(6), sm: theme.spacing(8) }}
>
<Check
noHighlightText={"Must be at least"}
text={"8 characters long"}
noHighlightText={t("authPasswordMustBeAtLeast")}
text={t("authPasswordCharactersLong")}
variant={feedbacks.length}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one special character"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordSpecialCharacter")}
variant={feedbacks.special}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one number"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordOneNumber")}
variant={feedbacks.number}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one upper character"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordUpperCharacter")}
variant={feedbacks.uppercase}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one lower character"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordLowerCharacter")}
variant={feedbacks.lowercase}
/>
<Check
noHighlightText={"Confirm password and password"}
text={"must match"}
noHighlightText={t("authPasswordConfirmAndPassword")}
text={t("authPasswordMustMatch")}
variant={feedbacks.confirm}
/>
</Stack>
@@ -140,7 +141,7 @@ function StepThree({ onSubmit, onBack }) {
}}
>
<ArrowBackRoundedIcon />
Back
{t("commonBack")}
</Button>
<Button
type="submit"
@@ -160,7 +161,7 @@ function StepThree({ onSubmit, onBack }) {
},
}}
>
Continue
{t("continue")}
</Button>
</Stack>
</Box>
@@ -4,6 +4,7 @@ import { useTheme } from "@emotion/react";
import { Box, Button, Stack, Typography } from "@mui/material";
import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
import TextInput from "../../../../Components/Inputs/TextInput";
import { useTranslation } from "react-i18next";
StepTwo.propTypes = {
form: PropTypes.object,
@@ -27,6 +28,7 @@ StepTwo.propTypes = {
function StepTwo({ form, errors, onSubmit, onChange, onBack }) {
const theme = useTheme();
const inputRef = useRef(null);
const { t } = useTranslation();
useEffect(() => {
if (inputRef.current) {
@@ -41,8 +43,8 @@ function StepTwo({ form, errors, onSubmit, onChange, onBack }) {
textAlign="center"
>
<Box>
<Typography component="h1">Sign Up</Typography>
<Typography>Enter your email address</Typography>
<Typography component="h1">{t("signUp")}</Typography>
<Typography>{t("enterEmail")}</Typography>
</Box>
<Box
@@ -58,7 +60,7 @@ function StepTwo({ form, errors, onSubmit, onChange, onBack }) {
<TextInput
type="email"
id="register-email-input"
label="Email"
label={t("commonEmail")}
isRequired={true}
placeholder="jordan.ellis@domain.com"
autoComplete="email"
@@ -89,7 +91,7 @@ function StepTwo({ form, errors, onSubmit, onChange, onBack }) {
}}
>
<ArrowBackRoundedIcon />
Back
{t("commonBack")}
</Button>
<Button
variant="contained"
@@ -105,7 +107,7 @@ function StepTwo({ form, errors, onSubmit, onChange, onBack }) {
},
}}
>
Continue
{t("continue")}
</Button>
</Stack>
</Box>
+22 -22
View File
@@ -17,11 +17,13 @@ import Logo from "../../assets/icons/checkmate-icon.svg?react";
import Background from "../../assets/Images/background-grid.svg?react";
import "./index.css";
import { useValidatePassword } from "./hooks/useValidatePassword";
import { useTranslation } from "react-i18next";
const SetNewPassword = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const theme = useTheme();
const { t } = useTranslation();
const passwordId = useId();
const confirmPasswordId = useId();
@@ -97,7 +99,7 @@ const SetNewPassword = () => {
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>Checkmate</Typography>
<Typography sx={{ userSelect: "none" }}>{t("commonAppName")}</Typography>
</Stack>
<Stack
width="100%"
@@ -142,10 +144,8 @@ const SetNewPassword = () => {
<LockIcon alt="lock icon" />
</IconBox>
</Stack>
<Typography component="h1">Set new password</Typography>
<Typography>
Your new password must be different to previously used passwords.
</Typography>
<Typography component="h1">{t("authSetNewPasswordTitle")}</Typography>
<Typography>{t("authSetNewPasswordDescription")}</Typography>
</Box>
<Box
width="100%"
@@ -166,7 +166,7 @@ const SetNewPassword = () => {
id={passwordId}
type="password"
name="password"
label="Password"
label={t("commonPassword")}
isRequired={true}
placeholder="••••••••"
value={form.password}
@@ -186,7 +186,7 @@ const SetNewPassword = () => {
id={confirmPasswordId}
type="password"
name="confirm"
label="Confirm password"
label={t("authSetNewPasswordConfirmPassword")}
isRequired={true}
placeholder="••••••••"
value={form.confirm}
@@ -201,33 +201,33 @@ const SetNewPassword = () => {
mb={theme.spacing(12)}
>
<Check
noHighlightText={"Must be at least"}
text={"8 characters long"}
noHighlightText={t("authPasswordMustBeAtLeast")}
text={t("authPasswordCharactersLong")}
variant={feedbacks.length}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one special character"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordSpecialCharacter")}
variant={feedbacks.special}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one number"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordOneNumber")}
variant={feedbacks.number}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one upper character"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordUpperCharacter")}
variant={feedbacks.uppercase}
/>
<Check
noHighlightText={"Must contain at least"}
text={"one lower character"}
noHighlightText={t("authPasswordMustContainAtLeast")}
text={t("authPasswordLowerCharacter")}
variant={feedbacks.lowercase}
/>
<Check
noHighlightText={"Confirm password and password"}
text={"must match"}
noHighlightText={t("authPasswordConfirmAndPassword")}
text={t("authPasswordMustMatch")}
variant={feedbacks.confirm}
/>
</Stack>
@@ -244,7 +244,7 @@ const SetNewPassword = () => {
}
sx={{ width: "100%", maxWidth: 400 }}
>
Reset password
{t("authSetNewPasswordResetPassword")}
</LoadingButton>
</Stack>
</Stack>
@@ -252,7 +252,7 @@ const SetNewPassword = () => {
textAlign="center"
p={theme.spacing(12)}
>
<Typography display="inline-block">Go back to —</Typography>
<Typography display="inline-block">{t("goBackTo")} —</Typography>
<Typography
component="span"
color={theme.palette.primary.main}
@@ -260,7 +260,7 @@ const SetNewPassword = () => {
onClick={() => navigate("/login")}
sx={{ userSelect: "none" }}
>
Log In
{t("authLoginTitle")}
</Typography>
</Box>
</Stack>
+16
View File
@@ -1,4 +1,5 @@
import axios from "axios";
import i18next from 'i18next';
const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL;
const FALLBACK_BASE_URL = "http://localhost:5000/api/v1";
import { clearAuthState } from "../Features/Auth/authSlice";
@@ -23,6 +24,21 @@ class NetworkService {
}
this.setBaseUrl(baseURL);
});
this.axiosInstance.interceptors.request.use(
(config) => {
const currentLanguage = i18next.language || 'en';
config.headers = {
...config.headers,
"Accept-Language": currentLanguage,
};
return config;
},
(error) => {
return Promise.reject(error);
}
);
this.axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
+36
View File
@@ -0,0 +1,36 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
const primaryLanguage = 'gb';
const translations = import.meta.glob('../locales/*.json', { eager: true });
const resources = {};
Object.keys(translations).forEach((path) => {
const langCode = path.match(/\/([^/]+)\.json$/)[1];
resources[langCode] = {
translation: translations[path].default || translations[path]
};
});
const savedLanguage = localStorage.getItem("language") || primaryLanguage;
i18n
.use(initReactI18next)
.init({
resources,
lng: savedLanguage,
fallbackLng: primaryLanguage,
debug: import.meta.env.MODE === 'development',
ns: ['translation'],
defaultNS: 'translation',
interpolation: {
escapeValue: false,
},
});
i18n.on("languageChanged", (lng) => {
localStorage.setItem("language", lng);
});
export default i18n;
+59
View File
@@ -0,0 +1,59 @@
{
"dontHaveAccount": "Don't have account",
"email": "E-mail",
"forgotPassword": "Forgot Password",
"password": "password",
"signUp": "Sign up",
"submit": "Submit",
"title": "Title",
"continue": "Continue",
"enterEmail": "Enter your email",
"authLoginTitle": "Log In",
"authLoginEnterPassword": "Enter your password",
"commonPassword": "Password",
"createPassword": "Create your password",
"createAPassword": "Create a password",
"commonBack": "Back",
"authForgotPasswordTitle": "Forgot password?",
"authForgotPasswordResetPassword": "Reset password",
"authRegisterAlreadyHaveAccount": "Already have an account?",
"commonAppName": "Checkmate",
"authLoginEnterEmail": "Enter your email",
"authRegisterTitle": "Create an account",
"authRegisterStepOneTitle": "Create your account",
"authRegisterStepOneDescription": "Enter your details to get started",
"authRegisterStepTwoTitle": "Set up your profile",
"authRegisterStepTwoDescription": "Tell us more about yourself",
"authRegisterStepThreeTitle": "Almost done!",
"authRegisterStepThreeDescription": "Review your information",
"authForgotPasswordDescription": "No worries, we'll send you reset instructions.",
"authForgotPasswordSendInstructions": "Send instructions",
"authForgotPasswordBackTo": "Back to",
"authCheckEmailTitle": "Check your email",
"authCheckEmailDescription": "We sent a password reset link to {{email}}",
"authCheckEmailResendEmail": "Resend email",
"authCheckEmailBackTo": "Back to",
"goBackTo": "Go back to",
"authCheckEmailDidntReceiveEmail": "Didn't receive the email?",
"authCheckEmailClickToResend": "Click to resend",
"authSetNewPasswordTitle": "Set new password",
"authSetNewPasswordDescription": "Your new password must be different from previously used passwords.",
"authSetNewPasswordNewPassword": "New password",
"authSetNewPasswordConfirmPassword": "Confirm password",
"confirmPassword": "Confirm your password",
"authSetNewPasswordResetPassword": "Reset password",
"authSetNewPasswordBackTo": "Back to",
"authPasswordMustBeAtLeast": "Must be at least",
"authPasswordCharactersLong": "8 characters long",
"authPasswordMustContainAtLeast": "Must contain at least",
"authPasswordSpecialCharacter": "one special character",
"authPasswordOneNumber": "one number",
"authPasswordUpperCharacter": "one upper character",
"authPasswordLowerCharacter": "one lower character",
"authPasswordConfirmAndPassword": "Confirm password and password",
"authPasswordMustMatch": "must match",
"authRegisterCreateAccount": "Create your account to get started",
"authRegisterCreateSuperAdminAccount": "Create your Super admin account to get started",
"authRegisterSignUpWithEmail": "Sign up with Email",
"authRegisterBySigningUp": "By signing up, you agree to our"
}
+59
View File
@@ -0,0 +1,59 @@
{
"dontHaveAccount": "Hesabınız yok mu",
"email": "E-posta",
"forgotPassword": "Parolamı unuttum",
"password": "Parola",
"signUp": "Kayıt Ol",
"submit": "Gönder",
"title": "Başlık",
"continue": "Devam Et",
"enterEmail": "E-posta adresinizi girin",
"authLoginTitle": "Giriş Yap",
"authLoginEnterPassword": "Parolanızı girin",
"commonPassword": "Parola",
"createPassword": "Parolanızı oluşturun",
"createAPassword": "Bir parola oluşturun",
"commonBack": "Geri",
"authForgotPasswordTitle": "Parolanızı mı unuttunuz?",
"authForgotPasswordResetPassword": "Parola sıfırla",
"authRegisterAlreadyHaveAccount": "Zaten hesabınız var mı?",
"commonAppName": "Checkmate",
"authLoginEnterEmail": "E-posta adresinizi girin",
"authRegisterTitle": "Hesap oluştur",
"authRegisterStepOneTitle": "Hesabınızı oluşturun",
"authRegisterStepOneDescription": "Başlamak için bilgilerinizi girin",
"authRegisterStepTwoTitle": "Profilinizi ayarlayın",
"authRegisterStepTwoDescription": "Kendiniz hakkında daha fazla bilgi verin",
"authRegisterStepThreeTitle": "Neredeyse bitti!",
"authRegisterStepThreeDescription": "Bilgilerinizi gözden geçirin",
"authForgotPasswordDescription": "Endişelenmeyin, size sıfırlama talimatlarını göndereceğiz.",
"authForgotPasswordSendInstructions": "Talimatları gönder",
"authForgotPasswordBackTo": "Geri dön",
"authCheckEmailTitle": "E-postanızı kontrol edin",
"authCheckEmailDescription": "{{email}} adresine şifre sıfırlama bağlantısı gönderdik",
"authCheckEmailResendEmail": "E-postayı yeniden gönder",
"authCheckEmailBackTo": "Geri dön",
"goBackTo": "Geri dön",
"authCheckEmailDidntReceiveEmail": "E-posta almadınız mı?",
"authCheckEmailClickToResend": "Yeniden göndermek için tıklayın",
"authSetNewPasswordTitle": "Yeni şifre belirle",
"authSetNewPasswordDescription": "Yeni şifreniz daha önce kullanılan şifrelerden farklı olmalıdır.",
"authSetNewPasswordNewPassword": "Yeni şifre",
"authSetNewPasswordConfirmPassword": "Parolayı onayla",
"confirmPassword": "Parolanızı onaylayın",
"authSetNewPasswordResetPassword": "Parola sıfırla",
"authSetNewPasswordBackTo": "Geri dön",
"authPasswordMustBeAtLeast": "En az",
"authPasswordCharactersLong": "8 karakter uzunluğunda olmalı",
"authPasswordMustContainAtLeast": "En az içermeli",
"authPasswordSpecialCharacter": "bir özel karakter",
"authPasswordOneNumber": "bir rakam",
"authPasswordUpperCharacter": "bir büyük harf",
"authPasswordLowerCharacter": "bir küçük harf",
"authPasswordConfirmAndPassword": "Onay şifresi ve şifre",
"authPasswordMustMatch": "eşleşmelidir",
"authRegisterCreateAccount": "Hesap oluşturmak için devam et",
"authRegisterCreateSuperAdminAccount": "Super admin hesabınızı oluşturmak için devam edin",
"authRegisterSignUpWithEmail": "E-posta ile kayıt ol",
"authRegisterBySigningUp": "Kayıt olarak, aşağıdaki şartları kabul ediyorsunuz:"
}
+2 -1
View File
@@ -1,6 +1,7 @@
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import "./Utils/i18n";
import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from "react-redux";
import { persistor, store } from "./store";
@@ -17,7 +18,7 @@ ReactDOM.createRoot(document.getElementById("root")).render(
>
<Router>
<NetworkServiceProvider>
<App />
<App />
</NetworkServiceProvider>
</Router>
</PersistGate>