@liujitcn/kratos-admin-core 0.0.21 → 0.0.24

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 (85) hide show
  1. package/dist/package/declarations/src/api/base/language.d.ts +3 -3
  2. package/dist/package/declarations/src/components/Dict/index.vue.d.ts +4 -3
  3. package/dist/package/declarations/src/components/Dict/value.d.ts +11 -0
  4. package/dist/package/declarations/src/locales/generated.d.ts +3382 -0
  5. package/dist/package/declarations/src/locales/index.d.ts +11 -21
  6. package/dist/package/declarations/src/rpc/base/v1/config.d.ts +11 -1
  7. package/dist/package/declarations/src/rpc/base/v1/language.d.ts +7 -13
  8. package/dist/package/declarations/src/rpc/base/v1/login.d.ts +13 -1
  9. package/dist/package/declarations/src/rpc/system/admin/v1/auth.d.ts +1 -1
  10. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +7 -77
  11. package/dist/package/declarations/src/rpc/system/admin/v1/base_translation.d.ts +54 -81
  12. package/dist/package/declarations/src/rpc/system/admin/v1/common.d.ts +13 -0
  13. package/dist/package/declarations/src/stores/modules/auth.d.ts +6 -6
  14. package/dist/package/declarations/src/utils/passwordCrypto.d.ts +1 -1
  15. package/dist/package/src/App.vue +2 -8
  16. package/dist/package/src/api/base/language.ts +4 -4
  17. package/dist/package/src/bootstrap.ts +1 -1
  18. package/dist/package/src/components/CronExpression/index.vue +19 -19
  19. package/dist/package/src/components/Dialog/FormDialog.vue +1 -1
  20. package/dist/package/src/components/Dict/index.vue +21 -7
  21. package/dist/package/src/components/Dict/value.ts +18 -0
  22. package/dist/package/src/components/ImportExcel/index.vue +10 -10
  23. package/dist/package/src/components/LocaleSwitch/index.vue +1 -1
  24. package/dist/package/src/components/ProForm/components/DynamicList.vue +1 -1
  25. package/dist/package/src/components/ProForm/components/KvList.vue +2 -2
  26. package/dist/package/src/components/ProForm/index.vue +2 -2
  27. package/dist/package/src/components/ProTable/components/ColSetting.vue +3 -3
  28. package/dist/package/src/components/ProTable/components/TableColumn.vue +1 -1
  29. package/dist/package/src/components/ProTable/index.vue +4 -4
  30. package/dist/package/src/components/SearchForm/components/SearchFormItem.vue +2 -2
  31. package/dist/package/src/components/SelectFilter/index.vue +1 -1
  32. package/dist/package/src/components/TreeFilter/index.vue +4 -4
  33. package/dist/package/src/components/Upload/File.vue +6 -6
  34. package/dist/package/src/components/Upload/Files.vue +7 -7
  35. package/dist/package/src/components/Upload/Img.vue +4 -4
  36. package/dist/package/src/components/Upload/Imgs.vue +5 -5
  37. package/dist/package/src/components/WangEditor/index.vue +1 -1
  38. package/dist/package/src/hooks/useDownload.ts +1 -1
  39. package/dist/package/src/hooks/useHandleData.ts +2 -2
  40. package/dist/package/src/hooks/useTheme.ts +1 -1
  41. package/dist/package/src/layouts/components/Header/components/AssemblySize.vue +1 -1
  42. package/dist/package/src/layouts/components/Header/components/Avatar.vue +5 -5
  43. package/dist/package/src/layouts/components/Header/components/Breadcrumb.vue +2 -2
  44. package/dist/package/src/layouts/components/Header/components/Fullscreen.vue +2 -2
  45. package/dist/package/src/layouts/components/Header/components/PasswordDialog.vue +1 -1
  46. package/dist/package/src/layouts/components/Header/components/SearchMenu.vue +3 -3
  47. package/dist/package/src/layouts/components/Main/index.vue +1 -0
  48. package/dist/package/src/layouts/components/Tabs/components/MoreButton.vue +5 -5
  49. package/dist/package/src/layouts/components/Tabs/index.vue +15 -1
  50. package/dist/package/src/layouts/components/ThemeDrawer/index.vue +7 -7
  51. package/dist/package/src/locales/README.md +2 -2
  52. package/dist/package/src/locales/en-US.json +142 -117
  53. package/dist/package/src/locales/es-ES.json +226 -201
  54. package/dist/package/src/locales/fr-FR.json +226 -201
  55. package/dist/package/src/locales/generated.ts +57 -0
  56. package/dist/package/src/locales/index.ts +54 -55
  57. package/dist/package/src/locales/ja-JP.json +177 -152
  58. package/dist/package/src/locales/ko-KR.json +221 -196
  59. package/dist/package/src/locales/zh-CN.json +142 -117
  60. package/dist/package/src/locales/zh-TW.json +147 -122
  61. package/dist/package/src/modules/kratosAdmin.ts +3 -17
  62. package/dist/package/src/routers/modules/dynamicRouter.ts +4 -4
  63. package/dist/package/src/routers/modules/staticRouter.ts +2 -2
  64. package/dist/package/src/rpc/base/v1/config.ts +12 -1
  65. package/dist/package/src/rpc/base/v1/language.ts +7 -13
  66. package/dist/package/src/rpc/base/v1/login.ts +14 -1
  67. package/dist/package/src/rpc/system/admin/v1/auth.ts +1 -1
  68. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +7 -79
  69. package/dist/package/src/rpc/system/admin/v1/base_translation.ts +54 -81
  70. package/dist/package/src/rpc/system/admin/v1/common.ts +21 -0
  71. package/dist/package/src/stores/modules/config.ts +2 -2
  72. package/dist/package/src/stores/modules/user.ts +1 -1
  73. package/dist/package/src/styles/element.scss +2 -0
  74. package/dist/package/src/utils/color.ts +4 -4
  75. package/dist/package/src/utils/eleValidate.ts +2 -2
  76. package/dist/package/src/utils/index.ts +3 -3
  77. package/dist/package/src/utils/passwordCrypto.ts +2 -2
  78. package/dist/package/src/utils/request.ts +6 -6
  79. package/dist/package/src/views/login/components/LoginForm.vue +15 -12
  80. package/package.json +2 -2
  81. package/vite.config.ts +12 -8
  82. package/dist/package/declarations/src/rpc/base/v1/enum.d.ts +0 -43
  83. package/dist/package/declarations/src/rpc/system/common/v1/enum.d.ts +0 -67
  84. package/dist/package/src/rpc/base/v1/enum.ts +0 -54
  85. package/dist/package/src/rpc/system/common/v1/enum.ts +0 -80
