refactor: add admin full i18n support

pull/90/head
moonrailgun 2 years ago
parent 4c168eb81f
commit 7c76344a55

@ -142,7 +142,7 @@ export const ModalCreateGroup: React.FC = React.memo(() => {
<div className="text-center mb-2">
{/* TODO: upload avatar */}
<Avatar size={80} name={name} />
<Avatar className="mx-auto" size={80} name={name} />
</div>
<div>

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Button, ButtonProps, Confirm } from 'react-admin';
import { Button, ButtonProps, Confirm, useTranslate } from 'react-admin';
interface Props extends Pick<ButtonProps, 'label'> {
component?: React.ComponentType<ButtonProps>;
@ -8,10 +8,12 @@ interface Props extends Pick<ButtonProps, 'label'> {
onConfirm?: () => void;
}
export const ButtonWithConfirm: React.FC<Props> = React.memo((props) => {
const translate = useTranslate();
const {
component: ButtonComponent = Button,
confirmTitle = '确认要进行该操作么?',
confirmContent = '该操作不可撤回',
confirmTitle = translate('custom.common.confirmTitle'),
confirmContent = translate('custom.common.confirmContent'),
} = props;
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);

@ -1,10 +1,13 @@
import React from 'react';
import { useTranslate } from 'react-admin';
import { Card, Box, Typography, CardActions, Button } from '@mui/material';
import HomeIcon from '@mui/icons-material/Home';
import CodeIcon from '@mui/icons-material/Code';
import logoSvg from './logo.svg';
export const Welcome: React.FC = React.memo(() => {
const translate = useTranslate();
return (
<Card
sx={{
@ -22,11 +25,11 @@ export const Welcome: React.FC = React.memo(() => {
<Box display="flex">
<Box flex="1">
<Typography variant="h5" component="h2" gutterBottom>
使 Tailchat
{translate('custom.dashboard.welcomeTitle')}
</Typography>
<Box maxWidth="40em">
<Typography variant="body1" component="p" gutterBottom>
Tailchat
{translate('custom.dashboard.welcomeDesc')}
</Typography>
</Box>
<CardActions
@ -46,7 +49,7 @@ export const Welcome: React.FC = React.memo(() => {
startIcon={<HomeIcon />}
target="__blank"
>
访
{translate('custom.dashboard.welcomeHomepage')}
</Button>
<Button
variant="contained"
@ -54,7 +57,7 @@ export const Welcome: React.FC = React.memo(() => {
startIcon={<CodeIcon />}
target="__blank"
>
{translate('custom.dashboard.welcomeSourcecode')}
</Button>
</CardActions>
</Box>

@ -5,7 +5,7 @@ import PersonIcon from '@mui/icons-material/Person';
import MessageIcon from '@mui/icons-material/Message';
import GroupIcon from '@mui/icons-material/Group';
import AttachFileIcon from '@mui/icons-material/AttachFile';
import { useGetList } from 'react-admin';
import { useGetList, useTranslate } from 'react-admin';
import { Grid } from '@mui/material';
export const Dashboard: React.FC = React.memo(() => {
@ -26,6 +26,8 @@ export const Dashboard: React.FC = React.memo(() => {
pagination: { page: 1, perPage: 1 },
});
const translate = useTranslate();
return (
<div>
<Welcome />
@ -35,7 +37,7 @@ export const Dashboard: React.FC = React.memo(() => {
<CardWithIcon
to="/admin/users"
icon={PersonIcon}
title={'用户数'}
title={translate('custom.dashboard.userCount')}
subtitle={usersNum}
/>
</Grid>
@ -43,7 +45,7 @@ export const Dashboard: React.FC = React.memo(() => {
<CardWithIcon
to="/admin/users"
icon={PersonIcon}
title={'临时用户数'}
title={translate('custom.dashboard.tempUserCount')}
subtitle={tempUsersNum}
/>
</Grid>
@ -51,7 +53,7 @@ export const Dashboard: React.FC = React.memo(() => {
<CardWithIcon
to="/admin/messages"
icon={MessageIcon}
title={'总消息数'}
title={translate('custom.dashboard.messageCount')}
subtitle={messageNum}
/>
</Grid>
@ -59,7 +61,7 @@ export const Dashboard: React.FC = React.memo(() => {
<CardWithIcon
to="/admin/groups"
icon={GroupIcon}
title={'总群组数'}
title={translate('custom.dashboard.groupCount')}
subtitle={groupNum}
/>
</Grid>
@ -67,7 +69,7 @@ export const Dashboard: React.FC = React.memo(() => {
<CardWithIcon
to="/admin/file"
icon={AttachFileIcon}
title={'总文件数'}
title={translate('custom.dashboard.fileCount')}
subtitle={fileNum}
/>
</Grid>

@ -5,6 +5,24 @@ export const englishCustom = {
panel: 'Panel',
name: 'Name',
permission: 'Permission',
confirmTitle: 'Are you sure you want to perform this operation?',
confirmContent: 'This action cannot be undone',
},
menu: {
network: 'Tailchat Network',
socket: 'Socket.IO TCP',
},
dashboard: {
welcomeTitle: 'Welcome to Tailchat Admin',
welcomeDesc:
'Tailchat is a completely open source instant messaging application',
welcomeHomepage: 'Visit the official website',
welcomeSourcecode: 'Browse the source code',
userCount: 'User Count',
tempUserCount: 'Temp User Count',
messageCount: 'Message Count',
groupCount: 'Group Count',
fileCount: 'File Count',
},
users: {
search: 'Search nickname or email',
@ -27,6 +45,22 @@ export const englishCustom = {
groupPanel: 'Panel Group',
pluginPanel: 'Plugin Panel',
},
network: {
nodeList: 'Node List',
id: 'ID',
hostname: 'Host Name',
cpuUsage: 'CPU Usage',
ipList: 'IP List',
sdkVersion: 'SDK Version',
serviceList: 'Service List',
actionList: 'Action List',
eventList: 'Event List',
},
socketio: {
tip1: 'The server URL is:',
tip2: 'The account password is the account password of Tailchat Admin',
btn: 'Open the Admin platform',
},
},
};
@ -37,6 +71,23 @@ export const chineseCustom = {
panel: '面板',
name: '名称',
permission: '权限',
confirmTitle: '确认要进行该操作么?',
confirmContent: '该操作不可撤回',
},
menu: {
network: 'Tailchat 网络',
socket: 'Socket.IO 长链接',
},
dashboard: {
welcomeTitle: '欢迎使用 Tailchat 后台管理程序',
welcomeDesc: 'Tailchat 是一个完全开源的即时通讯应用',
welcomeHomepage: '访问官网',
welcomeSourcecode: '浏览源码',
userCount: '用户数',
tempUserCount: '临时用户数',
messageCount: '总消息数',
groupCount: '总群组数',
fileCount: '总文件数',
},
users: {
search: '搜索昵称或邮箱',
@ -58,5 +109,21 @@ export const chineseCustom = {
groupPanel: '面板分组',
pluginPanel: '插件面板',
},
network: {
nodeList: '节点列表',
id: 'ID',
hostname: '主机名',
cpuUsage: 'CPU占用',
ipList: 'IP地址列表',
sdkVersion: 'SDK版本',
serviceList: '服务列表',
actionList: '操作列表',
eventList: '事件列表',
},
socketio: {
tip1: '服务器URL为:',
tip2: '账号密码为Tailchat后台的账号密码',
btn: '打开管理平台',
},
},
};

@ -4,12 +4,14 @@ import {
MenuProps,
ResourceMenuItem,
useResourceDefinitions,
useTranslate,
} from 'react-admin';
import FilterDramaIcon from '@mui/icons-material/FilterDrama';
import LinkIcon from '@mui/icons-material/Link';
export const TailchatMenu: React.FC<MenuProps> = React.memo((props) => {
const resources = useResourceDefinitions();
const translate = useTranslate();
return (
<Menu {...props}>
@ -21,13 +23,13 @@ export const TailchatMenu: React.FC<MenuProps> = React.memo((props) => {
<Menu.Item
to="/admin/network"
primaryText="Tailchat 网络"
primaryText={translate('custom.menu.network')}
leftIcon={<FilterDramaIcon />}
/>
<Menu.Item
to="/admin/socketio"
primaryText="Socket.IO 长链接"
primaryText={translate('custom.menu.socket')}
leftIcon={<LinkIcon />}
/>
</Menu>

@ -13,11 +13,13 @@ import {
} from '@mui/material';
import _uniq from 'lodash/uniq';
import { ChipItems } from '../../components/ChipItems';
import { useTranslate } from 'react-admin';
/**
* Tailchat
*/
export const TailchatNetwork: React.FC = React.memo(() => {
const translate = useTranslate();
const { data, loading } = useRequest(async () => {
const { data } = await request('/network/all');
@ -37,16 +39,16 @@ export const TailchatNetwork: React.FC = React.memo(() => {
}}
>
<Typography variant="h6" gutterBottom>
{translate('custom.network.nodeList')}
</Typography>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>ID</TableCell>
<TableCell></TableCell>
<TableCell>CPU</TableCell>
<TableCell>IP</TableCell>
<TableCell>SDK</TableCell>
<TableCell>{translate('custom.network.id')}</TableCell>
<TableCell>{translate('custom.network.hostname')}</TableCell>
<TableCell>{translate('custom.network.cpuUsage')}</TableCell>
<TableCell>{translate('custom.network.ipList')}</TableCell>
<TableCell>{translate('custom.network.sdkVersion')}</TableCell>
</TableRow>
</TableHead>
<TableBody>
@ -71,21 +73,21 @@ export const TailchatNetwork: React.FC = React.memo(() => {
</Table>
<Typography variant="h6" gutterBottom>
{translate('custom.network.serviceList')}
</Typography>
<Box flexWrap="wrap" overflow="hidden">
<ChipItems items={_uniq<string>(data.services ?? [])} />
</Box>
<Typography variant="h6" gutterBottom>
{translate('custom.network.actionList')}
</Typography>
<Box flexWrap="wrap" overflow="hidden">
<ChipItems items={_uniq<string>(data.actions ?? [])} />
</Box>
<Typography variant="h6" gutterBottom>
{translate('custom.network.eventList')}
</Typography>
<Box flexWrap="wrap" overflow="hidden">
<ChipItems items={_uniq<string>(data.events ?? [])} />

@ -1,4 +1,5 @@
import React from 'react';
import { useTranslate } from 'react-admin';
import { Typography, CardActions, Button, Box } from '@mui/material';
import { Card, CardContent } from '@mui/material';
@ -6,6 +7,7 @@ import { Card, CardContent } from '@mui/material';
* SocketIO
*/
export const SocketIOAdmin: React.FC = React.memo(() => {
const translate = useTranslate();
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
return (
@ -13,13 +15,13 @@ export const SocketIOAdmin: React.FC = React.memo(() => {
<Card>
<CardContent>
<Typography component="div">
URL:{' '}
{translate('custom.socketio.tip1')}{' '}
<strong>
{protocol}://{window.location.host}
</strong>
</Typography>
<Typography component="div">
Tailchat
{translate('custom.socketio.tip2')}
</Typography>
</CardContent>
<CardActions>
@ -29,7 +31,7 @@ export const SocketIOAdmin: React.FC = React.memo(() => {
window.open('https://admin.socket.io/');
}}
>
{translate('custom.socketio.btn')}
</Button>
</CardActions>
</Card>

Loading…
Cancel
Save