Uniapp-vue实现语言功能切换(多语言)

阐述如何使用unapp开发中vue方式实现移动端中列表点击弹出语言列表,然后进行选择语言!

bash 复制代码
<!-- pages/index/index.vue -->
<template>
  <view class="container">
    <!-- 语言切换弹窗 -->
    <LanguagePopup :visible="showLanguagePopup" @close="handlePopupClose" />
    
    <!-- 顶部装饰 -->
    <view class="top-decor">
      <view class="decor-circle circle-1"></view>
      <view class="decor-circle circle-2"></view>
      <view class="decor-circle circle-3"></view>
    </view>
    
    <!-- 主要内容 -->
    <view class="main-content">
      <!-- Logo区域 -->
      <view class="logo-container">
        <image class="logo" src="/static/logo.png" mode="aspectFit"></image>
        <view class="logo-glow"></view>
      </view>
      
      <!-- 欢迎语 -->
      <view class="welcome-container">
        <text class="welcome-text">{{ getTranslation('welcome') }}</text>
        <text class="title-text">{{ currentTitle }}</text>
        <view class="title-underline"></view>
      </view>
      
      <!-- 语言切换按钮 -->
      <view class="button-container">
        <view class="language-button" @tap="showLanguagePopup = true">
          <view class="button-inner">
            <text class="button-icon">🌐</text>
            <text class="button-text">{{ currentLanguageName }}</text>
            <view class="button-arrow">
              <text>▼</text>
            </view>
          </view>
          <view class="button-glow"></view>
        </view>
        
        <!-- 提示文本 -->
        <!-- <text class="hint-text">点击按钮切换应用语言</text> -->
      </view>

    </view>
  </view>
</template>

<script>
// 局部导入组件
import LanguagePopup from '@/components/LanguagePopup.vue'

export default {
  // 注册组件
  components: {
    LanguagePopup
  },
  
  data() {
    return {
      showLanguagePopup: false,
      currentTitle: 'Hello',
      currentLanguageName: 'English',
      languageCount: 3
    }
  },
  
  onLoad() {
    this.initLanguage()
    
    // 监听语言变化
    uni.$on('languageChanged', this.updateLanguage)
  },
  
  onUnload() {
    uni.$off('languageChanged', this.updateLanguage)
  },
  
  methods: {
    initLanguage() {
      try {
        const langModule = require('@/utils/language.js')
        const lang = langModule.getCurrentLanguage()
        this.currentTitle = lang.translations?.title || 'Hello'
        this.currentLanguageName = lang.name || 'English'
        
        // 获取语言数量
        const allLangs = langModule.getAllLanguages()
        this.languageCount = allLangs.length
      } catch (error) {
        console.log('语言模块加载失败:', error)
        // 使用默认值
        this.currentTitle = 'Hello'
        this.currentLanguageName = 'English'
        this.languageCount = 3
      }
    },
    
    getTranslation(key) {
      try {
        const langModule = require('@/utils/language.js')
        const translation = langModule.getTranslation(key)
        return translation || key
      } catch (error) {
        // 默认翻译
        const defaultTranslations = {
          'welcome': 'Welcome to',
          'title': 'Hello'
        }
        return defaultTranslations[key] || key
      }
    },
    
    handlePopupClose() {
      this.showLanguagePopup = false
    },
    
    updateLanguage() {
      try {
        const langModule = require('@/utils/language.js')
        const lang = langModule.getCurrentLanguage()
        this.currentTitle = lang.translations?.title || this.currentTitle
        this.currentLanguageName = lang.name || this.currentLanguageName
      } catch (error) {
        console.log('更新语言失败:', error)
      }
    }
  }
}
</script>

<style scoped>
.container {
  min-height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  position: relative;
  overflow: hidden;
}

/* 顶部装饰 */
.top-decor {
  position: absolute;
  top: -100rpx;
  right: -100rpx;
  width: 300rpx;
  height: 300rpx;
}

.decor-circle {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
}

.circle-1 {
  width: 200rpx;
  height: 200rpx;
  top: 0;
  right: 0;
}

.circle-2 {
  width: 120rpx;
  height: 120rpx;
  top: 40rpx;
  right: 40rpx;
  background: rgba(255, 255, 255, 0.15);
}

.circle-3 {
  width: 60rpx;
  height: 60rpx;
  top: 70rpx;
  right: 70rpx;
  background: rgba(255, 255, 255, 0.2);
}

/* 主要内容 */
.main-content {
  padding: 100rpx 40rpx 60rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  z-index: 1;
}

