frpc多语言设计完成

This commit is contained in:
nkdns 2024-11-29 16:36:59 +08:00
parent 8593eff752
commit ff0676a3b1
No known key found for this signature in database
10 changed files with 154 additions and 73 deletions

View File

@ -10,6 +10,9 @@ declare module 'vue' {
ClientConfigure: typeof import('./src/components/ClientConfigure.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElCol: typeof import('element-plus/es')['ElCol']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElInput: typeof import('element-plus/es')['ElInput']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']

View File

@ -13,6 +13,7 @@
"dependencies": {
"element-plus": "^2.5.3",
"vue": "^3.4.15",
"vue-i18n": "^10.0.5",
"vue-router": "^4.2.5"
},
"devDependencies": {

View File

@ -3,36 +3,39 @@
<header class="grid-content header-color">
<div class="header-content">
<div class="brand">
<a href="#">frp client</a>
<a href="#">{{ t("main.title") }}</a>
</div>
<div class="dark-switch">
<el-switch
v-model="darkmodeSwitch"
inline-prompt
active-text="Dark"
inactive-text="Light"
@change="toggleDark"
style="
<div class="right-ability">
<div class="lang-switch">
<el-dropdown>
<img src="./assets/lang.svg" alt="lang">
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :disabled="locale == 'en' ? true : false"
@click="switchLanguage('en')">English</el-dropdown-item>
<el-dropdown-item :disabled="locale == 'zh' ? true : false"
@click="switchLanguage('zh')">简体中文</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div class="dark-switch">
<el-switch v-model="darkmodeSwitch" inline-prompt :active-text="t('main.dark.Dark')"
:inactive-text="t('main.dark.Light')" @change="toggleDark" style="
--el-switch-on-color: #444452;
--el-switch-off-color: #589ef8;
"
/>
" />
</div>
</div>
</div>
</header>
<section>
<el-row>
<el-col id="side-nav" :xs="24" :md="4">
<el-menu
default-active="1"
mode="vertical"
theme="light"
router="false"
@select="handleSelect"
>
<el-menu-item index="/">Overview</el-menu-item>
<el-menu-item index="/configure">Configure</el-menu-item>
<el-menu-item index="">Help</el-menu-item>
<el-menu default-active="1" mode="vertical" theme="light" router="false" @select="handleSelect">
<el-menu-item index="/">{{ t("main.Overview") }}</el-menu-item>
<el-menu-item index="/configure">{{ t("main.Configure") }}</el-menu-item>
<el-menu-item index="">{{ t("main.Help") }}</el-menu-item>
</el-menu>
</el-col>
@ -50,11 +53,16 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useDark, useToggle } from '@vueuse/core'
import { useI18n } from 'vue-i18n';
const { t, locale } = useI18n();
const isDark = useDark()
const darkmodeSwitch = ref(isDark)
const toggleDark = useToggle(isDark)
const switchLanguage = (lang: string) => {
locale.value = lang;
localStorage.setItem('i18n', lang);
}
const handleSelect = (key: string) => {
if (key == '') {
window.open('https://github.com/fatedier/frp')
@ -107,10 +115,20 @@ html.dark .header-color {
text-decoration: none;
}
.dark-switch {
.right-ability {
display: flex;
justify-content: flex-end;
flex-grow: 1;
padding-right: 40px;
}
.lang-switch {
width: 30px;
margin-right: 10px;
}
.lang-switch img {
width: 100%;
height: auto;
}
</style>

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1732765556989" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1552" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M864 64a96 96 0 0 1 96 96v704a96 96 0 0 1-96 96H160a96 96 0 0 1-96-96V160a96 96 0 0 1 96-96h704z m0 64H160a32 32 0 0 0-32 32v704a32 32 0 0 0 32 32h704a32 32 0 0 0 32-32V160a32 32 0 0 0-32-32z m-322.4 256c0-31.456 40.64-44.032 58.4-18.08l133.6 195.168V384a32 32 0 0 1 64 0v280.48c0 31.456-40.64 44.032-58.4 18.08l-133.6-195.168v177.088a32 32 0 1 1-64 0z" fill="#ffffff" p-id="1553"></path><path d="M448 352a32 32 0 0 1 0 64H288v80h160a32 32 0 0 1 31.776 28.256L480 528a32 32 0 0 1-32 32H288v72.48h160a32 32 0 1 1 0 64H256a32 32 0 0 1-32-32V384a32 32 0 0 1 32-32z" fill="#ffffff" p-id="1554"></path></svg>

After

Width:  |  Height:  |  Size: 936 B

View File

@ -0,0 +1,25 @@
{
"main": {
"title": "frp client",
"Overview": "Overview",
"Configure": "Configure",
"Help": "Help",
"dark": {
"Dark": "Dark",
"Light": "Light"
}
},
"OverView": {
"name": "name",
"type": "type",
"local_addr": "local address",
"plugin": "plugin",
"remote_addr": "remote address",
"status": "status",
"err": "info"
},
"Configure": {
"Refresh": "Refresh",
"Upload": "Upload"
}
}

View File

@ -0,0 +1,25 @@
{
"main": {
"title": "frp 客户端",
"Overview": "总览",
"Configure": "配置",
"Help": "帮助",
"dark": {
"Dark": "暗",
"Light": "明"
}
},
"OverView": {
"name": "通道名称",
"type": "协议类型",
"local_addr": "本地地址",
"plugin": "插件",
"remote_addr": "远程地址",
"status": "状态",
"err": "信息"
},
"Configure": {
"Refresh": "读取配置",
"Upload": "保存配置"
}
}

View File

@ -1,21 +1,19 @@
<template>
<div>
<el-row id="head">
<el-button type="primary" @click="fetchData">Refresh</el-button>
<el-button type="primary" @click="uploadConfig">Upload</el-button>
<el-button type="primary" @click="fetchData">{{ t("Configure.Refresh") }}</el-button>
<el-button type="primary" @click="uploadConfig">{{ t("Configure.Upload") }}</el-button>
</el-row>
<el-input
type="textarea"
autosize
v-model="textarea"
placeholder="frpc configrue file, can not be empty..."
></el-input>
<el-input type="textarea" autosize v-model="textarea"
placeholder="frpc configrue file, can not be empty..."></el-input>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
let textarea = ref('')

View File

@ -3,47 +3,14 @@
<el-row>
<el-col :md="24">
<div>
<el-table
:data="status"
stripe
style="width: 100%"
:default-sort="{ prop: 'type', order: 'ascending' }"
>
<el-table-column
prop="name"
label="name"
sortable
></el-table-column>
<el-table-column
prop="type"
label="type"
width="150"
sortable
></el-table-column>
<el-table-column
prop="local_addr"
label="local address"
width="200"
sortable
></el-table-column>
<el-table-column
prop="plugin"
label="plugin"
width="200"
sortable
></el-table-column>
<el-table-column
prop="remote_addr"
label="remote address"
sortable
></el-table-column>
<el-table-column
prop="status"
label="status"
width="150"
sortable
></el-table-column>
<el-table-column prop="err" label="info"></el-table-column>
<el-table :data="status" stripe style="width: 100%" :default-sort="{ prop: 'type', order: 'ascending' }">
<el-table-column prop="name" :label="t('OverView.name')" sortable></el-table-column>
<el-table-column prop="type" :label="t('OverView.type')" width="150" sortable></el-table-column>
<el-table-column prop="local_addr" :label="t('OverView.local_addr')" width="200" sortable></el-table-column>
<el-table-column prop="plugin" :label="t('OverView.plugin')" width="200" sortable></el-table-column>
<el-table-column prop="remote_addr" :label="t('OverView.remote_addr')" sortable></el-table-column>
<el-table-column prop="status" :label="t('OverView.status')" width="150" sortable></el-table-column>
<el-table-column prop="err" :label="t('OverView.err')"></el-table-column>
</el-table>
</div>
</el-col>
@ -54,6 +21,8 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
let status = ref<any[]>([])

View File

@ -1,13 +1,24 @@
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n';
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import App from './App.vue'
import router from './router'
import './assets/dark.css'
import en from './assets/locales/en.json';
import zh from './assets/locales/zh.json';
const storedLocale = localStorage.getItem('i18n') || 'en';
const i18n = createI18n({
locale: storedLocale, // 默认语言
messages: {
en,
zh,
},
});
const app = createApp(App)
app.use(router)
app.use(i18n);
app.mount('#app')

View File

@ -205,6 +205,27 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917"
integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==
"@intlify/core-base@10.0.5":
version "10.0.5"
resolved "https://registry.npmmirror.com/@intlify/core-base/-/core-base-10.0.5.tgz#c4d992381f8c3a50c79faf67be3404b399c3be28"
integrity sha512-F3snDTQs0MdvnnyzTDTVkOYVAZOE/MHwRvF7mn7Jw1yuih4NrFYLNYIymGlLmq4HU2iIdzYsZ7f47bOcwY73XQ==
dependencies:
"@intlify/message-compiler" "10.0.5"
"@intlify/shared" "10.0.5"
"@intlify/message-compiler@10.0.5":
version "10.0.5"
resolved "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-10.0.5.tgz#4eeace9f4560020d5e5d77f32bed7755e71d8efd"
integrity sha512-6GT1BJ852gZ0gItNZN2krX5QAmea+cmdjMvsWohArAZ3GmHdnNANEcF9JjPXAMRtQ6Ux5E269ymamg/+WU6tQA==
dependencies:
"@intlify/shared" "10.0.5"
source-map-js "^1.0.2"
"@intlify/shared@10.0.5":
version "10.0.5"
resolved "https://registry.npmmirror.com/@intlify/shared/-/shared-10.0.5.tgz#1b46ca8b541f03508fe28da8f34e4bb85506d6bc"
integrity sha512-bmsP4L2HqBF6i6uaMqJMcFBONVjKt+siGluRq4Ca4C0q7W2eMaVZr8iCgF9dKbcVXutftkC7D6z2SaSMmLiDyA==
"@jridgewell/sourcemap-codec@^1.4.15":
version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
@ -2500,6 +2521,15 @@ vue-eslint-parser@^9.3.1, vue-eslint-parser@^9.4.2:
lodash "^4.17.21"
semver "^7.3.6"
vue-i18n@^10.0.5:
version "10.0.5"
resolved "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-10.0.5.tgz#fdf4e6c7b669e80cfa3a12ed9625e2b46671cdf0"
integrity sha512-9/gmDlCblz3i8ypu/afiIc/SUIfTTE1mr0mZhb9pk70xo2csHAM9mp2gdQ3KD2O0AM3Hz/5ypb+FycTj/lHlPQ==
dependencies:
"@intlify/core-base" "10.0.5"
"@intlify/shared" "10.0.5"
"@vue/devtools-api" "^6.5.0"
vue-router@^4.2.5:
version "4.2.5"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.2.5.tgz#b9e3e08f1bd9ea363fdd173032620bc50cf0e98a"