diff --git a/package.json b/package.json index bde5c05..d2017fa 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "license": "MIT", "dependencies": { + "@solid-primitives/i18n": "^1.2.4", "@solidjs/router": "^0.8.2", "@suid/icons-material": "^0.5.11", "@suid/material": "^0.11.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0894056..cc54387 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,7 @@ lockfileVersion: 5.4 specifiers: + '@solid-primitives/i18n': ^1.2.4 '@solidjs/router': ^0.8.2 '@suid/icons-material': ^0.5.11 '@suid/material': ^0.11.1 @@ -20,6 +21,7 @@ specifiers: vite-plugin-solid: ^2.6.1 dependencies: + '@solid-primitives/i18n': 1.2.4_solid-js@1.6.15 '@solidjs/router': 0.8.2_solid-js@1.6.15 '@suid/icons-material': 0.5.11_solid-js@1.6.15 '@suid/material': 0.11.1_solid-js@1.6.15 @@ -621,6 +623,23 @@ packages: resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==} dev: false + /@solid-primitives/context/0.2.1_solid-js@1.6.15: + resolution: {integrity: sha512-XIIwCOWpRKDersgkR9LNFXaJHIV8QlCFo/tq5bV0cAOZklcwOFcqi2bN+uWgEIQSWGjWXU2kc1H1/TzgYzVDlg==} + peerDependencies: + solid-js: ^1.6.12 + dependencies: + solid-js: 1.6.15 + dev: false + + /@solid-primitives/i18n/1.2.4_solid-js@1.6.15: + resolution: {integrity: sha512-4phkfhFKAfKWWwN+U5M77P8lq65J5XljyjPkZSVzk+AI2OwpO5aDtKpDxiAMWSS8aYhnfJvlfCkIY7X7XDCDLw==} + peerDependencies: + solid-js: ^1.6.12 + dependencies: + '@solid-primitives/context': 0.2.1_solid-js@1.6.15 + solid-js: 1.6.15 + dev: false + /@solidjs/router/0.8.2_solid-js@1.6.15: resolution: {integrity: sha512-gUKW+LZqxtX6y/Aw6JKyy4gQ9E7dLqp513oB9pSYJR1HM5c56Pf7eijzyXX+b3WuXig18Cxqah4tMtF0YGu80w==} peerDependencies: diff --git a/src/components/ActionItem/DetailAction.tsx b/src/components/ActionItem/DetailAction.tsx index a9dd257..c3a53ef 100644 --- a/src/components/ActionItem/DetailAction.tsx +++ b/src/components/ActionItem/DetailAction.tsx @@ -5,6 +5,7 @@ import { toast } from 'solid-toast'; import { DisplayServerItem } from '../../share/types'; import ModalContent from '../ModalContent/ModalContent'; import { getMapNameByFullId, getServerJoinCmd } from '../../share/utils'; +import { useTranslate } from '../../hooks/useTranslate'; interface DetailActionProps { open: Accessor<boolean>; @@ -14,12 +15,13 @@ interface DetailActionProps { function DetailAction(props: DetailActionProps) { const { open, onClose, data } = props; + const t = useTranslate(); const onJoinGame = async () => { try { console.log('joinCmd:', getServerJoinCmd(data()!)); await shell.open(getServerJoinCmd(data()!)); - toast.success('已发送命令请求,请检查 steam 是否被呼起', { + toast.success(t('message_join_game'), { position: 'top-right', }); } catch (e) { @@ -31,7 +33,7 @@ function DetailAction(props: DetailActionProps) { try { console.log('joinCmd:', getServerJoinCmd(data()!)); await clipboard.writeText(getServerJoinCmd(data()!)); - toast.success('已复制到剪贴板', { + toast.success(t('message_copy'), { position: 'top-right', }); } catch (e) { @@ -44,25 +46,39 @@ function DetailAction(props: DetailActionProps) { <ModalContent> <Show when={!!data()} - fallback={<Typography variant="h1">暂无内容</Typography>} + fallback={<Typography variant="h1">{t('empty')}</Typography>} > - <Typography variant="h5">名称:{data()!.name}</Typography> - <Typography variant="h5">描述:{data()!.comment}</Typography> - <Typography variant="h5">IP:{data()!.ipAddress}</Typography> - <Typography variant="h5">端口:{data()!.port}</Typography> - <Typography variant="h5">地区:{data()!.country}</Typography> - <Typography variant="h5">游戏版本:{data()!.version}</Typography> - <Typography variant="h5"> - 地图:{getMapNameByFullId(data()!.mapId)} + <Typography variant="h6">{t('column_server_name')}:</Typography> + <Typography variant="subtitle1">{data()!.name}</Typography> + + <Typography variant="h6">{t('column_desc')}:</Typography> + <Typography variant="subtitle1">{data()!.comment}</Typography> + + <Typography variant="h6">{t('column_ip')}:</Typography> + <Typography variant="subtitle1">{data()!.ipAddress}</Typography> + + <Typography variant="h6">{t('column_port')}:</Typography> + <Typography variant="subtitle1">{data()!.port}</Typography> + + <Typography variant="h6">{t('column_country')}:</Typography> + <Typography variant="subtitle1">{data()!.country}</Typography> + + <Typography variant="h6">{t('column_game_version')}:</Typography> + <Typography variant="subtitle1">{data()!.version}</Typography> + + <Typography variant="h6">{t('column_map')}:</Typography> + <Typography variant="subtitle1"> + {getMapNameByFullId(data()!.mapId)} </Typography> - <Typography variant="h5"> - 玩家负载: + + <Typography variant="h6">{t('column_player_load')}:</Typography> + <Typography variant="subtitle1"> {data()!.currentPlayers} / {data()!.maxPlayers} </Typography> <div class="flex"> <Button variant="contained" onClick={onJoinGame}> - 加入游戏 + {t('action_join_game')} </Button> <div class="ml-2"> <Button @@ -70,7 +86,7 @@ function DetailAction(props: DetailActionProps) { variant="contained" color="warning" > - 复制 steam 游戏启动连接 + {t('action_copy_join_cmd')} </Button> </div> </div> diff --git a/src/components/I18n/I18nProvider.tsx b/src/components/I18n/I18nProvider.tsx new file mode 100644 index 0000000..8c5673e --- /dev/null +++ b/src/components/I18n/I18nProvider.tsx @@ -0,0 +1,14 @@ +import { Component } from 'solid-js'; +import { createI18nContext, I18nContext } from '@solid-primitives/i18n'; + +export const I18nProvider: Component<{ + dict?: Record<string, Record<string, any>>; + locale?: string; + children?: any; +}> = (props) => { + const value = createI18nContext(props.dict, props.locale); + + return ( + <I18nContext.Provider value={value}>{props.children}</I18nContext.Provider> + ); +}; diff --git a/src/components/ServerList/ServerList.tsx b/src/components/ServerList/ServerList.tsx index d0996b2..1103342 100644 --- a/src/components/ServerList/ServerList.tsx +++ b/src/components/ServerList/ServerList.tsx @@ -13,6 +13,7 @@ import { import { Accessor, For, mapArray, Match, Show, Signal, Switch } from 'solid-js'; import ActionList from './ActionList'; import { IServerActionDefine } from './types'; +import { useTranslate } from '../../hooks/useTranslate'; interface IServerListProps { data: Accessor<DisplayServerItem[]>; @@ -24,6 +25,8 @@ interface IServerListProps { } function ServerList(props: IServerListProps) { + const t = useTranslate(); + const { data, pingLoading, latencyRecord, onPing, containerClass, actions } = props; @@ -32,12 +35,12 @@ function ServerList(props: IServerListProps) { <Table stickyHeader> <TableHead> <TableRow> - <TableCell>服务器名称</TableCell> - <TableCell>IP</TableCell> - <TableCell>端口</TableCell> - <TableCell>玩家负载</TableCell> - <TableCell>延迟</TableCell> - <TableCell>操作</TableCell> + <TableCell>{t('column_server_name')}</TableCell> + <TableCell>{t('column_ip')}</TableCell> + <TableCell>{t('column_port')}</TableCell> + <TableCell>{t('column_player_load')}</TableCell> + <TableCell>{t('column_latency')}</TableCell> + <TableCell>{t('column_action')}</TableCell> </TableRow> </TableHead> <TableBody> @@ -59,10 +62,10 @@ function ServerList(props: IServerListProps) { <Match when={latencyRecord()[server.ipAddress] === undefined} > - 未测速 + {t('response_non_ping')} </Match> <Match when={latencyRecord()[server.ipAddress] === -1}> - 超时 + {t('response_timeout')} </Match> </Switch> </Show> @@ -73,7 +76,7 @@ function ServerList(props: IServerListProps) { variant="text" onClick={() => onPing(server)} > - 测速 + {t('ping')} </Button> <Show when={!!actions}> <ActionList actions={actions!} data={server} /> diff --git a/src/entries/about/About.tsx b/src/entries/about/About.tsx index 95a836c..564a862 100644 --- a/src/entries/about/About.tsx +++ b/src/entries/about/About.tsx @@ -3,8 +3,10 @@ import { getName, getVersion } from '@tauri-apps/api/app'; import { open } from '@tauri-apps/api/shell'; import { AUTHORS, SOURCE_CODE_URL } from '../../constants'; import { createEffect, createSignal } from 'solid-js'; +import { useTranslate } from '../../hooks/useTranslate'; function About() { + const t = useTranslate(); const [appInfo, setAppInfo] = createSignal<{ name: string; version: string; @@ -38,23 +40,27 @@ function About() { return ( <Box> <Box p={2}> - <Typography variant="h5">RWR 服务器状态检测</Typography> + <Typography variant="h5">{t('app_full_name')}</Typography> </Box> <Divider /> <Box p={2}> - <Typography variant="subtitle1">应用名称: {appInfo()?.name}</Typography> <Typography variant="subtitle1"> - 应用版本: {appInfo()?.version} + {t('app_name')}: {appInfo()?.name} </Typography> <Typography variant="subtitle1"> - 源码地址: + {t('app_version')}: {appInfo()?.version} + </Typography> + <Typography variant="subtitle1"> + {t('app_source_code')}: <Button variant="text" onClick={openSourceUrl}> rwr-server-ping </Button> </Typography> - <Typography variant="subtitle1">作者: {AUTHORS.join(',')}</Typography> + <Typography variant="subtitle1"> + {t('app_authors')}: {AUTHORS.join(',')} + </Typography> </Box> <Divider /> diff --git a/src/entries/allList/AllList.tsx b/src/entries/allList/AllList.tsx index 0048e31..b687c57 100644 --- a/src/entries/allList/AllList.tsx +++ b/src/entries/allList/AllList.tsx @@ -8,8 +8,10 @@ import DetailAction from '../../components/ActionItem/DetailAction'; import { DisplayServerItem } from '../../share/types'; import { HomeContext } from '../../contexts/home'; import { toast } from 'solid-toast'; +import { useTranslate } from '../../hooks/useTranslate'; function AllList() { + const t = useTranslate(); const homeContext = useContext(HomeContext); const { @@ -26,15 +28,15 @@ function AllList() { const { show, ...elProps } = useDetailAction(); const actions: IServerActionDefine[] = [ { - title: '详情', + title: t('action_detail'), onClick: show, }, { - title: '收藏', + title: t('action_add_to_favorite'), onClick: async (s: DisplayServerItem) => { try { await homeContext?.configStore.addFavorite(s); - toast.success('添加成功'); + toast.success(t('message_add_success')); } catch (e: any) { toast.error(e.message); } @@ -51,7 +53,7 @@ function AllList() { </Show> <div class="flex"> <Button variant="contained" onClick={refreshList} disabled={loading()}> - 刷新服务器列表 + {t('refresh_server_list')} </Button> <div class="ml-2"> <Button @@ -60,7 +62,7 @@ function AllList() { onClick={pingList} disabled={pingListLoading()} > - 一键测速 + {t('quick_ping')} </Button> </div> </div> diff --git a/src/entries/favoriteList/FavoriteList.tsx b/src/entries/favoriteList/FavoriteList.tsx index 06be8a5..52e941d 100644 --- a/src/entries/favoriteList/FavoriteList.tsx +++ b/src/entries/favoriteList/FavoriteList.tsx @@ -3,14 +3,16 @@ import { Button, LinearProgress } from '@suid/material'; import { useServerList } from '../../components/ServerList/useServerList'; import ServerList from '../../components/ServerList/ServerList'; import { HomeContext } from '../../contexts/home'; -import { DisplayServerItem } from "../../share/types"; -import { toast } from "solid-toast"; -import { IServerActionDefine } from "../../components/ServerList/types"; +import { DisplayServerItem } from '../../share/types'; +import { toast } from 'solid-toast'; +import { IServerActionDefine } from '../../components/ServerList/types'; import { useDetailAction } from '../../components/ActionItem/useDetailAction'; -import DetailAction from "../../components/ActionItem/DetailAction"; +import DetailAction from '../../components/ActionItem/DetailAction'; +import { useTranslate } from '../../hooks/useTranslate'; function FavoriteList() { const homeContext = useContext(HomeContext); + const t = useTranslate(); const { loading, @@ -31,15 +33,15 @@ function FavoriteList() { const { show, ...elProps } = useDetailAction(); const actions: IServerActionDefine[] = [ { - title: '详情', + title: t('action_detail'), onClick: show, }, { - title: '移除', + title: t('action_remove'), onClick: async (s: DisplayServerItem) => { try { await homeContext?.configStore.removeFavorite(s); - toast.success('已移除'); + toast.success(t('message_remove')); await refreshList(); } catch (e: any) { toast.error(e.message); @@ -57,7 +59,7 @@ function FavoriteList() { </Show> <div class="flex"> <Button variant="contained" onClick={refreshList} disabled={loading()}> - 刷新服务器列表 + {t('refresh_server_list')} </Button> <div class="ml-2"> <Button @@ -66,7 +68,7 @@ function FavoriteList() { onClick={pingList} disabled={pingListLoading()} > - 一键测速 + {t('quick_ping')} </Button> </div> </div> diff --git a/src/entries/home/Home.tsx b/src/entries/home/Home.tsx index 6bd3046..4e99269 100644 --- a/src/entries/home/Home.tsx +++ b/src/entries/home/Home.tsx @@ -14,10 +14,14 @@ import { createEffect, createSignal, mapArray, Show } from 'solid-js'; import { Toaster } from 'solid-toast'; import { HomeContext, IHomeContextValue } from '../../contexts/home'; import { StoreModel } from '../../model/store'; +import { useTranslate } from '../../hooks/useTranslate'; +import { useI18n } from '@solid-primitives/i18n'; function Home() { const location = useLocation(); const [initLoading, setInitLoading] = createSignal(false); + const [_t, { locale }] = useI18n(); + const t = useTranslate(); const contextValue: IHomeContextValue = { configStore: new StoreModel(), @@ -25,7 +29,9 @@ function Home() { createEffect(() => { setInitLoading(true); - contextValue.configStore.init(); + contextValue.configStore.init().then((newConfig) => { + locale(newConfig.locale); + }); setInitLoading(false); }); @@ -42,7 +48,7 @@ function Home() { <Link href={m.link} class="w-full"> <ListItemButton selected={location.pathname === m.link}> <ListItemIcon>{m.icon}</ListItemIcon> - <ListItemText primary={m.title} /> + <ListItemText primary={t(m.title as any)} /> </ListItemButton> </Link> </ListItem> @@ -51,7 +57,7 @@ function Home() { </List> <Divider class="absolute right-0 p-1" orientation="vertical" /> </div> - <div class="flex-1 overflow-auto ml-2"> + <div class="flex-1 overflow-auto ml-2 p-2"> <Outlet /> </div> <Toaster /> diff --git a/src/entries/invasionList/InvasionList.tsx b/src/entries/invasionList/InvasionList.tsx index 8ffd945..08e21fd 100644 --- a/src/entries/invasionList/InvasionList.tsx +++ b/src/entries/invasionList/InvasionList.tsx @@ -8,9 +8,11 @@ import { DisplayServerItem } from '../../share/types'; import { HomeContext } from '../../contexts/home'; import { toast } from 'solid-toast'; import DetailAction from '../../components/ActionItem/DetailAction'; +import { useTranslate } from '../../hooks/useTranslate'; function InvasionList() { const homeContext = useContext(HomeContext); + const t = useTranslate(); const { loading, @@ -31,15 +33,15 @@ function InvasionList() { const { show, ...elProps } = useDetailAction(); const actions: IServerActionDefine[] = [ { - title: '详情', + title: t('action_detail'), onClick: show, }, { - title: '收藏', + title: t('action_add_to_favorite'), onClick: async (s: DisplayServerItem) => { try { await homeContext?.configStore.addFavorite(s); - toast.success('添加成功'); + toast.success(t('message_add_success')); } catch (e: any) { toast.error(e.message); } @@ -56,7 +58,7 @@ function InvasionList() { </Show> <div class="flex"> <Button variant="contained" onClick={refreshList} disabled={loading()}> - 刷新服务器列表 + {t('refresh_server_list')} </Button> <div class="ml-2"> <Button @@ -65,7 +67,7 @@ function InvasionList() { onClick={pingList} disabled={pingListLoading()} > - 一键测速 + {t('quick_ping')} </Button> </div> </div> diff --git a/src/entries/setting/Setting.tsx b/src/entries/setting/Setting.tsx index 364a31b..2a93dbd 100644 --- a/src/entries/setting/Setting.tsx +++ b/src/entries/setting/Setting.tsx @@ -1,9 +1,20 @@ import { createEffect, createSignal, useContext } from 'solid-js'; -import { Button } from '@suid/material'; +import { + Box, + Button, + Select, + MenuItem, + FormControl, + InputLabel, +} from '@suid/material'; import { HomeContext } from '../../contexts/home'; import toast from 'solid-toast'; +import { useI18n } from '@solid-primitives/i18n'; +import { useTranslate } from '../../hooks/useTranslate'; function Setting() { + const t = useTranslate(); + const [_t, { locale }] = useI18n(); const homeContext = useContext(HomeContext); const onReset = async () => { @@ -18,8 +29,24 @@ function Setting() { return ( <div> <Button color="error" variant="contained" onClick={onReset}> - 重置所有配置 + {t('config_reset')} </Button> + <Box p={2}> + <FormControl fullWidth> + <InputLabel>{t('language')}</InputLabel> + <Select + value={locale()} + onChange={(e) => { + locale(e.target.value); + homeContext?.configStore.updateLocale(e.target.value); + }} + label={t('language')} + > + <MenuItem value="zh_CN">{t('language_zh')}</MenuItem> + <MenuItem value="en_US">{t('language_en')}</MenuItem> + </Select> + </FormControl> + </Box> </div> ); } diff --git a/src/entries/ww2InvasionList/WW2InvasionList.tsx b/src/entries/ww2InvasionList/WW2InvasionList.tsx index 59262b8..5bb52f3 100644 --- a/src/entries/ww2InvasionList/WW2InvasionList.tsx +++ b/src/entries/ww2InvasionList/WW2InvasionList.tsx @@ -8,8 +8,10 @@ import { DisplayServerItem } from '../../share/types'; import { HomeContext } from '../../contexts/home'; import { toast } from 'solid-toast'; import DetailAction from '../../components/ActionItem/DetailAction'; +import { useTranslate } from "../../hooks/useTranslate"; function WW2InvasionList() { + const t = useTranslate(); const homeContext = useContext(HomeContext); const { @@ -31,11 +33,11 @@ function WW2InvasionList() { const { show, ...elProps } = useDetailAction(); const actions: IServerActionDefine[] = [ { - title: '详情', + title: t('action_detail'), onClick: show, }, { - title: '收藏', + title: t('action_add_to_favorite'), onClick: async (s: DisplayServerItem) => { try { await homeContext?.configStore.addFavorite(s); @@ -56,7 +58,7 @@ function WW2InvasionList() { </Show> <div class="flex"> <Button variant="contained" onClick={refreshList} disabled={loading()}> - 刷新服务器列表 + {t('refresh_server_list')} </Button> <div class="ml-2"> <Button @@ -65,7 +67,7 @@ function WW2InvasionList() { onClick={pingList} disabled={pingListLoading()} > - 一键测速 + {t('quick_ping')} </Button> </div> </div> diff --git a/src/hooks/useTranslate.ts b/src/hooks/useTranslate.ts new file mode 100644 index 0000000..32bb3b1 --- /dev/null +++ b/src/hooks/useTranslate.ts @@ -0,0 +1,10 @@ +import { useI18n } from '@solid-primitives/i18n'; +import Translate from '../locale/en_us'; + +type TranslateKey = keyof typeof Translate; + +export const useTranslate = () => { + const [t] = useI18n(); + + return (id: TranslateKey) => t(id); +}; diff --git a/src/index.tsx b/src/index.tsx index 9a9640f..4f475e2 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,13 +1,24 @@ /* @refresh reload */ import { render } from 'solid-js/web'; import { Router } from '@solidjs/router'; +import { createI18nContext } from '@solid-primitives/i18n'; import './index.css'; import App from './App'; +import zhCNMessages from './locale/zh_cn'; +import enUSMessages from './locale/en_us'; +import { I18nProvider } from './components/I18n/I18nProvider'; + +const messages = { + en_US: enUSMessages, + zh_CN: zhCNMessages, +}; render( () => ( <Router> - <App /> + <I18nProvider locale="zh_CN" dict={messages}> + <App /> + </I18nProvider> </Router> ), document.getElementById('root') as HTMLElement diff --git a/src/locale/en_us.ts b/src/locale/en_us.ts new file mode 100644 index 0000000..daa1f42 --- /dev/null +++ b/src/locale/en_us.ts @@ -0,0 +1,46 @@ +export default { + menu_all_server_list: 'All server list', + menu_invasion_server_list: 'Invasion server list', + menu_ww2_invasion_server_list: 'WW2 invasion server list', + app_full_name: 'RWR Server Ping', + app_name: 'App name', + app_version: 'App version', + app_source_code: 'App source code', + app_authors: 'App authors', + setting: 'Settings', + about: 'About', + menu_favorite: 'Favorites', + // action + action_detail: 'Detail', + action_add_to_favorite: 'Add to favorite', + action_remove: 'Remove', + action_join_game: 'Join game', + action_copy_join_cmd: 'Copy join game command', + config_reset: 'Reset all settings', + language: 'Language', + language_zh: '中文', + language_en: 'English', + refresh_server_list: 'Refresh Server List', + ping: 'Ping', + quick_ping: 'Quick Ping', + empty: 'Empty', + // message + message_add_success: 'Add successful', + message_remove: 'Removed', + message_join_game: 'Command has sent, please check if steam is launched', + message_copy: 'Copied to clipboard', + // column + column_server_name: 'Server name', + column_ip: 'IP', + column_port: 'Port', + column_player_load: 'Player load', + column_desc: 'Description', + column_country: 'Country', + column_map: 'Map', + column_game_version: 'Game version', + column_latency: 'Latency', + column_action: 'Action', + // response + response_timeout: 'Timeout', + response_non_ping: 'Not ping', +}; diff --git a/src/locale/zh_cn.ts b/src/locale/zh_cn.ts new file mode 100644 index 0000000..4b3156f --- /dev/null +++ b/src/locale/zh_cn.ts @@ -0,0 +1,46 @@ +export default { + menu_all_server_list: '所有服务器列表', + menu_invasion_server_list: '官方入侵服务器列表', + menu_ww2_invasion_server_list: '官方二战服务器列表', + app_full_name: 'RWR 服务器状态检测', + app_name: '应用名称', + app_version: '应用版本', + app_source_code: '源码地址', + app_authors: '作者', + setting: '设置', + about: '关于', + menu_favorite: '收藏夹', + // action + action_detail: '详情', + action_add_to_favorite: '收藏', + action_remove: '移除', + action_join_game: '加入游戏', + action_copy_join_cmd: '复制游戏启动链接', + config_reset: '重置所有配置', + language: '语言', + language_zh: '中文', + language_en: 'English', + refresh_server_list: '刷新服务器列表', + ping: '测速', + quick_ping: '一键测速', + empty: '暂无内容', + // message + message_add_success: '添加成功', + message_remove: '已移除', + message_join_game: '已发送命令请求,请检查 steam 是否被呼起', + message_copy: '已复制到剪贴板', + // column + column_server_name: '服务器名称', + column_ip: 'IP', + column_port: '端口', + column_player_load: '玩家负载', + column_desc: '描述', + column_country: '地区', + column_map: '地图', + column_game_version: '游戏版本', + column_latency: '延迟', + column_action: '操作', + // response + response_timeout: '超时', + response_non_ping: '未测速', +}; diff --git a/src/model/store.ts b/src/model/store.ts index 4bf0d29..4d6f646 100644 --- a/src/model/store.ts +++ b/src/model/store.ts @@ -11,11 +11,13 @@ interface IFavorite { export interface IAppConfig { favoriteList: IFavorite[]; + locale: string; } const genDefaultConfig = (): IAppConfig => { return { favoriteList: [], + locale: 'en_US' }; }; @@ -32,6 +34,8 @@ export class StoreModel { } else { await this.flushConfig(); } + + return this.config; } async flushConfig() { @@ -73,6 +77,11 @@ export class StoreModel { await this.flushConfig(); } + async updateLocale(locale: string) { + this.config.locale = locale; + await this.flushConfig(); + } + async reset() { this.config = genDefaultConfig(); await this.flushConfig(); diff --git a/src/routes.tsx b/src/routes.tsx index 3c339a1..2f70782 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -23,32 +23,32 @@ export const HOME_MENU: IMenuDefine = { export const MENU_LIST: IMenuDefine[] = [ { link: '/all_list', - title: '所有服务器列表', + title: 'menu_all_server_list', icon: <ListIcon />, }, { link: '/invasion_list', - title: '官方入侵服务器列表', + title: 'menu_invasion_server_list', icon: <ListIcon />, }, { link: '/ww2_invasion_list', - title: '官方二战服务器列表', + title: 'menu_ww2_invasion_server_list', icon: <ListIcon />, }, { link: '/favorite_list', - title: '收藏服务器列表', + title: 'menu_favorite', icon: <StarIcon />, }, { link: '/setting', - title: '设置', + title: 'setting', icon: <SettingsIcon />, }, { link: '/about', - title: '关于', + title: 'about', icon: <InfoIcon />, }, ];