diff --git a/src/layout/components/menu/item.vue b/src/layout/components/menu/item.vue index b2b8786..2c1b9e2 100644 --- a/src/layout/components/menu/item.vue +++ b/src/layout/components/menu/item.vue @@ -7,7 +7,7 @@ - {{route.meta?.title||route.name}} + {{ T(route.meta?.title) || T(route.name) }} - {{parseRoute(route).meta?.title||parseRoute(route).name}} + {{ T(parseRoute(route).meta?.title) || T(parseRoute(route).name) }} diff --git a/src/layout/index.vue b/src/layout/index.vue index 0d97f6b..8413160 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -1,85 +1,73 @@ - diff --git a/src/router/index.js b/src/router/index.js index 440314a..08e052d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -4,7 +4,7 @@ const constantRoutes = [ { path: '/login', name: 'Login', - meta: { title: '登录' }, + meta: { title: 'Login' }, component: () => import('@/views/login/login.vue'), }, @@ -45,25 +45,25 @@ export const asyncRoutes = [ path: '/my', name: 'My', redirect: '/my/info', - meta: { title: '我的', icon: 'UserFilled' }, + meta: { title: 'My', icon: 'UserFilled' }, component: () => import('@/layout/index.vue'), children: [ { path: '/', name: 'MyInfo', - meta: { title: '个人信息', icon: 'User' /*keepAlive: true*/ }, + meta: { title: 'Info', icon: 'User' /*keepAlive: true*/ }, component: () => import('@/views/my/info.vue'), }, { path: 'address_book', name: 'MyAddressBookList', - meta: { title: '地址簿管理', icon: 'Notebook' /*keepAlive: true*/ }, + meta: { title: 'AddressBooks', icon: 'Notebook' /*keepAlive: true*/ }, component: () => import('@/views/my/address_book/index.vue'), }, { path: 'tag', name: 'MyTagList', - meta: { title: '标签管理', icon: 'CollectionTag' /*keepAlive: true*/ }, + meta: { title: 'Tags', icon: 'CollectionTag' /*keepAlive: true*/ }, component: () => import('@/views/my/tag/index.vue'), }, ], @@ -72,62 +72,62 @@ export const asyncRoutes = [ path: '/user', name: 'User', redirect: '/user/index', - meta: { title: '系统', icon: 'Setting' }, + meta: { title: 'System', icon: 'Setting' }, component: () => import('@/layout/index.vue'), children: [ { path: 'peer', name: 'Peer', - meta: { title: '设备管理', icon: 'Monitor' /*keepAlive: true*/ }, + meta: { title: 'PeerManage', icon: 'Monitor' /*keepAlive: true*/ }, component: () => import('@/views/peer/index.vue'), }, { path: 'group', name: 'UserGroup', - meta: { title: '群组管理', icon: 'ChatRound' /*keepAlive: true*/ }, + meta: { title: 'GroupManage', icon: 'ChatRound' /*keepAlive: true*/ }, component: () => import('@/views/group/index.vue'), }, { path: 'index', name: 'UserList', - meta: { title: '用户列表', icon: 'User' /*keepAlive: true*/ }, + meta: { title: 'UserManage', icon: 'User' /*keepAlive: true*/ }, component: () => import('@/views/user/index.vue'), }, { path: 'add', name: 'UserAdd', - meta: { title: '用户添加', hide: true }, + meta: { title: 'UserAdd', hide: true }, component: () => import('@/views/user/edit.vue'), }, { path: 'edit/:id', name: 'UserEdit', - meta: { title: '用户编辑', hide: true }, + meta: { title: 'UserEdit', hide: true }, component: () => import('@/views/user/edit.vue'), }, { path: 'addressBook', name: 'UserAddressBook', - meta: { title: '地址簿管理', icon: 'Notebook' /*keepAlive: true*/ }, + meta: { title: 'AddressBookManage', icon: 'Notebook' /*keepAlive: true*/ }, component: () => import('@/views/address_book/index.vue'), }, { path: 'tag', name: 'UserTag', - meta: { title: '标签管理', icon: 'CollectionTag' /*keepAlive: true*/ }, + meta: { title: 'TagsManage', icon: 'CollectionTag' /*keepAlive: true*/ }, component: () => import('@/views/tag/index.vue'), }, { path: '/oauth', name: 'Oauth', - meta: { title: 'Oauth管理', icon: 'Link' /*keepAlive: true*/ }, + meta: { title: 'OauthManage', icon: 'Link' /*keepAlive: true*/ }, component: () => import('@/views/oauth/index.vue'), }, { path: '/loginLog', name: 'LoginLog', - meta: { title: '登录日志', icon: 'List' /*keepAlive: true*/ }, + meta: { title: 'LoginLog', icon: 'List' /*keepAlive: true*/ }, component: () => import('@/views/login/log.vue'), }, ], diff --git a/src/store/app.js b/src/store/app.js index 7c17a34..b1e32f7 100644 --- a/src/store/app.js +++ b/src/store/app.js @@ -1,13 +1,17 @@ import { defineStore, acceptHMRUpdate } from 'pinia' import logo from '@/assets/logo.png' +import zhCn from 'element-plus/es/locale/lang/zh-cn' +import en from 'element-plus/es/locale/lang/en' export const useAppStore = defineStore({ id: 'App', state: () => ({ setting: { - title: 'Gwen-Admin', + title: 'Rustdesk-Api-Admin', sideIsCollapse: false, logo, + lang: localStorage.getItem('lang') || 'zh-CN', + locale: zhCn, }, }), @@ -15,6 +19,14 @@ export const useAppStore = defineStore({ sideCollapse () { this.setting.sideIsCollapse = !this.setting.sideIsCollapse }, + setLang (lang) { + this.setting.lang = lang + this.setting.locale = lang === 'zh-CN' ? zhCn : en + localStorage.setItem('lang', lang) + }, + changeLang () { + this.setLang(this.setting.lang === 'zh-CN' ? 'en' : 'zh-CN') + }, }, }) diff --git a/src/store/tags.js b/src/store/tags.js index ccba942..c5b97c7 100644 --- a/src/store/tags.js +++ b/src/store/tags.js @@ -8,15 +8,15 @@ export const useTagsStore = defineStore({ }), actions: { initTags () { - this.tags.push( - { - name: 'Home', - path: '/Home', - title: '首页', - active: false, - closeable: false, - keepAlive: false, - }) + // this.tags.push( + // { + // name: 'Home', + // path: '/Home', + // title: '首页', + // active: false, + // closeable: false, + // keepAlive: false, + // }) }, addTag (route) { const tags = this.tags diff --git a/src/utils/i18n.js b/src/utils/i18n.js new file mode 100644 index 0000000..435826b --- /dev/null +++ b/src/utils/i18n.js @@ -0,0 +1,21 @@ +import en from '@/utils/i18n/en.json' +import zhCN from '@/utils/i18n/zh_CN.json' +import { useAppStore } from '@/store/app' +import { pinia } from '@/store' + +export function T (key, params, num = 0) { + const appStore = useAppStore(pinia) + const lang = appStore.setting.lang + const trans = lang === 'zh-CN' ? zhCN : en + const tran = trans[key] + if (!tran) { + return key + } + const msg = num > 0 ? (tran.Other ? tran.Other : tran.One) : tran.One + //msg 是这样 {name} is name + //params 是这样 {name: 'zhangsan'} + //替换 + return msg.replace(/{(\w+)}/g, function (match, key) { + return params[key] || match + }) +} diff --git a/src/utils/i18n/en.json b/src/utils/i18n/en.json new file mode 100644 index 0000000..6ffa99a --- /dev/null +++ b/src/utils/i18n/en.json @@ -0,0 +1,236 @@ +{ + "Login": { + "One": "Login" + }, + "Logout": { + "One": "Logout" + }, + "Register": { + "One": "Register" + }, + "Confirm": { + "One": "Confirm" + }, + "Username": { + "One": "Username" + }, + "Password": { + "One": "Password" + }, + "LoginSuccess": { + "One": "Login Success" + }, + "ForgotPassword": { + "One": "Forgot Password" + }, + "ResetPassword": { + "One": "Reset Password" + }, + "ChangePassword": { + "One": "Change Password" + }, + "Userinfo": { + "One": "User Info" + }, + "ParamRequired": { + "One": "{param} is required" + }, + "HasBind": { + "One": "Has bind" + }, + "NoBind": { + "One": "No bind" + }, + "UnBind": { + "One": "UnBind" + }, + "ToBind": { + "One": "To Bind" + }, + "Confirm?": { + "One": "{param} Confirm?" + }, + "Cancel": { + "One": "Cancel" + }, + "Platform": { + "One": "Platform" + }, + "Status": { + "One": "Status" + }, + "Actions": { + "One": "Actions" + }, + "Filter": { + "One": "Filter" + }, + "Add": { + "One": "Add" + }, + "Hostname": { + "One": "Hostname" + }, + "Alias": { + "One": "Alias" + }, + "Hash": { + "One": "Hash" + }, + "Tags": { + "One": "Tags" + }, + "Edit": { + "One": "Edit" + }, + "Delete": { + "One": "Delete" + }, + "Create": { + "One": "Create" + }, + "Update": { + "One": "Update" + }, + "LoginName": { + "One": "Login Name" + }, + "Submit": { + "One": "Submit" + }, + "OperationSuccess": { + "One": "Operation Success" + }, + "Owner": { + "One": "Owner" + }, + "Name": { + "One": "Name" + }, + "Color": { + "One": "Color" + }, + "CreatedAt": { + "One": "Created At" + }, + "UpdatedAt": { + "One": "Updated At" + }, + "Memory": { + "One": "Memory" + }, + "Os": { + "One": "Os" + }, + "Uuid": { + "One": "Uuid" + }, + "Version": { + "One": "Version" + }, + "Type": { + "One": "Type" + }, + "Group": { + "One": "Group" + }, + "CommonGroup": { + "One": "Common Group" + }, + "CommonGroupNote": { + "One": "Only admins can see group members and their devices" + }, + "SharedGroup": { + "One": "Shared Group" + }, + "SharedGroupNote": { + "One": "All users can see group members and their devices" + }, + "Nickname": { + "One": "Nickname" + }, + "UserTags": { + "One": "User Tags" + }, + "UserAddressBook": { + "One": "User Address Book" + }, + "IsAdmin": { + "One": "Is Admin" + }, + "PleaseInputNewPassword": { + "One": "Please input new password" + }, + "AutoRegister": { + "One": "Auto Register" + }, + "AutoRegisterNote": { + "One": "If Enable,An account will be automatically registered when a user logs in with OAuth without binding an existing account" + }, + "ThirdName": { + "One": "Third Name" + }, + "Close": { + "One": "Close" + }, + "OauthBinding": { + "One": "You are authorizing the binding" + }, + "OauthLogining": { + "One": "You are authorizing the login" + }, + "OauthCloseNote": { + "One": "If it is not authorized by you, please close the page directly" + }, + "OperationSuccessAndCloseAfter3Seconds": { + "One": "Operation Success,Close after 3 seconds" + }, + "ConfirmOauth": { + "One": "Confirm Oauth" + }, + "Device": { + "One": "Device" + }, + "ChangeLang": { + "One": "切换中文" + }, + "My": { + "One": "My" + }, + "Info": { + "One": "Info" + }, + "AddressBooks": { + "One": "Address Books" + }, + "System": { + "One": "System" + }, + "PeerManage": { + "One": "Peers" + }, + "AddressBookManage": { + "One": "Address Books" + }, + "GroupManage": { + "One": "Groups" + }, + "UserManage": { + "One": "Users" + }, + "UserAdd": { + "One": "User Add" + }, + "UserEdit": { + "One": "User Edit" + }, + "TagsManage": { + "One": "Tags" + }, + "OauthManage": { + "One": "Oauth" + }, + "LoginLog": { + "One": "Login Log" + } +} diff --git a/src/utils/i18n/zh_CN.json b/src/utils/i18n/zh_CN.json new file mode 100644 index 0000000..cfb18e4 --- /dev/null +++ b/src/utils/i18n/zh_CN.json @@ -0,0 +1,236 @@ +{ + "Login": { + "One": "登录" + }, + "Logout": { + "One": "退出登录" + }, + "Register": { + "One": "注册" + }, + "Confirm": { + "One": "确认" + }, + "Username": { + "One": "用户名" + }, + "Password": { + "One": "密码" + }, + "LoginSuccess": { + "One": "登录成功" + }, + "ForgotPassword": { + "One": "忘记密码" + }, + "ResetPassword": { + "One": "重置密码" + }, + "ChangePassword": { + "One": "修改密码" + }, + "Userinfo": { + "One": "用户信息" + }, + "ParamRequired": { + "One": "{param} 是必须的" + }, + "HasBind": { + "One": "已绑定" + }, + "NoBind": { + "One": "未绑定" + }, + "UnBind": { + "One": "解绑" + }, + "ToBind": { + "One": "绑定" + }, + "Confirm?": { + "One": "确定{param}?" + }, + "Cancel": { + "One": "取消" + }, + "Platform": { + "One": "平台" + }, + "Status": { + "One": "状态" + }, + "Actions": { + "One": "操作" + }, + "Filter": { + "One": "筛选" + }, + "Add": { + "One": "添加" + }, + "Hostname": { + "One": "主机名" + }, + "Alias": { + "One": "别名" + }, + "Hash": { + "One": "哈希" + }, + "Tags": { + "One": "标签" + }, + "Edit": { + "One": "编辑" + }, + "Delete": { + "One": "删除" + }, + "Create": { + "One": "创建" + }, + "Update": { + "One": "更新" + }, + "LoginName": { + "One": "登录名" + }, + "Submit": { + "One": "提交" + }, + "OperationSuccess": { + "One": "操作成功" + }, + "Owner": { + "One": "所有者" + }, + "Name": { + "One": "名称" + }, + "Color": { + "One": "颜色" + }, + "CreatedAt": { + "One": "创建时间" + }, + "UpdatedAt": { + "One": "更新时间" + }, + "Memory": { + "One": "内存" + }, + "Os": { + "One": "操作系统" + }, + "Uuid": { + "One": "UUID" + }, + "Version": { + "One": "版本" + }, + "Type": { + "One": "类型" + }, + "Group": { + "One": "组" + }, + "CommonGroup": { + "One": "普通组" + }, + "CommonGroupNote": { + "One": "只有管理员才能查看群组成员及其设备" + }, + "SharedGroup": { + "One": "共享组" + }, + "SharedGroupNote": { + "One": "所有用户都可以查看群组成员及其设备" + }, + "Nickname": { + "One": "昵称" + }, + "UserTags": { + "One": "用户标签" + }, + "UserAddressBook": { + "One": "用户地址簿" + }, + "IsAdmin": { + "One": "是否管理员" + }, + "PleaseInputNewPassword": { + "One": "请输入新密码" + }, + "AutoRegister": { + "One": "自动注册" + }, + "AutoRegisterNote": { + "One": "如果启用,则当用户使用 OAuth 登录时,将自动注册一个帐户,而无需绑定现有帐户" + }, + "ThirdName": { + "One": "第三方名称" + }, + "Close": { + "One": "关闭" + }, + "OauthBinding": { + "One": "您正在授权绑定" + }, + "OauthLogining": { + "One": "您正在授权登录" + }, + "OauthCloseNote": { + "One": "如不是您发起的授权,请直接关闭页面" + }, + "OperationSuccessAndCloseAfter3Seconds": { + "One": "操作成功,3秒后将自动关闭页面" + }, + "ConfirmOauth": { + "One": "确认授权" + }, + "Device": { + "One": "设备" + }, + "ChangeLang": { + "One": "ToEnglish" + }, + "My": { + "One": "我的" + }, + "Info": { + "One": "信息" + }, + "AddressBooks": { + "One": "地址簿" + }, + "System": { + "One": "系统" + }, + "PeerManage": { + "One": "设备管理" + }, + "AddressBookManage": { + "One": "地址簿管理" + }, + "GroupManage": { + "One": "群组管理" + }, + "UserManage": { + "One": "用户管理" + }, + "UserAdd": { + "One": "用户添加" + }, + "UserEdit": { + "One": "用户编辑" + }, + "TagsManage": { + "One": "标签管理" + }, + "OauthManage": { + "One": "Oauth管理" + }, + "LoginLog": { + "One": "登录日志" + } +} diff --git a/src/utils/request.js b/src/utils/request.js index efea2ba..7623db4 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -3,6 +3,7 @@ import { ElMessage } from 'element-plus' import { getToken, removeToken } from '@/utils/auth' import { useUserStore } from '@/store/user' import { pinia } from '@/store' +import { useAppStore } from '@/store/app' // create an axios instance const service = axios.create({ @@ -14,15 +15,23 @@ const service = axios.create({ // request interceptor service.interceptors.request.use( config => { + if (!config.headers) { + config.headers = {} + } const userStore = useUserStore(pinia) const token = userStore.token || getToken() if (token) { - if (!config.headers) { - config.headers = {} - } config.headers['api-token'] = token } + + const app = useAppStore() + const lang = app.setting.lang + if (lang) { + console.log('lang', lang) + config.headers['Accept-Language'] = lang + } + return config }, error => { @@ -66,7 +75,7 @@ service.interceptors.response.use( error => { if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') > -1) { - error.message = '请求超时!' + error.message = 'Connection Time Out!' } ElMessage({ message: error.message, diff --git a/src/views/address_book/index.js b/src/views/address_book/index.js index 192f78f..427eba7 100644 --- a/src/views/address_book/index.js +++ b/src/views/address_book/index.js @@ -1,7 +1,8 @@ -import { onActivated, onMounted, reactive, ref, watch } from 'vue' +import { reactive, ref } from 'vue' import { create, list, remove, update } from '@/api/address_book' import { ElMessage, ElMessageBox } from 'element-plus' import { useRoute } from 'vue-router' +import { T } from '@/utils/i18n' export function useRepositories () { const route = useRoute() @@ -35,9 +36,9 @@ export function useRepositories () { } const del = async (row) => { - const cf = await ElMessageBox.confirm('确定删除么?', { - confirmButtonText: '确定', - cancelButtonText: '取消', + const cf = await ElMessageBox.confirm(T('Confirm?', { param: T('Delete') }), { + confirmButtonText: T('Confirm'), + cancelButtonText: T('Cancel'), type: 'warning', }).catch(_ => false) if (!cf) { @@ -46,7 +47,7 @@ export function useRepositories () { const res = await remove({ row_id: row.row_id }).catch(_ => false) if (res) { - ElMessage.success('操作成功') + ElMessage.success(T('OperationSuccess')) getList() } } @@ -110,7 +111,7 @@ export function useRepositories () { const api = formData.row_id ? update : create const res = await api(formData).catch(_ => false) if (res) { - ElMessage.success('操作成功') + ElMessage.success(T('OperationSuccess')) formVisible.value = false getList() } diff --git a/src/views/address_book/index.vue b/src/views/address_book/index.vue index f64c017..ea7b791 100644 --- a/src/views/address_book/index.vue +++ b/src/views/address_book/index.vue @@ -1,8 +1,8 @@