aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2021-09-02 20:33:23 -0700
committerAnton Tananaev <anton.tananaev@gmail.com>2021-09-02 20:33:23 -0700
commite07d5ff079527da0c07c4f8ede0aaef272517393 (patch)
tree1941791e4b8ab4b98c3eeefb5e0d00b34ff1bec0
parent2b34c3d6c00c29b1590403e5d62e18b91145abcc (diff)
parent363198118bba28ad3a37e200a7db2ca02bf2eae7 (diff)
downloadetbsa-traccar-web-e07d5ff079527da0c07c4f8ede0aaef272517393.tar.gz
etbsa-traccar-web-e07d5ff079527da0c07c4f8ede0aaef272517393.tar.bz2
etbsa-traccar-web-e07d5ff079527da0c07c4f8ede0aaef272517393.zip
Merge into oyhan-master
-rw-r--r--modern/src/App.js87
-rw-r--r--modern/src/common/localization.js45
-rw-r--r--modern/src/components/registration/LoginForm.js21
3 files changed, 98 insertions, 55 deletions
diff --git a/modern/src/App.js b/modern/src/App.js
index ac7cdb2..5143ad8 100644
--- a/modern/src/App.js
+++ b/modern/src/App.js
@@ -38,53 +38,56 @@ import ResetPasswordForm from './components/registration/ResetPasswordForm';
import theme from './theme';
import GeofencesPage from './GeofencesPage';
import GeofencePage from './GeofencePage';
+import { LocalizationProvider } from './common/localization';
const App = () => {
const initialized = useSelector((state) => !!state.session.server && !!state.session.user);
return (
- <ThemeProvider theme={theme}>
- <CssBaseline />
- <SocketController />
- <CachingController />
- <Switch>
- <Route exact path="/login" component={LoginForm} />
- <Route exact path="/register" component={RegisterForm} />
- <Route exact path="/reset-password" component={ResetPasswordForm} />
- <Route>
- {!initialized ? (<LinearProgress />) : (
- <Switch>
- <Route exact path="/" component={MainPage} />
- <Route exact path="/replay" component={ReplayPage} />
- <Route exact path="/position/:id?" component={PositionPage} />
- <Route exact path="/user/:id?" component={UserPage} />
- <Route exact path="/device/:id?" component={DevicePage} />
- <Route exact path="/geofence/:id?" component={GeofencePage} />
- <Route exact path="/geofences" component={GeofencesPage} />
- <Route exact path="/settings/notifications" component={NotificationsPage} />
- <Route exact path="/settings/notification/:id?" component={NotificationPage} />
- <Route exact path="/settings/groups" component={GroupsPage} />
- <Route exact path="/settings/group/:id?" component={GroupPage} />
- <Route exact path="/settings/drivers" component={DriversPage} />
- <Route exact path="/settings/driver/:id?" component={DriverPage} />
- <Route exact path="/settings/attributes" component={ComputedAttributesPage} />
- <Route exact path="/settings/attribute/:id?" component={ComputedAttributePage} />
- <Route exact path="/settings/maintenances" component={MaintenancesPage} />
- <Route exact path="/settings/maintenance/:id?" component={MaintenancePage} />
- <Route exact path="/admin/server" component={ServerPage} />
- <Route exact path="/admin/users" component={UsersPage} />
- <Route exact path="/admin/statistics" component={StatisticsPage} />
- <Route exact path="/reports/route" component={RouteReportPage} />
- <Route exact path="/reports/event" component={EventReportPage} />
- <Route exact path="/reports/trip" component={TripReportPage} />
- <Route exact path="/reports/stop" component={StopReportPage} />
- <Route exact path="/reports/summary" component={SummaryReportPage} />
- <Route exact path="/reports/chart" component={ChartReportPage} />
- </Switch>
- )}
- </Route>
- </Switch>
- </ThemeProvider>
+ <LocalizationProvider>
+ <ThemeProvider theme={theme}>
+ <CssBaseline />
+ <SocketController />
+ <CachingController />
+ <Switch>
+ <Route exact path="/login" component={LoginForm} />
+ <Route exact path="/register" component={RegisterForm} />
+ <Route exact path="/reset-password" component={ResetPasswordForm} />
+ <Route>
+ {!initialized ? (<LinearProgress />) : (
+ <Switch>
+ <Route exact path="/" component={MainPage} />
+ <Route exact path="/replay" component={ReplayPage} />
+ <Route exact path="/position/:id?" component={PositionPage} />
+ <Route exact path="/user/:id?" component={UserPage} />
+ <Route exact path="/device/:id?" component={DevicePage} />
+ <Route exact path="/geofence/:id?" component={GeofencePage} />
+ <Route exact path="/geofences" component={GeofencesPage} />
+ <Route exact path="/settings/notifications" component={NotificationsPage} />
+ <Route exact path="/settings/notification/:id?" component={NotificationPage} />
+ <Route exact path="/settings/groups" component={GroupsPage} />
+ <Route exact path="/settings/group/:id?" component={GroupPage} />
+ <Route exact path="/settings/drivers" component={DriversPage} />
+ <Route exact path="/settings/driver/:id?" component={DriverPage} />
+ <Route exact path="/settings/attributes" component={ComputedAttributesPage} />
+ <Route exact path="/settings/attribute/:id?" component={ComputedAttributePage} />
+ <Route exact path="/settings/maintenances" component={MaintenancesPage} />
+ <Route exact path="/settings/maintenance/:id?" component={MaintenancePage} />
+ <Route exact path="/admin/server" component={ServerPage} />
+ <Route exact path="/admin/users" component={UsersPage} />
+ <Route exact path="/admin/statistics" component={StatisticsPage} />
+ <Route exact path="/reports/route" component={RouteReportPage} />
+ <Route exact path="/reports/event" component={EventReportPage} />
+ <Route exact path="/reports/trip" component={TripReportPage} />
+ <Route exact path="/reports/stop" component={StopReportPage} />
+ <Route exact path="/reports/summary" component={SummaryReportPage} />
+ <Route exact path="/reports/chart" component={ChartReportPage} />
+ </Switch>
+ )}
+ </Route>
+ </Switch>
+ </ThemeProvider>
+ </LocalizationProvider>
);
};
diff --git a/modern/src/common/localization.js b/modern/src/common/localization.js
index 9e2123a..90a5739 100644
--- a/modern/src/common/localization.js
+++ b/modern/src/common/localization.js
@@ -1,3 +1,5 @@
+import React, { useState, createContext, useContext } from "react";
+
import af from '../../../web/l10n/af.json';
import ar from '../../../web/l10n/ar.json';
import az from '../../../web/l10n/az.json';
@@ -110,8 +112,9 @@ const supportedLanguages = {
zh_TW: { data: zh_TW, name: '中文 (Taiwan)' },
};
-const languages = window.navigator.languages !== undefined ? window.navigator.languages.slice() : [];
-let language = window.navigator.userLanguage || window.navigator.language;
+const languageList = Object.entries(supportedLanguages).map((values) => ({ code: values[0], name: values[1].name }));
+const languages = localStorage.getItem('language') ? [localStorage.getItem('language')] : (window.navigator.languages !== undefined ? window.navigator.languages.slice() : []);
+let language = localStorage.getItem('language') || window.navigator.userLanguage || window.navigator.language;
languages.push(language);
languages.push(language.substring(0, 2));
languages.push('en');
@@ -128,8 +131,40 @@ for (let i = 0; i < languages.length; i++) {
}
}
-const selectedLanguage = supportedLanguages[language];
+let selectedLanguage = supportedLanguages[language];
+
+export const findStringKeys = (predicate) => {
+ return Object.keys(selectedLanguage.data).filter(predicate);
+}
+
+export default key => {
+ return selectedLanguage.data[key];
+};
+
+const setSelectedLanguage = (language) => {
+ selectedLanguage = supportedLanguages[language];
+ localStorage.setItem('language', language);
+}
+
+const defaultLanguage = language;
+
+const LocalizationContext = createContext({
+ language
+});
-export const findStringKeys = (predicate) => Object.keys(selectedLanguage.data).filter(predicate);
+export function LocalizationProvider(props) {
+ const [language, setLanguage] = useState(defaultLanguage);
+
+ const handleLanguageChange = (nextLanguage) => {
+ setSelectedLanguage(nextLanguage);
+ setLanguage(nextLanguage);
+ };
+
+ return <LocalizationContext.Provider value={{ language, setLanguage: handleLanguageChange, languageList }}>
+ {props.children}
+ </LocalizationContext.Provider>
+}
-export default (key) => selectedLanguage.data[key];
+export const useLocalization = () => {
+ return useContext(LocalizationContext);
+} \ No newline at end of file
diff --git a/modern/src/components/registration/LoginForm.js b/modern/src/components/registration/LoginForm.js
index e6da05e..9b5ca3e 100644
--- a/modern/src/components/registration/LoginForm.js
+++ b/modern/src/components/registration/LoginForm.js
@@ -6,7 +6,7 @@ import { useTheme } from '@material-ui/core/styles';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { sessionActions } from '../../store';
-import t from '../../common/localization';
+import t, { useLocalization } from '../../common/localization';
import StartPage from '../../StartPage';
const useStyles = makeStyles((theme) => ({
@@ -24,6 +24,7 @@ const LoginForm = () => {
const dispatch = useDispatch();
const history = useHistory();
const theme = useTheme();
+ const { language, languageList, setLanguage } = useLocalization();
const [failed, setFailed] = useState(false);
const [email, setEmail] = useState('');
@@ -61,16 +62,20 @@ const LoginForm = () => {
}
};
+ const handleLanguageChange = (e) => {
+ setLanguage(e.target.value);
+ };
+
return (
<StartPage>
<Grid container direction="column" spacing={2}>
{useMediaQuery(theme.breakpoints.down('md'))
&& (
- <Grid item className={classes.logoContainer}>
- <svg height="64" width="240">
- <use xlinkHref="/logo.svg#img" />
- </svg>
- </Grid>
+ <Grid item className={classes.logoContainer}>
+ <svg height="64" width="240">
+ <use xlinkHref="/logo.svg#img" />
+ </svg>
+ </Grid>
)}
<Grid item>
<TextField
@@ -124,8 +129,8 @@ const LoginForm = () => {
<Grid item xs>
<FormControl variant="filled" fullWidth>
<InputLabel>{t('loginLanguage')}</InputLabel>
- <Select>
- <MenuItem value="en">English</MenuItem>
+ <Select value={language} onChange={handleLanguageChange}>
+ {languageList.map((lang) => <MenuItem key={lang.code} value={lang.code}>{lang.name}</MenuItem>)}
</Select>
</FormControl>
</Grid>