feat: Add i18n support for supplier names and model types

- Add supplier name translations (Chinese, English, Korean)
- Add model type translations
- Update supplier.ts to include i18nKey for each supplier
- Update Vue components to use i18n translations
This commit is contained in:
kdrmlhcn
2025-11-07 10:27:00 +08:00
committed by dataeaseShu
parent 3fa2bae3b5
commit f687a322bb
10 changed files with 90 additions and 9 deletions
+3 -2
View File
@@ -1,10 +1,11 @@
export interface SelectOption {
label: string
value: string | number
i18nKey?: string
}
export const modelTypeOptions: SelectOption[] = [
{ label: '大语言模型', value: 0 },
{ label: '大语言模型', value: 0, i18nKey: 'modelType.llm' },
/* { label: 'Anthropic', value: 1 },
{ label: 'Baidu', value: 2 },
{ label: 'iFLYTEK', value: 3 },
@@ -17,5 +18,5 @@ export const modelTypeOptions: SelectOption[] = [
export const getModelTypeName = (value: any) => {
const tv = parseInt(value)
const item = modelTypeOptions.find((item) => item.value === tv)
return item?.label || ''
return item?.i18nKey || item?.label || ''
}
+12
View File
@@ -26,6 +26,7 @@ type ModelConfig = Record<
export const supplierList: Array<{
id: number
name: string
i18nKey: string
icon: any
type?: string
is_private?: boolean
@@ -34,6 +35,7 @@ export const supplierList: Array<{
{
id: 1,
name: '阿里云百炼',
i18nKey: 'supplier.alibaba_cloud_bailian',
icon: icon_alybl_colorful,
model_config: {
0: {
@@ -60,6 +62,7 @@ export const supplierList: Array<{
{
id: 2,
name: '千帆大模型',
i18nKey: 'supplier.qianfan_model',
icon: icon_bdyzn_colorful,
model_config: {
0: {
@@ -71,6 +74,7 @@ export const supplierList: Array<{
{
id: 3,
name: 'DeepSeek',
i18nKey: 'supplier.deepseek',
icon: icon_deepseek_colorful,
model_config: {
0: {
@@ -85,6 +89,7 @@ export const supplierList: Array<{
{
id: 4,
name: '腾讯混元',
i18nKey: 'supplier.tencent_hunyuan',
icon: icon_txhy_colorful,
model_config: {
0: {
@@ -104,6 +109,7 @@ export const supplierList: Array<{
{
id: 5,
name: '讯飞星火',
i18nKey: 'supplier.iflytek_spark',
icon: icon_xfhx_colorful,
model_config: {
0: {
@@ -156,6 +162,7 @@ export const supplierList: Array<{
{
id: 6,
name: 'Gemini',
i18nKey: 'supplier.gemini',
icon: icon_gemini_colorful,
model_config: {
0: {
@@ -174,6 +181,7 @@ export const supplierList: Array<{
{
id: 7,
name: 'OpenAI',
i18nKey: 'supplier.openai',
icon: icon_openai_colorful,
model_config: {
0: {
@@ -202,6 +210,7 @@ export const supplierList: Array<{
{
id: 8,
name: 'Kimi',
i18nKey: 'supplier.kimi',
icon: icon_kimi_colorful,
model_config: {
0: {
@@ -232,6 +241,7 @@ export const supplierList: Array<{
{
id: 9,
name: '腾讯云',
i18nKey: 'supplier.tencent_cloud',
icon: icon_txy_colorful,
model_config: {
0: {
@@ -249,6 +259,7 @@ export const supplierList: Array<{
{
id: 10,
name: '火山引擎',
i18nKey: 'supplier.volcano_engine',
icon: icon_hsyq_colorful,
model_config: {
0: {
@@ -311,6 +322,7 @@ export const supplierList: Array<{
{
id: 15,
name: '通用OpenAI',
i18nKey: 'supplier.generic_openai',
icon: icon_common_openai,
is_private: true,
model_config: {
+16
View File
@@ -716,5 +716,21 @@
"platform_disable": "{0} settings are not enabled!",
"input_account": "Please enter account",
"redirect_2_auth": "Redirecting to {0} authentication, {1} seconds..."
},
"supplier": {
"alibaba_cloud_bailian": "Alibaba Cloud Bailian",
"qianfan_model": "Qianfan Model",
"deepseek": "DeepSeek",
"tencent_hunyuan": "Tencent Hunyuan",
"iflytek_spark": "iFlytek Spark",
"gemini": "Gemini",
"openai": "OpenAI",
"kimi": "Kimi",
"tencent_cloud": "Tencent Cloud",
"volcano_engine": "Volcano Engine",
"generic_openai": "Generic OpenAI"
},
"modelType": {
"llm": "Large Language Model"
}
}
+16
View File
@@ -716,5 +716,21 @@
"platform_disable": "{0} 설정이 활성화되지 않았습니다!",
"input_account": "계정을 입력해 주세요",
"redirect_2_auth": "{0} 인증으로 리디렉션 중입니다, {1}초..."
},
"supplier": {
"alibaba_cloud_bailian": "알리바바 클라우드 바이리엔",
"qianfan_model": "치엔판 모델",
"deepseek": "DeepSeek",
"tencent_hunyuan": "텐센트 훈위안",
"iflytek_spark": "아이플라이텍 스파크",
"gemini": "Gemini",
"openai": "OpenAI",
"kimi": "Kimi",
"tencent_cloud": "텐센트 클라우드",
"volcano_engine": "볼케이노 엔진",
"generic_openai": "범용 OpenAI"
},
"modelType": {
"llm": "대형 언어 모델"
}
}
+16
View File
@@ -716,5 +716,21 @@
"platform_disable": "{0}设置未开启!",
"input_account": "请输入账号",
"redirect_2_auth": "正在跳转至 {0} 认证,{1} 秒..."
},
"supplier": {
"alibaba_cloud_bailian": "阿里云百炼",
"qianfan_model": "千帆大模型",
"deepseek": "DeepSeek",
"tencent_hunyuan": "腾讯混元",
"iflytek_spark": "讯飞星火",
"gemini": "Gemini",
"openai": "OpenAI",
"kimi": "Kimi",
"tencent_cloud": "腾讯云",
"volcano_engine": "火山引擎",
"generic_openai": "通用OpenAI"
},
"modelType": {
"llm": "大语言模型"
}
}
+1 -1
View File
@@ -69,7 +69,7 @@ defineExpose({ showErrorMask })
</div>
<div class="type-value">
<span class="type">{{ $t('model.model_type') }}</span>
<span class="value"> {{ modelType }}</span>
<span class="value"> {{ modelType.startsWith('modelType.') ? $t(modelType) : modelType }}</span>
</div>
<div class="type-value">
<span class="type">{{ $t('model.basic_model') }}</span>
+4 -1
View File
@@ -33,6 +33,7 @@ const searchLoading = ref(false)
const editModel = ref(false)
const activeStep = ref(0)
const activeName = ref('')
const activeNameI18nKey = ref('')
const activeType = ref('')
const modelFormRef = ref()
const cardRefs = ref<any[]>([])
@@ -185,6 +186,7 @@ const handleEditModel = (row: any) => {
editModel.value = true
activeType.value = row.supplier
activeName.value = row.supplier_item.name
activeNameI18nKey.value = row.supplier_item.i18nKey
modelApi.query(row.id).then((res: any) => {
modelConfigvVisible.value = true
nextTick(() => {
@@ -256,6 +258,7 @@ const clickModel = (ele: any) => {
const supplierChang = (ele: any) => {
activeName.value = ele.name
activeNameI18nKey.value = ele.i18nKey
nextTick(() => {
modelFormRef.value.supplierChang({ ...ele })
})
@@ -425,7 +428,7 @@ const submit = (item: any) => {
>
<template #header="{ close }">
<span style="white-space: nowrap">{{
editModel ? $t('dashboard.edit') + $t('common.empty') + activeName : t('model.add_model')
editModel ? $t('dashboard.edit') + $t('common.empty') + $t(activeNameI18nKey) : t('model.add_model')
}}</span>
<div v-if="!editModel" class="flex-center" style="width: 100%">
<el-steps custom style="max-width: 500px; flex: 1" :active="activeStep" align-center>
@@ -308,7 +308,7 @@ defineExpose({
<el-option
v-for="item in modelTypeOptions"
:key="item.value"
:label="item.label"
:label="item.i18nKey ? $t(item.i18nKey) : item.label"
:value="item.value"
/>
</el-select>
+12 -2
View File
@@ -1,14 +1,24 @@
<script lang="ts" setup>
import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
import { supplierList } from '@/entity/supplier'
const { t } = useI18n()
const keywords = ref('')
const modelListWithSearch = computed(() => {
if (!keywords.value) return supplierList
return supplierList.filter((ele) => ele.name.toLowerCase().includes(keywords.value.toLowerCase()))
return supplierList.filter((ele) => {
if (!ele.i18nKey) {
return ele.name.toLowerCase().includes(keywords.value.toLowerCase())
}
const translatedName = t(ele.i18nKey).toLowerCase()
const originalName = ele.name.toLowerCase()
const searchTerm = keywords.value.toLowerCase()
return translatedName.includes(searchTerm) || originalName.includes(searchTerm)
})
})
const emits = defineEmits(['clickModel'])
const handleModelClick = (item: any) => {
@@ -39,7 +49,7 @@ const handleModelClick = (item: any) => {
@click="handleModelClick(ele)"
>
<img width="32px" height="32px" :src="ele.icon" />
<span class="name">{{ ele.name }}</span>
<span class="name">{{ ele.i18nKey ? $t(ele.i18nKey) : ele.name }}</span>
</div>
<EmptyBackground
v-if="!!keywords && !modelListWithSearch.length"
@@ -1,9 +1,11 @@
<script lang="ts" setup>
import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
import { supplierList } from '@/entity/supplier'
const { t } = useI18n()
withDefaults(
defineProps<{
activeName: string
@@ -16,7 +18,12 @@ const keywords = ref('')
const modelListWithSearch = computed(() => {
if (!keywords.value) return supplierList
return supplierList.filter((ele) => ele.name.toLowerCase().includes(keywords.value.toLowerCase()))
return supplierList.filter((ele) => {
const translatedName = t(ele.i18nKey).toLowerCase()
const originalName = ele.name.toLowerCase()
const searchTerm = keywords.value.toLowerCase()
return translatedName.includes(searchTerm) || originalName.includes(searchTerm)
})
})
const emits = defineEmits(['clickModel'])
const handleModelClick = (item: any) => {
@@ -47,7 +54,7 @@ const handleModelClick = (item: any) => {
@click="handleModelClick(ele)"
>
<img width="18px" height="18px" :src="ele.icon" />
<span class="name">{{ ele.name }}</span>
<span class="name">{{ $t(ele.i18nKey) }}</span>
</div>
<EmptyBackground
v-if="!!keywords && !modelListWithSearch.length"