123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- <template>
- <div class="relative inline-block text-left " ref="dropdownContainerRef">
- <div
- @click="toggleDropdown"
- class="flex justify-center items-center gap-2 text-white opacity-80 text-sm"
- >
- <i class="icon-i18n"></i>
- {{ currentLocaleName || "Language" }}
- </div>
-
- <transition
- enter-active-class="transition ease-out duration-100"
- enter-from-class="transform opacity-0 scale-95"
- enter-to-class="transform opacity-100 scale-100"
- leave-active-class="transition ease-in duration-75"
- leave-from-class="transform opacity-100 scale-100"
- leave-to-class="transform opacity-0 scale-95"
- >
- <div
- v-if="isDropdownOpen"
- class="origin-top-right absolute right-0 mt-2 w-36 rounded-md shadow-lg bg-[var(--color-bg)] ring-1 ring-black ring-opacity-5 focus:outline-none z-10"
- role="menu"
- aria-orientation="vertical"
- aria-labelledby="options-menu"
- >
- <div class="py-1" role="none">
- <a
- v-for="locale in availableLocales"
- :key="locale.code"
- href="#"
- @click.prevent="selectLanguage(locale.code)"
- :class="[
- 'block px-4 py-2 text-sm opacity-80',
- currentLocale === locale.code
- ? 'text-white opacity-100 font-bold'
- : 'text-white hover: opacity-100',
- ]"
- role="menuitem"
- >
- {{ locale.name }}
- </a>
- </div>
- </div>
- </transition>
- </div>
- </template>
-
- <script setup lang="ts">
- /**
- * 语言切换组件 - 下拉菜单样式
- * 支持切换配置的语言
- */
- import { ref, computed } from "vue";
- import { useI18n } from "#imports"; // 修正 useI18n 导入
- import { onClickOutside } from "@vueuse/core"; // 导入 onClickOutside
-
- // 定义语言代码的类型,应该与 i18n 配置中的一致
- type LocaleCode = "zh" | "en" | "ja"; // 你需要根据你的 i18n 配置更新这个类型
-
- const { locale, locales, setLocale } = useI18n();
- const currentLocale = computed(() => locale.value);
- const isDropdownOpen = ref(false);
- const dropdownContainerRef = ref(null); // 创建 ref
-
- // 可用语言列表
- const availableLocales = computed(() => {
- // 确保 locales.value 是一个数组并且包含 code 和 name 属性
- return (
- (locales.value as Array<{ code: string; name: string }>) || []
- ).filter((l) => l.code && l.name);
- });
-
- // 当前选中语言的名称
- const currentLocaleName = computed(() => {
- const current = availableLocales.value.find(
- (l) => l.code === currentLocale.value
- );
- return current ? current.name : "";
- });
-
- /**
- * 切换下拉菜单的显示/隐藏状态
- */
- function toggleDropdown() {
- isDropdownOpen.value = !isDropdownOpen.value;
- }
-
- /**
- * 选择语言并关闭下拉菜单
- * @param {string} langCode - 选择的语言代码
- */
- async function selectLanguage(langCode: string) {
- if (currentLocale.value !== langCode) {
- try {
- // 使用类型断言,确保 langCode 是有效的 LocaleCode
- await setLocale(langCode as LocaleCode);
- } catch (error) {
- console.error("Failed to set locale:", error);
- // 这里可以添加用户反馈,例如显示一个错误提示
- }
- }
- isDropdownOpen.value = false; // 关闭下拉菜单
- }
-
- // 点击外部关闭下拉菜单
- onClickOutside(dropdownContainerRef, () => {
- if (isDropdownOpen.value) {
- isDropdownOpen.value = false;
- }
- });
- </script>
|