Skip to content

Commit 810a455

Browse files
fix: patterns bug
1 parent 7a8feca commit 810a455

23 files changed

Lines changed: 683 additions & 205 deletions

File tree

‎ui/AGENTS.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Pinia 3、Element Plus、Tailwind CSS 4 和 Sass;工作流画布基于 LogicFl
1818
| [VIEW_README.md](src/views/VIEW_README.md) | 页面职责、功能本地组织与业务约束 |
1919
| [WORKFLOW_README.md](src/workflow-canvas/WORKFLOW_README.md) | 画布内核、节点、资源查询与接入接口 |
2020
| [CONSTANT_README.md](src/constants/CONSTANT_README.md) | 共享展示常量 |
21+
| [LOCALE_README.md](src/locales/LOCALE_README.md) | 国际化分类、语言状态与使用约定 |
2122
| [UTILS_README.md](src/utils/UTILS_README.md) | 共享工具函数与组合式函数 |
2223

2324
新增专题规则文档时补充此索引;仅在目录、公开接口或使用规则变化时同步对应章节。
@@ -43,7 +44,7 @@ Pinia 3、Element Plus、Tailwind CSS 4 和 Sass;工作流画布基于 LogicFl
4344
| `src/constants/`、`src/utils/` | 跨功能常量与工具 |
4445
| `src/assets/`、`public/` | 源码导入资源/需要保留原文件名和 URL 的静态文件 |
4546

46-
国际化尚未集成,未创建 `src/locales/`。文件放入现有功能边界,不创建平行的顶层结构。
47+
国际化基础及分类规则见 [LOCALE_README.md](src/locales/LOCALE_README.md)。文件放入现有功能边界,不创建平行的顶层结构。
4748
各入口复用自己的 Pinia:Admin 使用 `@/stores/admin`,Chat 使用 `@/stores/chat` 的 `useStore()`;
4849
Store 内部协调状态时可直接引用同入口的具体 Store,避免聚合入口循环依赖。
4950
`src/stores/index.ts` 当前是 Admin 兼容入口,不能用它获取 Chat Store。

