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 />,
   },
 ];