add RU locale

This commit is contained in:
nikk gitanes
2021-06-04 19:32:37 +03:00
parent 92ca6d0f8f
commit 0cf0802a2f
13 changed files with 228 additions and 71 deletions

View File

@@ -8,6 +8,9 @@
"axios": "^0.21.1", "axios": "^0.21.1",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"fontsource-roboto": "^4.0.0", "fontsource-roboto": "^4.0.0",
"i18next": "^20.3.1",
"i18next-browser-languagedetector": "^6.1.1",
"i18next-xhr-backend": "^3.2.2",
"konva": "^8.0.1", "konva": "^8.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"material-ui-image": "^3.3.2", "material-ui-image": "^3.3.2",
@@ -16,6 +19,7 @@
"react-copy-to-clipboard": "^5.0.3", "react-copy-to-clipboard": "^5.0.3",
"react-div-100vh": "^0.6.0", "react-div-100vh": "^0.6.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-i18next": "^11.10.0",
"react-konva": "^17.0.2-4", "react-konva": "^17.0.2-4",
"react-measure": "^2.5.2", "react-measure": "^2.5.2",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",

File diff suppressed because one or more lines are too long

View File

@@ -14,21 +14,24 @@ import {
PowerSettingsNew as PowerSettingsNewIcon, PowerSettingsNew as PowerSettingsNewIcon,
} from '@material-ui/icons' } from '@material-ui/icons'
import List from '@material-ui/core/List' import List from '@material-ui/core/List'
import { useTranslation } from 'react-i18next'
import { AppSidebarStyle } from './style' import { AppSidebarStyle } from './style'
export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) { export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) {
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
return ( return (
<AppSidebarStyle isDrawerOpen={isDrawerOpen}> <AppSidebarStyle isDrawerOpen={isDrawerOpen}>
<List> <List>
<AddDialogButton /> <AddDialogButton />
<UploadDialog /> <UploadDialog />
<RemoveAll /> <RemoveAll />
<ListItem button component='a' key='Playlist all torrents' target='_blank' href={playlistAllHost()}> <ListItem button component='a' key={t('PlaylistAll')} target='_blank' href={playlistAllHost()}>
<ListItemIcon> <ListItemIcon>
<ListIcon /> <ListIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Playlist all torrents' /> <ListItemText primary={t('PlaylistAll')} />
</ListItem> </ListItem>
</List> </List>
@@ -37,11 +40,11 @@ export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) {
<List> <List>
<SettingsDialog /> <SettingsDialog />
<AboutDialog /> <AboutDialog />
<ListItem button key='Close server' onClick={() => fetch(shutdownHost())}> <ListItem button key={t('CloseServer')} onClick={() => fetch(shutdownHost())}>
<ListItemIcon> <ListItemIcon>
<PowerSettingsNewIcon /> <PowerSettingsNewIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Close server' /> <ListItemText primary={t('CloseServer')} />
</ListItem> </ListItem>
</List> </List>
@@ -52,7 +55,7 @@ export default function Sidebar({ isDrawerOpen, setIsDonationDialogOpen }) {
<ListItemIcon> <ListItemIcon>
<CreditCardIcon /> <CreditCardIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Donate' /> <ListItemText primary={t('Donate')} />
</ListItem> </ListItem>
</List> </List>
</AppSidebarStyle> </AppSidebarStyle>

View File

@@ -8,36 +8,38 @@ import InfoIcon from '@material-ui/icons/Info'
import ListItem from '@material-ui/core/ListItem' import ListItem from '@material-ui/core/ListItem'
import ListItemIcon from '@material-ui/core/ListItemIcon' import ListItemIcon from '@material-ui/core/ListItemIcon'
import ListItemText from '@material-ui/core/ListItemText' import ListItemText from '@material-ui/core/ListItemText'
import { useTranslation } from 'react-i18next'
export default function AboutDialog() { export default function AboutDialog() {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
return ( return (
<div> <div>
<ListItem button key='Settings' onClick={() => setOpen(true)}> <ListItem button key='Settings' onClick={() => setOpen(true)}>
<ListItemIcon> <ListItemIcon>
<InfoIcon /> <InfoIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='About' /> <ListItemText primary={t('About')} />
</ListItem> </ListItem>
<Dialog open={open} onClose={() => setOpen(false)} aria-labelledby='form-dialog-title' fullWidth maxWidth='lg'> <Dialog open={open} onClose={() => setOpen(false)} aria-labelledby='form-dialog-title' fullWidth maxWidth='lg'>
<DialogTitle id='form-dialog-title'>About</DialogTitle> <DialogTitle id='form-dialog-title'>{t('About')}</DialogTitle>
<DialogContent> <DialogContent>
<DialogContent> <DialogContent>
<center> <center>
<h2>Thanks to everyone who tested and helped.</h2> <h2>{t('ThanksToEveryone')}</h2>
</center> </center>
<br /> <br />
<h2>Special thanks:</h2> <h2>{t('SpecialThanks')}</h2>
<b>Anacrolix Matt Joiner</b> <a href='https://github.com/anacrolix/'>github.com/anacrolix</a> <b>anacrolix Matt Joiner</b> <a href='https://github.com/anacrolix/'>github.com/anacrolix</a>
<br /> <br />
<b>tsynik nikk Никита</b> <a href='https://github.com/tsynik'>github.com/tsynik</a> <b>nikk</b> <a href='https://github.com/tsynik'>github.com/tsynik</a>
<br /> <br />
<b>dancheskus</b> <a href='https://github.com/dancheskus'>github.com/dancheskus</a> <b>dancheskus</b> <a href='https://github.com/dancheskus'>github.com/dancheskus</a>
<br /> <br />
<b>Tw1cker Руслан Пахнев</b> <a href='https://github.com/Nemiroff'>github.com/Nemiroff</a> <b>tw1cker Руслан Пахнев</b> <a href='https://github.com/Nemiroff'>github.com/Nemiroff</a>
<br /> <br />
<b>SpAwN_LMG</b> <b>SpAwN_LMG</b>
<br /> <br />
@@ -46,7 +48,7 @@ export default function AboutDialog() {
<DialogActions> <DialogActions>
<Button onClick={() => setOpen(false)} color='primary' variant='outlined' autoFocus> <Button onClick={() => setOpen(false)} color='primary' variant='outlined' autoFocus>
Close {t('Close')}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>

View File

@@ -3,22 +3,23 @@ import ListItemIcon from '@material-ui/core/ListItemIcon'
import LibraryAddIcon from '@material-ui/icons/LibraryAdd' import LibraryAddIcon from '@material-ui/icons/LibraryAdd'
import ListItemText from '@material-ui/core/ListItemText' import ListItemText from '@material-ui/core/ListItemText'
import ListItem from '@material-ui/core/ListItem' import ListItem from '@material-ui/core/ListItem'
import { useTranslation } from 'react-i18next'
import AddDialog from './AddDialog' import AddDialog from './AddDialog'
export default function AddDialogButton() { export default function AddDialogButton() {
const [isDialogOpen, setIsDialogOpen] = useState(false) const [isDialogOpen, setIsDialogOpen] = useState(false)
const handleClickOpen = () => setIsDialogOpen(true) const handleClickOpen = () => setIsDialogOpen(true)
const handleClose = () => setIsDialogOpen(false) const handleClose = () => setIsDialogOpen(false)
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
return ( return (
<div> <div>
<ListItem button key='Add' onClick={handleClickOpen}> <ListItem button key='Add' onClick={handleClickOpen}>
<ListItemIcon> <ListItemIcon>
<LibraryAddIcon /> <LibraryAddIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Add from link' /> <ListItemText primary={t('AddFromLink')} />
</ListItem> </ListItem>
{isDialogOpen && <AddDialog handleClose={handleClose} />} {isDialogOpen && <AddDialog handleClose={handleClose} />}

View File

@@ -6,14 +6,17 @@ import DialogActions from '@material-ui/core/DialogActions'
import List from '@material-ui/core/List' import List from '@material-ui/core/List'
import ButtonGroup from '@material-ui/core/ButtonGroup' import ButtonGroup from '@material-ui/core/ButtonGroup'
import Button from '@material-ui/core/Button' import Button from '@material-ui/core/Button'
import { useTranslation } from 'react-i18next'
const donateFrame = const donateFrame =
'<iframe src="https://yoomoney.ru/quickpay/shop-widget?writer=seller&targets=TorrServer Donate&targets-hint=&default-sum=200&button-text=14&payment-type-choice=on&mobile-payment-type-choice=on&comment=on&hint=&successURL=&quickpay=shop&account=410013733697114" width="100%" height="302" frameborder="0" allowtransparency="true" scrolling="no"></iframe>' '<iframe src="https://yoomoney.ru/quickpay/shop-widget?writer=seller&targets=TorrServer Donate&targets-hint=&default-sum=200&button-text=14&payment-type-choice=on&mobile-payment-type-choice=on&comment=on&hint=&successURL=&quickpay=shop&account=410013733697114" width="100%" height="302" frameborder="0" allowtransparency="true" scrolling="no"></iframe>'
export default function DonateDialog({ onClose }) { export default function DonateDialog({ onClose }) {
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
return ( return (
<Dialog open onClose={onClose} aria-labelledby='form-dialog-title' fullWidth> <Dialog open onClose={onClose} aria-labelledby='form-dialog-title' fullWidth>
<DialogTitle id='form-dialog-title'>Donate</DialogTitle> <DialogTitle id='form-dialog-title'>{t('Donate')}</DialogTitle>
<DialogContent> <DialogContent>
<List> <List>
<ListItem key='DonateLinks'> <ListItem key='DonateLinks'>

View File

@@ -5,6 +5,7 @@ import ListItemText from '@material-ui/core/ListItemText'
import DeleteIcon from '@material-ui/icons/Delete' import DeleteIcon from '@material-ui/icons/Delete'
import { useState } from 'react' import { useState } from 'react'
import { torrentsHost } from 'utils/Hosts' import { torrentsHost } from 'utils/Hosts'
import { useTranslation } from 'react-i18next'
const fnRemoveAll = () => { const fnRemoveAll = () => {
fetch(torrentsHost(), { fetch(torrentsHost(), {
@@ -34,22 +35,23 @@ export default function RemoveAll() {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const closeDialog = () => setOpen(false) const closeDialog = () => setOpen(false)
const openDialog = () => setOpen(true) const openDialog = () => setOpen(true)
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
return ( return (
<> <>
<ListItem button key='Remove all' onClick={openDialog}> <ListItem button key={t('RemoveAll')} onClick={openDialog}>
<ListItemIcon> <ListItemIcon>
<DeleteIcon /> <DeleteIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Remove all' /> <ListItemText primary={t('RemoveAll')} />
</ListItem> </ListItem>
<Dialog open={open} onClose={closeDialog}> <Dialog open={open} onClose={closeDialog}>
<DialogTitle>Delete Torrent?</DialogTitle> <DialogTitle>{t('DeleteTorrents?')}</DialogTitle>
<DialogActions> <DialogActions>
<Button variant='outlined' onClick={closeDialog} color='primary'> <Button variant='outlined' onClick={closeDialog} color='primary'>
Cancel {t('Cancel')}
</Button> </Button>
<Button <Button
@@ -61,7 +63,7 @@ export default function RemoveAll() {
color='primary' color='primary'
autoFocus autoFocus
> >
Ok {t('OK')}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>

View File

@@ -12,6 +12,7 @@ import Button from '@material-ui/core/Button'
import { FormControlLabel, InputLabel, Select, Switch } from '@material-ui/core' import { FormControlLabel, InputLabel, Select, Switch } from '@material-ui/core'
import { settingsHost, setTorrServerHost, getTorrServerHost } from 'utils/Hosts' import { settingsHost, setTorrServerHost, getTorrServerHost } from 'utils/Hosts'
import axios from 'axios' import axios from 'axios'
import { useTranslation } from 'react-i18next'
export default function SettingsDialog() { export default function SettingsDialog() {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
@@ -27,6 +28,8 @@ export default function SettingsDialog() {
sets.CacheSize *= 1024 * 1024 sets.CacheSize *= 1024 * 1024
axios.post(settingsHost(), { action: 'set', sets }) axios.post(settingsHost(), { action: 'set', sets })
} }
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
useEffect(() => { useEffect(() => {
axios axios
@@ -82,21 +85,21 @@ export default function SettingsDialog() {
return ( return (
<div> <div>
<ListItem button key='Settings' onClick={handleClickOpen}> <ListItem button key={t('Settings')} onClick={handleClickOpen}>
<ListItemIcon> <ListItemIcon>
<SettingsIcon /> <SettingsIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Settings' /> <ListItemText primary={t('Settings')} />
</ListItem> </ListItem>
<Dialog open={open} onClose={handleClose} aria-labelledby='form-dialog-title' fullWidth> <Dialog open={open} onClose={handleClose} aria-labelledby='form-dialog-title' fullWidth>
<DialogTitle id='form-dialog-title'>Settings</DialogTitle> <DialogTitle id='form-dialog-title'>{t('Settings')}</DialogTitle>
<DialogContent> <DialogContent>
<TextField <TextField
onChange={onInputHost} onChange={onInputHost}
margin='dense' margin='dense'
id='TorrServerHost' id='TorrServerHost'
label='Host' label={t('Host')}
value={tsHost} value={tsHost}
type='url' type='url'
fullWidth fullWidth
@@ -107,87 +110,87 @@ export default function SettingsDialog() {
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='CacheSize' id='CacheSize'
label='Cache size' label={t('CacheSize')}
value={CacheSize} value={CacheSize}
type='number' type='number'
fullWidth fullWidth
/> />
<FormControlLabel <FormControlLabel
control={<Switch checked={PreloadBuffer} onChange={inputForm} id='PreloadBuffer' color='primary' />} control={<Switch checked={PreloadBuffer} onChange={inputForm} id='PreloadBuffer' color='primary' />}
label='Preload buffer' label={t('PreloadBuffer')}
/> />
<TextField <TextField
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='ReaderReadAHead' id='ReaderReadAHead'
label='Reader readahead' label={t('ReaderReadAHead')}
value={ReaderReadAHead} value={ReaderReadAHead}
type='number' type='number'
fullWidth fullWidth
/> />
<br /> <br />
<br /> <br />
<InputLabel htmlFor='RetrackersMode'>Retracker mode</InputLabel> <InputLabel htmlFor='RetrackersMode'>{t('RetrackersMode')}</InputLabel>
<Select onChange={inputForm} type='number' native id='RetrackersMode' value={RetrackersMode}> <Select onChange={inputForm} type='number' native id='RetrackersMode' value={RetrackersMode}>
<option value={0}>Don&apos;t add retrackers</option> <option value={0}>{t('DontAddRetrackers')}</option>
<option value={1}>Add retrackers</option> <option value={1}>{t('AddRetrackers')}</option>
<option value={2}>Remove retrackers</option> <option value={2}>{t('RemoveRetrackers')}</option>
<option value={3}>Replace retrackers</option> <option value={3}>{t('ReplaceRetrackers')}</option>
</Select> </Select>
<TextField <TextField
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='TorrentDisconnectTimeout' id='TorrentDisconnectTimeout'
label='Torrent disconnect timeout' label={t('TorrentDisconnectTimeout')}
value={TorrentDisconnectTimeout} value={TorrentDisconnectTimeout}
type='number' type='number'
fullWidth fullWidth
/> />
<FormControlLabel <FormControlLabel
control={<Switch checked={EnableIPv6} onChange={inputForm} id='EnableIPv6' color='primary' />} control={<Switch checked={EnableIPv6} onChange={inputForm} id='EnableIPv6' color='primary' />}
label='Enable IPv6' label={t('EnableIPv6')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={ForceEncrypt} onChange={inputForm} id='ForceEncrypt' color='primary' />} control={<Switch checked={ForceEncrypt} onChange={inputForm} id='ForceEncrypt' color='primary' />}
label='Force encrypt' label={t('ForceEncrypt')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={DisableTCP} onChange={inputForm} id='DisableTCP' color='primary' />} control={<Switch checked={DisableTCP} onChange={inputForm} id='DisableTCP' color='primary' />}
label='Disable TCP' label={t('DisableTCP')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={DisableUTP} onChange={inputForm} id='DisableUTP' color='primary' />} control={<Switch checked={DisableUTP} onChange={inputForm} id='DisableUTP' color='primary' />}
label='Disable UTP' label={t('DisableUTP')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={DisableUPNP} onChange={inputForm} id='DisableUPNP' color='primary' />} control={<Switch checked={DisableUPNP} onChange={inputForm} id='DisableUPNP' color='primary' />}
label='Disable UPNP' label={t('DisableUPNP')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={DisableDHT} onChange={inputForm} id='DisableDHT' color='primary' />} control={<Switch checked={DisableDHT} onChange={inputForm} id='DisableDHT' color='primary' />}
label='Disable DHT' label={t('DisableDHT')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={DisablePEX} onChange={inputForm} id='DisablePEX' color='primary' />} control={<Switch checked={DisablePEX} onChange={inputForm} id='DisablePEX' color='primary' />}
label='Disable PEX' label={t('DisablePEX')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={DisableUpload} onChange={inputForm} id='DisableUpload' color='primary' />} control={<Switch checked={DisableUpload} onChange={inputForm} id='DisableUpload' color='primary' />}
label='Disable upload' label={t('DisableUpload')}
/> />
<br /> <br />
<TextField <TextField
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='DownloadRateLimit' id='DownloadRateLimit'
label='Download rate limit' label={t('DownloadRateLimit')}
value={DownloadRateLimit} value={DownloadRateLimit}
type='number' type='number'
fullWidth fullWidth
@@ -196,7 +199,7 @@ export default function SettingsDialog() {
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='UploadRateLimit' id='UploadRateLimit'
label='Upload rate limit' label={t('UploadRateLimit')}
value={UploadRateLimit} value={UploadRateLimit}
type='number' type='number'
fullWidth fullWidth
@@ -205,7 +208,7 @@ export default function SettingsDialog() {
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='ConnectionsLimit' id='ConnectionsLimit'
label='Connections limit' label={t('ConnectionsLimit')}
value={ConnectionsLimit} value={ConnectionsLimit}
type='number' type='number'
fullWidth fullWidth
@@ -214,7 +217,7 @@ export default function SettingsDialog() {
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='DhtConnectionLimit' id='DhtConnectionLimit'
label='Dht connection limit' label={t('DhtConnectionLimit')}
value={DhtConnectionLimit} value={DhtConnectionLimit}
type='number' type='number'
fullWidth fullWidth
@@ -223,7 +226,7 @@ export default function SettingsDialog() {
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='PeersListenPort' id='PeersListenPort'
label='Peers listen port' label={t('PeersListenPort')}
value={PeersListenPort} value={PeersListenPort}
type='number' type='number'
fullWidth fullWidth
@@ -231,23 +234,23 @@ export default function SettingsDialog() {
<br /> <br />
<FormControlLabel <FormControlLabel
control={<Switch checked={UseDisk} onChange={inputForm} id='UseDisk' color='primary' />} control={<Switch checked={UseDisk} onChange={inputForm} id='UseDisk' color='primary' />}
label='Use disk' label={t('UseDisk')}
/> />
<br /> <br />
<FormControlLabel <FormControlLabel
control={ control={
<Switch checked={RemoveCacheOnDrop} onChange={inputForm} id='RemoveCacheOnDrop' color='primary' /> <Switch checked={RemoveCacheOnDrop} onChange={inputForm} id='RemoveCacheOnDrop' color='primary' />
} }
label='Remove cache from disk on drop torrent' label={t('RemoveCacheOnDrop')}
/> />
<br /> <br />
<small>If disabled, remove cache on delete torrent</small> <small>{t('RemoveCacheOnDropDesc')}</small>
<br /> <br />
<TextField <TextField
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
id='TorrentsSavePath' id='TorrentsSavePath'
label='Torrents save path' label={t('TorrentsSavePath')}
value={TorrentsSavePath} value={TorrentsSavePath}
type='url' type='url'
fullWidth fullWidth
@@ -258,11 +261,11 @@ export default function SettingsDialog() {
<DialogActions> <DialogActions>
<Button onClick={handleClose} color='primary' variant='outlined'> <Button onClick={handleClose} color='primary' variant='outlined'>
Cancel {t('Cancel')}
</Button> </Button>
<Button onClick={handleSave} color='primary' variant='outlined'> <Button onClick={handleSave} color='primary' variant='outlined'>
Save {t('Save')}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>

View File

@@ -10,12 +10,15 @@ import Slide from '@material-ui/core/Slide'
import { Button, DialogActions, DialogTitle, useMediaQuery, useTheme } from '@material-ui/core' import { Button, DialogActions, DialogTitle, useMediaQuery, useTheme } from '@material-ui/core'
import axios from 'axios' import axios from 'axios'
import ptt from 'parse-torrent-title' import ptt from 'parse-torrent-title'
import { useTranslation } from 'react-i18next'
import { StyledButton, TorrentCard, TorrentCardButtons, TorrentCardDescription, TorrentCardPoster } from './style' import { StyledButton, TorrentCard, TorrentCardButtons, TorrentCardDescription, TorrentCardPoster } from './style'
const Transition = forwardRef((props, ref) => <Slide direction='up' ref={ref} {...props} />) const Transition = forwardRef((props, ref) => <Slide direction='up' ref={ref} {...props} />)
export default function Torrent({ torrent }) { export default function Torrent({ torrent }) {
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
const [isDetailedInfoOpened, setIsDetailedInfoOpened] = useState(false) const [isDetailedInfoOpened, setIsDetailedInfoOpened] = useState(false)
const [isDeleteTorrentOpened, setIsDeleteTorrentOpened] = useState(false) const [isDeleteTorrentOpened, setIsDeleteTorrentOpened] = useState(false)
@@ -44,41 +47,41 @@ export default function Torrent({ torrent }) {
<TorrentCardButtons> <TorrentCardButtons>
<StyledButton onClick={openDetailedInfo}> <StyledButton onClick={openDetailedInfo}>
<UnfoldMoreIcon /> <UnfoldMoreIcon />
<span>Details</span> <span>{t('Details')}</span>
</StyledButton> </StyledButton>
<StyledButton onClick={() => dropTorrent(torrent)}> <StyledButton onClick={() => dropTorrent(torrent)}>
<CloseIcon /> <CloseIcon />
<span>Drop</span> <span>{t('Drop')}</span>
</StyledButton> </StyledButton>
<StyledButton onClick={openDeleteTorrentAlert}> <StyledButton onClick={openDeleteTorrentAlert}>
<DeleteIcon /> <DeleteIcon />
<span>Delete</span> <span>{t('Delete')}</span>
</StyledButton> </StyledButton>
</TorrentCardButtons> </TorrentCardButtons>
<TorrentCardDescription> <TorrentCardDescription>
<div className='description-title-wrapper'> <div className='description-title-wrapper'>
<div className='description-section-name'>Name</div> <div className='description-section-name'>{t('Name')}</div>
<div className='description-torrent-title'>{shortenText(parsedTitle, 100)}</div> <div className='description-torrent-title'>{shortenText(parsedTitle, 100)}</div>
</div> </div>
<div className='description-statistics-wrapper'> <div className='description-statistics-wrapper'>
<div className='description-statistics-element-wrapper'> <div className='description-statistics-element-wrapper'>
<div className='description-section-name'>Size</div> <div className='description-section-name'>{t('Size')}</div>
<div className='description-statistics-element-value'>{torrentSize > 0 && humanizeSize(torrentSize)}</div> <div className='description-statistics-element-value'>{torrentSize > 0 && humanizeSize(torrentSize)}</div>
</div> </div>
<div className='description-statistics-element-wrapper'> <div className='description-statistics-element-wrapper'>
<div className='description-section-name'>Speed</div> <div className='description-section-name'>{t('Speed')}</div>
<div className='description-statistics-element-value'> <div className='description-statistics-element-value'>
{downloadSpeed > 0 ? humanizeSize(downloadSpeed) : '---'} {downloadSpeed > 0 ? humanizeSize(downloadSpeed) : '---'}
</div> </div>
</div> </div>
<div className='description-statistics-element-wrapper'> <div className='description-statistics-element-wrapper'>
<div className='description-section-name'>Peers</div> <div className='description-section-name'>{t('Peers')}</div>
<div className='description-statistics-element-value'>{getPeerString(torrent) || '---'}</div> <div className='description-statistics-element-value'>{getPeerString(torrent) || '---'}</div>
</div> </div>
</div> </div>
@@ -97,10 +100,10 @@ export default function Torrent({ torrent }) {
</Dialog> </Dialog>
<Dialog open={isDeleteTorrentOpened} onClose={closeDeleteTorrentAlert}> <Dialog open={isDeleteTorrentOpened} onClose={closeDeleteTorrentAlert}>
<DialogTitle>Delete Torrent?</DialogTitle> <DialogTitle>{t('DeleteTorrent?')}</DialogTitle>
<DialogActions> <DialogActions>
<Button variant='outlined' onClick={closeDeleteTorrentAlert} color='primary'> <Button variant='outlined' onClick={closeDeleteTorrentAlert} color='primary'>
Cancel {t('Cancel')}
</Button> </Button>
<Button <Button
@@ -112,7 +115,7 @@ export default function Torrent({ torrent }) {
color='primary' color='primary'
autoFocus autoFocus
> >
Ok {t('OK')}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>

View File

@@ -4,6 +4,7 @@ import ListItem from '@material-ui/core/ListItem'
import PublishIcon from '@material-ui/icons/Publish' import PublishIcon from '@material-ui/icons/Publish'
import { torrentUploadHost } from 'utils/Hosts' import { torrentUploadHost } from 'utils/Hosts'
import axios from 'axios' import axios from 'axios'
import { useTranslation } from 'react-i18next'
export default function UploadDialog() { export default function UploadDialog() {
const handleCapture = ({ target: { files } }) => { const handleCapture = ({ target: { files } }) => {
@@ -13,18 +14,19 @@ export default function UploadDialog() {
data.append('file', file) data.append('file', file)
axios.post(torrentUploadHost(), data) axios.post(torrentUploadHost(), data)
} }
// eslint-disable-next-line no-unused-vars
const { t, i18n } = useTranslation('translations')
return ( return (
<div> <div>
<label htmlFor='raised-button-file'> <label htmlFor='raised-button-file'>
<input onChange={handleCapture} accept='*/*' type='file' style={{ display: 'none' }} id='raised-button-file' /> <input onChange={handleCapture} accept='*/*' type='file' style={{ display: 'none' }} id='raised-button-file' />
<ListItem button variant='raised' type='submit' component='span' key='Upload file'> <ListItem button variant='raised' type='submit' component='span' key={t('UploadFile')}>
<ListItemIcon> <ListItemIcon>
<PublishIcon /> <PublishIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Upload file' /> <ListItemText primary={t('UploadFile')} />
</ListItem> </ListItem>
</label> </label>
</div> </div>

View File

@@ -1,12 +1,42 @@
import { StrictMode } from 'react' import { StrictMode } from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { I18nextProvider } from 'react-i18next'
import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import XHR from 'i18next-xhr-backend'
import './index.css' import './index.css'
import App from './App' import App from './App'
import translationEng from './locales/en/translation.json'
import translationRus from './locales/ru/translation.json'
i18n
.use(XHR)
.use(LanguageDetector)
.init({
lng: 'ru', // default
fallbackLng: 'en', // use en if detected lng is not available
keySeparator: false, // we do not use keys in form messages.welcome
interpolation: {
escapeValue: false, // react already safes from xss
},
resources: {
en: {
translations: translationEng,
},
ru: {
translations: translationRus,
},
},
ns: ['translations'],
defaultNS: 'translations',
})
ReactDOM.render( ReactDOM.render(
<StrictMode> <StrictMode>
<I18nextProvider i18n={i18n}>
<App /> <App />
</I18nextProvider>
</StrictMode>, </StrictMode>,
document.getElementById('root'), document.getElementById('root'),
) )

View File

@@ -0,0 +1,52 @@
{
"About": "About",
"AddFromLink": "Add from Link",
"CacheSize": "Cache Size (Megabytes)",
"Cancel": "Cancel",
"Close": "Close",
"CloseServer": "Close Server",
"ConnectionsLimit": "Connections Limit",
"Delete": "Delete",
"DeleteTorrent?": "Delete Torrent?",
"DeleteTorrents?": "Delete All Torrents?",
"Details": "Details",
"DhtConnectionLimit": "DHT Connection Limit",
"DisableDHT": "Disable DHT",
"DisablePEX": "Disable PEX",
"DisableTCP": "Disable TCP",
"DisableUpload": "Disable Upload",
"DisableUPNP": "Disable UPNP",
"DisableUTP": "Disable UTP",
"Donate": "Donate",
"DownloadRateLimit": "Download Rate Limit",
"Drop": "Drop",
"EnableIPv6": "Enable IPv6",
"ForceEncrypt": "Force Encrypt Headers",
"Host": "Host",
"Name": "Name",
"OK": "OK",
"Peers": "Peers",
"PeersListenPort": "Peers Listen Port",
"PlaylistAll": "Playlist All",
"PreloadBuffer": "Preload Buffer",
"ReaderReadAHead": "Reader Read Ahead (5-100%)",
"RemoveAll": "Remove All",
"RemoveCacheOnDrop": "Remove Cache from Disk on Drop Torrent",
"RemoveCacheOnDropDesc": "If disabled, remove cache on delete torrent.",
"RetrackersMode": "Retrackers Mode",
"DontAddRetrackers": "Don&apos;t add retrackers",
"AddRetrackers": "Add retrackers",
"RemoveRetrackers": "Remove retrackers",
"ReplaceRetrackers": "Replace retrackers",
"Save": "Save",
"Settings": "Settings",
"Size": "Size",
"SpecialThanks": "Special Thanks:",
"Speed": "Speed",
"ThanksToEveryone": "Thanks to everyone who tested and helped.",
"TorrentDisconnectTimeout": "Torrent Disconnect Timeout",
"TorrentsSavePath": "Torrents Save Path",
"UploadFile": "Upload File",
"UploadRateLimit": "Upload Rate Limit",
"UseDisk": "Use Disk"
}

View File

@@ -0,0 +1,52 @@
{
"About": "О сервере",
"AddFromLink": "Добавить",
"CacheSize": "Размер кеша (Мегабайты)",
"Cancel": "Отмена",
"Close": "Закрыть",
"CloseServer": "Выкл. сервер",
"ConnectionsLimit": "Торрент-соединения",
"Delete": "Удалить",
"DeleteTorrent?": "Удалить торрент?",
"DeleteTorrents?": "Удалить все торренты?",
"Details": "Информация",
"DhtConnectionLimit": "Лимит подключений DHT",
"DisableDHT": "Откл. DHT",
"DisablePEX": "Откл. PEX",
"DisableTCP": "Откл. TCP",
"DisableUpload": "Откл. отдачу",
"DisableUPNP": "Откл. UPNP",
"DisableUTP": "Откл. UTP",
"Donate": "Поддержка",
"DownloadRateLimit": "Ограничение скорости загрузки",
"Drop": "Отключить",
"EnableIPv6": "Вкл. IPv6",
"ForceEncrypt": "Принудительное шифрование заголовков",
"Host": "Хост",
"Name": "Имя",
"OK": "OK",
"Peers": "Подключения",
"PeersListenPort": "Порт для входящих подключений",
"PlaylistAll": "Плейлист всех",
"PreloadBuffer": "Наполнять кеш перед началом воспроизведения",
"ReaderReadAHead": "Кеш предзагрузки (5-100%, рек.95%)",
"RemoveAll": "Удалить все",
"RemoveCacheOnDrop": "Очищать кеш на диске при отключении торрента",
"RemoveCacheOnDropDesc": "Если отключено, кеш очищается при удалении торрента.",
"RetrackersMode": "Ретрекеры",
"DontAddRetrackers": "Ничего не делать",
"AddRetrackers": "Добавлять",
"RemoveRetrackers": "Удалять",
"ReplaceRetrackers": "Заменять",
"Save": "Сохранить",
"Settings": "Настройки",
"Size": "Размер",
"SpecialThanks": "Отдельное спасибо:",
"Speed": "Скорость",
"ThanksToEveryone": "Спасибо всем, кто тестировал и помогал!",
"TorrentDisconnectTimeout": "Тайм-аут отключения торрента (секунды)",
"TorrentsSavePath": "Путь хранения кеша",
"UploadFile": "Загрузить файл",
"UploadRateLimit": "Ограничение скорости отдачи",
"UseDisk": "Использовать кеш на диске"
}