@liujitcn/kratos-admin-system 0.0.20 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +51 -50
  2. package/dist/package/declarations/src/api/system/base_language.d.ts +51 -0
  3. package/dist/package/declarations/src/api/system/base_translation.d.ts +7 -0
  4. package/dist/package/declarations/src/api/system/code_gen_i18n.d.ts +8 -0
  5. package/dist/package/declarations/src/components/DynamicTranslationCell.vue.d.ts +39 -0
  6. package/dist/package/declarations/src/components/DynamicTranslationEditor.vue.d.ts +23 -0
  7. package/dist/package/declarations/src/components/dynamicTranslation.d.ts +44 -0
  8. package/dist/package/declarations/src/rpc/system/admin/v1/base_config.d.ts +5 -0
  9. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +79 -0
  10. package/dist/package/declarations/src/rpc/system/admin/v1/base_language.d.ts +114 -0
  11. package/dist/package/declarations/src/rpc/system/admin/v1/base_menu.d.ts +40 -0
  12. package/dist/package/declarations/src/rpc/system/admin/v1/base_translation.d.ts +102 -0
  13. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen.d.ts +2 -0
  14. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen_column.d.ts +7 -0
  15. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen_table.d.ts +13 -0
  16. package/dist/package/declarations/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue.d.ts +23 -0
  17. package/dist/package/declarations/src/views/tool/code-gen/config.d.ts +7 -7
  18. package/dist/package/declarations/src/views/tool/language/index.vue.d.ts +3 -0
  19. package/dist/package/src/api/base/ai_message.ts +7 -12
  20. package/dist/package/src/api/base/sse.ts +3 -1
  21. package/dist/package/src/api/system/base_language.ts +137 -0
  22. package/dist/package/src/api/system/base_translation.ts +22 -0
  23. package/dist/package/src/api/system/code_gen_column.ts +17 -3
  24. package/dist/package/src/api/system/code_gen_i18n.ts +18 -0
  25. package/dist/package/src/api/system/code_gen_table.ts +12 -4
  26. package/dist/package/src/components/DynamicTranslationCell.vue +176 -0
  27. package/dist/package/src/components/DynamicTranslationEditor.vue +166 -0
  28. package/dist/package/src/components/dynamicTranslation.ts +86 -0
  29. package/dist/package/src/locales/README.md +28 -0
  30. package/dist/package/src/locales/en-US.json +929 -0
  31. package/dist/package/src/locales/es-ES.json +928 -0
  32. package/dist/package/src/locales/fr-FR.json +928 -0
  33. package/dist/package/src/locales/ja-JP.json +929 -0
  34. package/dist/package/src/locales/ko-KR.json +928 -0
  35. package/dist/package/src/locales/zh-CN.json +929 -0
  36. package/dist/package/src/locales/zh-TW.json +928 -0
  37. package/dist/package/src/module.ts +19 -1
  38. package/dist/package/src/rpc/system/admin/v1/base_config.ts +5 -0
  39. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +81 -0
  40. package/dist/package/src/rpc/system/admin/v1/base_language.ts +135 -0
  41. package/dist/package/src/rpc/system/admin/v1/base_menu.ts +41 -0
  42. package/dist/package/src/rpc/system/admin/v1/base_translation.ts +117 -0
  43. package/dist/package/src/rpc/system/admin/v1/code_gen.ts +5 -1
  44. package/dist/package/src/rpc/system/admin/v1/code_gen_column.ts +8 -0
  45. package/dist/package/src/rpc/system/admin/v1/code_gen_table.ts +15 -0
  46. package/dist/package/src/views/ai/chat/components/AiMarkdown.vue +1 -6
  47. package/dist/package/src/views/ai/chat/components/ChatPanel.vue +70 -53
  48. package/dist/package/src/views/ai/chat/components/SessionPanel.vue +20 -9
  49. package/dist/package/src/views/ai/chat/components/XSender.vue +36 -23
  50. package/dist/package/src/views/ai/chat/index.vue +55 -39
  51. package/dist/package/src/views/ai/chat/message.ts +18 -17
  52. package/dist/package/src/views/base/api/index.vue +121 -83
  53. package/dist/package/src/views/base/area/index.vue +81 -31
  54. package/dist/package/src/views/base/config/index.vue +272 -78
  55. package/dist/package/src/views/base/dept/index.vue +110 -61
  56. package/dist/package/src/views/base/dict/index.vue +137 -58
  57. package/dist/package/src/views/base/dict/item.vue +147 -61
  58. package/dist/package/src/views/base/job/index.vue +134 -81
  59. package/dist/package/src/views/base/job/log.vue +21 -22
  60. package/dist/package/src/views/base/log/index.vue +68 -46
  61. package/dist/package/src/views/base/menu/index.vue +257 -156
  62. package/dist/package/src/views/base/migration/index.vue +49 -29
  63. package/dist/package/src/views/base/post/index.vue +128 -59
  64. package/dist/package/src/views/base/role/index.vue +145 -78
  65. package/dist/package/src/views/base/tenant/index.vue +132 -63
  66. package/dist/package/src/views/base/user/components/dept-tree.vue +2 -1
  67. package/dist/package/src/views/base/user/index.vue +192 -112
  68. package/dist/package/src/views/profile/components/base.vue +44 -27
  69. package/dist/package/src/views/profile/components/password.vue +43 -27
  70. package/dist/package/src/views/profile/components/security.vue +89 -53
  71. package/dist/package/src/views/profile/index.vue +10 -9
  72. package/dist/package/src/views/tool/api-doc/index.vue +6 -2
  73. package/dist/package/src/views/tool/code-gen/code-preview/index.vue +30 -14
  74. package/dist/package/src/views/tool/code-gen/columns/index.vue +382 -273
  75. package/dist/package/src/views/tool/code-gen/columns/option-copy.ts +1 -6
  76. package/dist/package/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue +118 -0
  77. package/dist/package/src/views/tool/code-gen/components/CodeGenProgressDialog.vue +65 -36
  78. package/dist/package/src/views/tool/code-gen/components/CodePreviewPane.vue +8 -5
  79. package/dist/package/src/views/tool/code-gen/config.ts +114 -77
  80. package/dist/package/src/views/tool/code-gen/preview/data.ts +19 -17
  81. package/dist/package/src/views/tool/code-gen/preview/index.vue +96 -58
  82. package/dist/package/src/views/tool/code-gen/proto/index.vue +110 -62
  83. package/dist/package/src/views/tool/code-gen/table/index.vue +197 -117
  84. package/dist/package/src/views/tool/language/index.vue +256 -0
  85. package/dist/package/src/views/tool/project-doc/index.vue +17 -15
  86. package/package.json +6 -2
