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

相关推荐
长安牧笛2 小时前
制作本地美食测评评分工具,输入美食名称,口味,价格,自动生成评分,帮助消费者选择美食。
javascript
一字白首2 小时前
Vuex 进阶,模块化开发(Modules):解决单状态树臃肿问题
前端·javascript·vue.js
喵了几个咪2 小时前
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:用 JavaScript/Lua 解锁动态业务扩展能力
javascript·后端·微服务·golang·lua·admin
多看书少吃饭11 小时前
从Vue到Nuxt.js
前端·javascript·vue.js
前端一小卒12 小时前
从 v5 到 v6:这次 Ant Design 升级真的香
前端·javascript
前端不太难13 小时前
《Vue 项目路由 + Layout 的最佳实践》
前端·javascript·vue.js
老华带你飞13 小时前
物流信息管理|基于springboot 物流信息管理系统(源码+数据库+文档)
数据库·vue.js·spring boot
想学后端的前端工程师13 小时前
【Vue3组合式API实战指南:告别Options API的烦恼】
前端·javascript·vue.js
一勺-_-13 小时前
mermaid图片如何保存成svg格式
开发语言·javascript·ecmascript