/* Logo区域 */
.logo-container {
  position: relative;
  margin-bottom: 80rpx;
}

.logo {
  width: 240rpx;
  height: 240rpx;
  border-radius: 50%;
  box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.2);
  position: relative;
  z-index: 2;
}

.logo-glow {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 280rpx;
  height: 280rpx;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0%, 100% {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0.3;
  }
  50% {
    transform: translate(-50%, -50%) scale(1.1);
    opacity: 0.2;
  }
}

/* 欢迎语 */
.welcome-container {
  text-align: center;
  margin-bottom: 100rpx;
}

.welcome-text {
  display: block;
  font-size: 32rpx;
  color: rgba(255, 255, 255, 0.9);
  margin-bottom: 20rpx;
  font-weight: 400;
  letter-spacing: 2rpx;
}

.title-text {
  display: block;
  font-size: 72rpx;
  color: white;
  font-weight: 700;
  margin-bottom: 20rpx;
  letter-spacing: 1rpx;
  text-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.2);
}

.title-underline {
  width: 120rpx;
  height: 8rpx;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 4rpx;
  margin: 0 auto;
  animation: underlineSlide 2s ease-in-out infinite;
}

@keyframes underlineSlide {
  0%, 100% {
    width: 120rpx;
    opacity: 0.8;
  }
  50% {
    width: 160rpx;
    opacity: 1;
  }
}

/* 按钮容器 */
.button-container {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* 语言切换按钮 */
.language-button {
  position: relative;
  width: 100%;
  max-width: 500rpx;
  margin-bottom: 40rpx;
}

.button-inner {
  background: white;
  border-radius: 50rpx;
  padding: 30rpx 40rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 15rpx 40rpx rgba(0, 0, 0, 0.2);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  z-index: 2;
}

.language-button:active .button-inner {
  transform: scale(0.98);
  box-shadow: 0 8rpx 25rpx rgba(0, 0, 0, 0.15);
}

.button-icon {
  font-size: 40rpx;
  margin-right: 20rpx;
}

.button-text {
  font-size: 36rpx;
  font-weight: 600;
  color: #333;
  flex: 1;
  text-align: center;
}

.button-arrow {
  color: #999;
  font-size: 24rpx;
  transform: translateY(2rpx);
  transition: transform 0.3s;
}

.language-button:active .button-arrow {
  transform: translateY(2rpx) rotate(180deg);
}

.button-glow {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100% + 20rpx);
  height: calc(100% + 20rpx);
  border-radius: 55rpx;
  background: rgba(255, 255, 255, 0.2);
  filter: blur(15rpx);
  animation: buttonGlow 2s ease-in-out infinite;
}

@keyframes buttonGlow {
  0%, 100% {
    opacity: 0.5;
    transform: translate(-50%, -50%) scale(1);
  }
  50% {
    opacity: 0.8;
    transform: translate(-50%, -50%) scale(1.05);
  }
}





/* 响应式调整 */
@media (max-width: 600rpx) {
  .main-content {
    padding: 80rpx 30rpx 40rpx;
  }
  
  .logo {
    width: 200rpx;
    height: 200rpx;
  }
  
  .logo-glow {
    width: 240rpx;
    height: 240rpx;
  }
  
  .title-text {
    font-size: 60rpx;
  }
  
  .button-inner {
    padding: 25rpx 35rpx;
  }
  
  .button-text {
    font-size: 32rpx;
  }
}
</style>
bash 复制代码
// utils/language.js
import { getCurrentLanguage, setCurrentLanguage, getAllLanguages, t } from './languages/index.js'

export {
  getCurrentLanguage,
  setCurrentLanguage,
  getAllLanguages,
  t
}
bash 复制代码
// utils/languages/index.js

// 导入所有语言文件
import zhCN from './zh-CN.js'
 import zhTW from './zh-TW.js'
 import enUS from './en-US.js'
 import enGB from './en-GB.js'
import ja from './ja.js'
import ko from './ko.js'
import fr from './fr.js'
import de from './de.js'
import es from './es.js'
import ru from './ru.js'
import ar from './ar.js'
import pt from './pt.js'
import it from './it.js'

// 语言映射表
export const languages = {
  'zh-CN': zhCN,
   'zh-TW': zhTW,
  'en-US': enUS,
   'en-GB': enGB,
  'ja': ja,
  'ko': ko,
  'fr': fr,
  'de': de,
  'es': es,
  'ru': ru,
  'ar': ar,
  'pt': pt,
  'it': it
}