@@ -0,0 +1,176 @@
1
+ <template>
2
+ <el-popover
3
+ placement="top-start"
4
+ trigger="hover"
5
+ :show-after="120"
6
+ :width="360"
7
+ :enterable="true"
8
+ :teleported="true"
9
+ popper-class="dynamic-translation-cell__popover"
10
+ >
11
+ <template #reference>
12
+ <span class="dynamic-translation-cell">
13
+ <span class="dynamic-translation-cell__source">{{ displaySource || "--" }}</span>
14
+ </span>
15
+ </template>
16
+
17
+ <div class="dynamic-translation-cell__rows">
18
+ <div v-for="item in translationRows" :key="item.locale" class="dynamic-translation-cell__row">
19
+ <span class="dynamic-translation-cell__language">{{ getLanguageLabel(item.locale) }}</span>
20
+ <span class="dynamic-translation-cell__text">{{ item.text || t('system.common.value.none') }}</span>
21
+ <el-tag v-if="showStatus && !item.isSource" :type="statusTagType(item)" effect="light" size="small">
22
+ {{ statusLabel(item) }}
23
+ </el-tag>
24
+ </div>
25
+ </div>
26
+ </el-popover>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import { computed } from "vue";
31
+ import { t, useLocaleStore } from "@liujitcn/kratos-admin-core";
32
+ import { useEnabledBaseLanguages } from "@liujitcn/kratos-admin-system/api/system/base_language";
33
+ import { TranslationStatus } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_translation";
34
+ import { getLanguageLabel } from "./dynamicTranslation";
35
+
36
+ /** DynamicTranslationCellRecord 描述列表翻译预览所需的最小记录结构。 */
37
+ export interface DynamicTranslationCellRecord {
38
+ /** 语言区域。 */
39
+ locale: string;
40
+ /** 通用翻译文本,供系统配置使用。 */
41
+ text?: string;
42
+ /** 字典名称翻译。 */
43
+ name?: string;
44
+ /** 字典项标签翻译。 */
45
+ label?: string;
46
+ /** 菜单标题翻译。 */
47
+ title?: string;
48
+ /** 翻译审核状态。 */
49
+ translation_status?: TranslationStatus;
50
+ /** 中文源文是否已变化。 */
51
+ source_changed?: boolean;
52
+ }
53
+
54
+ /** DynamicTranslationCellProps 动态翻译列表单元格属性。 */
55
+ interface DynamicTranslationCellProps {
56
+ /** 资源源文。 */
57
+ source: string;
58
+ /** 非主语言翻译记录。 */
59
+ translations?: DynamicTranslationCellRecord[];
60
+ /** 源文所属语言,仅用于语言配置尚未加载时的回退。 */
61
+ sourceLocale?: string;
62
+ /** 从翻译记录中读取的文本字段。 */
63
+ textField?: "text" | "name" | "label" | "title";
64
+ /** 是否显示翻译状态标签。 */
65
+ showStatus?: boolean;
66
+ }
67
+
68
+ const props = withDefaults(defineProps<DynamicTranslationCellProps>(), {
69
+ translations: () => [],
70
+ sourceLocale: "zh-CN",
71
+ textField: "text",
72
+ showStatus: true
73
+ });
74
+
75
+ const { locale } = useLocaleStore();
76
+ const { languages } = useEnabledBaseLanguages();
77
+ const primaryLocale = computed(() => languages.value.find(item => item.is_primary)?.language_code ?? props.sourceLocale ?? "zh-CN");
78
+
79
+ const displaySource = computed(() => {
80
+ if (locale.value === primaryLocale.value) return props.source;
81
+ const record = props.translations.find(item => item.locale === locale.value);
82
+ if (record?.translation_status !== TranslationStatus.TRANSLATION_STATUS_REVIEWED) return props.source;
83
+ return getTranslationText(record) || props.source;
84
+ });
85
+
86
+ const translationRows = computed(() =>
87
+ languages.value
88
+ .filter(item => item.language_code !== locale.value)
89
+ .map(item => {
90
+ const itemLocale = item.language_code;
91
+ const isSource = itemLocale === primaryLocale.value;
92
+ const record = props.translations.find(item => item.locale === itemLocale);
93
+ const text = isSource ? props.source : record ? getTranslationText(record) : "";
94
+ return {
95
+ locale: itemLocale,
96
+ text,
97
+ isSource,
98
+ translation_status: record?.translation_status,
99
+ source_changed: record?.source_changed ?? false
100
+ };
101
+ })
102
+ );
103
+
104
+ /** getTranslationText 读取当前资源对应的翻译字段。 */
105
+ function getTranslationText(record: DynamicTranslationCellRecord) {
106
+ return record[props.textField] ?? "";
107
+ }
108
+
109
+ /** statusLabel 返回当前翻译审核状态文案。 */
110
+ function statusLabel(item: (typeof translationRows.value)[number]) {
111
+ if (item.source_changed) return t("system.translation.status.sourceChanged");
112
+ const statusKey =
113
+ {
114
+ [TranslationStatus.TRANSLATION_STATUS_PENDING]: "pending",
115
+ [TranslationStatus.TRANSLATION_STATUS_MACHINE]: "machine",
116
+ [TranslationStatus.TRANSLATION_STATUS_REVIEWED]: "reviewed"
117
+ }[item.translation_status ?? TranslationStatus.TRANSLATION_STATUS_PENDING] ?? "pending";
118
+ return t(`system.translation.status.${statusKey}`);
119
+ }
120
+
121
+ /** statusTagType 返回当前翻译审核状态对应的标签样式。 */
122
+ function statusTagType(item: (typeof translationRows.value)[number]) {
123
+ if (item.source_changed) return "warning";
124
+ if (item.translation_status === TranslationStatus.TRANSLATION_STATUS_REVIEWED) return "success";
125
+ if (item.translation_status === TranslationStatus.TRANSLATION_STATUS_MACHINE) return "primary";
126
+ return "info";
127
+ }
128
+ </script>
129
+
130
+ <style scoped>
131
+ .dynamic-translation-cell {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ min-width: 0;
135
+ max-width: 100%;
136
+ }
137
+
138
+ .dynamic-translation-cell__source {
139
+ min-width: 0;
140
+ overflow: hidden;
141
+ text-overflow: ellipsis;
142
+ white-space: nowrap;
143
+ }
144
+
145
+ </style>
146
+
147
+ <style>
148
+ .dynamic-translation-cell__popover .dynamic-translation-cell__rows {
149
+ display: flex;
150
+ flex-direction: column;
151
+ gap: 10px;
152
+ }
153
+
154
+ .dynamic-translation-cell__popover {
155
+ max-width: calc(100vw - 24px);
156
+ box-sizing: border-box;
157
+ }
158
+
159
+ .dynamic-translation-cell__popover .dynamic-translation-cell__row {
160
+ display: grid;
161
+ grid-template-columns: 76px minmax(0, 1fr) auto;
162
+ gap: 10px;
163
+ align-items: center;
164
+ }
165
+
166
+ .dynamic-translation-cell__popover .dynamic-translation-cell__language {
167
+ color: var(--el-text-color-regular);
168
+ font-weight: 600;
169
+ }
170
+
171
+ .dynamic-translation-cell__popover .dynamic-translation-cell__text {
172
+ min-width: 0;
173
+ color: var(--el-text-color-primary);
174
+ overflow-wrap: anywhere;
175
+ }
176
+ </style>
@@ -0,0 +1,166 @@
1
+ <template>
2
+ <div class="translation-editor">
3
+ <div v-for="item in localValues" :key="item.locale" class="translation-editor__row">
4
+ <div class="translation-editor__heading">
5
+ <span>{{ getLanguageLabel(item.locale) }}</span>
6
+ <el-tag :type="statusTagType(item)" effect="light" size="small">{{ statusLabel(item) }}</el-tag>
7
+ </div>
8
+ <div class="translation-editor__control">
9
+ <el-input
10
+ :model-value="item.text"
11
+ :maxlength="maxlength"
12
+ :type="multiline ? 'textarea' : 'text'"
13
+ :rows="multiline ? 6 : undefined"
14
+ show-word-limit
15
+ :placeholder="t('system.translation.placeholder.text', { language: getLanguageLabel(item.locale) })"
16
+ @update:model-value="value => updateText(item.locale, value)"
17
+ />
18
+ <el-tooltip
19
+ v-if="draftEnabled && resourceId > 0"
20
+ :content="t('system.translation.action.generateDraft', { language: getLanguageLabel(item.locale) })"
21
+ >
22
+ <el-button
23
+ :icon="MagicStick"
24
+ :loading="loadingLocale === item.locale"
25
+ :disabled="item.translation_status === TranslationStatus.TRANSLATION_STATUS_REVIEWED && !item.source_changed"
26
+ @click="generateDraft(item.locale)"
27
+ />
28
+ </el-tooltip>
29
+ </div>
30
+ </div>
31
+ <el-alert
32
+ v-if="resourceId === 0 && draftEnabled"
33
+ :title="t('system.translation.message.saveBeforeDraft')"
34
+ type="info"
35
+ :closable="false"
36
+ show-icon
37
+ />
38
+ </div>
39
+ </template>
40
+
41
+ <script setup lang="ts">
42
+ import { ref, watch } from "vue";
43
+ import { MagicStick } from "@element-plus/icons-vue";
44
+ import { t } from "@liujitcn/kratos-admin-core";
45
+ import { defBaseTranslationService } from "@liujitcn/kratos-admin-system/api/system/base_translation";
46
+ import {
47
+ BaseConfigTranslationField,
48
+ TranslationResourceType,
49
+ TranslationStatus
50
+ } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_translation";
51
+ import { getLanguageLabel, type DynamicTranslationValue } from "./dynamicTranslation";
52
+
53
+ /** DynamicTranslationEditorProps 动态翻译编辑器属性。 */
54
+ interface DynamicTranslationEditorProps {
55
+ modelValue: DynamicTranslationValue[];
56
+ resourceId: number;
57
+ resourceType: TranslationResourceType;
58
+ field?: BaseConfigTranslationField;
59
+ draftEnabled?: boolean;
60
+ maxlength?: number;
61
+ multiline?: boolean;
62
+ }
63
+
64
+ const props = withDefaults(defineProps<DynamicTranslationEditorProps>(), {
65
+ draftEnabled: false,
66
+ maxlength: 100,
67
+ multiline: false
68
+ });
69
+
70
+ const emit = defineEmits<{ "update:modelValue": [value: DynamicTranslationValue[]] }>();
71
+ const localValues = ref<DynamicTranslationValue[]>([]);
72
+ const loadingLocale = ref("");
73
+
74
+ watch(
75
+ () => props.modelValue,
76
+ value => {
77
+ localValues.value = value.map(item => ({ ...item }));
78
+ },
79
+ { immediate: true, deep: true }
80
+ );
81
+
82
+ /** updateText 更新指定语言的人工译文。 */
83
+ function updateText(locale: DynamicTranslationValue["locale"], text: string) {
84
+ const values = localValues.value.map(item => (item.locale === locale ? { ...item, text } : item));
85
+ localValues.value = values;
86
+ emit("update:modelValue", values);
87
+ }
88
+
89
+ /** generateDraft 为指定目标语言生成机器翻译草稿。 */
90
+ async function generateDraft(locale: DynamicTranslationValue["locale"]) {
91
+ loadingLocale.value = locale;
92
+ try {
93
+ const response = await defBaseTranslationService.GenerateTranslationDraft({
94
+ resource_type: props.resourceType,
95
+ resource_id: props.resourceId,
96
+ target_locale: locale,
97
+ field: props.field ?? BaseConfigTranslationField.BASE_CONFIG_TRANSLATION_FIELD_UNSPECIFIED
98
+ });
99
+ const values = localValues.value.map(item =>
100
+ item.locale === locale
101
+ ? {
102
+ ...item,
103
+ text: response.translation,
104
+ translation_status: response.translation_status,
105
+ source_changed: false,
106
+ source_hash: response.source_hash,
107
+ translation_provider: response.translation_provider,
108
+ translated_at: response.translated_at
109
+ }
110
+ : item
111
+ );
112
+ localValues.value = values;
113
+ emit("update:modelValue", values);
114
+ ElMessage.success(t("system.translation.message.draftSuccess", { language: getLanguageLabel(locale) }));
115
+ } finally {
116
+ loadingLocale.value = "";
117
+ }
118
+ }
119
+
120
+ /** statusLabel 返回当前翻译审核状态文案。 */
121
+ function statusLabel(item: DynamicTranslationValue) {
122
+ if (item.source_changed) return t("system.translation.status.sourceChanged");
123
+ const statusKey =
124
+ {
125
+ [TranslationStatus.TRANSLATION_STATUS_PENDING]: "pending",
126
+ [TranslationStatus.TRANSLATION_STATUS_MACHINE]: "machine",
127
+ [TranslationStatus.TRANSLATION_STATUS_REVIEWED]: "reviewed"
128
+ }[item.translation_status] ?? "pending";
129
+ return t(`system.translation.status.${statusKey}`);
130
+ }
131
+
132
+ /** statusTagType 返回当前翻译审核状态对应的标签样式。 */
133
+ function statusTagType(item: DynamicTranslationValue) {
134
+ if (item.source_changed) return "warning";
135
+ if (item.translation_status === TranslationStatus.TRANSLATION_STATUS_REVIEWED) return "success";
136
+ if (item.translation_status === TranslationStatus.TRANSLATION_STATUS_MACHINE) return "primary";
137
+ return "info";
138
+ }
139
+ </script>
140
+
141
+ <style scoped>
142
+ .translation-editor {
143
+ display: flex;
144
+ flex-direction: column;
145
+ gap: 14px;
146
+ width: 100%;
147
+ }
148
+ .translation-editor__row {
149
+ display: flex;
150
+ flex-direction: column;
151
+ gap: 6px;
152
+ }
153
+ .translation-editor__heading,
154
+ .translation-editor__control {
155
+ display: flex;
156
+ gap: 8px;
157
+ align-items: center;
158
+ }
159
+ .translation-editor__heading {
160
+ justify-content: space-between;
161
+ color: var(--el-text-color-regular);
162
+ }
163
+ .translation-editor__control :deep(.el-input) {
164
+ flex: 1;
165
+ }
166
+ </style>
@@ -0,0 +1,86 @@
1
+ import { TranslationStatus } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_translation";
2
+ import { getEnabledBaseLanguages } from "@liujitcn/kratos-admin-system/api/system/base_language";
3
+
4
+ /** DynamicTranslationValue 动态资源单语言翻译编辑状态。 */
5
+ export interface DynamicTranslationValue {
6
+ /** 语言代码。 */
7
+ locale: string;
8
+ text: string;
9
+ translation_status: TranslationStatus;
10
+ source_changed: boolean;
11
+ source_hash: string;
12
+ translation_provider: string;
13
+ translated_at: string;
14
+ id: number;
15
+ reviewed_by: number;
16
+ reviewed_at: string;
17
+ created_by: number;
18
+ updated_by: number;
19
+ created_at: string;
20
+ updated_at: string;
21
+ deleted_at: number;
22
+ }
23
+
24
+ /** DynamicTranslationRecord 描述三类动态资源翻译共有字段。 */
25
+ export interface DynamicTranslationRecord extends Omit<DynamicTranslationValue, "text"> {
26
+ title?: string;
27
+ name?: string;
28
+ label?: string;
29
+ }
30
+
31
+ /** DynamicLanguageOption 动态翻译编辑器显示的语言选项。 */
32
+ export interface DynamicLanguageOption {
33
+ /** 语言代码。 */
34
+ value: string;
35
+ /** 语言显示名称。 */
36
+ label: string;
37
+ }
38
+
39
+ /** 返回语言管理中启用且非主语言的翻译语言选项。 */
40
+ export function getEditableLanguageOptions(): DynamicLanguageOption[] {
41
+ return getEnabledBaseLanguages()
42
+ .filter(item => !item.is_primary)
43
+ .map(item => ({ value: item.language_code, label: item.native_name || item.language_name || item.language_code }));
44
+ }
45
+
46
+ /** 返回语言管理中的语言显示名称。 */
47
+ export function getLanguageLabel(locale: string): string {
48
+ const language = getEnabledBaseLanguages().find(item => item.language_code === locale);
49
+ return language?.native_name || language?.language_name || locale;
50
+ }
51
+
52
+ /** normalizeDynamicTranslations 将后端翻译记录补齐为全部非主语言编辑状态。 */
53
+ export function normalizeDynamicTranslations(
54
+ records: DynamicTranslationRecord[] | undefined,
55
+ textField: "title" | "name" | "label",
56
+ locales: string[] = getEditableLanguageOptions().map(item => item.value)
57
+ ): DynamicTranslationValue[] {
58
+ return locales.map(locale => {
59
+ const record = records?.find(item => item.locale === locale);
60
+ return {
61
+ id: record?.id ?? 0,
62
+ locale,
63
+ text: String(record?.[textField] ?? ""),
64
+ translation_status: record?.translation_status ?? TranslationStatus.TRANSLATION_STATUS_PENDING,
65
+ source_changed: record?.source_changed ?? false,
66
+ source_hash: record?.source_hash ?? "",
67
+ translation_provider: record?.translation_provider ?? "",
68
+ translated_at: record?.translated_at ?? "",
69
+ reviewed_by: record?.reviewed_by ?? 0,
70
+ reviewed_at: record?.reviewed_at ?? "",
71
+ created_by: record?.created_by ?? 0,
72
+ updated_by: record?.updated_by ?? 0,
73
+ created_at: record?.created_at ?? "",
74
+ updated_at: record?.updated_at ?? "",
75
+ deleted_at: record?.deleted_at ?? 0
76
+ };
77
+ });
78
+ }
79
+
80
+ /** serializeDynamicTranslations 将编辑状态转换回后端资源翻译结构。 */
81
+ export function serializeDynamicTranslations(
82
+ values: DynamicTranslationValue[],
83
+ textField: "title" | "name" | "label"
84
+ ): Array<{ locale: string; [key: string]: string }> {
85
+ return values.map(({ locale, text }) => ({ locale, [textField]: text }));
86
+ }
@@ -0,0 +1,28 @@
1
+ # 管理端 System 语言包
2
+
3
+ 本目录提供 System 管理业务模块的页面、AI、个人中心、基础资料和代码生成等业务文案。语言包由同级 `../module.ts` 导入,随 `systemAdminModule` 注册;管理端启动时由 core 的 `registerLocaleMessages` 合并,System 页面和组件通过 `t()` 或 `useLocaleStore()` 使用 `system.*` 键。
4
+
5
+ | 文件 | 用途 | 使用位置 |
6
+ | --- | --- | --- |
7
+ | `zh-CN.json` | System 模块简体中文固定 UI 默认语言包,也是七语键集合和占位符校验基准。 | 管理端固定文案默认语言及缺失翻译回退。 |
8
+ | `zh-TW.json` | System 模块繁体中文语言包。 | 管理端切换为繁体中文时由 Vue I18n 使用。 |
9
+ | `en-US.json` | System 模块英文语言包。 | 管理端切换为英文时由 Vue I18n 使用。 |
10
+ | `ja-JP.json` | System 模块日文语言包。 | 管理端切换为日文时由 Vue I18n 使用。 |
11
+ | `ko-KR.json` | System 模块韩语语言包。 | 管理端切换为韩语时由 Vue I18n 使用。 |
12
+ | `fr-FR.json` | System 模块法语语言包。 | 管理端切换为法语时由 Vue I18n 使用。 |
13
+ | `es-ES.json` | System 模块西班牙语语言包。 | 管理端切换为西班牙语时由 Vue I18n 使用。 |
14
+
15
+ ## 命名空间与使用位置
16
+
17
+ | 命名空间 | 文案范围 | 主要使用位置 |
18
+ | --- | --- | --- |
19
+ | `system.common.*` | System 页面共用的操作、字段、弹窗、状态和校验文案。 | `src/views/**` 下的列表页、表单和确认弹窗。 |
20
+ | `system.ai.*` | AI 会话、消息流、重试和错误提示。 | `src/views/ai/**`、`src/api/base/ai_message.ts`。 |
21
+ | `system.profile.*` | 个人资料、安全设置和用户中心导航。 | `src/views/profile/**`、`src/module.ts` 的用户菜单。 |
22
+ | `system.base.*` | 区域、配置、部门、字典、岗位、角色、租户、用户等基础管理页面。 | `src/views/base/**`。 |
23
+ | `system.codegen.*` | 代码生成配置、预览、列配置和多语言编辑。 | `src/views/tool/code-gen/**`。 |
24
+ | `system.translation.*` | 动态翻译编辑、草稿生成和语言包状态。 | `src/components/DynamicTranslationEditor.vue`、代码生成语言编辑组件。 |
25
+
26
+ 语言包由 `module.ts` 传入 `systemAdminModule.messages`,由 core 的 `registerLocaleMessages` 校验七语键集合、命名空间和占位符后注册到 Vue I18n;业务代码统一使用 `t('system....')` 或 `useLocaleStore()` 读取。
27
+
28
+ 语言键必须使用 `system.` 命名空间;语言包保持标准 JSON,不在文件内写注释。