refactor(web): i18n

This commit is contained in:
Acbox
2026-02-10 17:58:28 +08:00
parent 32513efcc4
commit 4d265b8f24
19 changed files with 372 additions and 221 deletions
+9 -22
View File
@@ -76,33 +76,20 @@ const curSelectSlide = (cur: string) => computed(() => {
})
const sidebarInfo = computed(() => [
{
title: t('slidebar.chat'),
title: t('sidebar.chat'),
name: 'chat',
icon: ['far', 'comments']
icon: ['far', 'comments'],
},
// {
// title: t('slidebar.home'),
// name: 'home',
// icon: mdiHome
// },
{
title: t('slidebar.model_setting'),
title: t('sidebar.models'),
name: 'models',
icon: ['fas', 'robot']
}, {
title: t('slidebar.setting'),
name: 'settings',
icon: ['fas', 'gear']
icon: ['fas', 'robot'],
},
{
title: t('sidebar.settings'),
name: 'settings',
icon: ['fas', 'gear'],
},
// {
// title: 'MCP',
// name: 'mcp',
// icon: mdiListBox
// }, {
// title: t('slidebar.platform'),
// name: 'platform',
// icon: mdiBookArrowDown
// }
])
</script>
@@ -6,15 +6,15 @@
variant="default"
class="ml-auto my-4"
>
添加平台
{{ $t('platform.addTitle') }}
</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-106.25">
<form @submit="addPlatform">
<DialogHeader>
<DialogTitle>添加平台</DialogTitle>
<DialogTitle>{{ $t('platform.addTitle') }}</DialogTitle>
<DialogDescription class="mb-4">
为模型添加使用平台
{{ $t('platform.addDescription') }}
</DialogDescription>
</DialogHeader>
@@ -26,12 +26,12 @@
>
<FormItem>
<FormLabel class="mb-2">
Name
{{ $t('platform.name') }}
</FormLabel>
<FormControl>
<Input
type="text"
placeholder="请输入Name"
:placeholder="$t('platform.namePlaceholder')"
v-bind="componentField"
autocomplete="name"
/>
@@ -49,7 +49,7 @@
>
<FormItem>
<FormLabel class="mb-2">
Config
{{ $t('platform.config') }}
</FormLabel>
<FormControl>
<TagsInput
@@ -67,7 +67,7 @@
<TagsInputItemDelete />
</TagsInputItem>
<TagsInputInput
placeholder="key:value 格式"
:placeholder="$t('platform.configPlaceholder')"
class="w-full py-1"
/>
</TagsInput>
@@ -85,7 +85,7 @@
>
<FormItem>
<FormLabel class="mb-2">
是否立即使用
{{ $t('platform.active') }}
</FormLabel>
<FormControl>
<Switch
@@ -103,11 +103,11 @@
<DialogFooter class="mt-4">
<DialogClose as-child>
<Button variant="outline">
取消
{{ $t('common.cancel') }}
</Button>
</DialogClose>
<Button type="submit">
添加平台
{{ $t('platform.addTitle') }}
</Button>
</DialogFooter>
</form>
@@ -9,19 +9,18 @@
<FontAwesomeIcon
:icon="['fas', 'plus']"
class="mr-1"
/> 添加
/> {{ $t('provider.addBtn') }}
</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-106.25">
<form @submit="createProvider">
<DialogHeader>
<DialogTitle>添加提供商</DialogTitle>
<DialogTitle>{{ $t('provider.add') }}</DialogTitle>
<DialogDescription>
<Separator class="my-4" />
</DialogDescription>
</DialogHeader>
<div class="flex-col gap-3 flex">
<FormField
v-slot="{ componentField }"
@@ -29,12 +28,12 @@
>
<FormItem>
<Label class="mb-2">
Name
{{ $t('provider.name') }}
</Label>
<FormControl>
<Input
type="text"
placeholder="请输入Name"
:placeholder="$t('provider.namePlaceholder')"
v-bind="componentField"
/>
</FormControl>
@@ -46,12 +45,12 @@
>
<FormItem>
<Label class="mb-2">
API 密钥
{{ $t('provider.apiKey') }}
</Label>
<FormControl>
<Input
type="text"
placeholder="请输入Api Key"
:placeholder="$t('provider.apiKeyPlaceholder')"
v-bind="componentField"
/>
</FormControl>
@@ -63,15 +62,15 @@
>
<FormItem>
<Label class="mb-2">
URL
{{ $t('provider.url') }}
</Label>
<FormControl>
<Input
type="text"
placeholder="请输入URL"
:placeholder="$t('provider.urlPlaceholder')"
v-bind="componentField"
/>
</FormControl>
</FormControl>
</FormItem>
</FormField>
<FormField
@@ -80,12 +79,12 @@
>
<FormItem>
<Label class="mb-2">
Type
{{ $t('provider.type') }}
</Label>
<FormControl>
<Select v-bind="componentField">
<SelectTrigger class="w-full">
<SelectValue :placeholder="$t('prompt.select', { msg: 'Type' })" />
<SelectValue :placeholder="$t('provider.typePlaceholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
@@ -106,7 +105,7 @@
<DialogFooter class="mt-8">
<DialogClose as-child>
<Button variant="outline">
Cancel
{{ $t('common.cancel') }}
</Button>
</DialogClose>
<Button
@@ -117,7 +116,7 @@
v-if="isLoading"
class="mr-1"
/>
添加MCP
{{ $t('provider.add') }}
</Button>
</DialogFooter>
</form>
@@ -130,7 +129,7 @@ import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
@@ -148,7 +147,7 @@ import {
SelectItem,
Separator,
Label,
Spinner
Spinner,
} from '@memoh/ui'
import { toTypedSchema } from '@vee-validate/zod'
import z from 'zod'
@@ -182,5 +181,4 @@ const createProvider = form.handleSubmit(async (value) => {
return
}
})
</script>
</script>
@@ -13,14 +13,14 @@
variant="outline"
@click="close"
>
{{ cancelText }}
{{ cancelText || $t('common.cancel') }}
</Button>
<Button
:disabled="loading"
@click="$emit('confirm'); close()"
>
<Spinner v-if="loading" />
{{ confirmText }}
{{ confirmText || $t('common.confirm') }}
</Button>
</div>
</PopoverContent>
@@ -43,8 +43,8 @@ withDefaults(defineProps<{
cancelText?: string
loading?: boolean
}>(), {
confirmText: '确定',
cancelText: '取消',
confirmText: '',
cancelText: '',
loading: false,
})
@@ -6,15 +6,15 @@
variant="default"
class="ml-auto my-4"
>
{{ $t("button.add", { msg: "MCP" }) }}
{{ $t('mcp.addTitle') }}
</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-106.25">
<form @submit="createMCP">
<DialogHeader>
<DialogTitle>{{ $t("button.add", { msg: "MCP" }) }}</DialogTitle>
<DialogTitle>{{ $t('mcp.addTitle') }}</DialogTitle>
<DialogDescription class="mb-4">
添加MCP完成操作
{{ $t('mcp.addDescription') }}
</DialogDescription>
</DialogHeader>
@@ -26,12 +26,12 @@
>
<FormItem>
<FormLabel class="mb-2">
Name
{{ $t('mcp.name') }}
</FormLabel>
<FormControl>
<Input
type="text"
:placeholder="$t('prompt.enter', { msg: 'Name' })"
:placeholder="$t('mcp.namePlaceholder')"
v-bind="componentField"
autocomplete="name"
/>
@@ -49,12 +49,12 @@
>
<FormItem>
<FormLabel class="mb-2">
Type
{{ $t('mcp.type') }}
</FormLabel>
<FormControl>
<Select v-bind="componentField">
<SelectTrigger class="w-full">
<SelectValue :placeholder="$t('prompt.select', { msg: 'Type' })" />
<SelectValue :placeholder="$t('mcp.typePlaceholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
@@ -78,12 +78,12 @@
>
<FormItem>
<FormLabel class="mb-2">
Cwd
{{ $t('mcp.cwd') }}
</FormLabel>
<FormControl>
<Input
type="text"
:placeholder="$t('prompt.enter', { msg: 'cwd' })"
:placeholder="$t('mcp.cwdPlaceholder')"
v-bind="componentField"
autocomplete="cwd"
/>
@@ -101,11 +101,11 @@
>
<FormItem>
<FormLabel class="mb-2">
Command
{{ $t('mcp.command') }}
</FormLabel>
<FormControl>
<Input
:placeholder="$t('prompt.enter', { msg: 'Command' })"
:placeholder="$t('mcp.commandPlaceholder')"
v-bind="componentField"
/>
</FormControl>
@@ -122,7 +122,7 @@
>
<FormItem>
<FormLabel class="mb-2">
Arguments
{{ $t('mcp.arguments') }}
</FormLabel>
<FormControl>
<TagsInput
@@ -140,7 +140,7 @@
<TagsInputItemDelete />
</TagsInputItem>
<TagsInputInput
:placeholder="$t('prompt.enter', { msg: 'Arguments' })"
:placeholder="$t('mcp.argumentsPlaceholder')"
class="w-full py-1"
/>
</TagsInput>
@@ -158,7 +158,7 @@
>
<FormItem>
<FormLabel class="mb-2">
Env
{{ $t('mcp.env') }}
</FormLabel>
<FormControl>
<TagsInput
@@ -176,7 +176,7 @@
<TagsInputItemDelete />
</TagsInputItem>
<TagsInputInput
:placeholder="$t('prompt.enter', { msg: 'Env' })"
:placeholder="$t('mcp.envPlaceholder')"
class="w-full py-1"
/>
</TagsInput>
@@ -195,7 +195,7 @@
<FormItem>
<FormControl>
<section class="flex gap-4">
<Label>{{ $t('state.open') }}</Label>
<Label>{{ $t('mcp.active') }}</Label>
<Switch
:model-value="componentField.modelValue"
@update:model-value="componentField['onUpdate:modelValue']"
@@ -212,11 +212,11 @@
<DialogFooter class="mt-4">
<DialogClose as-child>
<Button variant="outline">
Cancel
{{ $t('common.cancel') }}
</Button>
</DialogClose>
<Button type="submit">
{{ $t("button.add", { msg: "MCP" }) }}
{{ $t('mcp.addTitle') }}
</Button>
</DialogFooter>
</form>
@@ -3,33 +3,33 @@
<Dialog v-model:open="open">
<DialogTrigger as-child>
<Button variant="default">
{{ $t("button.add", { msg: "Model" }) }}
{{ $t('models.addModel') }}
</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-106.25">
<form @submit="addModel">
<DialogHeader>
<DialogTitle>
{{ title === 'edit' ? '编辑Model' : '添加Model' }}
{{ title === 'edit' ? $t('models.editModel') : $t('models.addModel') }}
</DialogTitle>
<DialogDescription class="mb-4">
<Separator class="my-4" />
</DialogDescription>
</DialogHeader>
<div class="flex flex-col gap-3">
<!-- 1. Type先选类型 -->
<!-- Type -->
<FormField
v-slot="{ componentField }"
name="type"
>
<FormItem>
<Label class="mb-2">
Type
{{ $t('models.type') }}
</Label>
<FormControl>
<Select v-bind="componentField">
<SelectTrigger class="w-full">
<SelectValue placeholder="选择模型类型" />
<SelectValue :placeholder="$t('models.typePlaceholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
@@ -46,46 +46,46 @@
</FormItem>
</FormField>
<!-- 2. Model Model ID -->
<!-- Model -->
<FormField
v-slot="{ componentField }"
name="model_id"
>
<FormItem>
<Label class="mb-2">
Model
{{ $t('models.model') }}
</Label>
<FormControl>
<Input
type="text"
placeholder="e.g. gpt-4o"
:placeholder="$t('models.modelPlaceholder')"
v-bind="componentField"
/>
</FormControl>
</FormItem>
</FormField>
<!-- 3. Display Name可选 -->
<!-- Display Name -->
<FormField
v-slot="{ componentField }"
name="name"
>
<FormItem>
<Label class="mb-2">
Display Name
<span class="text-muted-foreground text-xs ml-1">(optional)</span>
{{ $t('models.displayName') }}
<span class="text-muted-foreground text-xs ml-1">({{ $t('common.optional') }})</span>
</Label>
<FormControl>
<Input
type="text"
placeholder="自定义显示名称"
:placeholder="$t('models.displayNamePlaceholder')"
v-bind="componentField"
/>
</FormControl>
</FormItem>
</FormField>
<!-- 4. Dimensions embedding 时显示 -->
<!-- Dimensions (embedding only) -->
<FormField
v-if="selectedType === 'embedding'"
v-slot="{ componentField }"
@@ -93,19 +93,19 @@
>
<FormItem>
<Label class="mb-2">
Dimensions
{{ $t('models.dimensions') }}
</Label>
<FormControl>
<Input
type="number"
placeholder="e.g. 1536"
:placeholder="$t('models.dimensionsPlaceholder')"
v-bind="componentField"
/>
</FormControl>
</FormItem>
</FormField>
<!-- 5. 多模态 chat 时显示 -->
<!-- Multimodal (chat only) -->
<FormField
v-if="selectedType === 'chat'"
v-slot="{ componentField }"
@@ -113,7 +113,7 @@
>
<FormItem class="flex items-center justify-between">
<Label>
是否开启多模态
{{ $t('models.multimodal') }}
</Label>
<Switch
v-model="componentField.modelValue"
@@ -125,7 +125,7 @@
<DialogFooter class="mt-4">
<DialogClose as-child>
<Button variant="outline">
Cancel
{{ $t('common.cancel') }}
</Button>
</DialogClose>
<Button
@@ -133,7 +133,7 @@
:disabled="!form.meta.value.valid"
>
<Spinner v-if="isLoading" />
{{ title === 'edit' ? '保存' : $t("button.add", { msg: "Model" }) }}
{{ title === 'edit' ? $t('common.save') : $t('models.addModel') }}
</Button>
</DialogFooter>
</form>
@@ -176,7 +176,7 @@ import { type ModelInfo } from '@memoh/shared'
import { useCreateModel } from '@/composables/api/useModels'
const formSchema = toTypedSchema(z.object({
type: z.string().min(1, '请选择模型类型'),
type: z.string().min(1),
model_id: z.string().min(1),
name: z.string().optional(),
dimensions: z.coerce.number().min(1).optional(),
+115 -33
View File
@@ -1,39 +1,121 @@
{
"login": {
"username": "Username",
"password": "Password",
"login": "Login",
"register": "Register",
"forget": "Forgot your password?",
"exit": "Sign Out"
},
"prompt": {
"enter": "Please enter {msg}",
"select": "Please select {msg}"
},
"slidebar": {
"setting": "Settings",
"platform": "Platform",
"chat": "Create Chat",
"model_setting": "Model Settings",
"home": "Home"
},
"desc": {
"question": "your question"
},
"chat": {
"send": "Send",
"chat": "Chat"
},
"breadcrumb": {
"main": "Main"
},
"button": {
"common": {
"confirm": "Confirm",
"cancel": "Cancel",
"save": "Save",
"add": "Add",
"edit": "Edit",
"delete": "Delete",
"add": "Add {msg}"
"search": "Search",
"loading": "Loading...",
"operation": "Actions",
"enable": "Enable",
"optional": "optional"
},
"state":{
"open":"Open"
"auth": {
"welcome": "Welcome Back",
"username": "Username",
"password": "Password",
"login": "Sign In",
"register": "Sign Up",
"forgotPassword": "Forgot password?",
"logout": "Sign Out",
"logoutConfirm": "Are you sure you want to sign out?",
"loginFailed": "Login failed",
"invalidCredentials": "Invalid username or password",
"retryHint": "Please check and try again"
},
"sidebar": {
"chat": "Chat",
"models": "Models",
"settings": "Settings",
"home": "Home",
"platform": "Platform",
"mcp": "MCP"
},
"breadcrumb": {
"main": "Home"
},
"settings": {
"display": "Display Settings",
"language": "Language",
"languagePlaceholder": "Select language",
"theme": "Theme",
"themePlaceholder": "Select theme",
"themeLight": "Light",
"themeDark": "Dark",
"langZh": "中文",
"langEn": "English"
},
"chat": {
"greeting": "Hi! How can I help you today?",
"inputPlaceholder": "Type your question…",
"send": "Send"
},
"models": {
"title": "Models",
"searchPlaceholder": "Search providers…",
"addModel": "Add Model",
"editModel": "Edit Model",
"deleteModelConfirm": "Are you sure you want to delete this model?",
"emptyTitle": "No Models",
"emptyDescription": "Click the button above to add a model for this provider",
"type": "Type",
"typePlaceholder": "Select model type",
"model": "Model ID",
"modelPlaceholder": "e.g. gpt-4o",
"displayName": "Display Name",
"displayNamePlaceholder": "Custom display name",
"dimensions": "Dimensions",
"dimensionsPlaceholder": "e.g. 1536",
"multimodal": "Multimodal"
},
"provider": {
"add": "Add Provider",
"addBtn": "Add",
"name": "Name",
"namePlaceholder": "Enter provider name",
"apiKey": "API Key",
"apiKeyPlaceholder": "Enter API key",
"url": "Base URL",
"urlPlaceholder": "Enter base URL",
"type": "Type",
"typePlaceholder": "Select type",
"deleteConfirm": "Are you sure you want to delete this provider?",
"saveChanges": "Save Changes",
"emptyTitle": "No Providers",
"emptyDescription": "Add a model provider first to configure models"
},
"mcp": {
"addTitle": "Add MCP",
"addDescription": "Configure MCP server connection",
"name": "Name",
"namePlaceholder": "Enter name",
"type": "Type",
"typePlaceholder": "Select type",
"command": "Command",
"commandPlaceholder": "Enter start command",
"arguments": "Arguments",
"argumentsPlaceholder": "Enter arguments",
"cwd": "Working Directory",
"cwdPlaceholder": "Enter working directory path",
"env": "Environment",
"envPlaceholder": "Format: KEY:VALUE",
"active": "Enable Now"
},
"platform": {
"addTitle": "Add Platform",
"addDescription": "Configure a platform for model access",
"name": "Name",
"namePlaceholder": "Enter platform name",
"config": "Config",
"configPlaceholder": "Format: key:value",
"active": "Enable Now",
"running": "Running",
"platformLabel": "Platform",
"deleteConfirm": "Are you sure you want to delete this platform?"
},
"home": {
"title": "Home"
}
}
+108 -26
View File
@@ -1,39 +1,121 @@
{
"login": {
"common": {
"confirm": "确认",
"cancel": "取消",
"save": "保存",
"add": "添加",
"edit": "编辑",
"delete": "删除",
"search": "搜索",
"loading": "加载中...",
"operation": "操作",
"enable": "启用",
"optional": "可选"
},
"auth": {
"welcome": "欢迎回来",
"username": "用户名",
"password": "密码",
"login": "登录",
"register": "注册",
"forget": "忘记密码?",
"exit": "退出登录"
"forgotPassword": "忘记密码?",
"logout": "退出登录",
"logoutConfirm": "确定要退出当前账号吗?",
"loginFailed": "登录失败",
"invalidCredentials": "用户名或密码不正确",
"retryHint": "请检查后重新输入"
},
"desc": {
"question": "您的问题"
},
"prompt": {
"enter": "请输入{msg}",
"select": "请选择{msg}"
},
"slidebar": {
"setting": "设置",
"sidebar": {
"chat": "对话",
"models": "模型管理",
"settings": "设置",
"home": "首页",
"platform": "平台",
"chat": "创建对话",
"model_setting": "模型配置",
"home": "主页"
},
"chat": {
"send": "发送",
"chat": "对话"
"mcp": "MCP"
},
"breadcrumb": {
"main": "主菜单"
"main": "主"
},
"button": {
"edit": "编辑",
"delete": "删除",
"add": "添加{msg}"
"settings": {
"display": "显示设置",
"language": "语言",
"languagePlaceholder": "选择语言",
"theme": "主题",
"themePlaceholder": "选择主题",
"themeLight": "浅色",
"themeDark": "深色",
"langZh": "中文",
"langEn": "English"
},
"state": {
"open": "Open"
"chat": {
"greeting": "你好!有什么我可以帮你的吗?",
"inputPlaceholder": "输入你的问题…",
"send": "发送"
},
"models": {
"title": "模型",
"searchPlaceholder": "搜索服务商…",
"addModel": "添加模型",
"editModel": "编辑模型",
"deleteModelConfirm": "确定要删除这个模型吗?",
"emptyTitle": "暂无模型",
"emptyDescription": "点击上方按钮为当前服务商添加模型",
"type": "类型",
"typePlaceholder": "选择模型类型",
"model": "模型 ID",
"modelPlaceholder": "例如 gpt-4o",
"displayName": "显示名称",
"displayNamePlaceholder": "自定义显示名称",
"dimensions": "向量维度",
"dimensionsPlaceholder": "例如 1536",
"multimodal": "支持多模态"
},
"provider": {
"add": "添加服务商",
"addBtn": "添加",
"name": "名称",
"namePlaceholder": "输入服务商名称",
"apiKey": "API 密钥",
"apiKeyPlaceholder": "输入 API 密钥",
"url": "接口地址",
"urlPlaceholder": "输入接口地址",
"type": "类型",
"typePlaceholder": "选择类型",
"deleteConfirm": "确定要删除这个服务商吗?",
"saveChanges": "保存修改",
"emptyTitle": "暂无服务商",
"emptyDescription": "请先添加模型服务商,才能配置模型"
},
"mcp": {
"addTitle": "添加 MCP",
"addDescription": "配置 MCP 服务器连接",
"name": "名称",
"namePlaceholder": "输入名称",
"type": "类型",
"typePlaceholder": "选择类型",
"command": "命令",
"commandPlaceholder": "输入启动命令",
"arguments": "参数",
"argumentsPlaceholder": "输入启动参数",
"cwd": "工作目录",
"cwdPlaceholder": "输入工作目录路径",
"env": "环境变量",
"envPlaceholder": "格式:KEY:VALUE",
"active": "立即启用"
},
"platform": {
"addTitle": "添加平台",
"addDescription": "为模型配置调用平台",
"name": "名称",
"namePlaceholder": "输入平台名称",
"config": "配置",
"configPlaceholder": "格式:key:value",
"active": "立即启用",
"running": "运行中",
"platformLabel": "平台",
"deleteConfirm": "确定要删除这个平台吗?"
},
"home": {
"title": "首页"
}
}
+3 -2
View File
@@ -14,14 +14,14 @@
class="scroll-m-20 text-3xl font-semibold tracking-tight text-center"
style="font-family: 'Source Han Serif CN', 'Noto Serif SC', 'STSong', 'SimSun', serif;"
>
<TextGenerateEffect words="您好!有什么能帮助您的?" />
<TextGenerateEffect :words="$t('chat.greeting')" />
</h4>
</section>
<Textarea
v-model="curInputSay"
class="pb-16 pt-4"
:placeholder="$t('prompt.enter', { msg: $t('desc.question') })"
:placeholder="$t('chat.inputPlaceholder')"
/>
<section class="absolute bottom-0 h-14 px-2 inset-x-0 flex items-center">
@@ -32,6 +32,7 @@
>
<template v-if="!loading">
{{ $t('chat.send') }}
<FontAwesomeIcon :icon="['fas', 'paper-plane']" />
</template>
<LoadingDots v-else />
+2 -2
View File
@@ -1,5 +1,5 @@
<template>
<section>
<h1>主页</h1>
<section>
<h1>{{ $t('home.title') }}</h1>
</section>
</template>
+22 -22
View File
@@ -3,13 +3,13 @@
<section class="w-full max-w-sm flex flex-col gap-10 ">
<section>
<h3
class="scroll-m-20 text-3xl tracking-wide font-semibold text-white text-center"
class="scroll-m-20 text-3xl tracking-wide font-semibold text-white text-center"
style="font-family: 'Source Han Serif CN', 'Noto Serif SC', 'STSong', 'SimSun', serif;"
>
欢迎使用
{{ $t('auth.welcome') }}
</h3>
</section>
<form
<form
@submit="login"
>
<Card class="py-14">
@@ -23,14 +23,14 @@
class="mb-2"
for="username"
>
{{ $t("login.username") }}
{{ $t('auth.username') }}
</Label>
<FormControl>
<Input
v-bind="componentField"
id="username"
id="username"
type="text"
:placeholder="$t('prompt.enter', { msg: $t(`login.username`).toLocaleLowerCase() })"
:placeholder="$t('auth.username')"
autocomplete="new-password"
/>
</FormControl>
@@ -45,14 +45,14 @@
class="mb-2"
for="password"
>
{{ $t('login.password') }}
{{ $t('auth.password') }}
</Label>
<FormControl>
<FormControl>
<Input
id="password"
type="password"
:placeholder="$t('prompt.enter', { msg: $t(`login.password`).toLocaleLowerCase() })"
autocomplete="new-password"
type="password"
:placeholder="$t('auth.password')"
autocomplete="new-password"
v-bind="componentField"
/>
</FormControl>
@@ -63,11 +63,11 @@
href="#"
class="ml-auto inline-block text-sm underline mt-2"
>
{{ $t('login.forget') }}
{{ $t('auth.forgotPassword') }}
</a>
</div>
</CardContent>
<CardFooter class="flex flex-col gap-4">
<Button
class="w-full"
@@ -75,13 +75,13 @@
@click="login"
>
<Spinner v-if="loading" />
{{ $t("login.login") }}
{{ $t('auth.login') }}
</Button>
<Button
variant="outline"
class="w-full"
>
{{ $t("login.register") }}
{{ $t('auth.register') }}
</Button>
</CardFooter>
</Card>
@@ -101,7 +101,7 @@ import {
FormField,
FormItem,
Label,
Spinner
Spinner,
} from '@memoh/ui'
import { useRouter } from 'vue-router'
import { toTypedSchema } from '@vee-validate/zod'
@@ -110,9 +110,11 @@ import * as z from 'zod'
import { useUserStore } from '@/store/user'
import { ref } from 'vue'
import { toast } from 'vue-sonner'
import { useI18n } from 'vue-i18n'
import { login as loginApi } from '@/composables/api/useAuth'
const router = useRouter()
const { t } = useI18n()
const formSchema = toTypedSchema(z.object({
username: z.string().min(1),
@@ -137,17 +139,15 @@ const login = form.handleSubmit(async (values) => {
role: '',
}, data.access_token)
} else {
throw new Error('登录失败')
throw new Error(t('auth.loginFailed'))
}
router.replace({ name: 'Main' })
} catch {
toast.error('用户名或密码错误', {
description: '请重新输入用户名和密码',
toast.error(t('auth.invalidCredentials'), {
description: t('auth.retryHint'),
})
} finally {
loading.value = false
}
})
</script>
</script>
+3 -3
View File
@@ -70,7 +70,7 @@ const columns:ColumnDef<MCPType>[] = [
},
{
accessorKey: 'control',
header: () => h('div', { class: 'text-center' }, '操作'),
header: () => h('div', { class: 'text-center' }, i18nRef('common.operation').value),
cell: ({ row }) => h('div', {class:'flex gap-2'}, [
h(Button, {
onClick() {
@@ -82,7 +82,7 @@ const columns:ColumnDef<MCPType>[] = [
}
open.value=true
}
}, ()=>i18nRef('button.edit').value),
}, ()=>i18nRef('common.edit').value),
h(Button, {
variant: 'destructive',
async onClick() {
@@ -92,7 +92,7 @@ const columns:ColumnDef<MCPType>[] = [
return
}
}
},()=>i18nRef('button.delete').value)
},()=>i18nRef('common.delete').value)
])
}
]
@@ -18,7 +18,7 @@
</Button>
<ConfirmPopover
message="确认是否删除模型?"
:message="$t('models.deleteModelConfirm')"
:loading="deleteLoading"
@confirm="$emit('delete', model.name)"
>
@@ -2,7 +2,7 @@
<section>
<section class="flex justify-between items-center mb-4">
<h4 class="scroll-m-20 font-semibold tracking-tight">
模型
{{ $t('models.title') }}
</h4>
<CreateModel
v-if="providerId"
@@ -33,8 +33,8 @@
<FontAwesomeIcon :icon="['far', 'rectangle-list']" />
</EmptyMedia>
</EmptyHeader>
<EmptyTitle>还没有添加模型</EmptyTitle>
<EmptyDescription>请为当前Provider添加模型</EmptyDescription>
<EmptyTitle>{{ $t('models.emptyTitle') }}</EmptyTitle>
<EmptyDescription>{{ $t('models.emptyDescription') }}</EmptyDescription>
<EmptyContent />
</Empty>
</section>
@@ -3,7 +3,7 @@
<div class="**:[input]:mt-3 **:[input]:mb-4">
<section>
<h4 class="scroll-m-20 font-semibold tracking-tight">
Name
{{ $t('provider.name') }}
</h4>
<FormField
v-slot="{ componentField }"
@@ -13,7 +13,7 @@
<FormControl>
<Input
type="text"
placeholder="请输入名称"
:placeholder="$t('provider.namePlaceholder')"
v-bind="componentField"
/>
</FormControl>
@@ -23,7 +23,7 @@
<section>
<h4 class="scroll-m-20 font-semibold tracking-tight">
API 密钥
{{ $t('provider.apiKey') }}
</h4>
<FormField
v-slot="{ componentField }"
@@ -33,7 +33,7 @@
<FormControl>
<Input
type="text"
placeholder="请输入API密钥"
:placeholder="$t('provider.apiKeyPlaceholder')"
v-bind="componentField"
/>
</FormControl>
@@ -43,7 +43,7 @@
<section>
<h4 class="scroll-m-20 font-semibold tracking-tight">
URL
{{ $t('provider.url') }}
</h4>
<FormField
v-slot="{ componentField }"
@@ -53,7 +53,7 @@
<FormControl>
<Input
type="text"
placeholder="请输入URL"
:placeholder="$t('provider.urlPlaceholder')"
v-bind="componentField"
/>
</FormControl>
@@ -64,7 +64,7 @@
<section class="flex justify-end mt-4 gap-4">
<ConfirmPopover
message="确认是否删除模型平台?"
:message="$t('provider.deleteConfirm')"
:loading="deleteLoading"
@confirm="$emit('delete')"
>
@@ -80,7 +80,7 @@
:disabled="!hasChanges || !form.meta.value.valid"
>
<Spinner v-if="editLoading" />
确定修改
{{ $t('provider.saveChanges') }}
</Button>
</section>
</form>
@@ -96,7 +96,7 @@ import {
Spinner,
} from '@memoh/ui'
import ConfirmPopover from '@/components/confirm-popover/index.vue'
import { computed, toValue, watch } from 'vue'
import { computed, watch } from 'vue'
import { toTypedSchema } from '@vee-validate/zod'
import z from 'zod'
import { useForm } from 'vee-validate'
+4 -4
View File
@@ -95,7 +95,7 @@ const openStatus = reactive({
<InputGroup class="shadow-none">
<InputGroupInput
v-model="searchProviderTxt.temp_value"
placeholder="搜索模型平台"
:placeholder="$t('models.searchPlaceholder')"
/>
<InputGroupAddon
align="inline-end"
@@ -136,7 +136,7 @@ const openStatus = reactive({
<SidebarFooter>
<Select v-model:model-value="filterProvider">
<SelectTrigger class="w-full">
<SelectValue :placeholder="$t('prompt.select', { msg: 'Type' })" />
<SelectValue :placeholder="$t('provider.typePlaceholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
@@ -169,8 +169,8 @@ const openStatus = reactive({
<FontAwesomeIcon :icon="['far', 'rectangle-list']" />
</EmptyMedia>
</EmptyHeader>
<EmptyTitle>No Provider</EmptyTitle>
<EmptyDescription>没有添加模型提供商,无法配置模型</EmptyDescription>
<EmptyTitle>{{ $t('provider.emptyTitle') }}</EmptyTitle>
<EmptyDescription>{{ $t('provider.emptyDescription') }}</EmptyDescription>
<EmptyContent>
<!-- <Button>Add data</Button> -->
<AddProvider v-model:open="openStatus.provideOpen" />
@@ -3,12 +3,12 @@
<Card>
<CardHeader>
<CardTitle class="text-muted-foreground flex justify-between">
<span>平台:{{ platform.name }}</span>
<span>{{ $t('platform.platformLabel') }}: {{ platform.name }}</span>
<Badge
v-if="platform.active"
variant="outline"
>
运行中...
{{ $t('platform.running') }}
</Badge>
</CardTitle>
<CardContent class="mt-4 p-0">
@@ -31,13 +31,13 @@
class="ml-auto"
@click="$emit('edit', platform)"
>
编辑
{{ $t('common.edit') }}
</Button>
<Button
variant="destructive"
@click="$emit('delete', platform)"
>
删除
{{ $t('common.delete') }}
</Button>
</CardFooter>
</Card>
+14 -14
View File
@@ -5,27 +5,27 @@
:icon="['fas', 'gear']"
class="mr-2"
/>
显示设置
{{ $t('settings.display') }}
</h6>
<Separator />
<div class="mt-4 space-y-4">
<div class="flex items-center justify-between">
<Label>语言</Label>
<Label>{{ $t('settings.language') }}</Label>
<Select
:model-value="language"
@update:model-value="(v) => v && setLanguage(v as Locale)"
>
<SelectTrigger class="w-40">
<SelectValue placeholder="选择语言" />
<SelectValue :placeholder="$t('settings.languagePlaceholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="zh">
中文
{{ $t('settings.langZh') }}
</SelectItem>
<SelectItem value="en">
English
{{ $t('settings.langEn') }}
</SelectItem>
</SelectGroup>
</SelectContent>
@@ -35,21 +35,21 @@
<Separator />
<div class="flex items-center justify-between">
<Label>主题</Label>
<Label>{{ $t('settings.theme') }}</Label>
<Select
:model-value="theme"
@update:model-value="(v) => v && setTheme(v as 'light' | 'dark')"
>
<SelectTrigger class="w-40">
<SelectValue placeholder="选择主题" />
<SelectValue :placeholder="$t('settings.themePlaceholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="light">
亮色
{{ $t('settings.themeLight') }}
</SelectItem>
<SelectItem value="dark">
暗色
{{ $t('settings.themeDark') }}
</SelectItem>
</SelectGroup>
</SelectContent>
@@ -62,22 +62,22 @@
<template #default="{ close }">
<PopoverTrigger as-child>
<Button variant="outline">
{{ $t("login.exit") }}
{{ $t('auth.logout') }}
</Button>
</PopoverTrigger>
<PopoverContent class="w-80">
<p class="mb-4">
确认退出登录?
{{ $t('auth.logoutConfirm') }}
</p>
<div class="flex justify-end gap-3">
<Button
variant="outline"
@click="close"
>
取消
{{ $t('common.cancel') }}
</Button>
<Button @click="exit(); close()">
确定
{{ $t('common.confirm') }}
</Button>
</div>
</PopoverContent>
@@ -118,4 +118,4 @@ const exit = () => {
exitLogin()
router.replace({ name: 'Login' })
}
</script>
</script>
+6 -5
View File
@@ -17,34 +17,35 @@ const routes = [
redirect: '/main/chat',
meta: {
breadcrumb: i18nRef('breadcrumb.main')
},
children: [{
name: 'chat',
path: 'chat',
component: () => import('@/pages/chat/index.vue'),
meta: {
breadcrumb: i18nRef('chat.chat')
breadcrumb: i18nRef('sidebar.chat')
}
}, {
name: 'home',
path: 'home',
component: () => import('@/pages/home/index.vue'),
meta: {
breadcrumb: '主页'
breadcrumb: i18nRef('home.title')
}
}, {
name: 'models',
path: 'models',
component: () => import('@/pages/models/index.vue'),
meta: {
breadcrumb: i18nRef('slidebar.model_setting')
breadcrumb: i18nRef('sidebar.models')
}
}, {
name: 'settings',
path: 'settings',
component: () => import('@/pages/settings/index.vue'),
meta: {
breadcrumb: i18nRef('slidebar.setting')
breadcrumb: i18nRef('sidebar.settings')
}
}, {
name: 'mcp',
@@ -58,7 +59,7 @@ const routes = [
path: 'platform',
component: () => import('@/pages/platform/index.vue'),
meta: {
breadcrumb: i18nRef('slidebar.platform')
breadcrumb: i18nRef('sidebar.platform')
}
}]
}