1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 15:20:09 +01:00

Finished Chinese Simplified and Traditional translation

This commit is contained in:
Donald Zou 2024-09-23 00:17:30 +08:00
parent 21672f99d1
commit b664fccce2
8 changed files with 380 additions and 23 deletions

View File

@ -2134,20 +2134,50 @@ def API_Welcome_Finish():
DashboardConfig.SetConfig("Other", "welcome_session", False) DashboardConfig.SetConfig("Other", "welcome_session", False)
return ResponseObject() return ResponseObject()
class Locale:
def __init__(self):
self.localePath = './static/locale/'
self.activeLanguages = {}
with open(os.path.join(f"{self.localePath}active_languages.json"), "r") as f:
self.activeLanguages = json.loads(''.join(f.readlines()))
def getLanguage(self) -> dict | None:
currentLanguage = DashboardConfig.GetConfig("Server", "dashboard_language")[1]
if currentLanguage == "en":
return None
if os.path.exists(os.path.join(f"{self.localePath}{currentLanguage}.json")):
with open(os.path.join(f"{self.localePath}{currentLanguage}.json"), "r") as f:
return dict(json.loads(''.join(f.readlines())))
else:
return None
def updateLanguage(self, lang_id):
if not os.path.exists(os.path.join(f"{self.localePath}{lang_id}.json")):
DashboardConfig.SetConfig("Server", "dashboard_language", "en")
else:
DashboardConfig.SetConfig("Server", "dashboard_language", lang_id)
Locale = Locale()
@app.get(f'{APP_PREFIX}/api/locale') @app.get(f'{APP_PREFIX}/api/locale')
def API_Local_CurrentLang(): def API_Locale_CurrentLang():
# if param is None or len(param) == 0: return ResponseObject(data=Locale.getLanguage())
# with open(os.path.join("./static/locale/active_languages.json"), "r") as f:
# return ResponseObject(data=''.join(f.readlines()))
_, param = DashboardConfig.GetConfig("Server", "dashboard_language") @app.get(f'{APP_PREFIX}/api/locale/available')
def API_Locale_Available():
return ResponseObject(data=Locale.activeLanguages)
@app.post(f'{APP_PREFIX}/api/locale/update')
def API_Locale_Update():
data = request.get_json()
if 'lang_id' not in data.keys():
return ResponseObject(False, "Please specify a lang_id")
Locale.updateLanguage(data['lang_id'])
return ResponseObject(data=Locale.getLanguage())
if param == "en":
return ResponseObject()
if os.path.exists(os.path.join(f"./static/locale/{param}.json")):
with open(os.path.join(f"./static/locale/{param}.json"), "r") as f:
return ResponseObject(data=''.join(f.readlines()))

View File

