LanguageSwitcher.vue 4.5 KB
<template>
  <div class="language-switcher" :class="position">
    <el-dropdown @command="handleLanguageChange" trigger="click">
      <span class="language-trigger">
        <img
          v-if="locale === 'zh-CN'"
          src="/zhongwen.svg"
          alt="简体中文"
          class="icon-svg"
        />
        <img v-else src="/yingwen.svg" alt="English" class="icon-svg" />
        <span class="current-lang">{{ currentLanguageText }}</span>

        <el-icon class="arrow-icon"><ArrowDown /></el-icon>
      </span>
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item command="zh-CN">
            <span class="lang-option">
              <img src="/zhongwen.svg" alt="简体中文" class="icon-svg" />
              <span class="lang-text">简体中文</span>
            </span>
          </el-dropdown-item>
          <el-dropdown-item command="en-US">
            <span class="lang-option">
              <img src="/yingwen.svg" alt="English" class="icon-svg" />
              <span class="lang-text">English</span>
            </span>
          </el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted } from "vue";
import { useI18n } from "vue-i18n";
import { useAppStore } from "@/stores/app";
import { setI18nLocale } from "@/locales";
import { ArrowDown } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";

// Props
const props = defineProps({
  position: {
    type: String,
    default: "top-left",
    validator: (value: string) =>
      ["top-left", "top-right", "bottom-left", "bottom-right"].includes(value),
  },
});

const { locale } = useI18n();
const appStore = useAppStore();

// 当前语言显示文本
const currentLanguageText = computed(() => {
  return locale.value === "zh-CN" ? "简体中文" : "English";
});

// 处理语言切换
const handleLanguageChange = (lang: string) => {
  console.log("Language change requested:", lang, "current:", locale.value);
  if (lang !== locale.value && (lang === "zh-CN" || lang === "en-US")) {
    appStore.setLanguage(lang);
    setI18nLocale(lang as "zh-CN" | "en-US");
    ElMessage.success(
      lang === "zh-CN" ? "已切换到简体中文" : "Switched to English",
    );
    console.log("Language changed to:", lang);
  }
};

// 组件挂载时恢复语言设置
onMounted(() => {
  // 清理旧的 locale 键
  if (localStorage.getItem("locale")) {
    localStorage.removeItem("locale");
    console.log("LanguageSwitcher: 已清理旧的 locale 键");
  }

  const savedLang = localStorage.getItem("language");
  if (savedLang && ["zh-CN", "en-US"].includes(savedLang)) {
    setI18nLocale(savedLang as "zh-CN" | "en-US");
  }
  console.log("LanguageSwitcher mounted, current locale:", locale.value);
});
</script>

<style scoped lang="scss">
.language-switcher {
  position: absolute;
  z-index: 1000;

  &.top-left {
    top: 20px;
    left: 20px;
  }

  &.top-right {
    top: 20px;
    right: 20px;
  }

  &.bottom-left {
    bottom: 20px;
    left: 20px;
  }

  &.bottom-right {
    bottom: 20px;
    right: 20px;
  }
}

.language-trigger {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px 12px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  backdrop-filter: blur(10px);
  transition: all 0.3s ease;
  user-select: none;
  pointer-events: auto;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(0, 0, 0, 0.1);

  &:hover {
    background: rgba(255, 255, 255, 0.2);
    border-color: rgba(0, 0, 0, 0.15);
  }

  .globe-icon {
    font-size: 16px;
    color: #1e6fff;
  }

  .arrow-icon {
    font-size: 12px;
    color: #606266;
  }
}

.current-lang {
  color: #606266;
  font-weight: 400;
  font-size: 14px;
}

.lang-option {
  display: flex;
  align-items: center;
  gap: 8px;
}

.icon-svg {
  width: 16px;
  height: 16px;
  object-fit: contain;
  flex-shrink: 0;
}

.lang-text {
  font-size: 14px;
  color: #606266;
}

// 深色主题适配
:deep(.theme-dark) {
  .language-trigger {
    background: rgba(0, 0, 0, 0.3);
    border-color: rgba(255, 255, 255, 0.1);

    &:hover {
      background: rgba(0, 0, 0, 0.5);
      border-color: rgba(255, 255, 255, 0.2);
    }

    .current-lang,
    .arrow-icon {
      color: #fff;
    }
  }
}

// 亮色主题适配
:deep(.theme-light) {
  .language-trigger {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(0, 0, 0, 0.1);

    &:hover {
      background: rgba(255, 255, 255, 0.2);
      border-color: rgba(0, 0, 0, 0.15);
    }
  }
}
</style>