Skip to content

Commit

Permalink
Translation support (i18next) + Translation DE (#273)
Browse files Browse the repository at this point in the history
* Translation support (i18next) + Translation DE

* sign CLA

* update: Implemented all Requested Changes
- updated all trans-keys
- included support for dayjs
- all other minor change-requests
- some more keys/translations included

* update: minor Bugfixes + Improvements
- fixed some wrong references
- disabled debugging (i18next)
- switched to lazy loadable backend (i18next)
- more translations
- fixed unnecessary uses of Trans-Component (now uses t-func)

If you want this commit to be squashed, send me a msg.

* update: incl. de-CH, better dayjs
- include locale de-CH
- better handling of dayjs (works but WIP, see comments in code)
  • Loading branch information
madejackson authored Aug 1, 2024
1 parent 1f39e48 commit 560d5a3
Show file tree
Hide file tree
Showing 100 changed files with 2,581 additions and 1,023 deletions.
2 changes: 1 addition & 1 deletion .clabot
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"contributors": ["azukaar", "jwr1", "Jogai", "InterN0te", "catmandx", "revam", "Kawanaao", "davis4acca", "george-radu-cs"],
"contributors": ["azukaar", "jwr1", "Jogai", "InterN0te", "catmandx", "revam", "Kawanaao", "davis4acca", "george-radu-cs", "madejackson"],
"message": "We require contributors to sign our [Contributor License Agreement](https://github.com/azukaar/Cosmos-Server/blob/master/cla.md). In order for us to review and merge your code, add yourself to the .clabot file as contributor, as a way of signing the CLA."
}
8 changes: 5 additions & 3 deletions client/src/components/@extended/Breadcrumbs.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import { useEffect, useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';

// material-ui
import MuiBreadcrumbs from '@mui/material/Breadcrumbs';
Expand All @@ -12,6 +13,7 @@ import MainCard from '../MainCard';
// ==============================|| BREADCRUMBS ||============================== //

const Breadcrumbs = ({ navigation, title, ...others }) => {
const { t } = useTranslation();
const location = useLocation();
const [main, setMain] = useState();
const [item, setItem] = useState();
Expand Down Expand Up @@ -65,7 +67,7 @@ const Breadcrumbs = ({ navigation, title, ...others }) => {
if (main && main.type === 'collapse') {
mainContent = (
<Typography component={Link} to={document.location.pathname} variant="h6" sx={{ textDecoration: 'none' }} color="textSecondary">
{main.title}
{t(main.title)}
</Typography>
);
}
Expand All @@ -75,7 +77,7 @@ const Breadcrumbs = ({ navigation, title, ...others }) => {
itemTitle = item.title;
itemContent = (
<Typography variant="subtitle1" color="textPrimary">
{itemTitle}
{t(itemTitle)}
</Typography>
);

Expand All @@ -97,7 +99,7 @@ const Breadcrumbs = ({ navigation, title, ...others }) => {
</Grid>
{title && (
<Grid item sx={{ mt: 2 }}>
<Typography variant="h5">{item.title}</Typography>
<Typography variant="h5">{t(item.title)}</Typography>
</Grid>
)}
</Grid>
Expand Down
6 changes: 4 additions & 2 deletions client/src/components/apiModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import * as React from 'react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

const preStyle = {
backgroundColor: '#000',
Expand Down Expand Up @@ -40,6 +41,7 @@ const preStyle = {
}

const ApiModal = ({ callback, label }) => {
const { t } = useTranslation();
const [openModal, setOpenModal] = useState(false);
const [content, setContent] = useState("");
const [loading, setLoading] = useState(true);
Expand All @@ -58,7 +60,7 @@ const ApiModal = ({ callback, label }) => {

return <>
<Dialog open={openModal} onClose={() => setOpenModal(false)} fullWidth maxWidth={'sm'}>
<DialogTitle>Refresh Page</DialogTitle>
<DialogTitle>{t('global.refreshPage')}</DialogTitle>
<DialogContent>
<DialogContentText>
<pre style={preStyle}>
Expand All @@ -71,7 +73,7 @@ const ApiModal = ({ callback, label }) => {
loading={loading}
onClick={() => {
getContent();
}}>Refresh</LoadingButton>
}}>{t('global.refresh')}</LoadingButton>
<Button onClick={() => {
setOpenModal(false);
}}>Close</Button>
Expand Down
12 changes: 7 additions & 5 deletions client/src/components/confirmModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import * as React from 'react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

const ConfirmModal = ({ callback, label, content, startIcon }) => {
const { t } = useTranslation();
const [openModal, setOpenModal] = useState(false);

return <>
Expand All @@ -23,12 +25,12 @@ const ConfirmModal = ({ callback, label, content, startIcon }) => {
<DialogActions>
<Button onClick={() => {
setOpenModal(false);
}}>Cancel</Button>
}}>{t('global.cancelAction')}</Button>
<LoadingButton
onClick={() => {
callback();
setOpenModal(false);
}}>Confirm</LoadingButton>
}}>{t('global.confirmAction')}</LoadingButton>
</DialogActions>
</Dialog>

Expand All @@ -55,7 +57,7 @@ const ConfirmModalDirect = ({ callback, content, onClose }) => {
onClose && onClose();
setOpenModal(false);
}}>
<DialogTitle>Are you sure?</DialogTitle>
<DialogTitle>{t('global.confirmDeletion')}</DialogTitle>
<DialogContent>
<DialogContentText>
{content}
Expand All @@ -65,13 +67,13 @@ const ConfirmModalDirect = ({ callback, content, onClose }) => {
<Button onClick={() => {
setOpenModal(false);
onClose && onClose();
}}>Cancel</Button>
}}>{t('global.cancelAction')}</Button>
<LoadingButton
onClick={() => {
callback();
setOpenModal(false);
onClose && onClose();
}}>Confirm</LoadingButton>
}}>{t('global.confirmAction')}</LoadingButton>
</DialogActions>
</Dialog>
</>
Expand Down
13 changes: 7 additions & 6 deletions client/src/components/passwordModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import DialogTitle from '@mui/material/DialogTitle';
import { LoadingButton } from '@mui/lab';
import { useFormik, FormikProvider } from 'formik';
import * as Yup from 'yup';
import { useTranslation } from 'react-i18next';

const PasswordModal = ({ textInfos, cb, OnClose }) => {

const { t } = useTranslation();
const formik = useFormik({
initialValues: {
password: ''
},
validationSchema: Yup.object({
password: Yup.string().required('Required'),
password: Yup.string().required(t('global.required')),
}),
onSubmit: async (values, { setErrors, setStatus, setSubmitting }) => {
setSubmitting(true);
Expand All @@ -37,7 +38,7 @@ const PasswordModal = ({ textInfos, cb, OnClose }) => {
<>
<Dialog open={true} onClose={() => OnClose()}>
<FormikProvider value={formik}>
<DialogTitle>Confirm Password</DialogTitle>
<DialogTitle>{t('auth.confirmPassword')}</DialogTitle>
<DialogContent>
<DialogContentText>
<form onSubmit={formik.handleSubmit}>
Expand All @@ -46,7 +47,7 @@ const PasswordModal = ({ textInfos, cb, OnClose }) => {
fullWidth
id="password"
name="password"
label="Your Password"
label={t('auth.yourPassword')}
value={formik.values.password}
type="password"
onChange={formik.handleChange}
Expand All @@ -64,13 +65,13 @@ const PasswordModal = ({ textInfos, cb, OnClose }) => {
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => OnClose()}>Cancel</Button>
<Button onClick={() => OnClose()}>{t('global.cancelAction')}</Button>
<LoadingButton
disabled={formik.errors.submit}
onClick={formik.handleSubmit}
loading={formik.isSubmitting}
>
Confirm
{t('global.confirmAction')}
</LoadingButton>
</DialogActions>
</FormikProvider>
Expand Down
4 changes: 3 additions & 1 deletion client/src/components/tableView/prettyTableView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import { CircularProgress, Input, InputAdornment, Stack, TextField, useMediaQuer
import { SearchOutlined } from '@ant-design/icons';
import { useTheme } from '@mui/material/styles';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';

const PrettyTableView = ({ isLoading, getKey, data, columns, sort, onRowClick, linkTo, buttons, fullWidth }) => {
const { t } = useTranslation();
const [search, setSearch] = React.useState('');
const theme = useTheme();
const isDark = theme.palette.mode === 'dark';
Expand All @@ -35,7 +37,7 @@ const PrettyTableView = ({ isLoading, getKey, data, columns, sort, onRowClick, l
return (
<Stack direction="column" spacing={2} style={{width: fullWidth ? '100%': ''}}>
<Stack direction="row" spacing={2}>
<Input placeholder="Search"
<Input placeholder={t('global.searchPlaceholder')}
value={search}
style={{
width: '250px',
Expand Down
15 changes: 11 additions & 4 deletions client/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { BrowserRouter } from 'react-router-dom';
import customParseFormat from 'dayjs/plugin/customParseFormat'; // import this if you need to parse custom formats
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import localizedFormat from 'dayjs/plugin/localizedFormat'; // import this for localized formatting
import 'dayjs/locale/en-gb';

// import i18n (needs to be bundled ;))
import './utils/locales/i18n';
import { dayjsLocale, getLanguage } from './utils/locales/i18n';

// scroll bar
import 'simplebar/src/simplebar.css';
Expand All @@ -24,10 +27,14 @@ import reportWebVitals from './reportWebVitals';
import { LocalizationProvider } from '@mui/x-date-pickers';

import dayjs from 'dayjs';
import 'dayjs/locale/en-gb';
dayjs.extend(customParseFormat); // if needed
dayjs.extend(localizedFormat); // if needed
dayjs.locale('en-gb');

/* // Dynamically loading the dayjs-locale does not work.
import(`dayjs/locale/${getLanguage().toLowerCase()}.js`).then(() => dayjs.locale(language.toLowerCase()))
*/
// Workaround: dynamically load dayjs-locale does only with a const object, which more or less defeats de purpose --> maybe switch from dayjs to luxon or moment.js to not have to import every locale seperately
dayjsLocale(getLanguage());

// ==============================|| MAIN - REACT DOM RENDER ||============================== //

Expand All @@ -37,7 +44,7 @@ root.render(
<StrictMode>
<ReduxProvider store={store}>
<BrowserRouter basename="/">
<LocalizationProvider dateAdapter={AdapterDayjs}>
<LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale={getLanguage().toLowerCase()}>
<App />
</LocalizationProvider>
</BrowserRouter>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { Trans, useTranslation } from 'react-i18next';

// material-ui
import { Box, List, Typography } from '@mui/material';
Expand All @@ -10,6 +11,7 @@ import NavItem from './NavItem';
// ==============================|| NAVIGATION - LIST GROUP ||============================== //

const NavGroup = ({ item }) => {
const { t } = useTranslation();
const menu = useSelector((state) => state.menu);
const { drawerOpen } = menu;

Expand Down Expand Up @@ -39,7 +41,7 @@ const NavGroup = ({ item }) => {
drawerOpen && (
<Box sx={{ pl: 3, mb: 1.5 }}>
<Typography variant="subtitle2" color="textSecondary">
{item.title}
{t(item.title)}
</Typography>
{/* only available in paid version */}
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import { forwardRef, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';

// material-ui
import { useTheme } from '@mui/material/styles';
Expand All @@ -14,6 +15,7 @@ import { useClientInfos } from '../../../../../utils/hooks';
// ==============================|| NAVIGATION - LIST ITEM ||============================== //

const NavItem = ({ item, level }) => {
const { t } = useTranslation();
const theme = useTheme();
const dispatch = useDispatch();
const menu = useSelector((state) => state.menu);
Expand Down Expand Up @@ -148,7 +150,7 @@ const NavItem = ({ item, level }) => {
<ListItemText
primary={
<Typography variant="h6" sx={{ color: isSelected ? iconSelectedColor : textColor }}>
{item.title}
{t(item.title)}
</Typography>
}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

// material-ui
import { useTheme } from '@mui/material/styles';
Expand All @@ -19,7 +20,8 @@ import {
Typography,
useMediaQuery
} from '@mui/material';
import * as timeago from 'timeago.js';
import { register, format } from 'timeago.js';
import de from "timeago.js/lib/lang/de";

// project import
import MainCard from '../../../../components/MainCard';
Expand Down Expand Up @@ -50,6 +52,8 @@ const actionSX = {
// ==============================|| HEADER CONTENT - NOTIFICATION ||============================== //

const Notification = () => {
register('de', de);
const { t, i18n } = useTranslation();
const theme = useTheme();
const matchesXs = useMediaQuery(theme.breakpoints.down('md'));
const [notifications, setNotifications] = useState([]);
Expand Down Expand Up @@ -199,7 +203,7 @@ const Notification = () => {
>
<ClickAwayListener onClickAway={handleClose}>
<MainCard
title="Notification"
title={t('header.notificationTitle')}
elevation={0}
border={false}
content={false}
Expand Down Expand Up @@ -237,7 +241,7 @@ const Notification = () => {
<ListItemText
primary={<>
<Typography variant={notification.Read ? 'body' : 'h6'} noWrap>
{notification.Title}
{t(notification.Title)}
</Typography>
<div style={{
overflow: 'hidden',
Expand All @@ -246,13 +250,13 @@ const Notification = () => {
paddingLeft: '8px',
margin: '2px'
}}>
{notification.Message}
{t(notification.Message, { Vars: notification.Vars })}
</div></>
}
/>
<ListItemSecondaryAction>
<Typography variant="caption" noWrap>
{timeago.format(notification.Date)}
{format(notification.Date, i18n.resolvedLanguage)}
</Typography>
</ListItemSecondaryAction>
</ListItemButton>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

// material-ui
import { useTheme } from '@mui/material/styles';
Expand Down Expand Up @@ -54,6 +55,7 @@ function a11yProps(index) {
// ==============================|| HEADER CONTENT - PROFILE ||============================== //

const Profile = () => {
const { t } = useTranslation();
const theme = useTheme();

const handleLogout = async () => {
Expand Down Expand Up @@ -173,7 +175,7 @@ const Profile = () => {
textTransform: 'capitalize'
}}
icon={<UserOutlined style={{ marginBottom: 0, marginRight: '10px' }} />}
label="Profile"
label={t('header.profileLabel')}
{...a11yProps(0)}
/>
<Tab
Expand All @@ -185,7 +187,7 @@ const Profile = () => {
textTransform: 'capitalize'
}}
icon={<SettingOutlined style={{ marginBottom: 0, marginRight: '10px' }} />}
label="Setting"
label={t('header.settingLabel')}
{...a11yProps(1)}
/>
</Tabs>
Expand Down
Loading

0 comments on commit 560d5a3

Please sign in to comment.