LanguageSwitch.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. <template>
  2. <div class="page-container">
  3. <van-nav-bar
  4. :title="$t('common.confirm')"
  5. left-arrow
  6. fixed
  7. placeholder
  8. @click-left="router.back()"
  9. class="custom-nav"
  10. />
  11. <div class="content-body">
  12. <div
  13. v-for="item in langList"
  14. :key="item.code"
  15. class="lang-card"
  16. :class="{ 'active': currentLang === item.code }"
  17. @click="onSelectLang(item)"
  18. >
  19. <div class="flag-icon">{{ item.flagEmoji }}</div>
  20. <div class="text-info">
  21. <div class="native-name">{{ item.native }}</div>
  22. <div class="english-name">{{ item.english }}</div>
  23. </div>
  24. <div class="checkbox-area">
  25. <div v-if="currentLang === item.code" class="check-box">
  26. <van-icon name="success" color="#fff" size="14" />
  27. </div>
  28. </div>
  29. </div>
  30. </div>
  31. </div>
  32. </template>
  33. <script setup>
  34. import { ref } from 'vue';
  35. import { useRouter } from 'vue-router';
  36. import { useI18n } from 'vue-i18n';
  37. import { showLoadingToast, closeToast, Icon as VanIcon } from 'vant';
  38. import { loadLanguageAsync } from '@/locales/index.js';
  39. const router = useRouter();
  40. const { locale } = useI18n();
  41. const currentLang = ref(locale.value);
  42. const langList = [
  43. { code: 'en-US', native: 'English', english: 'English', flagEmoji: '🇺🇸' },
  44. { code: 'de-DE', native: 'Deutsch', english: 'German', flagEmoji: '🇩🇪' },
  45. { code: 'es-ES', native: 'Español', english: 'Spanish', flagEmoji: '🇪🇸' },
  46. { code: 'fr-FR', native: 'Français', english: 'French', flagEmoji: '🇫🇷' },
  47. { code: 'pt-PT', native: 'Português', english: 'Portuguese', flagEmoji: '🇵🇹' },
  48. { code: 'id-ID', native: 'Bahasa Indonesia', english: 'Indonesian', flagEmoji: '🇮🇩' },
  49. { code: 'ru-RU', native: 'Русский', english: 'Russian', flagEmoji: '🇷🇺' },
  50. { code: 'zh-CN', native: '简体中文', english: 'Chinese Simplified', flagEmoji: '🇨🇳' },
  51. ];
  52. const onSelectLang = async (item) => {
  53. const langCode = item.code;
  54. if (langCode === currentLang.value) return;
  55. showLoadingToast({
  56. message: 'Switching...',
  57. forbidClick: true,
  58. duration: 0,
  59. });
  60. try {
  61. await loadLanguageAsync(langCode);
  62. currentLang.value = langCode;
  63. closeToast();
  64. setTimeout(() => {
  65. // router.back();
  66. }, 200);
  67. } catch (error) {
  68. closeToast();
  69. }
  70. };
  71. </script>
  72. <style scoped lang="less">
  73. .page-container { min-height: 100vh; background-color: #f7f8fa; }
  74. .content-body { padding: 16px; }
  75. .lang-card {
  76. background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 12px;
  77. display: flex; align-items: center; border: 1px solid transparent;
  78. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02); transition: all 0.2s;
  79. &:active { background-color: #f2f3f5; }
  80. &.active { border-color: #ee0a24; background-color: #fffbfb; }
  81. }
  82. .flag-icon { font-size: 24px; margin-right: 16px; }
  83. .text-info { flex: 1; display: flex; flex-direction: column;
  84. .native-name { font-size: 16px; font-weight: 600; color: #323233; margin-bottom: 2px; }
  85. .english-name { font-size: 12px; color: #969799; }
  86. }
  87. .checkbox-area { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; }
  88. .check-box { width: 22px; height: 22px; background-color: #ee0a24; border-radius: 4px;
  89. display: flex; align-items: center; justify-content: center; }
  90. :deep(.custom-nav) { --van-nav-bar-icon-color: #333; --van-nav-bar-title-text-color: #333; }
  91. </style>