mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: i18n
This commit is contained in:
parent
7ea082427b
commit
c4de677c86
|
|
@ -25,6 +25,7 @@ interface User {
|
|||
is_edit_password?: boolean
|
||||
IS_XPACK?: boolean
|
||||
XPACK_LICENSE_IS_VALID?: boolean
|
||||
language: string
|
||||
}
|
||||
|
||||
interface LoginRequest {
|
||||
|
|
|
|||
|
|
@ -184,10 +184,10 @@ import { useRoute, useRouter } from 'vue-router'
|
|||
import { getImgUrl } from '@/utils/utils'
|
||||
import bus from '@/bus'
|
||||
import 'recorder-core/src/engine/mp3'
|
||||
|
||||
import 'recorder-core/src/engine/mp3-engine'
|
||||
import { MsgWarning } from '@/utils/message'
|
||||
import useStore from '@/stores'
|
||||
import { t } from '@/locales'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { application } = useStore()
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import bus from '@/bus'
|
|||
import { ref, nextTick, onMounted } from 'vue'
|
||||
import { t } from '@/locales'
|
||||
const isOpen = ref<boolean>(false)
|
||||
const eventVal = ref({})
|
||||
const eventVal = ref()
|
||||
function getSelection() {
|
||||
const selection = window.getSelection()
|
||||
if (selection && selection.anchorNode == null) {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, nextTick, watch, computed, onMounted } from 'vue'
|
||||
import { MsgError } from '@/utils/message'
|
||||
import { t } from '@/locales'
|
||||
defineOptions({ name: 'AppTable' })
|
||||
|
||||
import useStore from '@/stores'
|
||||
|
|
@ -102,7 +103,7 @@ function submitHandle() {
|
|||
loading.value = false
|
||||
}, 200)
|
||||
} else {
|
||||
MsgError(`${props.quickCreateName}不能为空!`)
|
||||
MsgError(`${props.quickCreateName}${t('components.dynamicsForm.tip.requiredMessage')}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
选项值
|
||||
{{ $t('components.dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
|
|
@ -12,13 +12,13 @@
|
|||
</div>
|
||||
</template>
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
标签</el-col
|
||||
>
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('components.dynamicsForm.tag.label') }}
|
||||
</el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
选项值</el-col
|
||||
{{ $t('components.dynamicsForm.Select.label') }}</el-col
|
||||
>
|
||||
</el-row>
|
||||
<el-row
|
||||
|
|
@ -30,11 +30,13 @@
|
|||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
|
||||
<el-input v-model="formValue.option_list[$index].label" :placeholder="$t('components.dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('components.dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
|
|
@ -50,7 +52,11 @@
|
|||
:label="$t('components.dynamicsForm.default.label')"
|
||||
:required="formValue.required"
|
||||
prop="default_value"
|
||||
:rules="formValue.required ? [{ required: true, message: $t('components.dynamicsForm.default.requiredMessage') }] : []"
|
||||
:rules="
|
||||
formValue.required
|
||||
? [{ required: true, message: $t('components.dynamicsForm.default.requiredMessage') }]
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="defaultValueCheckbox">
|
||||
<el-checkbox
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
选项值
|
||||
{{ $t('components.dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
|
|
@ -13,13 +13,13 @@
|
|||
</template>
|
||||
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
标签</el-col
|
||||
>
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('components.dynamicsForm.tag.label') }}
|
||||
</el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
选项值</el-col
|
||||
{{ $t('components.dynamicsForm.Select.label') }}</el-col
|
||||
>
|
||||
</el-row>
|
||||
<el-row
|
||||
|
|
@ -31,11 +31,13 @@
|
|||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
|
||||
<el-input v-model="formValue.option_list[$index].label" :placeholder="$t('components.dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('components.dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
选项值
|
||||
{{ $t('components.dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
|
|
@ -13,14 +13,14 @@
|
|||
</template>
|
||||
|
||||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
标签</el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
选项值</el-col
|
||||
>
|
||||
<el-col :span="10">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('components.dynamicsForm.tag.label') }}
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('components.dynamicsForm.Select.label') }}
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row
|
||||
style="width: 100%"
|
||||
|
|
@ -31,11 +31,15 @@
|
|||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].label"
|
||||
:placeholder="$t('components.dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('components.dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
选项值
|
||||
{{ $t('components.dynamicsForm.Select.label') }}
|
||||
<el-button link type="primary" @click.stop="addOption()">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
|
|
@ -15,12 +15,12 @@
|
|||
<el-row style="width: 100%" :gutter="10">
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
标签</el-col
|
||||
>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
选项值</el-col
|
||||
{{ $t('components.dynamicsForm.tag.label') }}</el-col
|
||||
>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
{{ $t('components.dynamicsForm.Select.label') }}
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row
|
||||
style="width: 100%"
|
||||
|
|
@ -31,11 +31,13 @@
|
|||
>
|
||||
<el-col :span="10"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].label" placeholder="请输入选项标签"
|
||||
<el-input v-model="formValue.option_list[$index].label" :placeholder="$t('components.dynamicsForm.tag.placeholder')"
|
||||
/></el-col>
|
||||
<el-col :span="12"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
<el-input v-model="formValue.option_list[$index].value" placeholder="请输入选项值"
|
||||
<el-input
|
||||
v-model="formValue.option_list[$index].value"
|
||||
:placeholder="$t('components.dynamicsForm.Select.label')"
|
||||
/></el-col>
|
||||
<el-col :span="1"
|
||||
><div class="grid-content ep-bg-purple" />
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@
|
|||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, watch } from 'vue'
|
||||
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
modelValue: any
|
||||
}>()
|
||||
|
|
@ -101,7 +101,7 @@ const getData = () => {
|
|||
props_info: {
|
||||
rules: [
|
||||
{
|
||||
message: formValue.value.label + '不能为空',
|
||||
message: formValue.value.label + t('components.dynamicsForm.tip.requiredMessage'),
|
||||
trigger: 'blur',
|
||||
required: formValue.value.required
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,66 +1,71 @@
|
|||
import { useLocalStorage, usePreferredLanguages } from '@vueuse/core';
|
||||
import { computed } from 'vue';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { useLocalStorage, usePreferredLanguages } from '@vueuse/core'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import useStore from '@/stores'
|
||||
const { user } = useStore()
|
||||
// 导入语言文件
|
||||
const langModules = import.meta.glob('./lang/*/index.ts', { eager: true }) as Record<string, () => Promise<{ default: Object }>>;
|
||||
const langModules = import.meta.glob('./lang/*/index.ts', { eager: true }) as Record<
|
||||
string,
|
||||
() => Promise<{ default: Object }>
|
||||
>
|
||||
|
||||
const langModuleMap = new Map<string, Object>();
|
||||
const langModuleMap = new Map<string, Object>()
|
||||
|
||||
export const langCode: Array<string> = [];
|
||||
export const langCode: Array<string> = []
|
||||
|
||||
export const localeConfigKey = 'MaxKB-locale';
|
||||
export const localeConfigKey = 'MaxKB-locale'
|
||||
|
||||
// 获取浏览器默认语言环境
|
||||
const languages = usePreferredLanguages();
|
||||
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]);
|
||||
});
|
||||
};
|
||||
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();
|
||||
generateLangModuleMap()
|
||||
|
||||
const message: Recordable = {};
|
||||
langModuleMap.forEach((value: any, key) => {
|
||||
message[key] = value.default;
|
||||
});
|
||||
return message;
|
||||
});
|
||||
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,
|
||||
});
|
||||
legacy: false,
|
||||
locale: user.getLanguage() || languages.value[0] || 'zh_CN',
|
||||
fallbackLocale: 'zh_CN',
|
||||
messages: importMessages.value,
|
||||
globalInjection: true
|
||||
})
|
||||
|
||||
export const langList = computed(() => {
|
||||
if (langModuleMap.size === 0) generateLangModuleMap();
|
||||
if (langModuleMap.size === 0) generateLangModuleMap()
|
||||
|
||||
const list:any=[]
|
||||
langModuleMap.forEach((value: any, key) => {
|
||||
list.push({
|
||||
label: value.default.lang,
|
||||
value: key,
|
||||
});
|
||||
});
|
||||
const list: any = []
|
||||
langModuleMap.forEach((value: any, key) => {
|
||||
list.push({
|
||||
label: value.default.lang,
|
||||
value: key
|
||||
})
|
||||
})
|
||||
|
||||
return list;
|
||||
});
|
||||
return list
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
export const { t } = i18n.global;
|
||||
export const { t } = i18n.global
|
||||
|
||||
export default i18n;
|
||||
export default i18n
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export default {
|
|||
},
|
||||
table: {
|
||||
name: 'File Name',
|
||||
char_length: 'Character Count',
|
||||
char_length: 'Character',
|
||||
paragraph: 'Segment',
|
||||
all: 'All',
|
||||
updateTime: 'Update Time'
|
||||
|
|
@ -111,7 +111,7 @@ export default {
|
|||
REVOKE: 'Cancelling'
|
||||
},
|
||||
enableStatus: {
|
||||
label: 'Enable Status',
|
||||
label: 'Status',
|
||||
enable: 'Enabled',
|
||||
close: 'Disabled'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -63,5 +63,16 @@ export default {
|
|||
label: '格式',
|
||||
placeholder: '请选择格式'
|
||||
}
|
||||
},
|
||||
Select: {
|
||||
label: '选项值',
|
||||
placeholder: '请输入选项值'
|
||||
},
|
||||
tag: {
|
||||
label: '标签',
|
||||
placeholder: '请输入选项标签'
|
||||
},
|
||||
Slider: {
|
||||
showInput:''
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,10 +203,12 @@ export const postStream: (url: string, data?: unknown) => Promise<Result<any> |
|
|||
) => {
|
||||
const { user } = useStore()
|
||||
const token = user.getToken()
|
||||
const language = user.getLanguage()
|
||||
const headers: HeadersInit = { 'Content-Type': 'application/json' }
|
||||
if (token) {
|
||||
headers['AUTHORIZATION'] = `${token}`
|
||||
}
|
||||
headers['Accept-Language'] = `${language}`
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import useUserStore from './user'
|
|||
const useApplicationStore = defineStore({
|
||||
id: 'application',
|
||||
state: () => ({
|
||||
location: `${window.location.origin}/ui/chat/`
|
||||
location: `${window.location.origin}/ui/chat/`,
|
||||
userLanguage: ''
|
||||
}),
|
||||
actions: {
|
||||
async asyncGetAllApplication() {
|
||||
|
|
@ -77,10 +78,10 @@ const useApplicationStore = defineStore({
|
|||
|
||||
async asyncGetAppProfile(loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const user = useUserStore()
|
||||
applicationApi
|
||||
.getAppProfile(loading)
|
||||
.then((data) => {
|
||||
this.userLanguage = data.data?.language
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import UserApi from '@/api/user'
|
|||
import ThemeApi from '@/api/theme'
|
||||
import { useElementPlusTheme } from 'use-element-plus-theme'
|
||||
import { defaultPlatformSetting } from '@/utils/theme'
|
||||
|
||||
import useApplicationStore from './application'
|
||||
export interface userStateTypes {
|
||||
userType: number // 1 系统操作者 2 对话用户
|
||||
userInfo: User | null
|
||||
|
|
@ -30,6 +30,12 @@ const useUserStore = defineStore({
|
|||
themeInfo: null
|
||||
}),
|
||||
actions: {
|
||||
getLanguage() {
|
||||
const application = useApplicationStore()
|
||||
return this.userType === 1
|
||||
? this.userInfo?.language || localStorage.getItem('language')
|
||||
: application?.userLanguage
|
||||
},
|
||||
showXpack() {
|
||||
return this.isXPack
|
||||
},
|
||||
|
|
@ -118,6 +124,7 @@ const useUserStore = defineStore({
|
|||
async profile() {
|
||||
return UserApi.profile().then(async (ok) => {
|
||||
this.userInfo = ok.data
|
||||
localStorage.setItem('language', ok.data?.language)
|
||||
return this.asyncGetProfile()
|
||||
})
|
||||
},
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
prop="char_length"
|
||||
:label="$t('views.document.table.char_length')"
|
||||
align="right"
|
||||
min-width="90"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ numberFormat(row.char_length) }}
|
||||
|
|
@ -85,6 +86,7 @@
|
|||
prop="paragraph_count"
|
||||
:label="$t('views.document.table.paragraph')"
|
||||
align="right"
|
||||
min-width="90"
|
||||
/>
|
||||
<el-table-column prop="status" :label="$t('views.document.fileStatus.label')" width="130">
|
||||
<template #header>
|
||||
|
|
@ -216,7 +218,7 @@
|
|||
<el-icon><Filter /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu style="width: 100px">
|
||||
<el-dropdown-menu style="width: 150px">
|
||||
<el-dropdown-item
|
||||
:class="filterMethod['hit_handling_method'] ? '' : 'is-active'"
|
||||
:command="beforeCommand('hit_handling_method', '')"
|
||||
|
|
@ -228,7 +230,7 @@
|
|||
:class="filterMethod['hit_handling_method'] === key ? 'is-active' : ''"
|
||||
class="justify-center"
|
||||
:command="beforeCommand('hit_handling_method', key)"
|
||||
>{{ value }}</el-dropdown-item
|
||||
>{{ $t(value) }}</el-dropdown-item
|
||||
>
|
||||
</template>
|
||||
</el-dropdown-menu>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ import AddParamDrawer from './AddParamDrawer.vue'
|
|||
import { MsgError, MsgSuccess } from '@/utils/message'
|
||||
import ModelApi from '@/api/model'
|
||||
import { input_type_list } from '@/components/dynamics-form/constructor/data'
|
||||
|
||||
import { t } from '@/locales'
|
||||
const props = defineProps<{
|
||||
model: Model
|
||||
}>()
|
||||
|
|
|
|||
Loading…
Reference in New Issue