Commit 85807a4a authored by guxukai's avatar guxukai

chore: 加入国际化

parent 67af728b
...@@ -142,6 +142,7 @@ ...@@ -142,6 +142,7 @@
│   │   │   └── lookup //开发参考 开发模式下会在左侧菜单显示 │   │   │   └── lookup //开发参考 开发模式下会在左侧菜单显示
│   │   │   └── icons │   │   │   └── icons
│   │   │   └── index.vue │   │   │   └── index.vue
│   │   ├── plugins //第三方插件
│   │   ├── router //路由相关 │   │   ├── router //路由相关
│   │   │   ├── constants.ts │   │   │   ├── constants.ts
│   │   │   ├── index.ts │   │   │   ├── index.ts
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
"name": "home", "name": "home",
"meta": { "meta": {
"element": "home/index.vue", "element": "home/index.vue",
"title": "home", "title": "首页",
"level": 1, "level": 1,
"icon": "homepage", "icon": "homepage",
"showInAsideMenu": true "showInAsideMenu": true
......
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router' import { router } from './router'
import { store } from '@shared/store' import { app } from '@shared/main'
import { createMockServer } from '@shared/mock' app.use(router).mount('#app')
import 'tailwindcss/tailwind.css'
import ElementPlus from 'element-plus'
import Components from '@shared/components/global/index'
import '@shared/assets/sass/index.scss'
import '@assets/icons'
import '@assets/font/font.css'
import '@assets/css/tailwind.css'
createMockServer()
const app = createApp(App)
app.use(store).use(router).use(ElementPlus).use(Components).mount('#app')
<template>
<el-config-provider :locale="zhCn">
<router-view />
</el-config-provider>
</template>
<script setup>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { useSplash } from '@shared/hooks/useSplash'
useSplash()
</script>
<style></style>
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router' import { router } from './router'
import { store } from '@shared/store' import { app } from '@shared/main'
import { createMockServer } from '@shared/mock' app.use(router).mount('#app')
import 'tailwindcss/tailwind.css'
import ElementPlus from 'element-plus'
import Components from '@shared/components/global/index'
import '@shared/assets/sass/index.scss'
import '@assets/icons'
import '@assets/font/font.css'
import '@assets/css/tailwind.css'
createMockServer()
const app = createApp(App)
app.use(store).use(router).use(ElementPlus).use(Components).mount('#app')
<template>
<el-config-provider :locale="zhCn">
<router-view />
</el-config-provider>
</template>
<script setup>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { useSplash } from '@shared/hooks/useSplash'
useSplash()
</script>
<style></style>
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router' import { router } from './router'
import { store } from '@shared/store' import { app } from '@shared/main'
import { createMockServer } from '@shared/mock' app.use(router).mount('#app')
import 'tailwindcss/tailwind.css'
import ElementPlus from 'element-plus'
import Components from '@shared/components/global/index'
import '@shared/assets/sass/index.scss'
import '@assets/icons'
import '@assets/font/font.css'
import '@assets/css/tailwind.css'
createMockServer()
const app = createApp(App)
app.use(store).use(router).use(ElementPlus).use(Components).mount('#app')
<template>
<el-config-provider :locale="zhCn">
<router-view />
</el-config-provider>
</template>
<script setup>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { useSplash } from '@shared/hooks/useSplash'
useSplash()
</script>
<style></style>
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router' import { router } from './router'
import { store } from '@shared/store' import { app } from '@shared/main'
import { createMockServer } from '@shared/mock' app.use(router).mount('#app')
import 'tailwindcss/tailwind.css'
import ElementPlus from 'element-plus'
import Components from '@shared/components/global/index'
import '@shared/assets/sass/index.scss'
import '@assets/icons'
import '@assets/font/font.css'
import '@assets/css/tailwind.css'
createMockServer()
const app = createApp(App)
app.use(store).use(router).use(ElementPlus).use(Components).mount('#app')
<template>
<el-config-provider :locale="zhCn">
<router-view />
</el-config-provider>
</template>
<script setup>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { useSplash } from '@shared/hooks/useSplash'
useSplash()
</script>
<style></style>
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router' import { router } from './router'
import { store } from '@shared/store' import { app } from '@shared/main'
import { createMockServer } from '@shared/mock' app.use(router).mount('#app')
import 'tailwindcss/tailwind.css'
import ElementPlus from 'element-plus'
import Components from '@shared/components/global/index'
import '@shared/assets/sass/index.scss'
import '@assets/icons'
import '@assets/font/font.css'
import '@assets/css/tailwind.css'
createMockServer()
const app = createApp(App)
app.use(store).use(router).use(ElementPlus).use(Components).mount('#app')
<template>
<el-config-provider :locale="zhCn">
<router-view />
</el-config-provider>
</template>
<script setup>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { useSplash } from '@shared/hooks/useSplash'
useSplash()
</script>
<style></style>
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router' import { router } from './router'
import { store } from '@shared/store' import { app } from '@shared/main'
import { createMockServer } from '@shared/mock' app.use(router).mount('#app')
import 'tailwindcss/tailwind.css'
import ElementPlus from 'element-plus'
import Components from '@shared/components/global/index'
import '@shared/assets/sass/index.scss'
import '@assets/icons'
import '@assets/font/font.css'
import '@assets/css/tailwind.css'
createMockServer()
const app = createApp(App)
app.use(store).use(router).use(ElementPlus).use(Components).mount('#app')
<template> <template>
<el-config-provider :locale="zhCn"> <el-config-provider :locale="currentLocale">
<router-view /> <router-view />
</el-config-provider> </el-config-provider>
</template> </template>
<script setup> <script setup>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { useSplash } from '@shared/hooks/useSplash' import { useSplash } from '@shared/hooks/useSplash'
import { useLocale } from '@shared/hooks/useLocale'
useSplash() useSplash()
const { currentLocale } = useLocale()
</script> </script>
<style></style> <style></style>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import en from 'element-plus/lib/locale/lang/en'
import { computed } from 'vue'
import { useLayout } from '@shared/store/modules/layout'
export const useLocale = () => {
const layoutStore = useLayout()
const currentLocale = computed(() => {
return layoutStore.currentLocale === 'zh' ? zhCn : en
})
return {
currentLocale,
}
}
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
<el-sub-menu :index="menu.name" v-if="menuList?.length"> <el-sub-menu :index="menu.name" v-if="menuList?.length">
<template #title> <template #title>
<i :class="`font-${menu.meta.icon}`" class="mr-6 text-xl cursor-pointer" /> <i :class="`font-${menu.meta.icon}`" class="mr-6 text-xl cursor-pointer" />
<span>{{ menu.meta.title }}</span> <span>{{ $t(`baas.menu.${menu.name}`) }}</span>
</template> </template>
<aside-menu-item v-for="item in menuList" :key="item.name" :menu="item" /> <aside-menu-item v-for="item in menuList" :key="item.name" :menu="item" />
</el-sub-menu> </el-sub-menu>
<el-menu-item :index="menu.name" @click="handleClickMenu()" v-else> <el-menu-item :index="menu.name" @click="handleClickMenu()" v-else>
<i :class="`font-${menu.meta.icon}`" class="mr-6 text-xl cursor-pointer" /> <i :class="`font-${menu.meta.icon}`" class="mr-6 text-xl cursor-pointer" />
<template #title> <template #title>
<span>{{ menu.meta.title }}</span> <span>{{ $t(`baas.menu.${menu.name}`) }}</span>
</template> </template>
</el-menu-item> </el-menu-item>
</template> </template>
......
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="globalization" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M478.33 433.6l-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362L368 281.65L401.17 362z" fill="currentColor"></path><path d="M267.84 342.92a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73c39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36c-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93c.92 1.19 1.83 2.35 2.74 3.51c-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59c22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z" fill="currentColor"></path></svg>
\ No newline at end of file
...@@ -70,6 +70,24 @@ ...@@ -70,6 +70,24 @@
@click="fullScreen" @click="fullScreen"
class="mr-6 text-xl cursor-pointer" class="mr-6 text-xl cursor-pointer"
/> />
<el-dropdown trigger="click">
<img src="./components/globalization.svg" class="mr-6" />
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
v-for="item in localeList"
:key="item.key"
@click="handleChangeLocale(item.key)"
:style="{
background: locale === item.key ? '#1b2a47' : '',
color: locale === item.key ? '#f4f4f5' : '#000',
}"
><el-icon v-show="locale === item.key"> <g-icon name="Check" /> </el-icon
>{{ item.value }}</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-badge type="danger" :value="12" class="mr-12"> <el-badge type="danger" :value="12" class="mr-12">
<g-icon name="Bell" class="w-[1em] h-[1em] text-xl cursor-pointer" /> <g-icon name="Bell" class="w-[1em] h-[1em] text-xl cursor-pointer" />
...@@ -89,11 +107,7 @@ ...@@ -89,11 +107,7 @@
class="flex flex-col pb-0 bg-gray-50 dark:bg-[#151930] dark:text-white transition transition-all duration-300" class="flex flex-col pb-0 bg-gray-50 dark:bg-[#151930] dark:text-white transition transition-all duration-300"
> >
<el-breadcrumb :separator-icon="ArrowRight" class="pl-1"> <el-breadcrumb :separator-icon="ArrowRight" class="pl-1">
<el-breadcrumb-item <el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="index" :to="{ path: item.path }">
v-for="(item, index) in layoutStore.$state.breadcrumbList"
:key="index"
:to="{ path: item.path }"
>
<span class="text-gray-700 dark:text-white">{{ item.title }}</span> <span class="text-gray-700 dark:text-white">{{ item.title }}</span>
</el-breadcrumb-item> </el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
...@@ -117,17 +131,31 @@ import { MessageUtils } from '../utils/message-utils' ...@@ -117,17 +131,31 @@ import { MessageUtils } from '../utils/message-utils'
import { useAuth } from '@shared/store/modules/auth' import { useAuth } from '@shared/store/modules/auth'
import { useLayout } from '@shared/store/modules/layout' import { useLayout } from '@shared/store/modules/layout'
import ConsoleMenu from './components/console-menu/index.vue' import ConsoleMenu from './components/console-menu/index.vue'
import { LocaleType } from '@shared/types/layout'
import { useI18n } from 'vue-i18n'
const props = defineProps({ const props = defineProps({
enableRouteFilter: { enableRouteFilter: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}) })
const { locale } = useI18n()
const layoutStore = useLayout() const layoutStore = useLayout()
const PROJECT_NAME = process.env.APP_NAME const PROJECT_NAME = process.env.APP_NAME
const $route = useRoute() const $route = useRoute()
const $router = useRouter() const $router = useRouter()
const currentActiveRoute = computed(() => $route.name as string) const currentActiveRoute = computed(() => $route.name as string)
const breadcrumbList = computed(() => layoutStore.breadcrumbList)
const localeList: { key: LocaleType; value: string }[] = [
{
key: 'zh',
value: '简体中文',
},
{
key: 'en',
value: 'English',
},
]
onMounted(() => { onMounted(() => {
setTheme(false) setTheme(false)
}) })
...@@ -233,4 +261,11 @@ const handleLogout = () => { ...@@ -233,4 +261,11 @@ const handleLogout = () => {
} }
}) })
} }
//切换语言
const handleChangeLocale = (l: LocaleType) => {
layoutStore.$patch({
currentLocale: l,
})
locale.value = l
}
</script> </script>
import { createApp } from 'vue'
import App from '@shared/App.vue'
import { store } from '@shared/store'
import { createMockServer } from '@shared/mock'
import 'tailwindcss/tailwind.css'
import ElementPlus from 'element-plus'
import Components from '@shared/components/global/index'
import '@shared/assets/sass/index.scss'
import '@assets/icons'
import '@assets/font/font.css'
import '@assets/css/tailwind.css'
import { i18n } from '@shared/plugins/i18n'
createMockServer()
export const app = createApp(App)
app.use(store).use(ElementPlus).use(Components).use(i18n)
<template>
<div>{{ $t('baas.menu.announce-list') }}</div>
</template>
<script lang="ts" setup></script>
// 按钮配置
export const buttonConfig = {
zh: {
baas: {},
},
en: {
baas: {},
},
}
type ButtonConfigItem = {
baas: {
button: {}
}
}
// 导航菜单配置
export const menusConfig: {
zh: MenusConfigItem
en: MenusConfigItem
} = {
zh: {
baas: {
menu: {
lookup: '开发参考',
icons: '图标库',
i18n: '国际化',
home: '首页',
chain: '链管理',
'announce-list': '公告列表',
notice: '站内信',
'alliance-chain': '联盟链',
'parallel-chain': '平行链',
'chain-log': '链日志',
'address-management': '地址管理',
'key-management': '密钥管理',
openapi: 'OpenApi',
'app-management': '授权管理',
'app-openapi': '接口文档',
},
},
},
en: {
baas: {
menu: {
lookup: 'lookup',
icons: 'icons',
i18n: 'i18n',
home: 'home',
chain: 'chain',
'announce-list': 'announce list',
notice: 'notice',
'alliance-chain': 'alliance chain',
'parallel-chain': 'parallel chain',
'chain-log': 'chain log',
'address-management': 'address management',
'key-management': 'key management',
openapi: 'openapi',
'app-management': 'app management',
'app-openapi': 'app openapi',
},
},
},
}
type MenusConfigItem = {
baas: {
menu: {
lookup: string
icons: string
i18n: string
home: string
notice: string
'announce-list': string
chain: string
'alliance-chain': string
'parallel-chain': string
'chain-log': string
'address-management': string
'key-management': string
openapi: string
'app-management': string
'app-openapi': string
}
}
}
//https://vuelidate-next.netlify.app/advanced_usage.html#i18n-support //https://vuelidate-next.netlify.app/advanced_usage.html#i18n-support
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
// element-plus国际化
import enLocale from 'element-plus/lib/locale/lang/en'
import zhLocale from 'element-plus/lib/locale/lang/zh-cn'
import { menusConfig } from '@shared/plugins/i18n/config/menu-config'
import { buttonConfig } from '@shared/plugins/i18n/config/button-config'
const localesList = [menusConfig, buttonConfig]
export const i18n = createI18n({ export const i18n = createI18n({
locale: 'zh', // set locale locale: sessionStorage.getItem('layout') ? JSON.parse(sessionStorage.getItem('layout')!).currentLocale : 'zh', // set locale
fallbackLocale: 'zh', // set fallback locale fallbackLocale: 'zh', // set fallback locale
messages: { messages: {
zh: { zh: {
validations: { baas: Object.assign({}, ...localesList.map(v => v.zh.baas)),
required: '参数不能为空.', ...zhLocale,
}, },
en: {
baas: Object.assign({}, ...localesList.map(v => v.en.baas)),
...enLocale,
}, },
}, },
}) })
...@@ -34,7 +34,16 @@ export const LOOKUP_ROUTES = ...@@ -34,7 +34,16 @@ export const LOOKUP_ROUTES =
title: '图标库', title: '图标库',
showInAsideMenu: true, showInAsideMenu: true,
level: 2, level: 2,
icon: '401', },
},
{
path: '/i18n',
name: 'i18n',
component: () => import('@shared/pages/lookup/i18n/index.vue'),
meta: {
title: '国际化',
showInAsideMenu: true,
level: 2,
}, },
}, },
], ],
......
...@@ -11,11 +11,12 @@ export const useLayout = defineStore('layout', { ...@@ -11,11 +11,12 @@ export const useLayout = defineStore('layout', {
path: '/', path: '/',
}, },
], ],
currentLocale: 'zh',
}), }),
persist: { persist: {
key: 'layout', key: 'layout',
storage: window.sessionStorage, storage: window.sessionStorage,
paths: ['breadcrumbList'], paths: ['breadcrumbList', 'currentLocale'],
overwrite: true, overwrite: true,
}, },
}) })
......
export type LayoutType = { export type LayoutType = {
breadcrumbList: BreadcrumbType[] breadcrumbList: BreadcrumbType[]
currentLocale: LocaleType
} }
export type LocaleType = 'zh' | 'en'
export type BreadcrumbType = { export type BreadcrumbType = {
title: string title: string
level: number level: number
......
import * as validators from '@vuelidate/validators'
import { i18n } from '@shared/utils/i18n-utils'
// or import { createI18nMessage } from '@vuelidate/validators'
const { createI18nMessage } = validators
// extract the `t` helper, should work for both Vue 2 and Vue 3 versions of vue-i18n
const { t } = i18n.global || i18n
// pass `t` and create your i18n message instance
const withI18nMessage = createI18nMessage({ t })
// wrap each validator.
export const required = withI18nMessage(validators.required)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment