国际化 - 项目实战1 - Vue3 + js + element-plus

271 阅读3分钟

Vue3 + js + element-plus 项目实战国际化

1 安装依赖

  npm install vue-i18n@next  # Vue3的i18n插件

2 创建语言文件

  // src/lang/language/en.js
  export default {
      lang: {
        changeLanguageSuccess: "Language changed successfully!",
        language: "English",
        china: "China",
        spain: "Spain",
        english: "English",
      },
      login: {
        title: "OK Cloud Management System",
        registro: "Registro",
        inputName: "Please enter your name",
        inputPassword: "Please enter your password",
        welcome: "Welcome",
        username: "Username",
        password: "Password",
        confirmPassword: "Confirm Password",
        solicitar: "Solicitar",
      },
      tips: {
        inputName: "Please enter your name",
        inputPassword: "Please enter your password",
        userNameSize: "Username length 3-10 characters",
        passwordSize: "The password must be 6-15 non-blank characters",
      },
      message: {
        successLogin: "login successful!",
      },
   }

3 配置 i18n 国际化入口文件

  // src/lang/language/index.jsimport { createI18n } from "vue-i18n"
  // 导入语言包
  import zh from "./language/zh.js"
  import en from "./language/en.js"
  import es from "./language/es.js"const messages = {
    zh: zh,
    en: en,
    es: es,
  }
  ​
  // 创建 i18n 实例
  const i18n = createI18n({
    legacy: false,    // 禁用 Legacy API,强制使用 Composition API
    locale: 'zh',     // 默认语言,再 App.vue中初始化
    fallbackLocale: 'zh', // 备用语言
    messages: messages,
  })
  ​
  export default i18n
  ​

4 配置element-plus

  
  // src/lang/language/element-plus-i18n.jsimport en from 'element-plus/es/locale/lang/en'
  import zhCn from 'element-plus/es/locale/lang/zh-cn'
  import es from 'element-plus/es/locale/lang/es'export const elementLocales = {
    en : en,
    es : es,
    zh : zhCn,
  }

5 全局挂载 i8n 组件

  // src/main.js// 国际化
  import i18n from '@/lang/index'
  // 国际化挂载
  app.use(i18n)

6 pinia 状态管理

  // src/store/modules/language.jsimport { defineStore } from 'pinia'
  import { ref } from 'vue'export const useLanguageStore = defineStore('language', () => {
    // 1 支持的语言列表(可根据需要扩展)
    const supportedLanguages = ['zh', 'en', 'es']
  ​
    // 2 初始化语言(从浏览器语言检测)
    function initLanguage() {
      // 1 获取浏览器默认语言
      const browserLang = navigator.language?.toLowerCase().split('-')[0]
      // 2 获取本地存储语言
      const storyData = localStorage.getItem('app-language')
      const localStoryLanguage = storyData ? JSON.parse(storyData).language : null;
      // 3 返回结果
      const res = localStoryLanguage || browserLang || 'zh'
      return res
    }
  ​
    // 3 当前语言
    const language = ref(initLanguage())
  ​
    // 4 设置语言
    function setLanguage(lang) {
      if (supportedLanguages.includes(lang)) {
        language.value = lang
        return true
      }
      return false
    }
  ​
    return {
      language,
      setLanguage
    }
  }, {
    persist: {
      key: 'app-language', // 自定义存储键名
      storage: localStorage, // 明确使用 localStorage(默认值)
    }
  })

7 配置入口文件

  // src/App.vue
  <template>
    <!-- element-plus 国际化组件处理 -->
    <el-config-provider :locale="elementLocales[lang]">
      <router-view></router-view>
    </el-config-provider>
  </template><script setup>
  // 国际化处理
  import { useLanguageStore } from '@/store/modules/language'
  import { elementLocales } from '@/lang/element-plus-i18n'
  import { useI18n } from 'vue-i18n'
  import { computed } from 'vue';
    
  // 获取最新的local值
  const languageStore = useLanguageStore()
  let lang = computed(() => languageStore.language)
  // 实时更新 i18n
  const {locale} = useI18n()
  locale.value = lang.value
   </script> 