@ -0,0 +1,86 @@
<script>
import LocaleText from "@/components/text/localeText.vue";
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
export default {
name: "dashboardLanguage",
components: {LocaleText},
setup(){
const store = DashboardConfigurationStore()
return {store}
},
data(){
return {
languages: undefined
}
},
mounted() {
fetchGet("/api/locale/available", {}, (res) => {
this.languages = res.data;
})
},
methods: {
changeLanguage(lang_id){
fetchPost("/api/locale/update", {
lang_id: lang_id
}, (res) => {
if (res.status){
this.store.Configuration.Server.dashboard_language = lang_id;
this.store.Locale = res.data
}else{
this.store.newMessage("Server", "Dashboard language update failed", "danger")
}
})
}
},
computed:{
currentLanguage(){
let lang = this.store.Configuration.Server.dashboard_language;
return this.languages.find(x => x.lang_id === lang)
}
}
}
</script>
<template>
<div class="card mb-4 shadow rounded-3">
<p class="card-header">
<LocaleText t="Dashboard Language"></LocaleText>
</p>
<div class="card-body d-flex gap-2">
<div class="dropdown w-100">
<button class="btn bg-primary-subtle text-primary-emphasis dropdown-toggle w-100 rounded-3"
:disabled="!this.languages"
type="button" data-bs-toggle="dropdown" aria-expanded="false">
<LocaleText t="Loading..." v-if="!this.languages"></LocaleText>
<span v-else>
{{ currentLanguage?.lang_name_localized }}
</span>
</button>
<ul class="dropdown-menu rounded-3 shadow" style="width: 500px">
<li v-for="x in this.languages">
<a class="dropdown-item d-flex align-items-center" role="button"
@click="this.changeLanguage(x.lang_id)"
>
<p class="me-auto mb-0">
{{ x.lang_name_localized }}
<small class="d-block" style="font-size: 0.8rem">
{{ x.lang_name }}
</small>
</p>
<i class="bi bi-check text-primary fs-5"
v-if="currentLanguage?.lang_id === x.lang_id"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@ -14,7 +14,7 @@ import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.
import {fetchGet} from "@/utilities/fetch.js"; import {fetchGet} from "@/utilities/fetch.js";
let Locale; let Locale;
await fetch("/api/locale").then(res => res.json()).then(res => Locale = JSON.parse(res.data)) await fetch("/api/locale").then(res => res.json()).then(res => Locale = res.data)
const app = createApp(App) const app = createApp(App)
@ -29,5 +29,7 @@ pinia.use(({ store }) => {
app.use(pinia) app.use(pinia)
const store = DashboardConfigurationStore() const store = DashboardConfigurationStore()
window.Locale = Locale; // window.Locale = Locale;
store.Locale = Locale;
app.mount('#app') app.mount('#app')

View File

@ -1,12 +1,16 @@
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
export const GetLocale = (key) => { export const GetLocale = (key) => {
if (window.Locale === null) const store = DashboardConfigurationStore()
if (store.Locale === null)
return key return key
const reg = Object.keys(window.Locale) const reg = Object.keys(store.Locale)
const match = reg.filter(x => { const match = reg.filter(x => {
return key.match(new RegExp('^' + x + '$', 'gi')) !== null return key.match(new RegExp('^' + x + '$', 'gi')) !== null
}) })
if (match.length === 0 || match.length > 1){ if (match.length === 0 || match.length > 1){
return key return key
} }
return key.replace(new RegExp(match[0], 'gi'), window.Locale[match[0]]) return key.replace(new RegExp(match[0], 'gi'), store.Locale[match[0]])
} }

View File

@ -1,5 +1,4 @@
<script> <script>
import {wgdashboardStore} from "@/stores/wgdashboardStore.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js"; import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import PeersDefaultSettingsInput from "@/components/settingsComponent/peersDefaultSettingsInput.vue"; import PeersDefaultSettingsInput from "@/components/settingsComponent/peersDefaultSettingsInput.vue";
import {ipV46RegexCheck} from "@/utilities/ipCheck.js"; import {ipV46RegexCheck} from "@/utilities/ipCheck.js";
@ -13,11 +12,13 @@ import DashboardSettingsInputIPAddressAndPort
import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue"; import DashboardAPIKeys from "@/components/settingsComponent/dashboardAPIKeys.vue";
import AccountSettingsMFA from "@/components/settingsComponent/accountSettingsMFA.vue"; import AccountSettingsMFA from "@/components/settingsComponent/accountSettingsMFA.vue";
import LocaleText from "@/components/text/localeText.vue"; import LocaleText from "@/components/text/localeText.vue";
import DashboardLanguage from "@/components/settingsComponent/dashboardLanguage.vue";
export default { export default {
name: "settings", name: "settings",
methods: {ipV46RegexCheck}, methods: {ipV46RegexCheck},
components: { components: {
DashboardLanguage,
LocaleText, LocaleText,
AccountSettingsMFA, AccountSettingsMFA,
DashboardAPIKeys, DashboardAPIKeys,
@ -39,14 +40,15 @@ export default {
<LocaleText t="Settings"></LocaleText> <LocaleText t="Settings"></LocaleText>
</h3> </h3>
<DashboardTheme></DashboardTheme> <DashboardTheme></DashboardTheme>
<DashboardLanguage></DashboardLanguage>
<div class="card mb-4 shadow rounded-3"> <div class="card mb-4 shadow rounded-3">
<p class="card-header"> <p class="card-header">
<LocaleText t="Peers Default Settings"></LocaleText> <LocaleText t="Peers Default Settings"></LocaleText>
</p> </p>
<div class="card-body"> <div class="card-body">
<PeersDefaultSettingsInput targetData="peer_global_dns" title="DNS"></PeersDefaultSettingsInput> <PeersDefaultSettingsInput targetData="peer_global_dns" title="DNS"></PeersDefaultSettingsInput>
<PeersDefaultSettingsInput targetData="peer_endpoint_allowed_ip" title="Peer Endpoint Allowed IPs"></PeersDefaultSettingsInput> <PeersDefaultSettingsInput targetData="peer_endpoint_allowed_ip" title="Endpoint Allowed IPs"></PeersDefaultSettingsInput>
<PeersDefaultSettingsInput targetData="peer_mtu" title="MTU (Max Transmission Unit)"></PeersDefaultSettingsInput> <PeersDefaultSettingsInput targetData="peer_mtu" title="MTU"></PeersDefaultSettingsInput>
<PeersDefaultSettingsInput targetData="peer_keep_alive" title="Persistent Keepalive"></PeersDefaultSettingsInput> <PeersDefaultSettingsInput targetData="peer_keep_alive" title="Persistent Keepalive"></PeersDefaultSettingsInput>
<PeersDefaultSettingsInput targetData="remote_endpoint" title="Peer Remote Endpoint" <PeersDefaultSettingsInput targetData="remote_endpoint" title="Peer Remote Endpoint"
:warning="true" warningText="This will be changed globally, and will be apply to all peer's QR code and configuration file." :warning="true" warningText="This will be changed globally, and will be apply to all peer's QR code and configuration file."

View File

@ -1,14 +1,17 @@
[ [
{ {
"lang_id": "en", "lang_id": "en",
"lang_name": "English" "lang_name": "English",
"lang_name_localized": "English"
}, },
{ {
"lang_id": "zh-CN", "lang_id": "zh-CN",
"lang_name": "Chinese (Simplified)" "lang_name": "Chinese (Simplified)",
"lang_name_localized": "中文(简体)"
}, },
{ {
"lang_id": "zh-HK", "lang_id": "zh-HK",
"lang_name": "Chinese (Traditional)" "lang_name": "Chinese (Traditional)",
"lang_name_localized": "中文(繁體)"
} }
] ]

View File

@ -220,5 +220,8 @@
"Sign in session ended, please sign in again": "登录已过期,请重新登录", "Sign in session ended, please sign in again": "登录已过期,请重新登录",
"Please specify an IP Address (v4/v6)": "请提供一个 IP 地址 v4或v6", "Please specify an IP Address (v4/v6)": "请提供一个 IP 地址 v4或v6",
"Please provide ipAddress and count": "请提供 ipAddress 和 count", "Please provide ipAddress and count": "请提供 ipAddress 和 count",
"Please provide ipAddress": "请提供 ipAddress" "Please provide ipAddress": "请提供 ipAddress",
"Dashboard Language": "面板语言",
"Dashboard language update failed": "面板语言更新失败",
"Peer Remote Endpoint": "端点末端地址"
} }

View File

@ -0,0 +1,227 @@
{
"Welcome to": "歡迎來到",
"Username": "用戶名",
"Password": "密碼",
"OTP from your authenticator": "您多重身份驗證器的一次性驗證碼",
"Sign In": "登錄",
"Signing In\\.\\.\\.": "正在登錄...",
"Access Remote Server": "訪問遠程服務器",
"Server": "服務器",
"Click": "點擊",
"Pinging...": "嘗試連接中...",
"to add your server": "添加您的服務器",
"Server List": "服務器列表",
"Sorry, your username or password is incorrect.": "對不起,您的用戶名或密碼不正確",
"Home": "主頁",
"Settings": "設定",
"Tools": "工具箱",
"Sign Out": "退出登錄",
"Checking for update...": "正在檢查是否有新版本...",
"You're on the latest version": "已經是最新版本",
"WireGuard Configurations": "WireGuard 配置",
"You don't have any WireGuard configurations yet. Please check the configuration folder or change it in Settings. By default the folder is /etc/wireguard.": "您還沒有任何WireGuard配置。請檢查您的配置文件夾或前往設置更改路徑。默認文件夾是 /etc/wireguard",
"Configuration": "配置",
"Configurations": "配置",
"Peers Default Settings": "端點默認設置",
"Dashboard Theme": "面板主題",
"Light": "簡約白",
"Dark": "簡約黑",
"This will be changed globally, and will be apply to all peer's QR code and configuration file.": "更改這個設定會應用到所有端點的配置文件和配置二維碼",
"WireGuard Configurations Settings": "WireGuard 配置設定",
"Configurations Directory": "配置文件路徑",
"Remember to remove / at the end of your path. e.g /etc/wireguard": "請把路徑最後的 /(左斜槓)移除,例如:/etc/wireguard",
"WGDashboard Account Settings": "WGDashboard 賬戶設定",
"Current Password": "當前密碼",
"New Password": "新密碼",
"Repeat New Password": "重復新密碼",
"Update Password": "更新密碼",
"Multi-Factor Authentication \\(MFA\\)": "多重身份驗證 (MFA)",
"Reset": "重置",
"Setup": "設置",
"API Keys": "API 秘鑰",
"API Key": "API 秘鑰",
"Key": "秘鑰",
"Enabled": "已啓用",
"Disabled": "已停用",
"No WGDashboard API Key": "沒有 WGDashboard API 秘鑰",
"Expire At": "過期於",
"Are you sure to delete this API key\\?": "確定刪除此 API 秘鑰?",
"Create API Key": "創建 API 秘鑰",
"When should this API Key expire\\?": "這個 API 秘鑰什麼時候過期呢?",
"Never Expire": "從不過期",
"Don't think that's a good idea": "我不覺得這是一個好主意",
"Creating\\.\\.\\.": "創建中...",
"Create": "創建",
"Status": "狀態",
"On": "已啓用",
"Off": "已停用",
"Turning On\\.\\.\\.": "啓用中...",
"Turning Off\\.\\.\\.": "停用中...",
"Address": "網絡地址",
"Listen Port": "監聽端口",
"Public Key": "公鑰",
"Connected Peers": "已連接端點",
"Total Usage": "總數據用量",
"Total Received": "總接收數據用量",
"Total Sent": "總發送數據用量",
"Peers Data Usage": "端點的數據用量",
"Real Time Received Data Usage": "實時接收數據量",
"Real Time Sent Data Usage": "實時發送數據量",
"Peer": "端點",
"Peers": "端點",
"Peer Settings": "端點設定",
"Download All": "全部下載",
"Search Peers\\.\\.\\.": "搜索端點...",
"Display": "顯示設置",
"Sort By": "排列方式",
"Refresh Interval": "刷新間隔",
"Name": "名稱",
"Allowed IPs": "允許的 IP 地址",
"Restricted": "已限制端點",
"(.*) Seconds": "$1 秒",
"(.*) Minutes": "$1 分鐘",
"Configuration Settings": "配置設定",
"Peer Jobs": "端點任務",
"Active Jobs": "未運行任務",
"All Active Jobs": "所有未運行任務",
"Logs": "日誌",
"Private Key": "秘鑰",
"\\(Required for QR Code and Download\\)": "(二維碼以及下載功能需要填寫秘鑰)",
"\\(Required\\)": "(必填項)",
"Endpoint Allowed IPs": "終結點允許的 IP 地址",
"DNS": "域名系統DNS",
"Optional Settings": "可選設定",
"Pre-Shared Key": "共享秘鑰",
"MTU": "最大傳輸單元",
"Persistent Keepalive": "持久保持活動",
"Reset Data Usage": "重置數據用量",
"Total": "總數據",
"Sent": "發送數據",
"Received": "接收數據",
"Revert": "撤銷更改",
"Save Peer": "保存端點",
"QR Code": "二維碼",
"Schedule Jobs": "計劃任務",
"Job": "任務",
"Job ID": "任務 ID",
"Unsaved Job": "未保存任務",
"This peer does not have any job yet\\.": "此端點還沒有任何任務",
"if": "如果",
"is": "是",
"then": "那就",
"larger than": "大於",
"Date": "日期",
"Restrict Peer": "限制端點",
"Delete Peer": "刪除端點",
"Edit": "編輯",
"Delete": "刪除",
"Deleting...": "刪除中...",
"Cancel": "取消",
"Save": "保存",
"No active job at the moment\\.": "沒有未運行的任務",
"Jobs Logs": "任務日誌",
"Updated at": "更新於",
"Refresh": "刷新",
"Filter": "篩選",
"Success": "成功",
"Failed": "失敗",
"Log ID": "任務 ID",
"Message": "消息",
"Share Peer": "分享端點",
"Currently the peer is not sharing": "此端點未被共享",
"Sharing\\.\\.\\.": "分享中...",
"Start Sharing": "開始分享",
"Stop Sharing\\.\\.\\.": "停止分享中...",
"Stop Sharing": "停止分享",
"Access Restricted": "已限制訪問",
"Restrict Access": "限制訪問",
"Restricting\\.\\.\\.": "限制訪問中...",
"Allow Access": "解除限制訪問",
"Allowing Access\\.\\.\\.": "解除限制訪問中...",
"Download \\& QR Code is not available due to no private key set for this peer": "下載以及二維碼功能不可用,需要填寫此端點的秘鑰",
"Add Peers": "創建端點",
"Bulk Add": "批量添加",
"By adding peers by bulk, each peer's name will be auto generated, and Allowed IP will be assign to the next available IP\\.": "如果選擇批量添加端點,系統會自動生成每一個端點的名稱,並且會自動安排可用的 IP 地址。",
"How many peers you want to add\\?": "您想添加多少個端點?",
"You can add up to (.*) peers": "您最多可以添加 $1 個端點",
"Use your own Private and Public Key": "使用您自己的秘鑰和公鑰",
"Enter IP Address/CIDR": "輸入 IP 地址/前綴長度",
"or": "或",
"Pick Available IP": "選擇可用的 IP 地址",
"No available IP containing": "沒有可用的 IP 地址含有 ",
"Add": "創建",
"Adding\\.\\.\\.": "創建中...",
"Failed to check available update": "獲取更新失敗",
"Nice to meet you!": "很高興見到您!",
"Please fill in the following fields to finish setup": "請填入以下信息來完成初始化設置",
"Create an account": "創建賬戶",
"Enter an username you like": "輸入一個您喜歡的用戶名",
"Enter a password": "輸入密碼",
"\\(At least 8 characters and make sure is strong enough!\\)": "(至少8個字符或以上並且確保它足夠複雜喲!)",
"Confirm password": "確認密碼",
"Next": "下一步",
"Saving\\.\\.\\.": "保存中...",
"1\\. Please scan the following QR Code to generate TOTP with your choice of authenticator": "1. 請使用您選擇的驗證器掃描以下二維碼來生成一次性驗證碼",
"Or you can click the link below:": "或者您可以點擊以下鏈接:",
"2\\. Enter the TOTP generated by your authenticator to verify": "2. 請輸入驗證器生成的一次性驗證碼進行驗證",
"TOTP verified!": "一次性驗證碼驗證成功!",
"I don't need MFA": "我不需要多重身份驗證 (MFA)",
"Complete": "完成",
"(v[0-9.]{1,}) is now available for update!": "有新版本 $1 可更新!",
"Current Version:": "當前版本: ",
"Oh no\\.\\.\\. This link is either expired or invalid\\.": "噢不!此鏈接已過期或不正確。",
"Scan QR Code with the WireGuard App to add peer": "使用 WireGuard APP 掃描以下二維碼來添加端點",
"or click the button below to download the ": "或點擊下面的按鈕下載 ",
" file": " 文件",
"FROM ": "來自 ",
"(.*) is on": "$1 已啓用",
"(.*) is off": "$1 已停用",
"Allowed IPs is invalid": "允許的 IP 地址錯誤",
"Peer created successfully": "成功創建端點",
"Please fill in all required box": "請填寫所有必填項",
"Please specify amount of peers you want to add": "請提供批量添加端點的數量",
"No more available IP can assign": "沒有更多可用的 IP 可以分配了",
"The maximum number of peers can add is (.*)": "最多只能添加$1個端點",
"Generating key pairs by bulk failed": "生成公鑰秘鑰失敗了",
"Failed to add peers in bulk": "批量創建端點失敗",
"This peer already exist": "此端點已存在",
"This IP is not available: (.*)": "此 IP 地址不可用:$1",
"Configuration does not exist": "此配置不存在",
"Peer does not exist": "此端點不存在",
"Please provide a valid configuration name": "請提供一個正確的配置名稱",
"Peer saved": "端點保存成功",
"Allowed IPs already taken by another peer": "允許的 IP 地址已被其他端點使用",
"Endpoint Allowed IPs format is incorrect": "終結點允許的 IP 地址格式不正確",
"DNS format is incorrect": "域名系統DNS格式不正確",
"MTU format is not correct": "最大傳輸單元格式不正確",
"Persistent Keepalive format is not correct": "持久保持活動格式不正確",
"Private key does not match with the public key": "秘鑰與公鑰不匹配",
"Update peer failed when updating Pre-Shared Key": "更新共享密鑰失敗",
"Update peer failed when updating Allowed IPs": "更新允許的 IP 地址失敗",
"Update peer failed when saving the configuration": "配置保存端點失敗",
"Peer data usage reset successfully": "端點數據重置成功",
"Peer download started": "端點文件下載開始",
"Please specify one or more peers": "請提供一個或更多端點",
"Share link failed to create. Reason: (.*)": "端點分享鏈接生成失敗。原因:$1",
"Link expire date updated": "分享鏈接過期時間更新成功",
"Link expire date failed to update. Reason: (.*)": "分享鏈接過期時間更新失敗。原因:$1",
"Peer job saved": "端點任務保存成功",
"Please specify job": "請提供任務",
"Please specify peer and configuration": "請提供配置名稱以及端點",
"Peer job deleted": "端點任務刪除成功",
"API Keys function is successfully enabled": "API 秘鑰功能開啓成功",
"API Keys function is successfully disabled": "API 秘鑰功能停用成功",
"API Keys function is failed to enable": "API 秘鑰功能開啓失敗",
"API Keys function is failed to disable": "API 秘鑰功能停用失敗",
"WGDashboard API Keys function is disabled": "WGDashboard 的 API 秘鑰功能並未開啓",
"WireGuard configuration path saved": "WireGuard 配置路徑保存成功",
"API Key deleted": "API 秘鑰刪除成功",
"API Key created": "API 秘鑰創建成功",
"Sign in session ended, please sign in again": "登錄已過期,請重新登錄",
"Please specify an IP Address (v4/v6)": "請提供一個 IP 地址 v4或v6",
"Please provide ipAddress and count": "請提供 ipAddress 和 count",
"Please provide ipAddress": "請提供 ipAddress",
"Dashboard Language": "面板語言",
"Dashboard language update failed": "面板語言更新失敗",
"Peer Remote Endpoint": "端點末端地址"
}