Multi-language/I18n support #22

This commit is contained in:
Proddy
2022-08-24 21:50:19 +02:00
parent 763337db3f
commit 1a4ce643fc
84 changed files with 5506 additions and 4196 deletions

View File

@@ -1,8 +1,8 @@
import { FC, useContext, useState } from 'react';
import { FC, useContext, useState, ChangeEventHandler } from 'react';
import { ValidateFieldsError } from 'async-validator';
import { useSnackbar } from 'notistack';
import { Box, Fab, Paper, Typography } from '@mui/material';
import { Box, Fab, Paper, Typography, MenuItem } from '@mui/material';
import ForwardIcon from '@mui/icons-material/Forward';
import * as AuthenticationApi from './api/authentication';
@@ -16,6 +16,11 @@ import { SignInRequest } from './types';
import { ValidatedTextField } from './components';
import { SIGN_IN_REQUEST_VALIDATOR, validate } from './validators';
import { I18nContext } from './i18n/i18n-react';
import type { Locales } from './i18n/i18n-types';
import { locales } from './i18n/i18n-util';
import { loadLocaleAsync } from './i18n/i18n-util.async';
const SignIn: FC = () => {
const authenticationContext = useContext(AuthenticationContext);
const { enqueueSnackbar } = useSnackbar();
@@ -31,6 +36,9 @@ const SignIn: FC = () => {
const validateAndSignIn = async () => {
setProcessing(true);
SIGN_IN_REQUEST_VALIDATOR.messages({
required: '%s ' + LL.IS_REQUIRED()
});
try {
await validate(SIGN_IN_REQUEST_VALIDATOR, signInRequest);
signIn();
@@ -47,7 +55,7 @@ const SignIn: FC = () => {
} catch (error: unknown) {
if (error instanceof AxiosError) {
if (error.response?.status === 401) {
enqueueSnackbar('Invalid login details', { variant: 'warning' });
enqueueSnackbar(LL.INVALID_LOGIN(), { variant: 'warning' });
}
} else {
enqueueSnackbar(extractErrorMessage(error, 'Unexpected error, please try again'), { variant: 'error' });
@@ -58,6 +66,15 @@ const SignIn: FC = () => {
const submitOnEnter = onEnterCallback(signIn);
const { locale, LL, setLocale } = useContext(I18nContext);
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({ target }) => {
const loc = target.value as Locales;
localStorage.setItem('lang', loc);
await loadLocaleAsync(loc);
setLocale(loc);
};
return (
<Box
display="flex"
@@ -81,11 +98,33 @@ const SignIn: FC = () => {
})}
>
<Typography variant="h4">{PROJECT_NAME}</Typography>
<Box
sx={{
'& .MuiTextField-root': { m: 2, width: '15ch' }
}}
>
<ValidatedTextField
name="locale"
label={LL.LANGUAGE()}
variant="outlined"
value={locale || ''}
onChange={onLocaleSelected}
margin="normal"
size="small"
select
>
{locales.map((loc) => (
<MenuItem key={loc} value={loc}>
{loc}
</MenuItem>
))}
</ValidatedTextField>
</Box>
<ValidatedTextField
fieldErrors={fieldErrors}
disabled={processing}
name="username"
label="Username"
label={LL.USERNAME()}
value={signInRequest.username}
onChange={updateLoginRequestValue}
margin="normal"
@@ -97,7 +136,7 @@ const SignIn: FC = () => {
disabled={processing}
type="password"
name="password"
label="Password"
label={LL.PASSWORD()}
value={signInRequest.password}
onChange={updateLoginRequestValue}
onKeyDown={submitOnEnter}
@@ -107,7 +146,7 @@ const SignIn: FC = () => {
/>
<Fab variant="extended" color="primary" sx={{ mt: 2 }} onClick={validateAndSignIn} disabled={processing}>
<ForwardIcon sx={{ mr: 1 }} />
Sign In
{LL.SIGN_IN()}
</Fab>
</Paper>
</Box>