通用管理后台组件库-3-vue-i18n国际化集成

i18n国际化集成

说明:使用vue-i18n库实现系统国际化,结合@intlify/unplugin-vue-i18n插件实现预加载(开发中国际化显示),同时集成elementplus中en和zh-cn文件的组件国际化。

1.国际化文件

/locales/en.json

json 复制代码
{
  "anything": "anything",
  "hello": "Hello"
}

/locales/zh-CN.json

json 复制代码
{
  "hello": "你好"
}

2.插件i18n ally, 使用命令添加文本国际化翻译

.vscode/setting.json

json 复制代码
{
  "i18n-ally.localesPaths": ["locales"],
  "i18n-ally.keystyle": "nested",
  "i18n-ally.sortKeys": true,
  "i18n-ally.namespace": true,
  "i18n-ally.enabledParsers": ["yaml", "js", "json"],
  "i18n-ally.sourceLanguage": "en",
  "i18n-ally.displayLanguage": "zh-CN",
  "i18n-ally.enabledFrameworks": ["vue"],
  "i18n-ally.translate.engines": [
    "baidu",
    "google"
  ]
}

3.国际化i18n.ts

typescript 复制代码
import type { App } from 'vue'
import { createI18n, type Locale } from 'vue-i18n'

// Legacy模式(选项式API):语言设置是直接赋值,vue2的赋值方式
// Composition模式(组合式API):语言设置是赋值给响应式变量

// 创建一个i18n实例
const i18n = createI18n({
  legacy: false,
  locale: '',
  messages: {}
})

// 解析locales目录下的所有语言文件,转换为对象,例如:{ en: () => import('../../locales/en.js'), zh-CN: () => import('../../locales/zh-CN.js') }
const localesMap = Object.fromEntries(
  Object.entries(import.meta.glob('../../locales/*.json')).map(([path, loadLocale]) => [
    path.match(/([\w-]*)\.json$/)?.[1],
    loadLocale
  ])
) as Record<Locale, () => Promise<{ default: Record<string, string> }>>

// 集成elementplus中的国际化文件en和zh-CN
const elementPlusLocaleMap = Object.fromEntries(
  Object.entries(import.meta.glob('../../node_modules/element-plus/dist/locale/*.mjs')).map(
    ([path, loadLocale]) => [path.match(/([\w-]*)\.mjs$/)?.[1], loadLocale]
  )
) as Record<Locale, () => Promise<{ default: Record<string, string> }>>

// 获取存在的语言数组
export const availableLocales = Object.keys(localesMap)

// 过滤elementplus中的国际化文件,只保留en和zh-CN
const filterEPLocaleMap = availableLocales.reduce(
  (acc: Record<Locale, () => Promise<{ default: Record<string, string> }>>, locale: Locale) => {
    return {
      ...acc,
      //locale.toLowerCase()将zh-CN转换为小写,elementplus中的语言文件都是小写的
      [locale]: elementPlusLocaleMap[locale.toLowerCase()]
    }
  },
  {}
)
// 记住用户选择的语言
const loadedLanguages: string[] = []

// 设置国际化(i18n)语言的函数
export function setI18nLanguage(locale: string) {
  // Composition模式赋值
  i18n.global.locale.value = locale
  if (typeof document !== 'undefined') {
    document.querySelector('html')?.setAttribute('lang', locale)
  }
}

// 加载国际化(i18n)语言包的异步函数
export async function loadLocaleMessages(lang: string) {
  // 如果语言包i18n已经加载过,则直接设置i18n.locale
  if (i18n.global.locale.value === lang || loadedLanguages.includes(lang)) {
    return setI18nLanguage(lang)
  }
  // 通过语言代码从预定义的语言映射中获取对应的语言包加载函数并执行
  const messages = await localesMap[lang]()
  // 获取elementplus的语言包
  const messagesEP = await filterEPLocaleMap[lang]()
  // 将加载的语言包设置到i18n实例中
  i18n.global.setLocaleMessage(lang, { ...messagesEP.default, ...messages.default })
  loadedLanguages.push(lang)
  return setI18nLanguage(lang)
}

// 挂载到app上
export default {
  install(app: App) {
    app.use(i18n)
    // 设置默认语言为中文
    loadLocaleMessages('zh-CN')
  }
}

main.ts中挂载到app上

javascript 复制代码
import i18n from './modules/i18n'
app.use(i18n)

4.构建和打包优化,因elementplus包中不止en和zh-cn文件,还有其他语言文件,所有在构建时过滤出en和zh-cn文件打包到dist中。

vite.config.ts

javascript 复制代码
import { fileURLToPath, URL } from 'node:url'
import path from 'node:path'
import fs from 'node:fs'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import vueDevTools from 'vite-plugin-vue-devtools'
import UnoCSS from 'unocss/vite'

import VueRouter from 'unplugin-vue-router/vite'
import { VueRouterAutoImports } from 'unplugin-vue-router'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import Layouts from 'vite-plugin-vue-layouts'
import { VitePWA } from 'vite-plugin-pwa'
import { viteMockServe } from 'vite-plugin-mock'
// import dotenv from 'dotenv'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// Load environment variables
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'

