Merge pull request #272 from jamebal/i18n

feat: add I18n config
This commit is contained in:
jmal 2024-09-20 14:05:37 +08:00 committed by GitHub
commit e06189fb6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 371 additions and 90 deletions

View File

@ -34,6 +34,7 @@
"jshint": "^2.11.1",
"less-loader": "^6.1.0",
"lib-flexible": "^0.3.2",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"monaco-editor": "^0.23.0",
"monaco-editor-vue": "^1.0.10",
@ -42,7 +43,7 @@
"mxcad": "^1.0.238",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"path-to-regexp": "3.3.0",
"pinyin": "^2.9.1",
"qrcode": "^1.5.1",
"scriptjs": "^2.5.9",
@ -56,6 +57,7 @@
"vue-aplayer": "^1.6.1",
"vue-color": "^2.8.1",
"vue-demi": "^0.14.6",
"vue-i18n": "^8.28.2",
"vue-runtime-helpers": "^1.1.2",
"vue-simple-uploader": "0.7.6",
"vuedraggable": "^2.23.2",

View File

@ -1493,7 +1493,7 @@ export default {
}
}
const isCurrentPath = (this.path + '/') === fileDoc
if ('deleteFile' === url && isCurrentPath) {
if ('deleteFile' === url && (isCurrentPath || this.$route.path.startsWith('/recently'))) {
this.getFileListEnter()
}
if ('createFile' === url) {

View File

@ -36,7 +36,8 @@
</el-dropdown-item>
</app-link>
<el-dropdown-item divided @click.native="logout">
<svg-icon icon-class="tuichudenglu"></svg-icon>退出登录
<svg-icon icon-class="tuichudenglu"></svg-icon>
{{ $t('login.logout') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>

View File

@ -73,7 +73,7 @@
<svg-icon class="webdav-icon" icon-class="disk-drive"></svg-icon>
<div class="wedav-text">WebDAV</div>
<el-tooltip placement="right" v-if="showCopyBtn">
<div slot="content">点击复制WebDAV地址<br />{{ webdavUrl }}</div>
<div slot="content">{{ $t('app.clickCopyWebDAVAddress') }}<br />{{ webdavUrl }}</div>
<svg-icon
class="copy-btn"
icon-class="menu-fuzhi"

73
src/locales/en_US.js Normal file
View File

@ -0,0 +1,73 @@
export default {
common: {
select: 'Select',
confirm: 'Confirm',
cancel: 'Cancel',
item: 'Item',
search: 'Search',
done: 'Done',
lang: 'Language',
pleaseEnter: 'Please enter',
modifiedSuccessfully: 'Modified successfully',
deletedSuccessfully: 'Deleted successfully',
uploadSuccessfully: 'Upload successfully',
tips: 'Tips',
},
route: {
home: 'Home',
favorite: 'Favorite',
image: 'Image',
video: 'Video',
audio: 'Audio',
fileTransfer: 'File Transfer',
},
login: {
username: 'Username',
password: 'Password',
login: 'Login',
logout: 'Logout',
create: 'Create',
confirmPassword: "Confirm Password",
rememberMe: 'Remember Me',
createAdmin: 'Create Admin',
ruleUsername: 'Please enter a valid username',
ruleConfirmPassword: 'Password does not match',
},
msg: {
netDiskLogoRuleFormat: 'Net Disk Logo can only be SVG|JPG|JPEG|PNG format!',
netDiskLogoRuleSize: 'Net Disk Logo size cannot exceed 128k!',
netDiskNameRule: 'Net Disk Name can only contain Chinese, numbers, letters, and underscores',
netDiskNameRuleEmpty: 'Net Disk Name cannot be empty',
enabled: 'Enabled',
disabled: 'Disabled',
},
app: {
browse: 'Browse',
selectItem: 'Select Item',
selectAll: 'Select All',
cancelSelectAll: 'Cancel',
clickCopyWebDAVAddress: 'Click to copy the WebDAV address',
setting: 'Setting',
generalSetting: 'General',
netDiskName: 'Net Disk Name',
netDiskLogo: 'Net Disk Logo',
clickChangeLogo: 'Click to change Logo',
enableWebP: 'Enable WebP',
storageWebP: 'Convert images to WebP format for storage',
rebuildIndex: 'Rebuild Index',
rebuildIndexDesc: 'Rebuilding the index is divided into two steps: 1. Synchronize basic file information, 2. Create an index for the file content',
rebuildIndexStep1: 'Synchronizing basic file information',
rebuildIndexStep2: 'Creating an index for the file content',
resetMenuAndRole: 'Reset Menu and Role',
resetMenuAndRoleDesc: 'Generally used to initialize role and menu data',
currentVersion: 'Current Version',
latestVersion: 'Latest Version',
updateOnGithub: 'Update on Github',
videoTranscoding: 'Video Transcoding',
previewConfig: 'Preview Config',
ldapAuth: 'LDAP Auth',
startSync: 'Start scanning? ',
confirmDeleteMenuAndRole: 'Are you sure you want to delete the current role and menu? ',
resetSuccessfully: 'Reset successfully',
}
}

73
src/locales/zh_CN.js Normal file
View File

@ -0,0 +1,73 @@
export default {
common: {
select: '选择',
confirm: '确定',
cancel: '取消',
item: '项',
search: '搜索',
done: '完成',
lang: '语言',
pleaseEnter: '请输入',
modifiedSuccessfully: '修改成功',
deletedSuccessfully: '删除成功',
uploadSuccessfully: '上传成功',
tips: '提示',
},
route: {
home: '首页',
favorite: '收藏',
image: '图片',
video: '视频',
audio: '音频',
fileTransfer: '文件传输',
},
login: {
username: '用户名',
password: '密码',
login: '登录',
logout: '登出',
create: '创建',
confirmPassword: "确认密码",
rememberMe: '记住我',
createAdmin: '创建管理员',
ruleUsername: '请输入有效的用户名',
ruleConfirmPassword: '密码不匹配',
},
msg: {
netDiskLogoRuleFormat: '网盘Logo只能是 SVG|JPG|JPEG|PNG 格式!',
netDiskLogoRuleSize: '网盘Logo大小不能超过 128k!',
netDiskNameRule: '网盘名称 只能包含中文,数字,字母,下划线',
netDiskNameRuleEmpty: '网盘名称不能为空',
enabled: '已启用',
disabled: '已禁用',
},
app: {
browse: '浏览',
selectItem: '选择项目',
selectAll: '全选',
cancelSelectAll: '取消全选',
clickCopyWebDAVAddress: '点击复制WebDAV地址',
setting: '设置',
generalSetting: '基本设置',
netDiskName: '网盘名称',
netDiskLogo: '网盘Logo',
clickChangeLogo: '点击更换Logo',
enableWebP: '启用WebP',
storageWebP: '将图片转换为WebP格式存储',
rebuildIndex: '重建索引',
rebuildIndexDesc: '重建索引分为两步: 1.同步文件基本信息, 2.为文件内容创建索引',
rebuildIndexStep1: '正在同步文件基本信息',
rebuildIndexStep2: '正在为文件内容创建索引',
resetMenuAndRole: '重置角色、菜单',
resetMenuAndRoleDesc: '一般用于初始化角色、菜单数据',
currentVersion: '当前版本',
latestVersion: '最新版本',
updateOnGithub: '在github上更新',
videoTranscoding: '视频转码',
previewConfig: '预览配置',
ldapAuth: 'LDAP认证',
startSync: '是否开始扫描? ',
confirmDeleteMenuAndRole: '您确定要删除当前角色、菜单吗? ',
resetSuccessfully: '重置成功',
}
}

View File

@ -10,6 +10,9 @@ import App from './App'
import store from './store'
import router from './router'
import VueI18n from 'vue-i18n';
import { loadLocaleMessages, getBrowserLocale } from '@/utils/loadLocaleMessages';
// ant-design-vue
import { Affix } from 'ant-design-vue';
Vue.use(Affix)
@ -23,11 +26,6 @@ import '@/permission' // permission control
import Viewer from 'v-viewer'
// import APlayer from 'vue-aplayer';
// Vue.use(APlayer, {
// defaultCover: 'https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60', // 设置播放器默认封面图片
// productionTip: false, // 是否在控制台输出版本信息
// });
Vue.use(Viewer)
@ -41,8 +39,22 @@ Vue.use(vant.ImagePreview)
import Minder from '@/components/Minder'
Vue.use(Minder)
Vue.use(VueI18n);
const messages = loadLocaleMessages();
const locale = store.getters.lang || getBrowserLocale(messages);
// i18n
const i18n = new VueI18n({
locale: locale,
fallbackLocale: 'en_US',
messages,
});
new Vue({
el: '#app',
i18n,
router,
store,
render: h => h(App),

View File

@ -1,6 +1,7 @@
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
lang: state => state.app.lang,
token: state => state.user.token,
shareToken: state => state.user.shareToken,
avatar: state => state.user.avatar,

View File

@ -1,13 +1,21 @@
import { getConsumerId, getShareToken, getToken, getUsername } from '@/utils/auth'
import Cookies from 'js-cookie'
const state = {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false
},
device: 'desktop'
const getDefaultState = () => {
const app = sessionStorage.getItem('app') && JSON.parse(sessionStorage.getItem('app'))
return {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false
},
device: 'desktop',
lang: app ? app.lang : undefined
}
}
const state = getDefaultState()
const mutations = {
TOGGLE_SIDEBAR: state => {
state.sidebar.opened = !state.sidebar.opened
@ -25,18 +33,32 @@ const mutations = {
},
TOGGLE_DEVICE: (state, device) => {
state.device = device
},
SET_LANG: (state, lang) => {
state.lang = lang
}
}
function setStorage() {
sessionStorage.setItem('app', JSON.stringify(state))
}
const actions = {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
setStorage()
},
closeSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation)
setStorage()
},
toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
setStorage()
},
setLang({ commit }, lang) {
commit('SET_LANG', lang)
setStorage()
}
}

View File

@ -22,18 +22,19 @@ import Layout from '@/layout'
import ParentView from '@/components/ParentView'
const getDefaultState = () => {
const store = sessionStorage.getItem('store') && JSON.parse(sessionStorage.getItem('store'))
return {
token: getToken(),
shareToken: getShareToken(),
name: getUsername(),
showName: '',
showName: store ? store.showName : '',
userInfo: {},
avatar: '',
avatar: store ? store.avatar : '',
userId: getConsumerId(),
menuList: [],
netdiskName: '',
netdiskLogo: '',
newVersion: '',
netdiskName: store ? store.netdiskName : '',
netdiskLogo: store ? store.netdiskLogo : '',
newVersion: store ? store.newVersion : '',
iframePreviewConfig: {}
}
}
@ -140,6 +141,7 @@ const actions = {
commit('SET_NETDISK_NAME', netdiskName)
commit('SET_NETDISK_LOGO', netdiskLogo)
setLogo(netdiskName, netdiskLogo)
sessionStorage.setItem('store', JSON.stringify(state))
},
// get user info

View File

@ -0,0 +1,27 @@
// 使用 require.context 动态加载 locales 目录中的语言文件
export function loadLocaleMessages() {
const locales = require.context('@/locales', true, /\.js$/)
return locales.keys().reduce((messages, key) => {
// 获取语言文件的默认导出
const locale = locales(key).default
// 根据文件名推断语言代码,比如将 `en_US.js` 解析为 `en_US`
const localeKey = key.match(/([a-zA-Z_]+)\./i)[1]
// 添加到 messages 对象
messages[localeKey] = locale
return messages
}, {})
}
export function getBrowserLanguage() {
const browserLanguage = navigator.language || navigator.userLanguage
return browserLanguage.replace('-', '_')
}
// 获取浏览器语言,判断是否支持,返回相应语言代码
export function getBrowserLocale(messages, fallbackLocale = 'en_US') {
return Object.keys(messages).includes(getBrowserLanguage()) ? getBrowserLanguage() : fallbackLocale
}

View File

@ -2,6 +2,7 @@
import store from '@/store'
import _ from "lodash";
import {getShareId, getShareToken, getToken, getUsername} from '@/utils/auth'
import { getBrowserLanguage } from '@/utils/loadLocaleMessages';
// create an axios instance
const service = axios.create({
@ -24,6 +25,8 @@ service.interceptors.request.use(
config.headers['share-token'] = getShareToken()
config.headers['shareId'] = getShareId()
}
// add i18n
config.headers['lang'] = store.getters.lang || getBrowserLanguage()
return config
},
error => {

View File

@ -16,16 +16,16 @@
<span>{{ name }}</span>
<div class="classification">
<van-cell title="首页" icon="wap-home-o" @click="clickFileType(null,{})"/>
<van-cell title="收藏" icon="star-o" @click="clickFileType(null,{isFavorite: true})"/>
<van-cell title="图片" icon="photo-o" @click="clickFileType('image',{isFolder: false})"/>
<van-cell title="视频" icon="video-o" @click="clickFileType('video',{isFolder: false})"/>
<van-cell title="音乐" icon="music-o" @click="clickFileType('audio',{isFolder: false})"/>
<van-cell title="文件传输" icon="upgrade" @click="uploadList"/>
<van-cell :title="$t('route.home')" icon="wap-home-o" @click="clickFileType(null,{})"/>
<van-cell :title="$t('route.favorite')" icon="star-o" @click="clickFileType(null,{isFavorite: true})"/>
<van-cell :title="$t('route.image')" icon="photo-o" @click="clickFileType('image',{isFolder: false})"/>
<van-cell :title="$t('route.video')" icon="video-o" @click="clickFileType('video',{isFolder: false})"/>
<van-cell :title="$t('route.audio')" icon="music-o" @click="clickFileType('audio',{isFolder: false})"/>
<van-cell :title="$t('route.fileTransfer')" icon="upgrade" @click="uploadList"/>
</div>
<div class="logout">
<van-button round type="danger" @click.native="logout">退出登录</van-button>
<van-button round type="danger" @click.native="logout">{{ $t('login.logout') }}</van-button>
</div>
</div>
</van-popup>
@ -43,10 +43,10 @@
<van-nav-bar
:style="vanNavBarClass"
v-if="pathList.length < 2 && !selectStatus"
title="浏览"
:title="$t('app.browse')"
right-arrow
@click-right="checkboxAll"
:right-text="this.selectRowData.length !== this.fileList.length ? '选择' : '取消'"
:right-text="this.selectRowData.length !== this.fileList.length ? $t('common.select') : $t('common.cancel')"
@click-left="leftMenu"
left-arrow>
<div class="header-button" slot="left">
@ -65,9 +65,9 @@
<van-nav-bar
:style="vanNavBarClass"
v-if="selectStatus"
:title="selectRowData.length === 0 ? '选择项目' : selectRowData.length+'项'"
:title="selectRowData.length === 0 ? $t('app.selectItem') : selectRowData.length + $t('common.item')"
right-arrow
:left-text="this.selectRowData.length !== this.fileList.length ? '全选' : '取消全选'"
:left-text="this.selectRowData.length !== this.fileList.length ? $t('app.selectAll') : $t('app.cancelSelectAll')"
@click-left="checkboxAll"
@click-right="cancelSelect"
right-text="完成"
@ -77,7 +77,7 @@
:style="vanNavBarClass"
v-if="pathList.length >= 2 && !selectStatus"
:title="pathList[pathList.length-1].folder"
:right-text="this.selectRowData.length !== this.fileList.length ? '选择' : '取消'"
:right-text="this.selectRowData.length !== this.fileList.length ? $t('common.select') : $t('common.cancel')"
left-arrow
@click-right="checkboxAll"
@click-left="clickBack">
@ -91,12 +91,12 @@
v-model="searchValue"
:show-action="searchStatus"
shape="round"
placeholder="搜索"
:placeholder="$t('common.search')"
@focus="startSearch"
@search="onSearch"
@input="onSearch"
>
<div slot="action" @click="endSearch">取消</div>
<div slot="action" @click="endSearch">{{ $t('common.cancel') }}</div>
</van-search>
</div>
</van-sticky>

View File

@ -18,7 +18,7 @@
</div>
</div>
</h3>
<h3 v-if="initialize" class="title">创建管理员</h3>
<h3 v-if="initialize" class="title">{{ $t('login.createAdmin') }}</h3>
</div>
<el-form-item prop="username">
@ -28,7 +28,7 @@
<el-input
ref="username"
v-model="loginForm.username"
placeholder="用户名"
:placeholder="$t('login.username')"
name="username"
type="text"
tabindex="1"
@ -45,7 +45,7 @@
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="密码"
:placeholder="$t('login.password')"
name="password"
tabindex="2"
auto-complete="on"
@ -58,7 +58,7 @@
<el-form-item v-if="!initialize" class="remember">
<!--<el-switch v-model="loginForm.rememberMe"></el-switch>-->
<el-checkbox label="记住我" v-model="loginForm.rememberMe"></el-checkbox>
<el-checkbox :label="$t('login.rememberMe')" v-model="loginForm.rememberMe"></el-checkbox>
</el-form-item>
<el-form-item v-if="initialize" prop="confirmPassword">
@ -70,7 +70,7 @@
ref="password"
v-model="loginForm.confirmPassword"
:type="passwordType"
placeholder="确认密码"
:placeholder="$t('login.confirmPassword')"
name="password"
tabindex="2"
auto-complete="on"
@ -80,7 +80,7 @@
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
<el-button :loading="loading" type="primary" style="width:100%;margin: 30px 0;" @click.native.prevent="handleLogin">{{initialize?'创建':'登录'}}</el-button>
<el-button :loading="loading" type="primary" style="width:100%;margin: 30px 0;" @click.native.prevent="handleLogin">{{initialize?$t('login.create'):$t('login.login')}}</el-button>
</el-form>
</el-card>
</div>
@ -101,7 +101,6 @@ import { getWebstieRecord } from "@/api/setting-api";
import { hasUser, initialization } from '@/api/user'
import { getRememberName } from '@/utils/auth'
import Logo from "@/components/Logo";
import Bus from "@/assets/js/bus";
export default {
name: 'Login',
@ -109,7 +108,7 @@ export default {
data() {
const validateUsername = (rule, value, callback) => {
if (!this.validUsername(value)) {
callback(new Error('请输入正确的用户名'))
callback(new Error(this.$t('login.ruleUsername')))
} else {
callback()
}
@ -123,7 +122,7 @@ export default {
const confirmPassword = (rule, value, callback) => {
if (value.length < 6) {
} else if(this.loginForm.password !== value) {
callback(new Error('密码不一致'))
callback(new Error(this.$t('login.ruleConfirmPassword')))
} else {
callback()
}
@ -131,14 +130,14 @@ export default {
return {
beianUrl: "http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=",
webstieRecord: {
copyright: 'Copyright © 2020 Journey Magical AL',
copyright: '',
recordPermissionNum: '',
netdiskName: 'jmalcloud',
netdiskLogo: ''
netdiskName: '',
netdiskLogo: this.$store.state.user.netdiskLogo
},
loginForm: {
username: '',
password: '',
username: this.$route.query.username || '',
password: this.$route.query.password || '',
rememberMe: false,
confirmPassword: ''
},
@ -182,7 +181,6 @@ export default {
this.loginForm.username = rememberName
this.loginForm.rememberMe = true
}
getWebstieRecord().then((res) => {
this.webstieRecord = res.data
if (this.webstieRecord.netdiskName || this.webstieRecord.netdiskLogo) {
@ -212,7 +210,7 @@ export default {
this.loading = true
initialization(data).then(()=>{
this.initialize = false
this.$message.success('创建成功')
this.$message.success(this.$t('message.createSuccess'))
this.loading = false
})
}else{

View File

@ -4,22 +4,22 @@
<div slot="header">
<div class="box-card-header">
<div class="clearfix card-header-back">
<span>网盘设置</span>
<span>{{ $t('app.setting') }}</span>
</div>
</div>
</div>
<div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="基本设置" name="1">
<el-tab-pane :label="$t('app.generalSetting')" name="1">
<div v-if="activeName === '1'">
<div class="config-itme-label">网盘名称:
<el-input placeholder="请输入网盘名称" v-model="netdiskName" minlength="1" maxlength="10" size="medium"
<div class="config-itme-label">{{ $t('app.netDiskName') }}:
<el-input :placeholder="$t('common.pleaseEnter')" v-model="netdiskName" minlength="1" maxlength="10" size="medium"
:style="{width: inputNetdiskNameWidth+'px'}"
@keyup.enter.native="updateNetdiskName" @input="inputNetdiskName">
<el-button v-if="showAckBtn" slot="append" icon="el-icon-check" @click="updateNetdiskName"></el-button>
</el-input>
</div>
<div class="config-itme-label logo">网盘Logo:
<div class="config-itme-label logo">{{ $t('app.netDiskLogo') }}:
<el-upload
class="avatar-uploader"
:action="uploadUrl"
@ -29,8 +29,8 @@
<Logo v-model="logoFileName" width="80" class="avatar"></Logo>
</el-upload>
</div>
<span class="instruction">点击更换Logo</span>
<div class="config-itme-label">启用webp:
<span class="instruction">{{ $t('app.clickChangeLogo') }}</span>
<div class="config-itme-label">{{ $t('app.enableWebP') }}:
<el-switch
v-model="webpEnabled"
active-color="#13ce66"
@ -40,27 +40,26 @@
</el-switch>
</div>
<span class="instruction">
将图片转换为webp格式存储,在不降低图片质量的情况下,极大降低图片文件的体积,建议开启.
<a href="https://baike.baidu.com/item/webp%E6%A0%BC%E5%BC%8F" target="_blank">什么是webp?</a>
</span>
<div class="config-itme-label">重建索引:
{{ $t('app.storageWebP') }}
</span>
<div class="config-itme-label">{{ $t('app.rebuildIndex') }}:
<el-button class="sync-button" size="mini" :loading="syncLoading" type="primary" @click="sync()"><i class="el-icon-refresh"></i></el-button>
<span v-show="syncPercent < 100">正在同步文件基本信息: {{ syncPercent }}%</span>
<span v-show="indexingPercent > 0 && indexingPercent < 100">正在为文件内容创建索引: </span><span v-show="indexingPercent > 0 && indexingPercent < 100">{{ indexingPercent }}%</span>
<span v-show="syncPercent < 100">{{ $t('app.rebuildIndexStep1') }}: {{ syncPercent }}%</span>
<span v-show="indexingPercent > 0 && indexingPercent < 100">{{ $t('app.rebuildIndexStep2') }}: </span><span v-show="indexingPercent > 0 && indexingPercent < 100">{{ indexingPercent }}%</span>
</div>
<span class="instruction">重建索引分为两步: 1.同步文件基本信息, 2.为文件内容创建索引</span>
<div class="config-itme-label">重置角色、菜单:
<span class="instruction">{{ $t('app.rebuildIndexDesc') }}</span>
<div class="config-itme-label">{{ $t('app.resetMenuAndRole') }}:
<el-button class="sync-button" size="mini" :loading="resetLoading" type="danger"
@click="resetMenuAndRole()">
<i class="el-icon-refresh-left"></i></el-button>
</div>
<span class="instruction">一般用于初始化角色、菜单数据</span>
<span class="instruction">{{ $t('app.resetMenuAndRoleDesc') }}</span>
<div class="config-itme-label">当前版本:v{{currentVersion}}
<div class="config-itme-label">{{ $t('app.currentVersion') }}:v{{currentVersion}}
<el-badge v-if="newVersion" value="new" class="item"/>
</div>
<span class="instruction">最新版本:{{newVersion ? newVersion : 'v' + currentVersion}}
<a href="https://github.com/jamebal/jmal-cloud-view/releases" target="_blank">在github上更新</a>
<span class="instruction">{{ $t('app.latestVersion') }}:{{newVersion ? newVersion : 'v' + currentVersion}}
<a href="https://github.com/jamebal/jmal-cloud-view/releases" target="_blank">{{ $t('app.updateOnGithub') }}</a>
</span>
</div>
@ -70,21 +69,26 @@
<office-config></office-config>
</div>
</el-tab-pane>
<el-tab-pane label="视频转码" name="3" class="setting-tab-panel">
<el-tab-pane :label="$t('app.videoTranscoding')" name="3" class="setting-tab-panel">
<div v-if="activeName === '3'">
<transcode-config></transcode-config>
</div>
</el-tab-pane>
<el-tab-pane label="预览配置" name="4" class="setting-tab-panel">
<el-tab-pane :label="$t('app.previewConfig')" name="4" class="setting-tab-panel">
<div v-if="activeName === '4'">
<preview-config></preview-config>
</div>
</el-tab-pane>
<el-tab-pane label="LDAP认证" name="5" class="setting-tab-panel">
<el-tab-pane :label="$t('app.ldapAuth')" name="5" class="setting-tab-panel">
<div v-if="activeName === '5'">
<ldap-config></ldap-config>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('common.lang')" name="6" class="setting-tab-panel">
<div v-if="activeName === '6'">
<language-config></language-config>
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-card>
@ -98,6 +102,7 @@ import settingApi, { getSetting } from "@/api/setting-api";
import Logo from "@/components/Logo";
import getPageTitle from "@/utils/get-page-title";
import UploadImageInput from "@/components/input/UploadImageInput.vue";
import LanguageConfig from '@/views/setting/cloudSetting/languageConfig.vue'
import PreviewConfig from '@/views/setting/cloudSetting/previewConfig.vue'
import {mapGetters, mapState} from "vuex";
import store from "@/store";
@ -107,19 +112,19 @@ import TranscodeConfig from "@/views/setting/cloudSetting/transcodeConfig.vue";
import OfficeConfig from "@/views/setting/cloudSetting/officeConfig.vue";
export default {
components: { PreviewConfig, OfficeConfig, TranscodeConfig, LdapConfig, TaskProgress, UploadImageInput, Logo},
components: { LanguageConfig, PreviewConfig, OfficeConfig, TranscodeConfig, LdapConfig, TaskProgress, UploadImageInput, Logo},
data() {
return {
activeName: '1',
uploadUrl: `${process.env.VUE_APP_BASE_API}/user/setting/upload_logo?jmal-token=${this.$store.state.user.token}&name=${this.$store.state.user.name}`,
title: '网盘管理',
title: this.$t('app.setting'),
syncLoading: false,
clickSync: false,
indexingPercent: 100,
syncPercent: 100,
resetLoading: false,
webpEnabled: false,
logoFileName: '',
logoFileName: this.$store.state.user.netdiskLogo || '',
netdiskName: 'JmalCloud',
showAckBtn: false,
inputNetdiskNameWidth: 150,
@ -133,8 +138,6 @@ export default {
this.getIsSync()
if (this.$route.query.tab) {
this.activeName = this.$route.query.tab
if (this.activeName === '2') {
}
}
},
computed: {
@ -171,10 +174,11 @@ export default {
const correctFormat = this.logoFileTypeList.includes(file.type);
const isLtOneM = file.size / 1024 < 128;
if (!correctFormat) {
this.$message.error('网盘Logo只能是 SVG|JPG|JPEG|PNG 格式!');
this.$message.error(this.$t('msg.netDiskLogoRuleFormat').toString());
return correctFormat && isLtOneM;
}
if (!isLtOneM) {
this.$message.error('网盘Logo大小不能超过 128k!');
this.$message.error(this.$t('msg.netDiskLogoRuleSize').toString());
}
return correctFormat && isLtOneM;
},
@ -204,7 +208,7 @@ export default {
// 修改网盘名称
updateNetdiskName() {
if (!this.netdiskName) {
this.$message.warning("网盘名称不能为空")
this.$message.warning(this.$t('msg.netDiskNameRuleEmpty').toString())
return
}
//中文,数字,字母,下划线
@ -218,13 +222,13 @@ export default {
store.dispatch('updateMessage', {event: 'updateLogo'})
document.title = getPageTitle(this.$route.meta.title)
})
this.$message.success("网盘名称 修改成功")
this.$message.success(`${this.$t('app.netDiskName')} ${this.$t('common.modifiedSuccessfully')}`)
this.setInputBlur()
}).catch(() => {
this.setInputBlur()
})
} else {
this.$message.warning("网盘名称 只能包含中文,数字,字母,下划线")
this.$message.warning(`${this.$t('msg.netDiskNameRule')}`)
}
},
getInfo() {
@ -252,9 +256,9 @@ export default {
this.syncLoading = !((this.syncPercent === 100 && this.indexingPercent === 100) || (this.syncPercent === 0 && this.indexingPercent === 0));
},
sync() {
this.$confirm('是否开始扫描? ', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(`${this.$t('app.startSync')}`, `${this.$t('common.tips')}`, {
confirmButtonText: `${this.$t('common.confirm')}`,
cancelButtonText: `${this.$t('common.cancel')}`,
type: 'warning'
}).then(() => {
this.syncLoading = true
@ -269,14 +273,14 @@ export default {
},
// 重置角色菜单
resetMenuAndRole() {
this.$confirm('您确定要删除当前角色、菜单吗? ', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(`${this.$t('app.confirmDeleteMenuAndRole')}`, `${this.$t('common.tips')}`, {
confirmButtonText: `${this.$t('common.confirm')}`,
cancelButtonText: `${this.$t('common.cancel')}`,
type: 'warning'
}).then(() => {
this.resetLoading = true
settingApi.resetMenuAndRole().then(() => {
this.$message.success("重置完成")
this.$message.success(this.$t('app.resetSuccessfully').toString())
this.resetLoading = false
}).catch(() => {
this.resetLoading = false
@ -287,7 +291,7 @@ export default {
},
webpChange(webpEnabled) {
settingApi.disabledWebp({userId: this.$store.state.user.userId, disabled: !webpEnabled}).then(() => {
webpEnabled ? this.$message.success('webp 已启用') : this.$message.warning('webp 已禁用')
webpEnabled ? this.$message.success(`WebP ${this.$t('msg.enabled')}`) : this.$message.warning(`WebP ${this.$t('msg.disabled')}`)
}).catch(() => {
this.webpEnabled = !this.webpEnabled
})

View File

@ -0,0 +1,63 @@
<template>
<div class="container">
<el-form ref="previewConfigForm" :model="configFormData" label-width="120px" size="small" style="width: 450px" autocomplete="off">
<el-form-item :label="$t('common.lang')" prop="lang">
<el-select v-model="configFormData.lang" @change="changeLanguage">
<el-option
v-for="item in languageOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { loadLocaleMessages, getBrowserLocale } from '@/utils/loadLocaleMessages';
export default {
name: 'LanguageConfig',
props: {
data: {
type: Array,
default: [],
},
},
computed: {},
data() {
return {
languageOptions: [
{ value: 'en_US', label: 'English' },
{ value: 'zh_CN', label: '简体中文' },
],
configFormData: {
lang: '',
},
}
},
mounted() {
if (this.$store.getters.lang) {
this.configFormData.lang = this.$store.getters.lang
} else {
this.configFormData.lang = getBrowserLocale(loadLocaleMessages())
}
},
methods: {
changeLanguage(lang) {
this.$store.dispatch('app/setLang', lang)
this.$i18n.locale = lang;
},
},
}
</script>
<style lang="scss" scoped>
.container {
padding: 0 !important;
}
</style>