@@ -111,14 +111,14 @@ const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
111
111
  if (!imgType)
112
112
  ElNotification({
113
113
  title: t("common.title.warning"),
114
- message: t("core.upload.imageFormatInvalid"),
114
+ message: t("core.upload.image_format_invalid"),
115
115
  type: "warning"
116
116
  });
117
117
  if (!imgSize)
118
118
  setTimeout(() => {
119
119
  ElNotification({
120
120
  title: t("common.title.warning"),
121
- message: t("core.upload.imageSizeExceeded", { size: props.fileSize }),
121
+ message: t("core.upload.image_size_exceeded", { size: props.fileSize }),
122
122
  type: "warning"
123
123
  });
124
124
  }, 0);
@@ -157,7 +157,7 @@ const uploadSuccess = (response: FileInfo | undefined, uploadFile: UploadFile) =
157
157
  formItemContext?.prop && formContext?.validateField([formItemContext.prop as string]);
158
158
  ElNotification({
159
159
  title: t("common.title.notice"),
160
- message: t("core.upload.imageSuccess"),
160
+ message: t("core.upload.image_success"),
161
161
  type: "success"
162
162
  });
163
163
  };
@@ -177,7 +177,7 @@ const handleRemove = (file: UploadFile) => {
177
177
  const uploadError = () => {
178
178
  ElNotification({
179
179
  title: t("common.title.warning"),
180
- message: t("core.upload.imageFailed"),
180
+ message: t("core.upload.image_failed"),
181
181
  type: "error"
182
182
  });
183
183
  };
@@ -188,7 +188,7 @@ const uploadError = () => {
188
188
  const handleExceed = () => {
189
189
  ElNotification({
190
190
  title: t("common.title.warning"),
191
- message: t("core.upload.imageLimitExceeded", { limit: props.limit }),
191
+ message: t("core.upload.image_limit_exceeded", { limit: props.limit }),
192
192
  type: "warning"
193
193
  });
194
194
  };
@@ -61,7 +61,7 @@ const props = withDefaults(defineProps<RichEditorProps>(), {
61
61
  const editorMenuConfig = props.editorConfig.MENU_CONF ?? {};
62
62
  const resolvedEditorConfig = computed(() => ({
63
63
  ...props.editorConfig,
64
- placeholder: props.editorConfig.placeholder || t("common.placeholder.inputContent"),
64
+ placeholder: props.editorConfig.placeholder || t("common.placeholder.input_content"),
65
65
  MENU_CONF: editorMenuConfig
66
66
  }));
67
67
 
@@ -19,7 +19,7 @@ export const useDownload = async (
19
19
  if (isNotify) {
20
20
  ElNotification({
21
21
  title: t("common.title.notice"),
22
- message: t("core.download.largeFileNotice"),
22
+ message: t("core.download.large_file_notice"),
23
23
  type: "info",
24
24
  duration: 3000
25
25
  });
@@ -17,7 +17,7 @@ export const useHandleData = (
17
17
  confirmType: HandleData.MessageType = "warning"
18
18
  ) => {
19
19
  return new Promise((resolve, reject) => {
20
- ElMessageBox.confirm(t("core.data.confirmAction", { action: message }), t("common.title.warning"), {
20
+ ElMessageBox.confirm(t("core.data.confirm_action", { action: message }), t("common.title.warning"), {
21
21
  confirmButtonText: t("common.action.confirm"),
22
22
  cancelButtonText: t("common.action.cancel"),
23
23
  type: confirmType,
@@ -28,7 +28,7 @@ export const useHandleData = (
28
28
  if (!res) return reject(false);
29
29
  ElMessage({
30
30
  type: "success",
31
- message: t("core.data.operationSuccess", { action: message })
31
+ message: t("core.data.operation_success", { action: message })
32
32
  });
33
33
  resolve(true);
34
34
  })
@@ -30,7 +30,7 @@ export const useTheme = () => {
30
30
  const changePrimary = (val: string | null) => {
31
31
  if (!val) {
32
32
  val = DEFAULT_PRIMARY;
33
- ElMessage({ type: "success", message: t("core.theme.primaryReset", { color: DEFAULT_PRIMARY }) });
33
+ ElMessage({ type: "success", message: t("core.theme.primary_reset", { color: DEFAULT_PRIMARY }) });
34
34
  }
35
35
  // 计算主题颜色变化
36
36
  document.documentElement.style.setProperty("--el-color-primary", val);
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <el-tooltip effect="dark" :content="t('core.header.sizeSelect')" placement="bottom" :show-after="200">
2
+ <el-tooltip effect="dark" :content="t('core.header.size_select')" placement="bottom" :show-after="200">
3
3
  <el-dropdown trigger="click" @command="setAssemblySize">
4
4
  <i :class="'iconfont icon-contentright'" class="toolBar-icon"></i>
5
5
  <template #dropdown>
@@ -55,9 +55,9 @@ const userMenuActions = getAdminUserMenuActions();
55
55
  const dropdownRef = ref<DropdownInstance>();
56
56
  const { t } = useLocaleStore();
57
57
  const avatarSrc = ref(defaultAvatar);
58
- const displayName = computed(() => userStore.userInfo.nick_name || userStore.userInfo.user_name || t("core.layout.notSet"));
59
- const roleName = computed(() => userStore.userInfo.role_name || t("core.layout.roleUnassigned"));
60
- const deptName = computed(() => userStore.userInfo.dept_name || t("core.layout.departmentUnassigned"));
58
+ const displayName = computed(() => userStore.userInfo.nick_name || userStore.userInfo.user_name || t("core.layout.not_set"));
59
+ const roleName = computed(() => userStore.userInfo.role_name || t("core.layout.role_unassigned"));
60
+ const deptName = computed(() => userStore.userInfo.dept_name || t("core.layout.department_unassigned"));
61
61
  const profileSummary = computed(() => `${roleName.value} / ${deptName.value}`);
62
62
  const availableUserMenuActions = computed(() => {
63
63
  return userMenuActions.flatMap(action => {
@@ -86,7 +86,7 @@ watch(
86
86
 
87
87
  /** 退出登录并清理当前登录态。 */
88
88
  const logout = () => {
89
- ElMessageBox.confirm(t("core.layout.logoutConfirm"), t("common.title.warning"), {
89
+ ElMessageBox.confirm(t("core.layout.logout_confirm"), t("common.title.warning"), {
90
90
  confirmButtonText: t("common.action.confirm"),
91
91
  cancelButtonText: t("common.action.cancel"),
92
92
  type: "warning"
@@ -96,7 +96,7 @@ const logout = () => {
96
96
 
97
97
  // 2.重定向到登录页
98
98
  router.replace(LOGIN_URL);
99
- ElMessage.success(t("core.layout.logoutSuccess"));
99
+ ElMessage.success(t("core.layout.logout_success"));
100
100
  });
101
101
  };
102
102
 
@@ -27,7 +27,7 @@ import { ArrowRight } from "@element-plus/icons-vue";
27
27
  import { useAuthStore } from "../../../../stores/modules/auth";
28
28
  import { useGlobalStore } from "../../../../stores/modules/global";
29
29
  import type { RouteItem } from "../../../../rpc/system/admin/v1/auth";
30
- import { BaseMenuType } from "../../../../rpc/system/common/v1/enum";
30
+ import { BaseMenuType } from "../../../../rpc/system/admin/v1/common";
31
31
  import { getRouteMetaIcon, getRouteMetaTitle, getRouteTarget, isExternalPath } from "../../../../utils";
32
32
  import { useLocaleStore } from "../../../../locales";
33
33
 
@@ -45,7 +45,7 @@ const breadcrumbList = computed(() => {
45
45
  {
46
46
  path: HOME_URL,
47
47
  name: "home",
48
- type: BaseMenuType.MENU,
48
+ type: BaseMenuType.BASE_MENU_TYPE_MENU,
49
49
  meta: { icon: "HomeFilled", title: t("core.layout.home"), params: [] },
50
50
  children: []
51
51
  },
@@ -14,7 +14,7 @@ import { useLocaleStore } from "../../../../locales";
14
14
 
15
15
  const isFullscreen = ref(screenfull.isFullscreen);
16
16
  const { t } = useLocaleStore();
17
- const fullscreenTooltip = computed(() => (isFullscreen.value ? t("core.header.fullscreenExit") : t("core.header.fullscreen")));
17
+ const fullscreenTooltip = computed(() => (isFullscreen.value ? t("core.header.fullscreen_exit") : t("core.header.fullscreen")));
18
18
 
19
19
  onMounted(() => {
20
20
  screenfull.on("change", () => {
@@ -24,7 +24,7 @@ onMounted(() => {
24
24
  });
25
25
 
26
26
  const handleFullScreen = () => {
27
- if (!screenfull.isEnabled) ElMessage.warning(t("core.header.fullscreenUnsupported"));
27
+ if (!screenfull.isEnabled) ElMessage.warning(t("core.header.fullscreen_unsupported"));
28
28
  screenfull.toggle();
29
29
  };
30
30
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <el-dialog v-model="dialogVisible" :title="t('core.layout.passwordChange')" width="500px" draggable>
2
+ <el-dialog v-model="dialogVisible" :title="t('core.layout.password_change')" width="500px" draggable>
3
3
  <span>This is Password</span>
4
4
  <template #footer>
5
5
  <span class="dialog-footer">
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <div class="search-menu">
3
- <el-tooltip effect="dark" :content="t('core.header.menuSearch')" placement="bottom" :show-after="200">
3
+ <el-tooltip effect="dark" :content="t('core.header.menu_search')" placement="bottom" :show-after="200">
4
4
  <i :class="'iconfont icon-sousuo'" class="toolBar-icon" @click="handleOpen"></i>
5
5
  </el-tooltip>
6
6
  <el-dialog class="search-dialog" v-model="isShowSearch" :width="600" :show-close="false" top="10vh">
7
7
  <el-input
8
8
  v-model="searchMenu"
9
9
  ref="menuInputRef"
10
- :placeholder="t('core.header.menuSearchPlaceholder')"
10
+ :placeholder="t('core.header.menu_search_placeholder')"
11
11
  size="large"
12
12
  clearable
13
13
  :prefix-icon="Search"
@@ -29,7 +29,7 @@
29
29
  <i :class="'iconfont icon-huiche'" class="menu-enter" @click="handleOpen"></i>
30
30
  </div>
31
31
  </div>
32
- <el-empty v-else class="mt20 mb20" :image-size="100" :description="t('core.header.menuSearchEmpty')" />
32
+ <el-empty v-else class="mt20 mb20" :image-size="100" :description="t('core.header.menu_search_empty')" />
33
33
  </el-dialog>
34
34
  </div>
35
35
  </template>
@@ -79,6 +79,7 @@ const listeningWindow = useDebounceFn(() => {
79
79
  if (!isCollapse.value && screenWidth.value < 1200) globalStore.setGlobalState("isCollapse", true);
80
80
  if (isCollapse.value && screenWidth.value > 1200) globalStore.setGlobalState("isCollapse", false);
81
81
  }, 100);
82
+ listeningWindow();
82
83
  window.addEventListener("resize", listeningWindow, false);
83
84
  onBeforeUnmount(() => {
84
85
  window.removeEventListener("resize", listeningWindow);
@@ -12,19 +12,19 @@
12
12
  <el-icon><FullScreen /></el-icon>{{ t("core.tabs.maximize") }}
13
13
  </el-dropdown-item>
14
14
  <el-dropdown-item divided @click="closeCurrentTab">
15
- <el-icon><Remove /></el-icon>{{ t("core.tabs.closeCurrent") }}
15
+ <el-icon><Remove /></el-icon>{{ t("core.tabs.close_current") }}
16
16
  </el-dropdown-item>
17
17
  <el-dropdown-item @click="tabStore.closeTabsOnSide(currentTabPath, 'left')">
18
- <el-icon><DArrowLeft /></el-icon>{{ t("core.tabs.closeLeft") }}
18
+ <el-icon><DArrowLeft /></el-icon>{{ t("core.tabs.close_left") }}
19
19
  </el-dropdown-item>
20
20
  <el-dropdown-item @click="tabStore.closeTabsOnSide(currentTabPath, 'right')">
21
- <el-icon><DArrowRight /></el-icon>{{ t("core.tabs.closeRight") }}
21
+ <el-icon><DArrowRight /></el-icon>{{ t("core.tabs.close_right") }}
22
22
  </el-dropdown-item>
23
23
  <el-dropdown-item divided @click="tabStore.closeMultipleTab(currentTabPath)">
24
- <el-icon><CircleClose /></el-icon>{{ t("core.tabs.closeOther") }}
24
+ <el-icon><CircleClose /></el-icon>{{ t("core.tabs.close_other") }}
25
25
  </el-dropdown-item>
26
26
  <el-dropdown-item @click="closeAllTab">
27
- <el-icon><FolderDelete /></el-icon>{{ t("core.tabs.closeAll") }}
27
+ <el-icon><FolderDelete /></el-icon>{{ t("core.tabs.close_all") }}
28
28
  </el-dropdown-item>
29
29
  </el-dropdown-menu>
30
30
  </template>
@@ -27,17 +27,25 @@ import { TabsPaneContext, TabPaneName } from "element-plus";
27
27
  import { getRouteMetaAffix, getRouteMetaFull, getRouteMetaIcon, getRouteMetaKeepAlive, getRouteMetaTitle } from "../../../utils";
28
28
  import MoreButton from "./components/MoreButton.vue";
29
29
  import { getAdminTabPath } from "../../../modules";
30
+ import { useLocaleStore } from "../../../locales";
30
31
 
31
32
  const route = useRoute();
32
33
  const router = useRouter();
33
34
  const tabStore = useTabsStore();
34
35
  const authStore = useAuthStore();
35
36
  const globalStore = useGlobalStore();
37
+ const { locale, t } = useLocaleStore();
36
38
 
37
39
  const tabsMenuValue = ref(getAdminTabPath(route));
38
40
  const tabsMenuList = computed(() => tabStore.tabsMenuList);
39
41
  const tabsIcon = computed(() => globalStore.tabsIcon);
40
42
 
43
+ /** 获取当前路由标签标题,兼容静态路由的多语言标题键。 */
44
+ const getCurrentRouteTitle = () => {
45
+ const titleKey = typeof route.meta.titleKey === "string" ? route.meta.titleKey : "";
46
+ return titleKey ? t(titleKey) : String(route.meta.title ?? "");
47
+ };
48
+
41
49
  onMounted(() => {
42
50
  tabsDrop();
43
51
  initTabs();
@@ -52,7 +60,7 @@ watch(
52
60
  tabsMenuValue.value = tabPath;
53
61
  const tabsParams = {
54
62
  icon: route.meta.icon as string,
55
- title: route.meta.title as string,
63
+ title: getCurrentRouteTitle(),
56
64
  path: tabPath,
57
65
  name: route.name as string,
58
66
  close: !route.meta.affix,
@@ -63,6 +71,12 @@ watch(
63
71
  { immediate: true }
64
72
  );
65
73
 
74
+ watch(locale, () => {
75
+ const currentTabPath = getAdminTabPath(route);
76
+ const currentTab = tabStore.tabsMenuList.find(item => item.path === currentTabPath);
77
+ if (currentTab && route.meta.titleKey) currentTab.title = getCurrentRouteTitle();
78
+ });
79
+
66
80
  // 初始化固定标签
67
81
  const initTabs = () => {
68
82
  authStore.flatMenuListGet.forEach(item => {
@@ -52,8 +52,8 @@
52
52
  </div>
53
53
  <div class="theme-item">
54
54
  <span>
55
- {{ t("core.theme.asideInverted") }}
56
- <el-tooltip effect="dark" :content="t('core.theme.asideInvertedTip')" placement="top">
55
+ {{ t("core.theme.aside_inverted") }}
56
+ <el-tooltip effect="dark" :content="t('core.theme.aside_inverted_tip')" placement="top">
57
57
  <el-icon><QuestionFilled /></el-icon>
58
58
  </el-tooltip>
59
59
  </span>
@@ -61,8 +61,8 @@
61
61
  </div>
62
62
  <div class="theme-item mb50">
63
63
  <span>
64
- {{ t("core.theme.headerInverted") }}
65
- <el-tooltip effect="dark" :content="t('core.theme.headerInvertedTip')" placement="top">
64
+ {{ t("core.theme.header_inverted") }}
65
+ <el-tooltip effect="dark" :content="t('core.theme.header_inverted_tip')" placement="top">
66
66
  <el-icon><QuestionFilled /></el-icon>
67
67
  </el-tooltip>
68
68
  </span>
@@ -97,7 +97,7 @@
97
97
  {{ t("core.theme.interface") }}
98
98
  </el-divider>
99
99
  <div class="theme-item">
100
- <span>{{ t("core.theme.menuCollapse") }}</span>
100
+ <span>{{ t("core.theme.menu_collapse") }}</span>
101
101
  <el-switch v-model="isCollapse" />
102
102
  </div>
103
103
  <div class="theme-item">
@@ -113,7 +113,7 @@
113
113
  <el-switch v-model="breadcrumb" />
114
114
  </div>
115
115
  <div class="theme-item">
116
- <span>{{ t("core.theme.breadcrumbIcon") }}</span>
116
+ <span>{{ t("core.theme.breadcrumb_icon") }}</span>
117
117
  <el-switch v-model="breadcrumbIcon" />
118
118
  </div>
119
119
  <div class="theme-item">
@@ -121,7 +121,7 @@
121
121
  <el-switch v-model="tabs" />
122
122
  </div>
123
123
  <div class="theme-item">
124
- <span>{{ t("core.theme.tabsIcon") }}</span>
124
+ <span>{{ t("core.theme.tabs_icon") }}</span>
125
125
  <el-switch v-model="tabsIcon" />
126
126
  </div>
127
127
  <div class="theme-item">
@@ -4,7 +4,7 @@
4
4
 
5
5
  | 文件 | 用途 | 使用位置 |
6
6
  | --- | --- | --- |
7
- | `zh-CN.json` | 简体中文固定 UI 默认语言包,也是七语键集合和占位符校验基准。 | 管理端固定文案默认语言及缺失翻译回退。 |
7
+ | `zh-CN.json` | 简体中文固定 UI 默认语言包,也是所有语言键集合和占位符校验基准。 | 管理端固定文案默认语言及缺失翻译回退。 |
8
8
  | `zh-TW.json` | 繁体中文公共语言包。 | 管理端切换为繁体中文时由 Vue I18n 使用。 |
9
9
  | `en-US.json` | 英文公共语言包。 | 管理端切换为英文时由 Vue I18n 使用。 |
10
10
  | `ja-JP.json` | 日文公共语言包。 | 管理端切换为日文时由 Vue I18n 使用。 |
@@ -12,4 +12,4 @@
12
12
  | `fr-FR.json` | 法语公共语言包。 | 管理端切换为法语时由 Vue I18n 使用。 |
13
13
  | `es-ES.json` | 西班牙语公共语言包。 | 管理端切换为西班牙语时由 Vue I18n 使用。 |
14
14
 
15
- 语言包是标准 JSON,不能在文件内直接写注释;新增或修改键时七种语言必须同步更新。
15
+ 语言包是标准 JSON,不能在文件内直接写注释;新增语言或修改键后执行仓库根目录的 `make i18n-sync`,脚本会校验所有语言并生成注册产物。语言切换选项固定显示后端 `base_language.native_name`,接口不可用时使用代码内置的原生名称;`common.language.*` 仅用于普通文案和语言迁移初始数据。新增语言的完整文件清单见[国际化语言扩展指南](../../../../../../docs/国际化语言扩展指南.md)。