mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat(i18n): initialize vue-i18n for internationalization support
- Added vue-i18n as a dependency. - Configured vue-i18n in the main application file. - Created initial locale files with translations.
This commit is contained in:
parent
9d808b4ccd
commit
a50e356f42
|
|
@ -11,3 +11,4 @@ declare module 'katex'
|
|||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
declare type Recordable<T = any> = Record<string, T>;
|
||||
|
|
|
|||
|
|
@ -641,6 +641,25 @@ export const iconMap: any = {
|
|||
])
|
||||
}
|
||||
},
|
||||
'app-translate': {
|
||||
iconReader: () => {
|
||||
return h('svg', {
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 20 20",
|
||||
fill: "currentColor",
|
||||
class: "w-5 h-5"
|
||||
}, [
|
||||
h('path', {
|
||||
d: "M7.75 2.75a.75.75 0 0 0-1.5 0v1.258a32.987 32.987 0 0 0-3.599.278.75.75 0 1 0 .198 1.487A31.545 31.545 0 0 1 8.7 5.545 19.381 19.381 0 0 1 7 9.56a19.418 19.418 0 0 1-1.002-2.05.75.75 0 0 0-1.384.577 20.935 20.935 0 0 0 1.492 2.91 19.613 19.613 0 0 1-3.828 4.154.75.75 0 1 0 .945 1.164A21.116 21.116 0 0 0 7 12.331c.095.132.192.262.29.391a.75.75 0 0 0 1.194-.91c-.204-.266-.4-.538-.59-.815a20.888 20.888 0 0 0 2.333-5.332c.31.031.618.068.924.108a.75.75 0 0 0 .198-1.487 32.832 32.832 0 0 0-3.599-.278V2.75Z"
|
||||
}),
|
||||
h('path', {
|
||||
"fill-rule": "evenodd",
|
||||
d: "M13 8a.75.75 0 0 1 .671.415l4.25 8.5a.75.75 0 1 1-1.342.67L15.787 16h-5.573l-.793 1.585a.75.75 0 1 1-1.342-.67l4.25-8.5A.75.75 0 0 1 13 8Zm2.037 6.5L13 10.427 10.964 14.5h4.073Z",
|
||||
"clip-rule": "evenodd"
|
||||
})
|
||||
]);
|
||||
}
|
||||
},
|
||||
'app-user': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
|
|
|
|||
|
|
@ -11,30 +11,28 @@
|
|||
<TopMenu></TopMenu>
|
||||
</div>
|
||||
<div class="flex-center avatar">
|
||||
<el-tooltip effect="dark" content="项目地址" placement="top">
|
||||
<AppIcon
|
||||
iconName="app-github"
|
||||
class="cursor color-secondary mr-8 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl('https://github.com/1Panel-dev/MaxKB')"
|
||||
></AppIcon>
|
||||
<el-tooltip effect="dark" :content="$t('layout.topbar.github')" placement="top">
|
||||
<AppIcon iconName="app-github" class="cursor color-secondary mr-8 ml-8" style="font-size: 20px"
|
||||
@click="toUrl('https://github.com/1Panel-dev/MaxKB')"></AppIcon>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" content="用户手册" placement="top">
|
||||
<AppIcon
|
||||
iconName="app-reading"
|
||||
class="cursor color-secondary mr-8 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl('https://github.com/1Panel-dev/MaxKB/wiki')"
|
||||
></AppIcon>
|
||||
<el-tooltip effect="dark" :content="$t('layout.topbar.handbook')" placement="top">
|
||||
<AppIcon iconName="app-reading" class="cursor color-secondary mr-8 ml-8" style="font-size: 20px"
|
||||
@click="toUrl('https://github.com/1Panel-dev/MaxKB/wiki')"></AppIcon>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" content="论坛求助" placement="top">
|
||||
<AppIcon
|
||||
iconName="app-help"
|
||||
class="cursor color-secondary mr-16 ml-8"
|
||||
style="font-size: 20px"
|
||||
@click="toUrl('https://bbs.fit2cloud.com/c/mk/11')"
|
||||
></AppIcon>
|
||||
<el-tooltip effect="dark" :content="$t('layout.topbar.forum')" placement="top">
|
||||
<AppIcon iconName="app-help" class="cursor color-secondary mr-8 ml-8" style="font-size: 20px"
|
||||
@click="toUrl('https://bbs.fit2cloud.com/c/mk/11')"></AppIcon>
|
||||
</el-tooltip>
|
||||
<el-dropdown trigger="click" type="primary">
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="(lang, index) in langList" :key="index" :value="lang.value"
|
||||
@click="changeLang(lang.value)">{{ lang.label }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
<AppIcon iconName="app-translate" class="cursor color-secondary mr-16 ml-8" style="font-size: 20px" @click="">
|
||||
</AppIcon>
|
||||
</el-dropdown>
|
||||
<Avatar></Avatar>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -43,9 +41,15 @@
|
|||
import TopMenu from './top-menu/index.vue'
|
||||
import Avatar from './avatar/index.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { langList } from '@/locales/index';
|
||||
import { useLocale } from '@/locales/useLocale';
|
||||
const router = useRouter()
|
||||
const defaultTitle = import.meta.env.VITE_APP_TITLE
|
||||
|
||||
const { changeLocale } = useLocale();
|
||||
const changeLang = (lang: string) => {
|
||||
changeLocale(lang);
|
||||
};
|
||||
function toUrl(url: string) {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
|
@ -58,6 +62,7 @@ function toUrl(url: string) {
|
|||
|
||||
.app-title-container {
|
||||
margin-right: 45px;
|
||||
|
||||
.app-title-icon {
|
||||
background-image: url('@/assets/logo.png');
|
||||
background-size: 100% 100%;
|
||||
|
|
@ -69,6 +74,7 @@ function toUrl(url: string) {
|
|||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 2em;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
import { useLocalStorage, usePreferredLanguages } from '@vueuse/core';
|
||||
import { computed } from 'vue';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
// 导入语言文件
|
||||
const langModules = import.meta.glob('./lang/*/index.ts', { eager: true }) as Record<string, () => Promise<{ default: Object }>>;
|
||||
|
||||
const langModuleMap = new Map<string, Object>();
|
||||
|
||||
export const langCode: Array<string> = [];
|
||||
|
||||
export const localeConfigKey = 'MaxKB-locale';
|
||||
|
||||
// 获取浏览器默认语言环境
|
||||
const languages = usePreferredLanguages();
|
||||
|
||||
// 生成语言模块列表
|
||||
const generateLangModuleMap = () => {
|
||||
const fullPaths = Object.keys(langModules);
|
||||
fullPaths.forEach((fullPath) => {
|
||||
const k = fullPath.replace('./lang', '');
|
||||
const startIndex = 1;
|
||||
const lastIndex = k.lastIndexOf('/');
|
||||
const code = k.substring(startIndex, lastIndex);
|
||||
langCode.push(code);
|
||||
langModuleMap.set(code, langModules[fullPath]);
|
||||
});
|
||||
};
|
||||
|
||||
// 导出 Message
|
||||
const importMessages = computed(() => {
|
||||
generateLangModuleMap();
|
||||
|
||||
const message: Recordable = {};
|
||||
langModuleMap.forEach((value: any, key) => {
|
||||
message[key] = value.default;
|
||||
});
|
||||
return message;
|
||||
});
|
||||
|
||||
export const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: useLocalStorage(localeConfigKey, 'zh_CN').value || languages.value[0] || 'zh_CN',
|
||||
fallbackLocale: 'zh_CN',
|
||||
messages: importMessages.value,
|
||||
globalInjection: true,
|
||||
});
|
||||
|
||||
export const langList = computed(() => {
|
||||
if (langModuleMap.size === 0) generateLangModuleMap();
|
||||
|
||||
const list:any=[]
|
||||
langModuleMap.forEach((value: any, key) => {
|
||||
list.push({
|
||||
label: value.default.lang,
|
||||
value: key,
|
||||
});
|
||||
});
|
||||
|
||||
return list;
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
export const { t } = i18n.global;
|
||||
|
||||
export default i18n;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
export default {
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import en from 'element-plus/es/locale/lang/en';
|
||||
import components from './components';
|
||||
import layout from './layout';
|
||||
import pages from './pages';
|
||||
|
||||
export default {
|
||||
lang: 'English',
|
||||
layout,
|
||||
pages,
|
||||
components,
|
||||
en,
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
topbar: {
|
||||
github:"Github",
|
||||
handbook:"Handbook",
|
||||
forum:"Forum"
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
export default {
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
export default {
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
import components from './components';
|
||||
import layout from './layout';
|
||||
import pages from './pages';
|
||||
|
||||
export default {
|
||||
lang: '简体中文',
|
||||
layout,
|
||||
pages,
|
||||
components,
|
||||
zhCn,
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
topbar: {
|
||||
github:"项目地址",
|
||||
handbook:"用户手册",
|
||||
forum:"论坛求助"
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
export default {
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { useLocalStorage } from '@vueuse/core';
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { i18n, langCode, localeConfigKey } from '@/locales/index';
|
||||
|
||||
export function useLocale() {
|
||||
const { locale } = useI18n({ useScope: 'global' });
|
||||
function changeLocale(lang: string) {
|
||||
// 如果切换的语言不在对应语言文件里则默认为简体中文
|
||||
if (!langCode.includes(lang)) {
|
||||
lang = 'zh_CN';
|
||||
}
|
||||
|
||||
locale.value = lang;
|
||||
useLocalStorage(localeConfigKey, 'zh_CN').value = lang;
|
||||
}
|
||||
|
||||
const getComponentsLocale = computed(() => {
|
||||
return i18n.global.getLocaleMessage(locale.value).componentsLocale;
|
||||
});
|
||||
|
||||
return {
|
||||
changeLocale,
|
||||
getComponentsLocale,
|
||||
locale,
|
||||
};
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import directives from '@/directives'
|
|||
import App from './App.vue'
|
||||
import router from '@/router'
|
||||
import Components from '@/components'
|
||||
|
||||
import i18n from './locales';
|
||||
const app = createApp(App)
|
||||
app.use(store)
|
||||
app.use(directives)
|
||||
|
|
@ -24,5 +24,6 @@ app.use(ElementPlus, {
|
|||
app.use(theme)
|
||||
|
||||
app.use(router)
|
||||
app.use(i18n);
|
||||
app.use(Components)
|
||||
app.mount('#app')
|
||||
|
|
|
|||
Loading…
Reference in New Issue