mirror of
https://github.com/CzBiX/qb-web.git
synced 2026-04-01 18:10:16 +08:00
Add switch language feature
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
>
|
||||
<v-card v-if="!!config">
|
||||
<v-card-title v-text="content.title" />
|
||||
<v-card-text v-text="content.text" />
|
||||
<v-card-text class="content" v-text="content.text" />
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
@@ -104,3 +104,9 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -10,20 +10,88 @@
|
||||
<img class="icon" src="/favicon.ico">
|
||||
<span class="title hidden-sm-and-down ml-3 mr-5">qBittorrent Web UI</span>
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<v-select
|
||||
class="locales"
|
||||
:items="locales"
|
||||
prepend-inner-icon="mdi-translate"
|
||||
v-model="currentLocale"
|
||||
hide-details
|
||||
solo
|
||||
flat
|
||||
/>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { mapMutations } from 'vuex';
|
||||
|
||||
import i18n, { tr, locales } from '@/locale';
|
||||
import { DialogType } from '@/store/types';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
value: Boolean,
|
||||
},
|
||||
data() {
|
||||
const locales_ = Object.entries(locales).map(([key, value]) => {
|
||||
return {
|
||||
text: value,
|
||||
value: key,
|
||||
};
|
||||
});
|
||||
|
||||
const locale = i18n.locale();
|
||||
|
||||
return {
|
||||
locales: locales_,
|
||||
oldLocale: locale,
|
||||
currentLocale: locale,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'showDialog',
|
||||
'showSnackBar',
|
||||
]),
|
||||
toggle() {
|
||||
this.$emit('input', !this.value);
|
||||
},
|
||||
async switchLocale(locale: string) {
|
||||
if (locale === this.oldLocale) {
|
||||
return;
|
||||
}
|
||||
|
||||
const confirm = await new Promise((resolve) => {
|
||||
this.showDialog({
|
||||
content: {
|
||||
text: tr('dialog.switch_locale.msg', { lang: locales[locale] }),
|
||||
type: DialogType.OkCancel,
|
||||
callback: resolve,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
if (!confirm) {
|
||||
this.currentLocale = this.oldLocale;
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.commit('updateConfig', {
|
||||
key: 'locale',
|
||||
value: locale,
|
||||
});
|
||||
|
||||
this.showSnackBar(tr('dialog.switch_locale.reloading'))
|
||||
|
||||
location.reload();
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
currentLocale(v) {
|
||||
this.switchLocale(v);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -49,4 +117,20 @@ export default Vue.extend({
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
// Fix width
|
||||
// see: https://github.com/vuetifyjs/vuetify/issues/6275
|
||||
.locales {
|
||||
flex-grow: 0;
|
||||
|
||||
&::v-deep .v-select__selections {
|
||||
.v-select__selection {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -82,7 +82,11 @@ export default {
|
||||
move: 'Are you sure to move selected torrents to category %{category}?',
|
||||
reset: 'Are you sure to reset category of selected torrents?',
|
||||
also_move_same_name_torrents: 'Also move one same named torrent |||| Also move %{smart_count} same named torrents',
|
||||
}
|
||||
},
|
||||
switch_locale: {
|
||||
msg: 'Are you sure to switch language to %{lang}?\nThis action will reload page.',
|
||||
reloading: 'Reloading…',
|
||||
},
|
||||
},
|
||||
|
||||
state: {
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
import { isString } from 'lodash';
|
||||
import Polyglot from 'node-polyglot';
|
||||
import en from './en';
|
||||
|
||||
import { loadConfig } from '@/store/config';
|
||||
|
||||
const polyglot = new Polyglot({
|
||||
phrases: en,
|
||||
});
|
||||
|
||||
const locales: any = {
|
||||
export const locales: {[key: string]: string} = {
|
||||
en: 'English',
|
||||
'zh-CN': '中文',
|
||||
};
|
||||
|
||||
function updateLocale() {
|
||||
const { languages } = navigator;
|
||||
let locale: string | undefined = loadConfig()['locale'];
|
||||
if (!locale) {
|
||||
const { languages } = navigator;
|
||||
|
||||
let locale;
|
||||
for (const code of languages) {
|
||||
if (code in locales) {
|
||||
locale = code;
|
||||
break;
|
||||
for (const code of languages) {
|
||||
if (code in locales) {
|
||||
locale = code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,14 +75,18 @@ export default {
|
||||
hint: '每行一个链接',
|
||||
},
|
||||
delete_torrents: {
|
||||
msg: '你确定要删除选中的种子吗?',
|
||||
msg: '确定要删除选中的种子吗?',
|
||||
also_delete_same_name_torrents: '同时删除 %{smart_count} 个同名的种子',
|
||||
},
|
||||
set_category: {
|
||||
move: '你确定要移动选中的种子到分类 %{category} 吗?',
|
||||
reset: '你确定重置选中的种子的分类吗?',
|
||||
move: '确定要移动选中的种子到分类 %{category} 吗?',
|
||||
reset: '确定重置选中的种子的分类吗?',
|
||||
also_move_same_name_torrents: '同时移动 %{smart_count} 个同名的种子',
|
||||
}
|
||||
},
|
||||
switch_locale: {
|
||||
msg: '确定要切换语言为 %{lang} 吗?\n这将会刷新页面。',
|
||||
reloading: '刷新中…',
|
||||
},
|
||||
},
|
||||
|
||||
state: {
|
||||
|
||||
@@ -15,13 +15,14 @@ const defaultConfig = {
|
||||
category: null,
|
||||
site: null,
|
||||
},
|
||||
locale: null,
|
||||
};
|
||||
|
||||
function saveConfig(obj: any) {
|
||||
localStorage.setItem(configKey, JSON.stringify(obj));
|
||||
}
|
||||
|
||||
function loadConfig() {
|
||||
export function loadConfig() {
|
||||
const tmp = localStorage.getItem(configKey);
|
||||
if (!tmp) {
|
||||
return {};
|
||||
|
||||
Reference in New Issue
Block a user