‎ui/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"vue-codemirror": "^6.1.1",
5858
"vue-demi": "^0.14.10",
5959
"vue-draggable-plus": "^0.6.1",
60+
"vue-i18n": "^11.4.18",
6061
"vue-router": "^5.1.0"
6162
},
6263
"devDependencies": {

‎ui/pnpm-lock.yaml‎

Lines changed: 410 additions & 108 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎ui/src/App.vue‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
<script setup lang="ts">
2+
import { computed } from 'vue'
3+
import { useI18n } from 'vue-i18n'
4+
import zhCn from 'element-plus/es/locale/lang/zh-cn'
5+
import en from 'element-plus/es/locale/lang/en'
6+
import zhTw from 'element-plus/es/locale/lang/zh-tw'
7+
import { normalizeLocale } from '@/locales/config'
28
import { RouterView } from 'vue-router'
39
import { TOOLTIP_SHOW_DELAY } from '@/components/global/mk-tooltip/constants'
410
11+
const { locale } = useI18n({ useScope: 'global' })
12+
const elementLocales = { 'zh-CN': zhCn, 'en-US': en, 'zh-Hant': zhTw }
13+
const elementLocale = computed(() => elementLocales[normalizeLocale(locale.value)])
14+
515
const tableConfig = { tooltipOptions: { showAfter: TOOLTIP_SHOW_DELAY } }
616
</script>
717

818
<template>
9-
<el-config-provider :table="tableConfig">
19+
<el-config-provider :table="tableConfig" :locale="elementLocale">
1020
<RouterView />
1121
</el-config-provider>
1222
</template>

‎ui/src/chat.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { createApp } from 'vue'
22
import ElementPlus from 'element-plus'
3-
import zhCn from 'element-plus/es/locale/lang/zh-cn'
43

54
import App from './App.vue'
65
import { configureMarkdownEditor } from '@/components/global/markdown-editor/config'
76
import router from '@/router/chat'
8-
import { pinia } from '@/stores/chat'
7+
import { pinia, useStore } from '@/stores/chat'
8+
import { createAppI18n } from '@/locales'
99
import 'element-plus/dist/index.css'
1010
import '@/styles/tailwind.css'
1111
import '@/styles/index.scss'
@@ -15,7 +15,8 @@ configureMarkdownEditor()
1515
const app = createApp(App)
1616

1717
app.use(pinia)
18+
app.use(createAppI18n(useStore().user))
1819
app.use(router)
19-
app.use(ElementPlus, { locale: zhCn })
20+
app.use(ElementPlus)
2021

2122
app.mount('#app')

‎ui/src/constants/CONSTANT_README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ API 枚举值。例如角色类型和登录方式以 `src/api/enums` 为唯一
4545

4646
`document.ts` 的 `DOCUMENT_HIT_HANDLING_LABELS` 维护文档命中处理方式的展示文案,
4747
映射键引用 API 枚举 `DOCUMENT_HIT_HANDLING`。
48+
`DOCUMENT_SPLIT_PATTERN_OPTIONS` 维护文档分段标识的完整选项与正则值,知识库文档策略表单和工作流分段节点共同引用。
4849

4950
`file-type.ts` 维护图片、文档、视频和音频的文件扩展名常量,扩展名统一使用大写。
5051
使用方判断文件类型时先将后缀转换为大写,再与对应常量匹配。

‎ui/src/constants/document.ts‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,59 @@ export const DOCUMENT_HIT_HANDLING_LABELS = {
55
[DOCUMENT_HIT_HANDLING.OPTIMIZATION]: '模型优化',
66
[DOCUMENT_HIT_HANDLING.DIRECTLY_RETURN]: '直接回答',
77
} as const
8+
9+
// 与后端 DocumentSerializers.SplitPattern 的固定标识保持一致;顺序由用户选择决定。
10+
export const DOCUMENT_SPLIT_PATTERN_OPTIONS = [
11+
{
12+
label: '#',
13+
value: '(?<=^)# .*|(?<=\\n)# .*',
14+
},
15+
{
16+
label: '##',
17+
value: '(?<=\\n)(?<!#)## (?!#).*|(?<=^)(?<!#)## (?!#).*',
18+
},
19+
{
20+
label: '###',
21+
value: '(?<=\\n)(?<!#)### (?!#).*|(?<=^)(?<!#)### (?!#).*',
22+
},
23+
{
24+
label: '####',
25+
value: '(?<=\\n)(?<!#)#### (?!#).*|(?<=^)(?<!#)#### (?!#).*',
26+
},
27+
{
28+
label: '#####',
29+
value: '(?<=\\n)(?<!#)##### (?!#).*|(?<=^)(?<!#)##### (?!#).*',
30+
},
31+
{
32+
label: '######',
33+
value: '(?<=\\n)(?<!#)###### (?!#).*|(?<=^)(?<!#)###### (?!#).*',
34+
},
35+
{
36+
label: '-',
37+
value: '(?<! )- .*',
38+
},
39+
{
40+
label: '空格',
41+
value: '(?<! ) (?! )',
42+
},
43+
{
44+
label: '分号',
45+
value: '(?<!;);(?!;)',
46+
},
47+
{
48+
label: '逗号',
49+
value: '(?<!,),(?!,)',
50+
},
51+
{
52+
label: '句号',
53+
value: '(?<!。)。(?!。)',
54+
},
55+
{
56+
label: '回车',
57+
value: '(?<!\\n)\\n(?!\\n)',
58+
},
59+
{
60+
label: '空行',
61+
value: '(?<!\\n)\\n\\n(?!\\n)',
62+
},
63+
]

‎ui/src/layout/avatar-dropdown/index.vue‎

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ref, useTemplateRef } from 'vue'
33
import { useRouter } from 'vue-router'
44
import LoginApi from '@/api/admin/auth/login'
55
import { LOGIN_METHOD } from '@/api/enums'
6+
import { LOCALE_OPTIONS, type Locale } from '@/locales/config'
67
import { useStore } from '@/stores'
78
import ChangePasswordDialog from './ChangePasswordDialog.vue'
89
import AboutDialog from './AboutDialog.vue'
@@ -11,16 +12,9 @@ import perm from '@/permission/index.ts'
1112
1213
defineOptions({ name: 'AvatarDropdown' })
1314
14-
type Language = 'en' | 'zh-CN' | 'zh-TW'
15-
16-
const currentLanguage = ref<Language>('zh-CN')
15+
const currentLanguage = ref<Locale>('zh-CN')
1716
const router = useRouter()
1817
const { auth, user, theme } = useStore()
19-
const languages: Array<{ label: string; value: Language }> = [
20-
{ label: 'English', value: 'en' },
21-
{ label: '简体中文', value: 'zh-CN' },
22-
{ label: '繁體中文', value: 'zh-TW' },
23-
]
2418
2519
// 修改当前账号密码。
2620
const changePasswordDialogRef = ref<InstanceType<typeof ChangePasswordDialog>>()
@@ -104,7 +98,7 @@ function toUrl(url?: string) {
10498
<template #dropdown>
10599
<MkDropdownMenu class="w-52">
106100
<MkDropdownItem
107-
v-for="language in languages"
101+
v-for="language in LOCALE_OPTIONS"
108102
:key="language.value"
109103
selectable
110104
:selected="currentLanguage === language.value"

‎ui/src/locales/LOCALE_README.md‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# 国际化规则
2+
3+
`src/locales` 负责界面语言、语言包和入口初始化。当前支持 `zh-CN`、`en-US` 与 `zh-Hant`,
4+
默认及缺失文案回退为简体中文。语言包暂随入口加载,新增语言时再评估按需加载。
5+
6+
## 分类
7+
8+
按“业务域 → 对象或场景 → 文案用途”组织;文件按业务域划分,不对应组件目录。
9+
当前只建立实际使用的 common.json,不预建空业务包。
10+
11+
| 业务域 | 内容 |
12+
| ----------- | ------------------------------------------------ |
13+
| common | 无业务含义的操作、基础校验、界面偏好和通用错误页 |
14+
| auth | 登录、退出、找回密码、身份认证 |
15+
| navigation | 导航菜单、面包屑、浏览器页面标题 |
16+
| application | 智能体创建、配置、发布、版本 |
17+
| knowledge | 知识库、文档、分段、问题、标签、检索 |
18+
| model | 模型、供应商、模型参数与连接测试 |
19+
| tool | 工具、MCP、Skill 管理 |
20+
| workflow | 画布、节点、变量、调试与执行展示 |
21+
| chat | 对话输入、消息操作、历史会话与对话状态 |
22+
| workspace | 工作空间、成员、空间级设置 |
23+
| system | 用户、角色、系统配置、许可证 |
24+
25+
业务域内按实际对象拆分,如 knowledge.document;末级按用途使用:
26+
`title`、`description`、`actions`、`fields`、`validation`、`messages`、`dialogs`、
27+
`states`、`options`、`empty`。fields 内使用字段名下的 label、placeholder、description。
28+
common.errors 用于通用错误场景,例如 common.errors.notFound.description。
29+
30+
归属以业务含义判断:知识库检索模式归 knowledge,知识库检索节点归 workflow。
31+
系统资源管理复用原业务域,不复制到 system。多处使用不等于通用;相同中文但业务语义
32+
不同可以使用不同 key。用户内容、提示词、协议枚举和已保存节点名称不进入语言包。
33+
34+
## 使用约定
35+
36+
- key 使用表达业务含义的英文 camelCase,不使用中文、数字序号或 misc 等模糊分类。
37+
- JSON 文件不重复包裹业务域,由 index.ts 挂载命名空间;各语言保持相同 key 与插值参数。
38+
- 完整句子整体翻译,动态内容使用命名参数;不用片段拼接句子。
39+
- 组件显式导入 useI18n,并使用全局作用域的 t;不使用自动注入的 $t。
40+
- 依赖语言的选项和校验规则在 computed 或执行时翻译,不在模块初始化时固化翻译结果。
41+
- 新增业务包时更新 index.ts 的所有语言及 MessageSchema,以中文结构约束翻译 key。
42+
- 非组件代码通过调用方传入翻译能力,不依赖某个入口的全局国际化单例。
43+
44+
## 语言状态
45+
46+
Admin 和 Chat 分别调用 createAppI18n,连接自己的 User Store;该模块不导入任何 Store。
47+
Store 是语言状态来源,通过 setLanguage 更新,不能直接修改 Vue I18n 的 locale。
48+
App.vue 通过当前 locale 配置 Element Plus,初始化同时维护 html.lang。
49+
50+
两个入口继续共用 MaxKB-locale。初始化按本地缓存、浏览器语言、默认中文选择;
51+
英语变体归一为 en-US;zh-Hant、zh-TW、zh-HK、zh-MO 归一为 zh-Hant,
52+
显式 zh-Hans 优先使用简体,其余语言回退 zh-CN。Element Plus 的繁体映射为 zh-tw。Admin 加载账号后继续采用账号语言。
53+
跨标签页缓存变化同步到当前 Store。请求头复用原请求层的 user.language。
54+
当前语言选择只保存本地,不写回账号;账号偏好优先级在账号设置模块中处理。
55+
56+
## 分批迁移
57+
58+
404 页面为当前样例,提供简体、英文及繁体切换。其余界面、路由标题、编辑器及日期格式专项
59+
按模块接入,允许过渡期保留原中文。每批完成后等待用户检查,未经确认不扩展下一批。

‎ui/src/locales/config.ts‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/** 定义当前支持的界面语言与偏好存储规则。 */
2+
export const LANGUAGE_STORAGE_KEY = 'MaxKB-locale'
3+
export const DEFAULT_LOCALE = 'zh-CN'
4+
export const LOCALE_OPTIONS = [
5+
{ value: 'zh-CN', label: '简体中文' },
6+
{ value: 'en-US', label: 'English' },
7+
{ value: 'zh-Hant', label: '繁體中文' },
8+
] as const
9+
export type Locale = (typeof LOCALE_OPTIONS)[number]['value']
10+
11+
/** 将浏览器或账号语言映射到已支持的界面语言。 */
12+
export function normalizeLocale(language: string | null | undefined): Locale {
13+
const [languageCode, ...subtags] = language?.replaceAll('_', '-').toLowerCase().split('-') ?? []
14+
if (languageCode === 'en') return 'en-US'
15+
if (languageCode === 'zh') {
16+
// 显式文字体系优先于地区,例如 zh-Hans-HK 仍使用简体。
17+
if (subtags.includes('hans')) return 'zh-CN'
18+
if (subtags.includes('hant') || subtags.some((subtag) => ['tw', 'hk', 'mo'].includes(subtag))) return 'zh-Hant'
19+
}
20+
return DEFAULT_LOCALE
21+
}
22+
23+
/** 优先读取本地偏好,其次使用浏览器语言,最终回退简体中文。 */
24+
export function getDefaultLanguage(): Locale {
25+
return normalizeLocale(localStorage.getItem(LANGUAGE_STORAGE_KEY) || navigator.language)
26+
}

0 commit comments

Comments
 (0)