// 默认语言
const DEFAULT_LANGUAGE = 'zh-CN'

// 获取当前语言
export function getCurrentLanguage() {
  try {
    const langCode = uni.getStorageSync('currentLanguage') || DEFAULT_LANGUAGE
    return languages[langCode] || languages[DEFAULT_LANGUAGE]
  } catch (error) {
    console.error('获取语言失败:', error)
    return languages[DEFAULT_LANGUAGE]
  }
}

// 设置当前语言
export function setCurrentLanguage(langCode) {
  if (languages[langCode]) {
    try {
      uni.setStorageSync('currentLanguage', langCode)
      
      // 如果是RTL语言,设置页面方向
      if (languages[langCode].rtl) {
        uni.setNavigationBarStyle({
          frontColor: '#ffffff',
          backgroundColor: '#1AAD19',
          animation: {
            duration: 400,
            timingFunc: 'easeIn'
          }
        })
      }
      
      return true
    } catch (error) {
      console.error('设置语言失败:', error)
      return false
    }
  }
  return false
}

// 获取所有语言列表
export function getAllLanguages() {
  return Object.values(languages)
}

// 获取翻译文本
export function getTranslation(key, langCode = null) {
  const lang = langCode ? (languages[langCode] || getCurrentLanguage()) : getCurrentLanguage()
  return lang.translations[key] || key
}

// 简化的翻译函数
export function t(key) {
  return getTranslation(key)
}
bash 复制代码
// utils/languages/zh-CN.js
export default {
  code: 'zh-CN',
  name: '简体中文',
  translations: {
    title: '你好',
    selectLanguage: '选择语言',
    languageChanged: '语言切换成功',
    hello: '你好世界',
    welcome: '欢迎使用我们的应用',
    settings: '设置',
    about: '关于',
    contact: '联系我们',
    home: '首页',
    profile: '个人资料',
    logout: '退出登录'
  }
}
bash 复制代码
// utils/languages/en-US.js
export default {
  code: 'en-US',
  name: 'English (US)',
  translations: {
    title: 'Hello',
    selectLanguage: 'Select Language',
    languageChanged: 'Language changed successfully',
    hello: 'Hello World',
    welcome: 'Welcome to our app',
    settings: 'Settings',
    about: 'About',
    contact: 'Contact Us',
    home: 'Home',
    profile: 'Profile',
    logout: 'Logout'
  }
}
bash 复制代码
// utils/languages/ko.js
export default {
  code: 'ko',
  name: '한국어',
  translations: {
    title: '안녕하세요',
    selectLanguage: '언어 선택',
    languageChanged: '언어가 성공적으로 변경되었습니다',
    hello: '안녕하세요 세계',
    welcome: '우리 앱에 오신 것을 환영합니다',
    settings: '설정',
    about: '약',
    contact: '문의하기',
    home: '홈',
    profile: '프로필',
    logout: '로그아웃'
  }
}

main:

bash 复制代码
import App from './App'

// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
  ...App
})
app.$mount()
// #endif

// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
  const app = createSSRApp(App)
  return {
    app
  }
}
// #endif

此时就完成了语言功能的切换~!nice

相关推荐
北辰alk6 分钟前
解决Vue打包后静态资源图片失效的终极指南
vue.js
摸鱼的春哥1 小时前
AI编排实战:用 n8n + DeepSeek + Groq 打造全自动视频洗稿流水线
前端·javascript·后端
Coder_Boy_2 小时前
基于SpringAI的在线考试系统设计总案-知识点管理模块详细设计
android·java·javascript
Jing_Rainbow2 小时前
【Vue-2/Lesson62(2025-12-10)】模块化与 Node.js HTTP 服务器开发详解🧩
前端·vue.js·node.js
冴羽3 小时前
2026 年 Web 前端开发的 8 个趋势!
前端·javascript·vue.js
五仁火烧4 小时前
Vue3 项目的默认端口行为
服务器·vue.js·nginx·容器·vue
fengbizhe4 小时前
bootstrapTable转DataTables,并给有着tfoot的DataTables加滚动条
javascript·bootstrap
刘一说4 小时前
TypeScript 与 JavaScript:现代前端开发的双子星
javascript·ubuntu·typescript
EndingCoder4 小时前
类的继承和多态
linux·运维·前端·javascript·ubuntu·typescript
用户47949283569154 小时前
React 终于出手了:彻底终结 useEffect 的"闭包陷阱"
前端·javascript·react.js