8 封装切换语言组件

  <template>
      <el-dropdown placement="bottom-end" @command="selectLanguage">
          <!-- 展示给客户,默认看到的 -->
          <span class="el-dropdown-link">
              <strong>{{ $t('lang.language') }}</strong>
              <svg-icon :icon-class="languageStore.language" />
              <el-icon><CaretBottom/></el-icon>
          </span>
          <!-- 语言下拉列表 -->
          <template #dropdown>
              <el-dropdown-menu>
                  <el-dropdown-item command="zh" >中文</el-dropdown-item>
                  <el-dropdown-item command="es" >Español</el-dropdown-item>
                  <el-dropdown-item command="en" >English</el-dropdown-item>
              </el-dropdown-menu>
          </template> 
      </el-dropdown>
  </template><script setup name="LangSelect">
  import { useI18n } from 'vue-i18n'
  import { useLanguageStore } from '@/store/modules/language';
  import { CaretBottom } from '@element-plus/icons-vue';
  import { changeLanguage } from '../../api/login';
  import { ElMessage } from 'element-plus';
  ​
  const languageStore = useLanguageStore()
  console.log("当前的语言状态是:",languageStore.language)
  // 实时更新 i18n
  const {locale} = useI18n()
  const {t} = useI18n()
  const javaLang = {
      zh : "zh_CN",
      es : "es_ES",
      en : "en_US"
  }
  const selectLanguage = (key) => {
    languageStore.setLanguage(key)
    locale.value = key
    changeLanguage(javaLang[key]).then(res => {
      //window.location.reload()
      ElMessage.success(t('lang.changeLanguageSuccess'))
    })
  }
  ​
  </script><style lang="scss" scoped>
  .el-dropdown-link{
    height: 100%;
    margin-left: 10px;
    margin-right: 10px;
    padding: 0;
    display: flex;
    align-items: center;
    // color: $layout-font-color;
    // font-size: 20px;
    border: none !important;  // 隐藏组件el-dropdown 的边框
    outline: none !important;  // 隐藏组件el-dropdown 的边框
    .svg-icon{
      margin-left: 5px;
      font-size: 40px;
    }
  }
  ​
  </style>

9 使用多语言

9.1 vue模板中使用

  <template>
    <div>
      <h1>{{ $t('message.welcome') }}</h1>
      <el-button>{{ $t('buttons.submit') }}</el-button>
    </div>
  </template>
  <script setup>
  import { useI18n } from 'vue-i18n'
  const { t } = useI18n()
  </script>

9.2 Script 中使用

  <script setup>
  import { useI18n } from 'vue-i18n'const { t } = useI18n()
  console.log(t('message.hello'))
  ​
  </script>

9.3 Js文件中使用(全局)

  
  import i18n from '@/lang/index'const t = i18n.global.t
  router.beforeEach((to, from, next) => {
    ...
    if (to.meta.title) {
      const title = t(to.meta.title)
      useSettingsStore().setTitle(title) // 存储到Store(设置网页标题)
    }
    ...
  }

9.4 路由标题国际化

9.4.1 固态路由维护
  // src/router/index.js// 1 路由 meta.title 维护映射字段"route.home"
  const routes = [
    {
      path: '/home',
      component: () => import('@/views/home'),
      meta: {
        title: 'route.home' // 使用语言包中的key
      }
    }
  ]
9.4.2 动态路由维护
  
  // 菜单管理 -> 修改菜单名称 "route.home"
9.4.3 维护组件展示路由
  // 1 网页标题 /src/permission.js// 路由前置守卫
  router.beforeEach((to, from, next) => {
    ...
    if (to.meta.title) {
      const title = i18n.global.t(to.meta.title)
      useSettingsStore().setTitle(title) // 存储到Store(设置网页标题)
    }
    ...
  }
    
    // 2 侧边栏菜单 /src/compoments/Sidebar/SidebarItem/index.vue
    // 3 面包屑菜单 /src/compoments/Sidebar/TagsView/index.vue
    // 4 面包屑导航组件 /src/compoments/Breadcrumb/index.vue
    {{ $t(item.meta.title) }}
    
    import { useI18n } from 'vue-i18n'  
    const { t } = useI18n() ;
    
  ​

10 嵌套翻译

1 引用翻译
`${t('importData.importOrderDetail')}_${new Date().getTime()}.xlsx`

2 嵌套翻译
    2.1 翻译字段
        importData.messageSuccessError'成功条数 {count}, 失败条数 {error}'
    2.2 翻译引用
        t('importData.messageSuccessError', 
        {count: result.data.successCount, error: result.data.failedList.length}
        )