mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-19 23:29:52 +08:00
添加国际化支持:引入 vue-i18n,更新多个组件以支持语言切换和文本翻译
This commit is contained in:
64
src/@core/components/LocaleSwitcher.vue
Normal file
64
src/@core/components/LocaleSwitcher.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import { SUPPORTED_LOCALES, SupportedLocale } from '@/locales/types'
|
||||
import { setI18nLanguage, getCurrentLocale } from '@/plugins/i18n'
|
||||
|
||||
// 当前语言
|
||||
const currentLocale = ref<SupportedLocale>(getCurrentLocale())
|
||||
|
||||
// 支持的语言列表
|
||||
const locales = computed(() => {
|
||||
return Object.entries(SUPPORTED_LOCALES).map(([key, locale]) => ({
|
||||
value: key as SupportedLocale,
|
||||
title: locale.title,
|
||||
flag: locale.flag,
|
||||
icon: `flag-${key.split('-')[0]}`,
|
||||
}))
|
||||
})
|
||||
|
||||
// 切换语言
|
||||
async function changeLocale(locale: SupportedLocale) {
|
||||
try {
|
||||
await setI18nLanguage(locale)
|
||||
currentLocale.value = locale
|
||||
// 刷新页面
|
||||
window.location.reload()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前语言图标
|
||||
const getCurrentIcon = computed(() => {
|
||||
const locale = locales.value.find(l => l.value === currentLocale.value)
|
||||
return locale?.flag || '🌐'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VMenu class="locale-menu" scrim>
|
||||
<template v-slot:activator="{ props }">
|
||||
<IconBtn v-bind="props">
|
||||
<span class="text-xl">{{ getCurrentIcon }}</span>
|
||||
</IconBtn>
|
||||
</template>
|
||||
<VList>
|
||||
<div class="px-2">
|
||||
<VListItem
|
||||
v-for="locale in locales"
|
||||
:key="locale.value"
|
||||
@click="changeLocale(locale.value)"
|
||||
:active="currentLocale === locale.value"
|
||||
class="mb-1"
|
||||
>
|
||||
<template #prepend>
|
||||
<span class="text-xl me-2">{{ locale.flag }}</span>
|
||||
</template>
|
||||
<VListItemTitle>{{ locale.title }}</VListItemTitle>
|
||||
<template #append v-if="currentLocale === locale.value">
|
||||
<VIcon icon="mdi-check" color="primary" size="small" />
|
||||
</template>
|
||||
</VListItem>
|
||||
</div>
|
||||
</VList>
|
||||
</VMenu>
|
||||
</template>
|
||||
@@ -6,6 +6,7 @@ import api from '@/api'
|
||||
import { checkPrefersColorSchemeIsDark } from '@/@core/utils'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import { saveLocalTheme } from '../utils/theme'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// 显示器宽度
|
||||
const display = useDisplay()
|
||||
@@ -27,6 +28,8 @@ const getNextThemeName = () => {
|
||||
|
||||
const $toast = useToast()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
// 自定义CSS弹窗
|
||||
const cssDialog = ref(false)
|
||||
|
||||
@@ -64,14 +67,6 @@ function changeTheme(theme: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 是否有滚动条
|
||||
function hasScrollbar(el?: Element | null) {
|
||||
if (!el || el.nodeType !== Node.ELEMENT_NODE) return false
|
||||
|
||||
const style = window.getComputedStyle(el)
|
||||
return style.overflowY === 'scroll' || (style.overflowY === 'auto' && el.scrollHeight > el.clientHeight)
|
||||
}
|
||||
|
||||
// 监听系统主题变化
|
||||
try {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme)
|
||||
@@ -158,7 +153,7 @@ onMounted(() => {
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-palette" />
|
||||
</template>
|
||||
<VListItemTitle>自定义主题</VListItemTitle>
|
||||
<VListItemTitle>{{ t('theme.custom') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
</div>
|
||||
</VList>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@use "@configured-variables" as variables;
|
||||
|
||||
// ————————————————————————————————————
|
||||
//* ——— Perfect Scrollbar
|
||||
// Perfect Scrollbar
|
||||
// ————————————————————————————————————
|
||||
|
||||
.v-application.v-theme--dark {
|
||||
|
||||
Reference in New Issue
Block a user