PinnovateCloud/components/LanguageSwitcher.vue
2025-09-11 10:55:59 +08:00

144 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="language-switcher">
<div class="relative">
<button
@click="toggleDropdown"
:class="[
'flex items-center px-4 py-2 rounded-md transition-colors duration-300 shadow-sm border',
isDark ? 'bg-white/10 text-white hover:bg-white/20 border-white/20' : 'bg-gray-50 text-gray-700 hover:bg-gray-100 border-gray-200'
]"
>
<span class="font-medium">{{ getLanguageName(locale) }}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 ml-2 transition-transform duration-200"
:class="{ 'rotate-180': isOpen }"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div
v-if="isOpen"
class="absolute mt-2 w-40 right-0 bg-white rounded-md shadow-xl py-1 z-10 border border-gray-200 overflow-hidden transition-opacity duration-200 ease-in-out"
>
<button
v-for="loc in availableLocales"
:key="loc"
@click="switchLanguage(loc)"
class="w-full text-left px-4 py-3 text-sm text-gray-700 hover:bg-gray-100 hover:text-primary transition-colors duration-150 flex items-center"
:class="{ 'bg-gray-100 text-primary font-medium': loc === currentLocale }"
:disabled="isChangingLanguage"
>
<span class="w-5 h-5 inline-flex items-center justify-center mr-3">
<span v-if="loc === currentLocale" class="w-2 h-2 rounded-full bg-primary"></span>
</span>
{{ getLanguageName(loc) }}
</button>
</div>
</div>
<span v-if="showLabel" class="ml-2 text-xs text-gray-400">当前语言: {{ getLanguageName(currentLocale) }}</span>
</div>
</template>
<script setup>
import { useI18n } from 'vue-i18n'
import { computed, ref, onMounted, onUnmounted } from 'vue'
import { useLanguageTransition } from '~/composables/useLanguageTransition'
import { useRoute, useRouter } from 'vue-router'
const props = defineProps({
isDark: {
type: Boolean,
default: true
}
})
const route = useRoute()
const router = useRouter()
const { locale, availableLocales } = useI18n()
const currentLocale = computed(() => locale.value)
const isOpen = ref(false)
const showLabel = ref(false) // 是否显示当前语言的标签根据需要可以设置为true
// 使用语言过渡效果
const { smoothSwitchLanguage, isChangingLanguage } = useLanguageTransition()
function getLanguageName(localeCode) {
const languageNames = {
'cn': '简体中文',
'zh': 'English',
'zh-TW': '繁體中文'
}
return languageNames[localeCode] || localeCode
}
function switchLanguage(newLocale) {
if (isChangingLanguage.value) return
// 获取当前路径,去掉语言前缀
const currentPath = route.path
const parts = currentPath.split('/')
// 如果当前URL已经包含语言代码则去掉它
let pathWithoutLocale = currentPath
if (availableLocales.includes(parts[1])) {
pathWithoutLocale = currentPath.substring(parts[1].length + 1) || '/'
}
// 构建带有新语言代码的路径
const newPath = newLocale === 'zh'
? `/${newLocale}${pathWithoutLocale === '/' ? '' : pathWithoutLocale}`
: `/${newLocale}${pathWithoutLocale === '/' ? '' : pathWithoutLocale}`
// 使用平滑过渡方法切换语言并导航到新路径
smoothSwitchLanguage(newLocale)
// 导航到新路径
router.push(newPath)
isOpen.value = false
}
function toggleDropdown() {
if (isChangingLanguage.value) return
isOpen.value = !isOpen.value
}
// 点击外部关闭下拉菜单
function closeDropdown(e) {
if (!e.target.closest('.language-switcher')) {
isOpen.value = false
}
}
// 在组件挂载时添加事件监听
onMounted(() => {
document.addEventListener('click', closeDropdown)
})
// 在组件卸载时移除事件监听
onUnmounted(() => {
document.removeEventListener('click', closeDropdown)
})
</script>
<style scoped>
.language-switcher {
display: flex;
align-items: center;
position: relative;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.absolute {
animation: fadeIn 0.2s ease-out;
}
</style>