// https://vite.dev/config/
export default defineConfig(({ mode }) => {
  // 加载环境变量
  const env = loadEnv(mode, process.cwd()) // 加载 `.env.[mode]`

  const enablePWADEBUG = env.VITE_PWA_DEBUG === 'true'
  const enableMock = env.VITE_MOCK_ENABLE === 'true'

  /**
   * elementplus国际化文件打包和构建优化,只保留zh-cn和en文件到dist中。
   * 过滤elementplus的.mjs文件,不打包不需要的locales
   * 判断,/locales中对应的文件名的.mjs文件作为过滤条件->保留
   */
  function filterElementPlusLocales(id: string) {
    // 返回true表示打包,false表示不打包
    // locales文件查找
    const localesDir = path.resolve(__dirname, 'locales')
    const localesFiles = fs
      .readdirSync(localesDir)
      .map((file) => file.match(/([\w-]*)\.json$/)?.[1] || '')
    if (id.includes('element-plus/dist/locale')) {
      // 获取id的basename
      const basename = path.basename(id, '.mjs')
      // 判断basename是否在localesFiles中
      return !localesFiles.some((file) => basename === file.toLowerCase())
    }
    return false
  }

  return {
    build: {
      rollupOptions: {
        // id:文件名,external:是否打包
        external: (id) => filterElementPlusLocales(id)
      }
    },
    plugins: [
      VueRouter(),
      vue(),
      vueJsx(),
      vueDevTools(),
      UnoCSS(),
      AutoImport({
        include: [
          /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
          /\.vue$/,
          /\.vue\?vue/, // .vue
          /\.md$/ // .md
        ],

        // global imports to register
        imports: [
          // presets
          'vue',
          // 'vue-router'
          VueRouterAutoImports,
          '@vueuse/core'
        ],
        resolvers: [ElementPlusResolver()]
      }),
      Components({
        directoryAsNamespace: false,
        collapseSamePrefixes: true,
        resolvers: [ElementPlusResolver()]
      }),
      Layouts({
        layoutsDirs: 'src/layouts',
        defaultLayout: 'default'
      }),
      VitePWA({
        injectRegister: 'auto',
        manifest: {
          name: 'Vite App',
          short_name: 'Vite App',
          theme_color: '#ffffff',
          icons: [
            {
              src: '/192x192.png',
              sizes: '192x192',
              type: 'image/png'
            },
            {
              src: '/512x512.png',
              sizes: '512x512',
              type: 'image/png'
            }
          ]
        },
        registerType: 'autoUpdate',
        workbox: {
          navigateFallback: '/',
          // 如果大家有很大的资源文件,wasm bundle.js
          globPatterns: ['**/*.*']
        },
        devOptions: {
          enabled: enablePWADEBUG,
          suppressWarnings: true,
          navigateFallbackAllowlist: [/^\/$/],
          type: 'module'
        }
      }),
      viteMockServe({
        mockPath: 'mock',
        enable: enableMock
      }),
      createSvgIconsPlugin({
        // 指定需要缓存的图标文件夹
        iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
        // 指定symbolId格式
        symbolId: 'icon-[dir]-[name]'
      }),
      VueI18nPlugin({
        include: [path.resolve(__dirname, './locales/**')],
        // 组合式赋值方式,契合Vue3.0
        compositionOnly: true
      })
    ],
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url))
      }
    }
  }
})

5.使用和效果

bash 复制代码
<div>自定义国际化:{{ $t('hello') }}</div>
<div>elementplus国际化:{{ $t('el.colorpicker.confirm') }}</div>
<div>{{ $t('anything') }}</div>
<el-select v-model="locale" placeholder="请选择" @change="changeLocale"
  <el-option label="中文" value="zh-CN" />
  <el-option label="英文" value="en" />
</el-select>
相关推荐
AlanHou2 小时前
Three.js:Web 最重要的 3D 渲染引擎的技术综述
前端·webgl·three.js
JS_GGbond2 小时前
前端必备技能:彻底搞懂JavaScript深浅拷贝,告别数据共享的坑!
前端
拖拉斯旋风2 小时前
React 跨层级组件通信:使用 `useContext` 打破“长安的荔枝”困境
前端·react.js
沛沛老爹2 小时前
Web开发者快速上手AI Agent:Dify本地化部署与提示词优化实战
前端·人工智能·rag·faq·文档细粒度
时光追逐者2 小时前
一款基于 .NET 9 构建的企业级 Web RBAC 快速开发框架
前端·c#·.net·.net core
张拭心2 小时前
"氛围编程"程序员被解雇了
android·前端·人工智能
SomUrim2 小时前
ruoyi-vue-plus中await axios报错undefined的问题(请求正常)
前端·ruoyi
daizikui2 小时前
streamlit实现登录功能
服务器·前端·javascript
广州华水科技2 小时前
如何通过单北斗形变监测一体机提高大坝安全监测效率?
前端