添加国际化支持:引入 vue-i18n,更新多个组件以支持语言切换和文本翻译

This commit is contained in:
jxxghp
2025-04-27 17:44:09 +08:00
parent 80ae853582
commit d0b3bc8137
27 changed files with 973 additions and 374 deletions

View 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>

View File

@@ -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>

View File

@@ -1,7 +1,7 @@
@use "@configured-variables" as variables;
// ————————————————————————————————————
//* ——— Perfect Scrollbar
// Perfect Scrollbar
// ————————————————————————————————————
.v-application.v-theme--dark {