language-popup.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <template>
  2. <uni-popup
  3. class="language-popup"
  4. ref="languageRef"
  5. type="bottom"
  6. :is-mask-click="false"
  7. borderRadius="10px 10px 0 0"
  8. >
  9. <view class="popup-content">
  10. <view class="popup-header">
  11. <text style="width: 100%">{{ $t("index.languageChange") }}</text>
  12. <text class="close-btn" @click="close">×</text>
  13. </view>
  14. <view class="language-options">
  15. <view
  16. v-for="(item, index) in locales"
  17. :key="item.code"
  18. class="language-option"
  19. :class="{ selected: getDisplayLanguageCode === item.code }"
  20. @click="handleLanguageSelection(item.code)"
  21. >
  22. {{ item.text }}
  23. </view>
  24. </view>
  25. </view>
  26. </uni-popup>
  27. </template>
  28. <script setup>
  29. import { computed, ref, watch, onMounted } from "vue";
  30. import { useI18n } from "vue-i18n";
  31. // 定义语言映射关系
  32. const LANGUAGE_MAPPING = {
  33. 'zh-Hans': 'zh-Hans',
  34. 'zh-CN': 'zh-Hans',
  35. 'en': 'en',
  36. 'ru': 'ru',
  37. 'auto': 'auto'
  38. }
  39. const emit = defineEmits(['close', 'language-change'])
  40. const { t, locale } = useI18n({
  41. useScope: 'global'
  42. })
  43. // 语言列表
  44. const locales = [
  45. { text: t('locale.auto'), code: 'auto' },
  46. { text: t('locale.en'), code: 'en' },
  47. { text: t('locale.zh-hans'), code: 'zh-Hans' },
  48. { text: t('locale.ru'), code: 'ru' }
  49. ]
  50. // 当前选择的语言(存储在本地的设置)
  51. const selectedLanguage = ref(uni.getStorageSync("language") || "auto");
  52. // 获取系统语言并映射到支持的语言
  53. const getSystemLanguage = () => {
  54. try {
  55. const systemLang = uni.getSystemInfoSync().language;
  56. console.log("🚀 ~ getSystemLanguage ~ systemLang:", systemLang)
  57. // 检查是否在映射表中
  58. if (LANGUAGE_MAPPING[systemLang]) {
  59. return LANGUAGE_MAPPING[systemLang];
  60. }
  61. // 检查语言前缀(例如 "en-US" -> "en")
  62. const langPrefix = systemLang.split('-')[0];
  63. if (SUPPORTED_LANGUAGES.includes(langPrefix)) {
  64. return langPrefix;
  65. }
  66. // 默认返回中文
  67. return 'zh-Hans';
  68. } catch (error) {
  69. console.error('获取系统语言失败:', error);
  70. return 'zh-Hans';
  71. }
  72. }
  73. // 计算属性:获取实际使用的语言代码
  74. const activeLanguage = computed(() => {
  75. if (selectedLanguage.value === "auto") {
  76. return getSystemLanguage();
  77. }
  78. return LANGUAGE_MAPPING[selectedLanguage.value] || selectedLanguage.value;
  79. });
  80. // 计算属性:用于显示的语言代码(处理auto选项)
  81. const getDisplayLanguageCode = computed(() => {
  82. return selectedLanguage.value === "auto" ? "auto" : activeLanguage.value;
  83. });
  84. const languageRef = ref(null);
  85. onMounted(() => {
  86. console.log("language-popup mounted", activeLanguage.value);
  87. console.log("language-popup mounted", uni.getSystemInfoSync().language);
  88. // 初始化时设置语言
  89. setAppLanguage(activeLanguage.value);
  90. });
  91. // 设置应用语言
  92. const setAppLanguage = (lang) => {
  93. try {
  94. locale.value = lang;
  95. uni.setLocale(lang);
  96. emit("language-change", lang);
  97. } catch (error) {
  98. console.error("Failed to set locale:", error);
  99. }
  100. };
  101. // 打开弹窗
  102. const open = () => {
  103. languageRef.value.open();
  104. };
  105. // 关闭弹窗
  106. const close = () => {
  107. languageRef.value.close();
  108. };
  109. // 处理语言选择
  110. const handleLanguageSelection = (lang) => {
  111. console.log("🚀 ~ handleLanguageSelection ~ lang:", lang)
  112. console.log("🚀 ~ handleLanguageSelection ~ selectedLanguage.value:", selectedLanguage.value)
  113. if (lang === selectedLanguage.value) {
  114. console.log(`🚀 ~ handleLanguageSelection ~ uni.getStorageSync("language"):`, uni.getStorageSync("language"))
  115. if (!uni.getStorageSync("language") ) {
  116. uni.setStorageSync("language", lang);
  117. }
  118. close();
  119. return;
  120. }
  121. uni.showModal({
  122. content: t("index.language-change-confirm"),
  123. cancelText: t("operation.cancel"),
  124. confirmText: t("operation.confirm"),
  125. success: (res) => {
  126. if (res.confirm) {
  127. // 更新选择的语言
  128. selectedLanguage.value = lang;
  129. // 保存到本地存储
  130. uni.setStorageSync("language", lang);
  131. // 设置应用语言
  132. setAppLanguage(activeLanguage.value);
  133. close();
  134. }
  135. },
  136. });
  137. };
  138. // 监听语言变化
  139. watch(selectedLanguage, (newVal) => {
  140. console.log("Language changed to:", newVal);
  141. });
  142. // 提供外部方法
  143. const expose = {
  144. open,
  145. };
  146. defineExpose(expose);
  147. </script>
  148. <style lang="scss" scoped>
  149. .language-popup {
  150. position: fixed;
  151. top: 0;
  152. left: 0;
  153. width: 100%;
  154. height: 100%;
  155. background-color: rgba(0, 0, 0, 0.5);
  156. display: flex;
  157. justify-content: center;
  158. align-items: center;
  159. z-index: 999;
  160. }
  161. .popup-content {
  162. background-color: #fff;
  163. width: 100%;
  164. // max-width: 300px;
  165. border-radius: 10px 10px 0px 0px;
  166. overflow: hidden;
  167. }
  168. .popup-header {
  169. padding: 15px;
  170. background-color: #007aff;
  171. color: #fff;
  172. display: flex;
  173. justify-content: space-between;
  174. align-items: center;
  175. text-align: center;
  176. }
  177. .close-btn {
  178. font-size: 20px;
  179. cursor: pointer;
  180. }
  181. .language-options {
  182. padding: 15px;
  183. }
  184. .language-option {
  185. padding: 10px;
  186. border-bottom: 1px solid #eee;
  187. cursor: pointer;
  188. text-align: center;
  189. }
  190. .language-option:last-child {
  191. border-bottom: none;
  192. }
  193. .language-option.selected {
  194. color: #007aff;
  195. font-weight: bold;
  196. }
  197. </style>