feat: refine i18n for uc (#4957)

#### What type of PR is this?

/area console
/kind improvement
/milestone 2.11.x

#### What this PR does / why we need it:

完善个人中心相关页面的 i18n。

#### Special notes for your reviewer:

测试各个语言的个人中心相关页面。

#### Does this PR introduce a user-facing change?

```release-note
完善个人中心相关页面的 i18n。
```
pull/4941/head
Ryan Wang 2023-11-30 18:56:10 +08:00 committed by GitHub
parent 5208b5c925
commit 5e76da018d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 2179 additions and 1727 deletions

View File

@ -179,7 +179,7 @@ onMounted(() => {
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<a <a
v-tooltip="'个人中心'" v-tooltip="$t('core.sidebar.operations.profile.tooltip')"
class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100" class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100"
href="/uc" href="/uc"
> >
@ -188,6 +188,7 @@ onMounted(() => {
/> />
</a> </a>
<div <div
v-tooltip="$t('core.sidebar.operations.logout.tooltip')"
class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100" class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100"
@click="handleLogout" @click="handleLogout"
> >

View File

@ -161,7 +161,7 @@ const handleResetForm = () => {
] ]
" "
type="text" type="text"
label="登录之后默认跳转位置" :label="$t('core.role.editing_modal.fields.redirect_on_login')"
></FormKit> ></FormKit>
</FormKit> </FormKit>
</div> </div>

View File

@ -123,7 +123,7 @@ function handleRouteToUC() {
type="primary" type="primary"
@click="handleRouteToUC" @click="handleRouteToUC"
> >
个人中心 {{ $t("core.user.detail.actions.profile.title") }}
</VButton> </VButton>
<VDropdown v-if="currentUserHasPermission(['system:users:manage'])"> <VDropdown v-if="currentUserHasPermission(['system:users:manage'])">
<VButton type="default"> <VButton type="default">

View File

@ -44,7 +44,7 @@ function handleRouteToNotification(notification: Notification) {
<VCard <VCard
:body-class="['h-full', '@container', '!p-0', '!overflow-auto']" :body-class="['h-full', '@container', '!p-0', '!overflow-auto']"
class="h-full" class="h-full"
:title="$t('core.notification.title')" :title="$t('core.dashboard.widgets.presets.notification.title')"
> >
<template #actions> <template #actions>
<div style="padding: 12px 16px"> <div style="padding: 12px 16px">
@ -59,7 +59,7 @@ function handleRouteToNotification(notification: Notification) {
<VLoading v-if="isLoading" /> <VLoading v-if="isLoading" />
<VEmpty <VEmpty
v-else-if="!notifications?.length" v-else-if="!notifications?.length"
:title="$t('core.notification.empty.titles.unread')" :title="$t('core.dashboard.widgets.presets.notification.empty.title')"
> >
<template #actions> <template #actions>
<VButton :loading="isFetching" @click="refetch"> <VButton :loading="isFetching" @click="refetch">

View File

@ -26,7 +26,7 @@ editor:
audio: 音频 audio: 音频
table: 表格 table: 表格
no_results: 没有搜索结果 no_results: 没有搜索结果
placeholder: "输入 / 以选择输入类型" placeholder: 输入 / 以选择输入类型
link: link:
add_link: 添加链接 add_link: 添加链接
edit_link: 修改链接 edit_link: 修改链接

View File

@ -83,7 +83,7 @@ const handleUploadAvatar = () => {
handleCloseCropperModal(); handleCloseCropperModal();
}) })
.catch(() => { .catch(() => {
Toast.error(t("core.user.detail.avatar.toast_upload_failed")); Toast.error(t("core.components.user_avatar.toast_upload_failed"));
}) })
.finally(() => { .finally(() => {
uploadSaving.value = false; uploadSaving.value = false;
@ -93,7 +93,7 @@ const handleUploadAvatar = () => {
const handleRemoveCurrentAvatar = () => { const handleRemoveCurrentAvatar = () => {
Dialog.warning({ Dialog.warning({
title: t("core.user.detail.avatar.remove.title"), title: t("core.components.user_avatar.remove.title"),
description: t("core.common.dialog.descriptions.cannot_be_recovered"), description: t("core.common.dialog.descriptions.cannot_be_recovered"),
confirmType: "danger", confirmType: "danger",
confirmText: t("core.common.buttons.confirm"), confirmText: t("core.common.buttons.confirm"),
@ -111,7 +111,7 @@ const handleRemoveCurrentAvatar = () => {
queryClient.invalidateQueries({ queryKey: ["user-detail"] }); queryClient.invalidateQueries({ queryKey: ["user-detail"] });
}) })
.catch(() => { .catch(() => {
Toast.error(t("core.user.detail.avatar.toast_remove_failed")); Toast.error(t("core.components.user_avatar.toast_remove_failed"));
}); });
}, },
}); });
@ -174,7 +174,7 @@ const hasAvatar = computed(() => {
<VModal <VModal
:visible="visibleCropperModal" :visible="visibleCropperModal"
:width="1200" :width="1200"
:title="$t('core.user.detail.avatar.cropper_modal.title')" :title="$t('core.components.user_avatar.cropper_modal.title')"
mount-to-body mount-to-body
@update:visible="handleCloseCropperModal" @update:visible="handleCloseCropperModal"
> >

View File

@ -64,7 +64,7 @@ const defaultToolbars: ToolbarItem[] = [
onClick: () => { onClick: () => {
emit("changeFile"); emit("changeFile");
}, },
title: t("core.user.detail.avatar.tooltips.upload"), title: t("core.components.user_avatar.tooltips.upload"),
}, },
{ {
name: "zoomIn", name: "zoomIn",
@ -72,7 +72,7 @@ const defaultToolbars: ToolbarItem[] = [
onClick: () => { onClick: () => {
cropper.value?.zoom(0.1); cropper.value?.zoom(0.1);
}, },
title: t("core.user.detail.avatar.tooltips.zoom_in"), title: t("core.components.user_avatar.tooltips.zoom_in"),
}, },
{ {
name: "zoomOut", name: "zoomOut",
@ -80,7 +80,7 @@ const defaultToolbars: ToolbarItem[] = [
onClick: () => { onClick: () => {
cropper.value?.zoom(-0.1); cropper.value?.zoom(-0.1);
}, },
title: t("core.user.detail.avatar.tooltips.zoom_out"), title: t("core.components.user_avatar.tooltips.zoom_out"),
}, },
{ {
name: "flipHorizontal", name: "flipHorizontal",
@ -88,7 +88,7 @@ const defaultToolbars: ToolbarItem[] = [
onClick: () => { onClick: () => {
cropper.value?.scaleX(-cropper.value?.getData().scaleX || -1); cropper.value?.scaleX(-cropper.value?.getData().scaleX || -1);
}, },
title: t("core.user.detail.avatar.tooltips.flip_horizontal"), title: t("core.components.user_avatar.tooltips.flip_horizontal"),
}, },
{ {
name: "flipVertical", name: "flipVertical",
@ -96,7 +96,7 @@ const defaultToolbars: ToolbarItem[] = [
onClick: () => { onClick: () => {
cropper.value?.scaleY(-cropper.value?.getData().scaleY || -1); cropper.value?.scaleY(-cropper.value?.getData().scaleY || -1);
}, },
title: t("core.user.detail.avatar.tooltips.flip_vertical"), title: t("core.components.user_avatar.tooltips.flip_vertical"),
}, },
{ {
name: "reset", name: "reset",
@ -104,7 +104,7 @@ const defaultToolbars: ToolbarItem[] = [
onClick: () => { onClick: () => {
cropper.value?.reset(); cropper.value?.reset();
}, },
title: t("core.user.detail.avatar.tooltips.reset"), title: t("core.components.user_avatar.tooltips.reset"),
}, },
]; ];
const previewElement = ref<HTMLElement>(); const previewElement = ref<HTMLElement>();

View File

@ -42,7 +42,9 @@ core:
title: Account binding title: Account binding
common: common:
toast: toast:
mounted: The current login method is not bound to an account, Please bind or sign up a new account first mounted: >-
The current login method is not bound to an account, Please bind or
sign up a new account first
operations: operations:
login_and_bind: login_and_bind:
button: Login and Bind button: Login and Bind
@ -75,12 +77,21 @@ core:
backup: Backup backup: Backup
operations: operations:
logout: logout:
button: Logout tooltip: Logout
title: Are you sure you want to log out? title: Are you sure you want to log out?
profile: profile:
button: Profile tooltip: Profile
visit_homepage: visit_homepage:
title: Visit homepage title: Visit homepage
uc_sidebar:
menu:
items:
profile: Profile
notification: Notifications
posts: Posts
operations:
console:
tooltip: Console
dashboard: dashboard:
title: Dashboard title: Dashboard
actions: actions:
@ -104,7 +115,11 @@ core:
title: Recent Posts title: Recent Posts
visits: "{visits} Visits" visits: "{visits} Visits"
comments: "{comments} Comments" comments: "{comments} Comments"
publishTime: "Publish Time {publishTime}" publishTime: Publish Time {publishTime}
notification:
title: Notifications
empty:
title: No unread notifications
quicklink: quicklink:
title: Quick Link title: Quick Link
actions: actions:
@ -127,7 +142,9 @@ core:
refresh_search_engine: refresh_search_engine:
title: Refresh Search Engine title: Refresh Search Engine
dialog_title: Do you want to refresh the search engine index? dialog_title: Do you want to refresh the search engine index?
dialog_content: This operation will recreate search engine indexes for all published posts. dialog_content: >-
This operation will recreate search engine indexes for all
published posts.
success_message: Refresh search engine index successfully. success_message: Refresh search engine index successfully.
evict_page_cache: evict_page_cache:
title: Refresh Page Cache title: Refresh Page Cache
@ -152,10 +169,14 @@ core:
operations: operations:
delete: delete:
title: Are you sure you want to delete this post? title: Are you sure you want to delete this post?
description: This operation will move the post to the recycle bin, and it can be restored from the recycle bin later. description: >-
This operation will move the post to the recycle bin, and it can be
restored from the recycle bin later.
delete_in_batch: delete_in_batch:
title: Are you sure you want to delete the selected posts? title: Are you sure you want to delete the selected posts?
description: This operation will move the posts to the recycle bin, and it can be restored from the recycle bin later. description: >-
This operation will move the posts to the recycle bin, and it can be
restored from the recycle bin later.
filters: filters:
status: status:
items: items:
@ -252,7 +273,9 @@ core:
operations: operations:
delete: delete:
title: Are you sure you want to delete this tag? title: Are you sure you want to delete this tag?
description: After deleting this tag, the association with the corresponding article will be removed. This operation cannot be undone. description: >-
After deleting this tag, the association with the corresponding
article will be removed. This operation cannot be undone.
editing_modal: editing_modal:
titles: titles:
update: Update post tag update: Update post tag
@ -283,7 +306,9 @@ core:
operations: operations:
delete: delete:
title: Are you sure you want to delete this category? title: Are you sure you want to delete this category?
description: After deleting this category, the association with corresponding articles will be removed. This operation cannot be undone. description: >-
After deleting this category, the association with corresponding
articles will be removed. This operation cannot be undone.
add_sub_category: add_sub_category:
button: Add sub category button: Add sub category
editing_modal: editing_modal:
@ -320,10 +345,14 @@ core:
operations: operations:
delete: delete:
title: Are you sure you want to delete this page? title: Are you sure you want to delete this page?
description: This operation will move the page to the recycle bin, and it can be restored from the recycle bin later. description: >-
This operation will move the page to the recycle bin, and it can be
restored from the recycle bin later.
delete_in_batch: delete_in_batch:
title: Are you sure you want to delete the selected pages? title: Are you sure you want to delete the selected pages?
description: This operation will move the pages to the recycle bin, and it can be restored from the recycle bin later. description: >-
This operation will move the pages to the recycle bin, and it can be
restored from the recycle bin later.
filters: filters:
status: status:
items: items:
@ -410,16 +439,22 @@ core:
operations: operations:
delete_comment: delete_comment:
title: Are you sure you want to delete this comment? title: Are you sure you want to delete this comment?
description: All replies under the comments will be deleted at the same time, and this operation cannot be undone. description: >-
All replies under the comments will be deleted at the same time, and
this operation cannot be undone.
delete_comment_in_batch: delete_comment_in_batch:
title: Are you sure you want to delete the selected comments? title: Are you sure you want to delete the selected comments?
description: All replies under the comments will be deleted at the same time, and this operation cannot be undone. description: >-
All replies under the comments will be deleted at the same time, and
this operation cannot be undone.
approve_comment_in_batch: approve_comment_in_batch:
button: Approve button: Approve
title: Are you sure you want to approve the selected comments for review? title: Are you sure you want to approve the selected comments for review?
approve_applies_in_batch: approve_applies_in_batch:
button: Approve all replies button: Approve all replies
title: Are you sure you want to approve all replies to this comment for review? title: >-
Are you sure you want to approve all replies to this comment for
review?
delete_reply: delete_reply:
title: Are you sure you want to delete this reply? title: Are you sure you want to delete this reply?
approve_reply: approve_reply:
@ -468,7 +503,9 @@ core:
storage_policies: Storage Policies storage_policies: Storage Policies
empty: empty:
title: There are no attachments in the current group. title: There are no attachments in the current group.
message: The current group has no attachments, you can try refreshing or uploading attachments. message: >-
The current group has no attachments, you can try refreshing or
uploading attachments.
actions: actions:
upload: Upload Attachment upload: Upload Attachment
operations: operations:
@ -484,10 +521,10 @@ core:
filters: filters:
storage_policy: storage_policy:
label: Storage Policy label: Storage Policy
result: "Storage Policy{storage_policy}" result: Storage Policy{storage_policy}
owner: owner:
label: Owner label: Owner
result: "Owner{owner}" result: Owner{owner}
sort: sort:
items: items:
create_time_desc: Latest uploaded create_time_desc: Latest uploaded
@ -531,18 +568,28 @@ core:
delete: delete:
button: And move attachment to ungrouped button: And move attachment to ungrouped
title: Are you sure you want to delete this group? title: Are you sure you want to delete this group?
description: The group will be deleted, and the attachments under the group will be moved to ungrouped. This operation cannot be undone. description: >-
toast_success: Deletion successful, {total} attachments have been moved to ungrouped The group will be deleted, and the attachments under the group will
be moved to ungrouped. This operation cannot be undone.
toast_success: >-
Deletion successful, {total} attachments have been moved to
ungrouped
delete_with_attachments: delete_with_attachments:
button: Also delete attachments button: Also delete attachments
title: Are you sure you want to delete this group? title: Are you sure you want to delete this group?
description: Deleting the group and all attachments within it, this action cannot be undone. description: >-
toast_success: Deletion successful, {total} attachments have been deleted simultaneously Deleting the group and all attachments within it, this action cannot
be undone.
toast_success: >-
Deletion successful, {total} attachments have been deleted
simultaneously
policies_modal: policies_modal:
title: Storage Policies title: Storage Policies
empty: empty:
title: There is currently no available storage strategy. title: There is currently no available storage strategy.
message: There are no available storage policies at the moment. You can try refreshing or creating a new policy. message: >-
There are no available storage policies at the moment. You can try
refreshing or creating a new policy.
operations: operations:
delete: delete:
title: Are you sure you want to delete this policy? title: Are you sure you want to delete this policy?
@ -575,7 +622,7 @@ core:
label: Attachments label: Attachments
operations: operations:
select: select:
result: "({count} items selected)" result: ({count} items selected)
theme: theme:
title: Themes title: Themes
common: common:
@ -587,7 +634,9 @@ core:
management: Themes management: Themes
empty: empty:
title: There are currently no activated or selected themes. title: There are currently no activated or selected themes.
message: There are currently no activated or selected themes, you can switch themes or install new ones. message: >-
There are currently no activated or selected themes, you can switch
themes or install new ones.
actions: actions:
switch: Switch Theme switch: Switch Theme
operations: operations:
@ -596,18 +645,24 @@ core:
toast_success: Active theme successful toast_success: Active theme successful
reset: reset:
title: Are you sure you want to reset all configurations of the theme? title: Are you sure you want to reset all configurations of the theme?
description: This operation will delete the saved configuration and reset it to default settings. description: >-
This operation will delete the saved configuration and reset it to
default settings.
toast_success: Reset configuration successful toast_success: Reset configuration successful
reload: reload:
button: Reload button: Reload
title: Are you sure you want to reload all configurations of the theme? title: Are you sure you want to reload all configurations of the theme?
description: This operation will only reload the theme configuration and settings form definition, and will not delete any saved configurations. description: >-
This operation will only reload the theme configuration and settings
form definition, and will not delete any saved configurations.
toast_success: Reload configuration successful toast_success: Reload configuration successful
uninstall: uninstall:
title: Are you sure you want to uninstall this theme? title: Are you sure you want to uninstall this theme?
uninstall_and_delete_config: uninstall_and_delete_config:
button: Uninstall and delete config button: Uninstall and delete config
title: Are you sure you want to uninstall this theme and its corresponding settings? title: >-
Are you sure you want to uninstall this theme and its corresponding
settings?
remote_download: remote_download:
title: Remote download address detected, do you want to download? title: Remote download address detected, do you want to download?
description: "Please carefully verify whether this address can be trusted: {url}" description: "Please carefully verify whether this address can be trusted: {url}"
@ -625,7 +680,9 @@ core:
url: Remote URL url: Remote URL
empty: empty:
title: There are no installed themes currently. title: There are no installed themes currently.
message: There are currently no installed themes, you can try refreshing or installing a new theme. message: >-
There are currently no installed themes, you can try refreshing or
installing a new theme.
not_installed_empty: not_installed_empty:
title: There are no themes currently not installed. title: There are no themes currently not installed.
preview_model: preview_model:
@ -661,10 +718,14 @@ core:
toast_success: Setting successful toast_success: Setting successful
delete_menu: delete_menu:
title: Are you sure you want to delete this menu? title: Are you sure you want to delete this menu?
description: All menu items under this menu will be deleted at the same time, and this operation cannot be undone. description: >-
All menu items under this menu will be deleted at the same time, and
this operation cannot be undone.
delete_menu_item: delete_menu_item:
title: Are you sure you want to delete this menu item? title: Are you sure you want to delete this menu item?
description: All sub-menu items will be deleted at the same time, and cannot be restored after deletion. description: >-
All sub-menu items will be deleted at the same time, and cannot be
restored after deletion.
add_sub_menu_item: add_sub_menu_item:
button: Add sub menu item button: Add sub menu item
list: list:
@ -691,7 +752,7 @@ core:
placeholder: Select the parent menu item placeholder: Select the parent menu item
ref_kind: ref_kind:
label: Type label: Type
placeholder: "Please select {label}" placeholder: Please select {label}
options: options:
custom: Custom custom: Custom
post: Post post: Post
@ -715,13 +776,17 @@ core:
detail: Detail detail: Detail
empty: empty:
title: There are no installed plugins currently. title: There are no installed plugins currently.
message: There are no installed plugins currently, you can try refreshing or installing new plugins. message: >-
There are no installed plugins currently, you can try refreshing or
installing new plugins.
actions: actions:
install: Install Plugin install: Install Plugin
operations: operations:
reset: reset:
title: Are you sure you want to reset all configurations of the plugin? title: Are you sure you want to reset all configurations of the plugin?
description: This operation will delete the saved configuration and reset it to default settings. description: >-
This operation will delete the saved configuration and reset it to
default settings.
toast_success: Reset configuration successfully toast_success: Reset configuration successfully
uninstall: uninstall:
title: Are you sure you want to uninstall this plugin? title: Are you sure you want to uninstall this plugin?
@ -729,13 +794,19 @@ core:
title: Are you sure you want to uninstall these plugin? title: Are you sure you want to uninstall these plugin?
uninstall_and_delete_config: uninstall_and_delete_config:
button: Uninstall and delete config button: Uninstall and delete config
title: Are you sure you want to uninstall this plugin and its corresponding configuration? title: >-
Are you sure you want to uninstall this plugin and its corresponding
configuration?
uninstall_and_delete_config_in_batch: uninstall_and_delete_config_in_batch:
button: Uninstall and delete config button: Uninstall and delete config
title: Are you sure you want to uninstall these plugin and its corresponding configuration? title: >-
Are you sure you want to uninstall these plugin and its corresponding
configuration?
uninstall_when_enabled: uninstall_when_enabled:
confirm_text: Stop running and uninstall confirm_text: Stop running and uninstall
description: The current plugin is still in the enabled state and will be uninstalled after it stops running. This operation cannot be undone. description: >-
The current plugin is still in the enabled state and will be
uninstalled after it stops running. This operation cannot be undone.
change_status_in_batch: change_status_in_batch:
activate_title: Are you sure you want to activate these plugins? activate_title: Are you sure you want to activate these plugins?
inactivate_title: Are you sure you want to inactivate these plugins? inactivate_title: Are you sure you want to inactivate these plugins?
@ -767,7 +838,9 @@ core:
description: Would you like to activate the currently installed plugin? description: Would you like to activate the currently installed plugin?
existed_during_installation: existed_during_installation:
title: The plugin already exists. title: The plugin already exists.
description: The currently installed plugin already exists, do you want to upgrade? description: >-
The currently installed plugin already exists, do you want to
upgrade?
detail: detail:
title: Plugin detail title: Plugin detail
header: header:
@ -783,8 +856,8 @@ core:
last_starttime: Last Start Time last_starttime: Last Start Time
loader: loader:
toast: toast:
entry_load_failed: "Failed to load plugins entry file" entry_load_failed: Failed to load plugins entry file
style_load_failed: "Failed to load plugins stylesheet file" style_load_failed: Failed to load plugins stylesheet file
extension_points: extension_points:
editor: editor:
providers: providers:
@ -796,7 +869,9 @@ core:
identity_authentication: Identity authentication identity_authentication: Identity authentication
empty: empty:
title: There are no users that meet the filtering criteria currently. title: There are no users that meet the filtering criteria currently.
message: There are no users that match the filtering criteria at present. You can try refreshing or creating a new user. message: >-
There are no users that match the filtering criteria at present. You can
try refreshing or creating a new user.
operations: operations:
delete: delete:
title: Are you sure you want to delete this user? title: Are you sure you want to delete this user?
@ -854,19 +929,13 @@ core:
title: User detail title: User detail
tabs: tabs:
detail: Detail detail: Detail
notification-preferences: Notification Preferences
pat: Personal Access Tokens
actions: actions:
update_profile: update_profile:
title: Update profile title: Update profile
change_password: change_password:
title: Change password title: Change password
operations: profile:
bind: title: Profile
button: Bind
unbind:
button: Unbind
title: "Are you sure you want to unbind the login method for {display_name}?"
fields: fields:
display_name: Display name display_name: Display name
username: Username username: Username
@ -875,21 +944,107 @@ core:
bio: Bio bio: Bio
creation_time: Creation time creation_time: Creation time
identity_authentication: Identity authentication identity_authentication: Identity authentication
avatar: role:
title: Avatar title: Roles
toast_upload_failed: Failed to upload avatar common:
toast_remove_failed: Failed to delete avatar text:
cropper_modal: contains_all_permissions: Contains all permissions
title: Crop Avatar contains_n_permissions: Contains {count} permissions
remove: system_reserved: System Reserved
title: Are you sure you want to delete the avatar? custom: Custom
tooltips: dependent_on: Dependent on {roles}
upload: Upload provided_by_plugin: Provided by {plugin}
zoom_in: Zoom In operations:
zoom_out: Zoom Out delete:
flip_horizontal: Flip Horizontal title: Are you sure you want to delete this role?
flip_vertical: Flip Vertical description: >-
reset: Reset After the role is deleted, the associated users will have their role
bindings removed and this operation cannot be undone.
create_based_on_this_role:
button: Create based on this role
detail:
title: Role detail
header:
title: Role information
tabs:
detail: Detail
permissions: Permissions
fields:
display_name: Display name
name: Name
type: Type
creation_time: Creation time
permissions_detail:
system_reserved_alert:
description: >-
The system reserved role does not support modification, it is
recommended to create a new role based on this one.
editing_modal:
titles:
create: Create role
update: Update role
groups:
general: General
permissions: Permissions
fields:
display_name: Display name
redirect_on_login: Default redirect location after logging in
identity_authentication:
title: Identity Authentication
tabs:
detail: Detail
setting: Settings
operations:
enable:
title: Are you sure you want to enable this identity authentication method?
disable:
title: Are you sure you want to disable this identity authentication method?
disable_privileged:
tooltip: The authentication method reserved by the system cannot be disabled
detail:
title: Identity authentication detail
fields:
display_name: Display name
description: Description
website: Website
help_page: Help page
authentication_url: Login URL
uc_profile:
title: Profile
tabs:
detail: Detail
notification-preferences: Notification Preferences
pat: Personal Access Tokens
actions:
update_profile:
title: Update profile
change_password:
title: Change password
detail:
fields:
display_name: Display name
username: Username
email: Email
roles: Roles
bio: Bio
creation_time: Creation time
identity_authentication: Identity authentication
operations:
bind:
button: Bind
unbind:
button: Unbind
title: Are you sure you want to unbind the login method for {display_name}?
email_not_set:
description: >-
Your email address has not been set yet. Click the button below to set
it up.
title: Set up email
email_not_verified:
description: >-
Your email address has not been verified yet, click the button below
to verify it
title: Verify email
pat: pat:
operations: operations:
delete: delete:
@ -911,7 +1066,7 @@ core:
message: You can try refreshing or creating a new personal access token message: You can try refreshing or creating a new personal access token
fields: fields:
expiresAt: expiresAt:
dynamic: "Expires on {expiresAt}" dynamic: Expires on {expiresAt}
forever: Never expires forever: Never expires
status: status:
normal: Normal normal: Normal
@ -933,67 +1088,54 @@ core:
notification-preferences: notification-preferences:
fields: fields:
type: Type type: Type
role:
title: Roles
common:
text:
contains_all_permissions: Contains all permissions
contains_n_permissions: Contains {count} permissions
system_reserved: System Reserved
custom: Custom
dependent_on: Dependent on {roles}
provided_by_plugin: Provided by {plugin}
operations:
delete:
title: Are you sure you want to delete this role?
description: After the role is deleted, the associated users will have their role bindings removed and this operation cannot be undone.
create_based_on_this_role:
button: Create based on this role
detail:
title: Role detail
header:
title: Role information
tabs:
detail: Detail
permissions: Permissions
fields:
display_name: Display name
name: Name
type: Type
creation_time: Creation time
permissions_detail:
system_reserved_alert:
description: The system reserved role does not support modification, it is recommended to create a new role based on this one.
editing_modal: editing_modal:
titles: title: Edit Profile
create: Create role
update: Update role
groups: groups:
general: General general: General
permissions: Permissions annotations: Annotations
fields: fields:
display_name: Display name username:
identity_authentication: label: Username
title: Identity Authentication validation: Please enter a valid username.
tabs: display_name:
detail: Detail label: Display name
setting: Settings email:
label: Email
phone:
label: Phone
avatar:
label: Avatar
bio:
label: Bio
change_password_modal:
title: Change password
fields:
new_password:
label: New password
confirm_password:
label: Confirm password
email_verify_modal:
fields:
code:
label: Verification code
email:
label: Email address
new_email:
label: New email address
operations: operations:
enable: send_code:
title: Are you sure you want to enable this identity authentication method? buttons:
disable: countdown: Resend in {timer} seconds
title: Are you sure you want to disable this identity authentication method? send: Send the verification code
disable_privileged: sending: sending
tooltip: The authentication method reserved by the system cannot be disabled toast_email_empty: Please enter your email address
detail: toast_success: Verification code sent
title: Identity authentication detail verify:
fields: toast_success: Verification successful
display_name: Display name titles:
description: Description modify: Modify email address
website: Website verify: Verify email
help_page: Help page uc_notification:
authentication_url: Login URL
notification:
title: Notifications title: Notifications
tabs: tabs:
unread: Unread unread: Unread
@ -1005,6 +1147,9 @@ core:
operations: operations:
mark_as_read: mark_as_read:
button: Mark as read button: Mark as read
delete:
description: Are you sure you want to delete this notification?
title: Delete
setting: setting:
title: Settings title: Settings
actuator: actuator:
@ -1039,7 +1184,10 @@ core:
database: "Database: {database}" database: "Database: {database}"
os: "Operating system: {os}" os: "Operating system: {os}"
alert: alert:
external_url_invalid: The external access url detected is inconsistent with the current access url, which may cause some links to fail to redirect properly. Please check the external access url settings. external_url_invalid: >-
The external access url detected is inconsistent with the current access
url, which may cause some links to fail to redirect properly. Please
check the external access url settings.
backup: backup:
title: Backup and Restore title: Backup and Restore
tabs: tabs:
@ -1052,14 +1200,19 @@ core:
create: create:
button: Create backup button: Create backup
title: Create backup title: Create backup
description: Are you sure you want to create a backup? This operation may last for a long time. description: >-
Are you sure you want to create a backup? This operation may last for
a long time.
toast_success: Requested to create a backup toast_success: Requested to create a backup
delete: delete:
title: Delete the backup title: Delete the backup
description: Are you sure you want to delete the backup? description: Are you sure you want to delete the backup?
restore: restore:
title: Restore successfully title: Restore successfully
description: After successful restore, you need to restart Halo to load the system resources normally. After clicking OK, we will automatically restart Halo. description: >-
After successful restore, you need to restart Halo to load the system
resources normally. After clicking OK, we will automatically restart
Halo.
restart: restart:
toast_success: Requested to restart toast_success: Requested to restart
remote_download: remote_download:
@ -1077,9 +1230,15 @@ core:
expiresAt: Expires {expiresAt} expiresAt: Expires {expiresAt}
restore: restore:
tips: tips:
first: 1. The restore process may last for a long time, please do not refresh the page during this period. first: >-
second: 2. During the restore process, although the existing data will not be cleaned up, if there is a conflict, the data will be overwritten. 1. The restore process may last for a long time, please do not refresh
third: 3. After the restore is completed, you need to restart Halo to load the system resources normally. the page during this period.
second: >-
2. During the restore process, although the existing data will not be
cleaned up, if there is a conflict, the data will be overwritten.
third: >-
3. After the restore is completed, you need to restart Halo to load
the system resources normally.
complete: Restore completed, waiting for restart... complete: Restore completed, waiting for restart...
start: Start restore start: Start restore
tabs: tabs:
@ -1202,7 +1361,7 @@ core:
extensions: extensions:
placeholder: placeholder:
options: options:
placeholder: "Enter / to select input type." placeholder: Enter / to select input type.
toolbox: toolbox:
attachment: Attachment attachment: Attachment
show_hide_sidebar: Show/Hide Sidebar show_hide_sidebar: Show/Hide Sidebar
@ -1229,18 +1388,35 @@ core:
social_auth_providers: social_auth_providers:
title: Third-party login title: Third-party login
app_download_alert: app_download_alert:
description: "Themes and plugins for Halo can be downloaded at the following addresses:" description: >-
Themes and plugins for Halo can be downloaded at the following
addresses:
sources: sources:
app_store: "Official App Store: {url}" app_store: "Official App Store: {url}"
github: "GitHub: {url}" github: "GitHub: {url}"
user_avatar:
title: Avatar
toast_upload_failed: Failed to upload avatar
toast_remove_failed: Failed to delete avatar
cropper_modal:
title: Crop Avatar
remove:
title: Are you sure you want to delete the avatar?
tooltips:
upload: Upload
zoom_in: Zoom In
zoom_out: Zoom Out
flip_horizontal: Flip Horizontal
flip_vertical: Flip Vertical
reset: Reset
composables: composables:
content_cache: content_cache:
toast_recovered: Recovered unsaved content from cache toast_recovered: Recovered unsaved content from cache
formkit: formkit:
category_select: category_select:
creation_label: "Create {text} category" creation_label: Create {text} category
tag_select: tag_select:
creation_label: "Create {text} tag" creation_label: Create {text} tag
validation: validation:
trim: Please remove the leading and trailing spaces trim: Please remove the leading and trailing spaces
common: common:
@ -1278,9 +1454,11 @@ core:
detail: Detail detail: Detail
select: Select select: Select
view_all: View all view_all: View all
verify: Verify
modify: Modify
radio: radio:
"yes": Yes "yes": "Yes"
"no": No "no": "No"
select: select:
public: Public public: Public
private: Private private: Private
@ -1302,10 +1480,10 @@ core:
copy_success: Copied successfully copy_success: Copied successfully
operation_failed: Failed to operate operation_failed: Failed to operate
download_failed: Failed to download download_failed: Failed to download
save_failed_and_retry: "Failed to save, please retry" save_failed_and_retry: Failed to save, please retry
publish_failed_and_retry: "Failed to publish, please retry" publish_failed_and_retry: Failed to publish, please retry
network_error: "Network error, please check your connection" network_error: Network error, please check your connection
login_expired: "Login expired, please log in again" login_expired: Login expired, please log in again
forbidden: Access denied forbidden: Access denied
not_found: Resource not found not_found: Resource not found
server_internal_error: Internal server error server_internal_error: Internal server error
@ -1316,7 +1494,9 @@ core:
warning: Warning warning: Warning
descriptions: descriptions:
cannot_be_recovered: This operation is irreversible. cannot_be_recovered: This operation is irreversible.
editor_not_found: No editor found that matches the {raw_type} format. Please check if the editor plugin has been installed. editor_not_found: >-
No editor found that matches the {raw_type} format. Please check if
the editor plugin has been installed.
filters: filters:
results: results:
keyword: "Keyword: {keyword}" keyword: "Keyword: {keyword}"
@ -1346,3 +1526,15 @@ core:
recovering: Recovering recovering: Recovering
fields: fields:
post_count: "{count} Posts" post_count: "{count} Posts"
uc_post:
creation_modal:
title: Create post
operations:
cancel_publish:
description: Are you sure you want to cancel publishing?
title: Cancel publish
publish_modal:
title: Publish post
setting_modal:
title: Post settings
title: My posts

File diff suppressed because it is too large Load Diff

View File

@ -75,12 +75,21 @@ core:
backup: 备份 backup: 备份
operations: operations:
logout: logout:
button: 退出登录 tooltip: 退出登录
title: 确定要退出登录吗? title: 确定要退出登录吗?
profile: profile:
button: 个人资料 tooltip: 个人中心
visit_homepage: visit_homepage:
title: 访问首页 title: 访问首页
uc_sidebar:
menu:
items:
profile: 我的
notification: 消息
posts: 文章
operations:
console:
tooltip: 管理控制台
dashboard: dashboard:
title: 仪表板 title: 仪表板
actions: actions:
@ -102,9 +111,13 @@ core:
title: 页面 title: 页面
recent_published: recent_published:
title: 最近文章 title: 最近文章
visits: "访问量 {visits}" visits: 访问量 {visits}
comments: "评论 {comments}" comments: 评论 {comments}
publishTime: "发布日期 {publishTime}" publishTime: 发布日期 {publishTime}
notification:
title: 通知
empty:
title: 当前没有未读的消息
quicklink: quicklink:
title: 快捷访问 title: 快捷访问
actions: actions:
@ -163,19 +176,19 @@ core:
draft: 未发布 draft: 未发布
visible: visible:
label: 可见性 label: 可见性
result: "可见性:{visible}" result: 可见性:{visible}
items: items:
public: 公开 public: 公开
private: 私有 private: 私有
category: category:
label: 分类 label: 分类
result: "分类:{category}" result: 分类:{category}
tag: tag:
label: 标签 label: 标签
result: "标签:{tag}" result: 标签:{tag}
author: author:
label: 作者 label: 作者
result: "作者:{author}" result: 作者:{author}
sort: sort:
items: items:
publish_time_desc: 较近发布 publish_time_desc: 较近发布
@ -185,8 +198,8 @@ core:
list: list:
fields: fields:
categories: 分类: categories: 分类:
visits: "访问量 {visits}" visits: 访问量 {visits}
comments: "评论 {comments}" comments: 评论 {comments}
pinned: 已置顶 pinned: 已置顶
settings: settings:
title: 文章设置 title: 文章设置
@ -239,6 +252,18 @@ core:
recovery_in_batch: recovery_in_batch:
title: 确定要恢复选中的文章吗? title: 确定要恢复选中的文章吗?
description: 该操作会将文章恢复到被删除之前的状态。 description: 该操作会将文章恢复到被删除之前的状态。
uc_post:
title: 我的文章
setting_modal:
title: 文章设置
creation_modal:
title: 创建文章
publish_modal:
title: 发布文章
operations:
cancel_publish:
title: 取消发布
description: 确定要取消发布吗?
post_editor: post_editor:
title: 文章编辑 title: 文章编辑
untitled: 未命名文章 untitled: 未命名文章
@ -331,13 +356,13 @@ core:
draft: 未发布 draft: 未发布
visible: visible:
label: 可见性 label: 可见性
result: "可见性:{visible}" result: 可见性:{visible}
items: items:
public: 公开 public: 公开
private: 私有 private: 私有
author: author:
label: 作者 label: 作者
result: "作者:{author}" result: 作者:{author}
sort: sort:
items: items:
publish_time_desc: 较近发布 publish_time_desc: 较近发布
@ -346,8 +371,8 @@ core:
create_time_asc: 较早创建 create_time_asc: 较早创建
list: list:
fields: fields:
visits: "访问量 {visits}" visits: 访问量 {visits}
comments: "评论 {comments}" comments: 评论 {comments}
settings: settings:
title: 页面设置 title: 页面设置
groups: groups:
@ -433,7 +458,7 @@ core:
pending_review: 待审核 pending_review: 待审核
owner: owner:
label: 评论者 label: 评论者
result: "评论者:{owner}" result: 评论者:{owner}
sort: sort:
items: items:
last_reply_time_desc: 较近回复 last_reply_time_desc: 较近回复
@ -484,10 +509,10 @@ core:
filters: filters:
storage_policy: storage_policy:
label: 存储策略 label: 存储策略
result: "存储策略:{storage_policy}" result: 存储策略:{storage_policy}
owner: owner:
label: 上传者 label: 上传者
result: "上传者:{owner}" result: 上传者:{owner}
sort: sort:
items: items:
create_time_desc: 较近上传 create_time_desc: 较近上传
@ -691,7 +716,7 @@ core:
placeholder: 选择上级菜单项 placeholder: 选择上级菜单项
ref_kind: ref_kind:
label: 类型 label: 类型
placeholder: "请选择{label}" placeholder: 请选择{label}
options: options:
custom: 自定义链接 custom: 自定义链接
post: 文章 post: 文章
@ -783,8 +808,8 @@ core:
last_starttime: 最近一次启动 last_starttime: 最近一次启动
loader: loader:
toast: toast:
entry_load_failed: "加载插件入口文件失败" entry_load_failed: 加载插件入口文件失败
style_load_failed: "加载插件样式文件失败" style_load_failed: 加载插件样式文件失败
extension_points: extension_points:
editor: editor:
providers: providers:
@ -854,19 +879,13 @@ core:
title: 用户详情 title: 用户详情
tabs: tabs:
detail: 详情 detail: 详情
notification-preferences: 通知配置
pat: 个人令牌
actions: actions:
update_profile: update_profile:
title: 修改资料 title: 修改资料
change_password: change_password:
title: 修改密码 title: 修改密码
operations: profile:
bind: title: 个人中心
button: 绑定
unbind:
button: 解绑
title: "确定要取消绑定 {display_name} 的登录方式吗?"
fields: fields:
display_name: 显示名称 display_name: 显示名称
username: 用户名 username: 用户名
@ -875,21 +894,99 @@ core:
bio: 描述 bio: 描述
creation_time: 注册时间 creation_time: 注册时间
identity_authentication: 登录方式 identity_authentication: 登录方式
avatar: role:
title: 头像 title: 角色
toast_upload_failed: 上传头像失败 common:
toast_remove_failed: 删除头像失败 text:
cropper_modal: contains_all_permissions: 包含所有权限
title: 裁剪头像 contains_n_permissions: 包含 {count} 个权限
remove: system_reserved: 系统保留
title: 确定要删除头像吗? custom: 自定义
tooltips: dependent_on: 依赖于 {roles}
upload: 上传 provided_by_plugin: 由 {plugin} 提供
zoom_in: 放大 operations:
zoom_out: 缩小 delete:
flip_horizontal: 水平翻转 title: 确定要删除该角色吗?
flip_vertical: 垂直翻转 description: 该角色删除后,相关联的用户将被删除角色绑定,该操作不可恢复。
reset: 重置 create_based_on_this_role:
button: 基于此角色创建
detail:
title: 角色详情
header:
title: 角色信息
tabs:
detail: 详情
permissions: 权限设置
fields:
display_name: 名称
name: 别名
type: 类型
creation_time: 创建时间
permissions_detail:
system_reserved_alert:
description: 系统保留的角色不支持修改,推荐基于此角色创建一个新的角色。
editing_modal:
titles:
create: 创建角色
update: 编辑角色
groups:
general: 基本信息
permissions: 权限
fields:
display_name: 名称
redirect_on_login: 登录之后默认跳转位置
identity_authentication:
title: 身份认证
tabs:
detail: 详情
setting: 设置
operations:
enable:
title: 确定要启用该身份认证方式吗?
disable:
title: 确定要停用该身份认证方式吗?
disable_privileged:
tooltip: 系统保留的认证方式,无法禁用
detail:
title: 身份认证详情
fields:
display_name: 名称
description: 描述
website: 网站
help_page: 帮助页面
authentication_url: 登录入口
uc_profile:
title: 我的
tabs:
detail: 详情
notification-preferences: 通知配置
pat: 个人令牌
actions:
update_profile:
title: 修改资料
change_password:
title: 修改密码
detail:
fields:
display_name: 显示名称
username: 用户名
email: 电子邮箱
roles: 角色
bio: 描述
creation_time: 注册时间
identity_authentication: 登录方式
operations:
bind:
button: 绑定
unbind:
button: 解绑
title: 确定要取消绑定 {display_name} 的登录方式吗?
email_not_set:
title: 设置电子邮箱
description: 电子邮箱地址还未设置,点击下方按钮进行设置
email_not_verified:
title: 验证电子邮箱
description: 电子邮箱地址还未验证,点击下方按钮进行验证
pat: pat:
operations: operations:
delete: delete:
@ -933,67 +1030,54 @@ core:
notification-preferences: notification-preferences:
fields: fields:
type: 通知类型 type: 通知类型
role:
title: 角色
common:
text:
contains_all_permissions: 包含所有权限
contains_n_permissions: 包含 {count} 个权限
system_reserved: 系统保留
custom: 自定义
dependent_on: 依赖于 {roles}
provided_by_plugin: 由 {plugin} 提供
operations:
delete:
title: 确定要删除该角色吗?
description: 该角色删除后,相关联的用户将被删除角色绑定,该操作不可恢复。
create_based_on_this_role:
button: 基于此角色创建
detail:
title: 角色详情
header:
title: 角色信息
tabs:
detail: 详情
permissions: 权限设置
fields:
display_name: 名称
name: 别名
type: 类型
creation_time: 创建时间
permissions_detail:
system_reserved_alert:
description: 系统保留的角色不支持修改,推荐基于此角色创建一个新的角色。
editing_modal: editing_modal:
titles: title: 编辑资料
create: 创建角色
update: 编辑角色
groups: groups:
general: 基本信息 general: 常规
permissions: 权限 annotations: 元数据
fields: fields:
display_name: 名称 username:
identity_authentication: label: 用户名
title: 身份认证 validation: 请输入有效的用户名
tabs: display_name:
detail: 详情 label: 显示名称
setting: 设置 email:
label: 电子邮箱
phone:
label: 手机号
avatar:
label: 头像
bio:
label: 描述
change_password_modal:
title: 密码修改
fields:
new_password:
label: 新密码
confirm_password:
label: 确认密码
email_verify_modal:
titles:
modify: 修改电子邮箱
verify: 验证电子邮箱
fields:
new_email:
label: 新电子邮箱
email:
label: 电子邮箱
code:
label: 验证码
operations: operations:
enable: send_code:
title: 确定要启用该身份认证方式吗? buttons:
disable: sending: 发送中
title: 确定要停用该身份认证方式吗? send: 发送验证码
disable_privileged: countdown: "{timer} 秒后重发"
tooltip: 系统保留的认证方式,无法禁用 toast_success: 验证码已发送
detail: toast_email_empty: 请输入电子邮箱
title: 身份认证详情 verify:
fields: toast_success: 验证成功
display_name: 名称 uc_notification:
description: 描述
website: 网站
help_page: 帮助页面
authentication_url: 登录入口
notification:
title: 消息 title: 消息
tabs: tabs:
unread: 未读 unread: 未读
@ -1005,6 +1089,9 @@ core:
operations: operations:
mark_as_read: mark_as_read:
button: 标记为已读 button: 标记为已读
delete:
title: 删除消息
description: 确定要删除该消息吗?
setting: setting:
title: 设置 title: 设置
actuator: actuator:
@ -1202,7 +1289,7 @@ core:
extensions: extensions:
placeholder: placeholder:
options: options:
placeholder: "输入 / 以选择输入类型" placeholder: 输入 / 以选择输入类型
toolbox: toolbox:
attachment: 选择附件 attachment: 选择附件
show_hide_sidebar: 显示 / 隐藏侧边栏 show_hide_sidebar: 显示 / 隐藏侧边栏
@ -1231,8 +1318,23 @@ core:
app_download_alert: app_download_alert:
description: Halo 的主题和插件可以在以下地址下载: description: Halo 的主题和插件可以在以下地址下载:
sources: sources:
app_store: "官方应用市场:{url}" app_store: 官方应用市场:{url}
github: "GitHub{url}" github: GitHub{url}
user_avatar:
title: 头像
toast_upload_failed: 上传头像失败
toast_remove_failed: 删除头像失败
cropper_modal:
title: 裁剪头像
remove:
title: 确定要删除头像吗?
tooltips:
upload: 上传
zoom_in: 放大
zoom_out: 缩小
flip_horizontal: 水平翻转
flip_vertical: 垂直翻转
reset: 重置
composables: composables:
content_cache: content_cache:
toast_recovered: 已从缓存中恢复未保存的内容 toast_recovered: 已从缓存中恢复未保存的内容
@ -1278,6 +1380,8 @@ core:
detail: 详情 detail: 详情
select: 选择 select: 选择
view_all: 查看全部 view_all: 查看全部
verify: 验证
modify: 修改
radio: radio:
"yes": "yes":
"no": "no":
@ -1319,9 +1423,9 @@ core:
editor_not_found: 未找到符合 {raw_type} 格式的编辑器,请检查是否已安装编辑器插件。 editor_not_found: 未找到符合 {raw_type} 格式的编辑器,请检查是否已安装编辑器插件。
filters: filters:
results: results:
keyword: "关键词:{keyword}" keyword: 关键词:{keyword}
sort: "排序:{sort}" sort: 排序:{sort}
status: "状态:{status}" status: 状态:{status}
labels: labels:
sort: 排序 sort: 排序
status: 状态 status: 状态

View File

@ -75,12 +75,21 @@ core:
backup: 備份 backup: 備份
operations: operations:
logout: logout:
button: 登出 tooltip: 登出
title: 確定要登出嗎? title: 確定要登出嗎?
profile: profile:
button: 個人資料 tooltip: 個人中心
visit_homepage: visit_homepage:
title: 訪問首頁 title: 訪問首頁
uc_sidebar:
menu:
items:
profile: 我的
notification: 消息
posts: 文章
operations:
console:
tooltip: 管理控制台
dashboard: dashboard:
title: 儀表板 title: 儀表板
actions: actions:
@ -102,9 +111,13 @@ core:
title: 頁面 title: 頁面
recent_published: recent_published:
title: 最近文章 title: 最近文章
visits: "訪問量 {visits}" visits: 訪問量 {visits}
comments: "留言 {comments}" comments: 留言 {comments}
publishTime: "發佈日期 {publishTime}" publishTime: 發佈日期 {publishTime}
notification:
title: 通知
empty:
title: 当前没有未读的消息
quicklink: quicklink:
title: 快捷訪問 title: 快捷訪問
actions: actions:
@ -163,19 +176,19 @@ core:
draft: 未發布 draft: 未發布
visible: visible:
label: 可見性 label: 可見性
result: "可見性:{visible}" result: 可見性:{visible}
items: items:
public: 公開 public: 公開
private: 私有 private: 私有
category: category:
label: 分類 label: 分類
result: "分類:{category}" result: 分類:{category}
tag: tag:
label: 標籤 label: 標籤
result: "標籤:{tag}" result: 標籤:{tag}
author: author:
label: 作者 label: 作者
result: "作者:{author}" result: 作者:{author}
sort: sort:
items: items:
publish_time_desc: 較近發布 publish_time_desc: 較近發布
@ -185,8 +198,8 @@ core:
list: list:
fields: fields:
categories: 分類: categories: 分類:
visits: "訪問量 {visits}" visits: 訪問量 {visits}
comments: "留言 {comments}" comments: 留言 {comments}
pinned: 已置頂 pinned: 已置頂
settings: settings:
title: 文章設置 title: 文章設置
@ -331,13 +344,13 @@ core:
draft: 未發布 draft: 未發布
visible: visible:
label: 可見性 label: 可見性
result: "可見性:{visible}" result: 可見性:{visible}
items: items:
public: 公開 public: 公開
private: 私有 private: 私有
author: author:
label: 作者 label: 作者
result: "作者:{author}" result: 作者:{author}
sort: sort:
items: items:
publish_time_desc: 較近發布 publish_time_desc: 較近發布
@ -346,8 +359,8 @@ core:
create_time_asc: 較早創建 create_time_asc: 較早創建
list: list:
fields: fields:
visits: "訪問量 {visits}" visits: 訪問量 {visits}
comments: "留言 {comments}" comments: 留言 {comments}
settings: settings:
title: 頁面設置 title: 頁面設置
groups: groups:
@ -433,7 +446,7 @@ core:
pending_review: 待審核 pending_review: 待審核
owner: owner:
label: 留言者 label: 留言者
result: "留言者:{owner}" result: 留言者:{owner}
sort: sort:
items: items:
last_reply_time_desc: 較近回覆 last_reply_time_desc: 較近回覆
@ -484,10 +497,10 @@ core:
filters: filters:
storage_policy: storage_policy:
label: 存儲策略 label: 存儲策略
result: "存儲策略:{storage_policy}" result: 存儲策略:{storage_policy}
owner: owner:
label: 上傳者 label: 上傳者
result: "上傳者:{owner}" result: 上傳者:{owner}
sort: sort:
items: items:
create_time_desc: 較近上傳 create_time_desc: 較近上傳
@ -691,7 +704,7 @@ core:
placeholder: 選擇上級選單項 placeholder: 選擇上級選單項
ref_kind: ref_kind:
label: 類型 label: 類型
placeholder: "請選擇{label}" placeholder: 請選擇{label}
options: options:
custom: 自定義連結 custom: 自定義連結
post: 文章 post: 文章
@ -783,8 +796,8 @@ core:
last_starttime: 最近一次啟動 last_starttime: 最近一次啟動
loader: loader:
toast: toast:
entry_load_failed: "讀取插件入口文件失敗" entry_load_failed: 讀取插件入口文件失敗
style_load_failed: "讀取插件樣式文件失敗" style_load_failed: 讀取插件樣式文件失敗
extension_points: extension_points:
editor: editor:
providers: providers:
@ -854,19 +867,13 @@ core:
title: 用戶詳情 title: 用戶詳情
tabs: tabs:
detail: 詳情 detail: 詳情
notification-preferences: 通知配置
pat: 個人令牌
actions: actions:
update_profile: update_profile:
title: 修改資料 title: 修改資料
change_password: change_password:
title: 修改密碼 title: 修改密碼
operations: profile:
bind: title: 個人中心
button: 綁定
unbind:
button: 解綁
title: "確定要取消綁定 {display_name} 的登入方式嗎?"
fields: fields:
display_name: 顯示名稱 display_name: 顯示名稱
username: 用戶名 username: 用戶名
@ -875,64 +882,6 @@ core:
bio: 描述 bio: 描述
creation_time: 註冊時間 creation_time: 註冊時間
identity_authentication: 登入方式 identity_authentication: 登入方式
avatar:
title: 頭像
toast_upload_failed: 上傳頭像失敗
toast_remove_failed: 刪除頭像失敗
cropper_modal:
title: 裁剪頭像
remove:
title: 確定要刪除頭像嗎?
tooltips:
upload: 上傳
zoom_in: 放大
zoom_out: 縮小
flip_horizontal: 水平翻轉
flip_vertical: 垂直翻轉
reset: 重置
pat:
operations:
delete:
title: 刪除個人令牌
description: 您確定要刪除此個人令牌嗎?
revoke:
button: 撤銷
title: 撤銷個人令牌
description: 您確定要撤銷此個人令牌嗎?
toast_success: 撤銷成功
copy:
title: 請立即複製並保存,令牌僅顯示一次。
restore:
button: 還原
toast_success: 還原成功
list:
empty:
title: 目前尚未建立個人令牌
message: 您可以嘗試重新整理或建立新的個人令牌
fields:
expiresAt:
dynamic: "到期於 {expiresAt}"
forever: 永久有效
status:
normal: 正常
revoked: 已撤銷
expired: 已過期
creation_modal:
title: 建立個人令牌
groups:
general: 基本資訊
permissions: 權限
fields:
name:
label: 名稱
expiresAt:
label: 到期時間
help: 留空代表永不過期
description:
label: 描述
notification-preferences:
fields:
type: 通知類型
role: role:
title: 角色 title: 角色
common: common:
@ -973,6 +922,7 @@ core:
permissions: 權限 permissions: 權限
fields: fields:
display_name: 名稱 display_name: 名稱
redirect_on_login: 登入之後預設跳轉位置
identity_authentication: identity_authentication:
title: 身份認證 title: 身份認證
tabs: tabs:
@ -993,7 +943,129 @@ core:
website: 網站 website: 網站
help_page: 幫助頁面 help_page: 幫助頁面
authentication_url: 登入入口 authentication_url: 登入入口
notification: uc_profile:
title: 我的
tabs:
detail: 詳情
notification-preferences: 通知配置
pat: 個人令牌
actions:
update_profile:
title: 修改資料
change_password:
title: 修改密碼
detail:
fields:
display_name: 顯示名稱
username: 用戶名
email: 電子郵箱
roles: 角色
bio: 描述
creation_time: 註冊時間
identity_authentication: 登入方式
operations:
bind:
button: 綁定
unbind:
button: 解綁
title: 確定要取消綁定 {display_name} 的登入方式嗎?
email_not_set:
description: 電子郵件地址尚未設置,點擊下方按鈕進行設置
title: 設定電子郵件信箱
email_not_verified:
description: 電子郵件地址尚未驗證,點擊下方按鈕進行驗證
title: 驗證電子郵件信箱
pat:
operations:
delete:
title: 刪除個人令牌
description: 您確定要刪除此個人令牌嗎?
revoke:
button: 撤銷
title: 撤銷個人令牌
description: 您確定要撤銷此個人令牌嗎?
toast_success: 撤銷成功
copy:
title: 請立即複製並保存,令牌僅顯示一次。
restore:
button: 還原
toast_success: 還原成功
list:
empty:
title: 目前尚未建立個人令牌
message: 您可以嘗試重新整理或建立新的個人令牌
fields:
expiresAt:
dynamic: 到期於 {expiresAt}
forever: 永久有效
status:
normal: 正常
revoked: 已撤銷
expired: 已過期
creation_modal:
title: 建立個人令牌
groups:
general: 基本資訊
permissions: 權限
fields:
name:
label: 名稱
expiresAt:
label: 到期時間
help: 留空代表永不過期
description:
label: 描述
notification-preferences:
fields:
type: 通知類型
editing_modal:
title: 編輯資料
groups:
general: 常規
annotations: 元數據
fields:
username:
label: 用戶名
validation: 請輸入有效的用戶名
display_name:
label: 顯示名稱
email:
label: 電子郵箱
phone:
label: 手機號
avatar:
label: 頭像
bio:
label: 描述
change_password_modal:
title: 密碼修改
fields:
new_password:
label: 新密碼
confirm_password:
label: 確認密碼
email_verify_modal:
fields:
code:
label: 驗證碼
email:
label: 電子郵件信箱
new_email:
label: 新電子郵件信箱
operations:
send_code:
buttons:
countdown: "{timer} 秒後重發"
send: 發送驗證碼
sending: 發送中
toast_email_empty: 請輸入電子郵件信箱
toast_success: 驗證碼已發送
verify:
toast_success: 驗證成功
titles:
modify: 修改電子郵件信箱
verify: 驗證電子郵件信箱
uc_notification:
title: 訊息 title: 訊息
tabs: tabs:
unread: 未讀 unread: 未讀
@ -1005,6 +1077,9 @@ core:
operations: operations:
mark_as_read: mark_as_read:
button: 標記為已讀 button: 標記為已讀
delete:
description: 確定要刪除該訊息嗎?
title: 刪除訊息
setting: setting:
title: 設置 title: 設置
actuator: actuator:
@ -1202,7 +1277,7 @@ core:
extensions: extensions:
placeholder: placeholder:
options: options:
placeholder: "輸入 / 以選擇輸入類型" placeholder: 輸入 / 以選擇輸入類型
toolbox: toolbox:
attachment: 選擇附件 attachment: 選擇附件
show_hide_sidebar: 顯示 / 隱藏側邊欄 show_hide_sidebar: 顯示 / 隱藏側邊欄
@ -1231,8 +1306,23 @@ core:
app_download_alert: app_download_alert:
description: Halo 的主題和插件可以在以下地址下載: description: Halo 的主題和插件可以在以下地址下載:
sources: sources:
app_store: "官方應用市場:{url}" app_store: 官方應用市場:{url}
github: "GitHub{url}" github: GitHub{url}
user_avatar:
title: 頭像
toast_upload_failed: 上傳頭像失敗
toast_remove_failed: 刪除頭像失敗
cropper_modal:
title: 裁剪頭像
remove:
title: 確定要刪除頭像嗎?
tooltips:
upload: 上傳
zoom_in: 放大
zoom_out: 縮小
flip_horizontal: 水平翻轉
flip_vertical: 垂直翻轉
reset: 重置
composables: composables:
content_cache: content_cache:
toast_recovered: 已從緩存中恢復未保存的內容 toast_recovered: 已從緩存中恢復未保存的內容
@ -1278,6 +1368,8 @@ core:
detail: 詳情 detail: 詳情
select: 選擇 select: 選擇
view_all: 查看全部 view_all: 查看全部
modify: 修改
verify: 驗證
radio: radio:
"yes": "yes":
"no": "no":
@ -1319,9 +1411,9 @@ core:
editor_not_found: 未找到符合 {raw_type} 格式的編輯器,請檢查是否已安裝編輯器插件。 editor_not_found: 未找到符合 {raw_type} 格式的編輯器,請檢查是否已安裝編輯器插件。
filters: filters:
results: results:
keyword: "關鍵字:{keyword}" keyword: 關鍵字:{keyword}
sort: "排序:{sort}" sort: 排序:{sort}
status: "狀態:{status}" status: 狀態:{status}
labels: labels:
sort: 排序 sort: 排序
status: 狀態 status: 狀態
@ -1346,3 +1438,15 @@ core:
recovering: 還原中 recovering: 還原中
fields: fields:
post_count: "{count} 篇文章" post_count: "{count} 篇文章"
uc_post:
creation_modal:
title: 創建文章
operations:
cancel_publish:
description: 確定要取消發布嗎?
title: 取消發布
publish_modal:
title: 發布文章
setting_modal:
title: 文章設定
title: 我的文章

View File

@ -145,7 +145,7 @@ onMounted(() => {
</div> </div>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<a <a
v-tooltip="'管理控制台'" v-tooltip="$t('core.uc_sidebar.operations.console.tooltip')"
class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100" class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100"
href="/console" href="/console"
> >
@ -154,6 +154,7 @@ onMounted(() => {
/> />
</a> </a>
<div <div
v-tooltip="$t('core.sidebar.operations.logout.tooltip')"
class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100" class="group inline-block cursor-pointer rounded-full p-1.5 transition-all hover:bg-gray-100"
@click="handleLogout" @click="handleLogout"
> >

View File

@ -419,7 +419,7 @@ useSessionKeepAlive();
<PostCreationModal <PostCreationModal
v-if="postCreationModal" v-if="postCreationModal"
title="创建文章" :title="$t('core.uc_post.creation_modal.title')"
:content="content" :content="content"
@close="postCreationModal = false" @close="postCreationModal = false"
@success="onCreatePostSuccess" @success="onCreatePostSuccess"
@ -427,7 +427,7 @@ useSessionKeepAlive();
<PostCreationModal <PostCreationModal
v-if="postPublishModal" v-if="postPublishModal"
title="发布文章" :title="$t('core.uc_post.publish_modal.title')"
:content="content" :content="content"
publish publish
@close="postPublishModal = false" @close="postPublishModal = false"

View File

@ -84,7 +84,7 @@ const {
</script> </script>
<template> <template>
<VPageHeader title="我的文章"> <VPageHeader :title="$t('core.uc_post.title')">
<template #icon> <template #icon>
<IconBookRead class="mr-2 self-center" /> <IconBookRead class="mr-2 self-center" />
</template> </template>
@ -121,21 +121,13 @@ const {
value: undefined, value: undefined,
}, },
{ {
label: '已发布', label: $t('core.post.filters.status.items.published'),
value: 'PUBLISHED', value: 'PUBLISHED',
}, },
{ {
label: '待审核', label: $t('core.post.filters.status.items.draft'),
value: 'PENDING_APPROVAL',
},
{
label: '未发布',
value: 'DRAFT', value: 'DRAFT',
}, },
{
label: '发布失败',
value: 'FAILED',
},
]" ]"
/> />
<div <div

View File

@ -67,8 +67,10 @@ async function handlePublish() {
function handleUnpublish() { function handleUnpublish() {
Dialog.warning({ Dialog.warning({
title: "取消发布", title: t("core.uc_post.operations.cancel_publish.title"),
description: "确定要取消发布吗?", description: t("core.uc_post.operations.cancel_publish.description"),
confirmText: t("core.common.buttons.confirm"),
cancelText: t("core.common.buttons.cancel"),
async onConfirm() { async onConfirm() {
await apiClient.uc.post.unpublishMyPost({ await apiClient.uc.post.unpublishMyPost({
name: props.post.post.metadata.name, name: props.post.post.metadata.name,
@ -216,17 +218,17 @@ function handleUnpublish() {
}) })
" "
> >
编辑 {{ $t("core.common.buttons.edit") }}
</VDropdownItem> </VDropdownItem>
<HasPermission :permissions="['uc:posts:publish']"> <HasPermission :permissions="['uc:posts:publish']">
<VDropdownItem <VDropdownItem
v-if="post.post.metadata.labels?.[postLabels.PUBLISHED] === 'false'" v-if="post.post.metadata.labels?.[postLabels.PUBLISHED] === 'false'"
@click="handlePublish" @click="handlePublish"
> >
发布 {{ $t("core.common.buttons.publish") }}
</VDropdownItem> </VDropdownItem>
<VDropdownItem v-else type="danger" @click="handleUnpublish"> <VDropdownItem v-else type="danger" @click="handleUnpublish">
取消发布 {{ $t("core.common.buttons.cancel_publish") }}
</VDropdownItem> </VDropdownItem>
</HasPermission> </HasPermission>
</template> </template>

View File

@ -88,7 +88,7 @@ function onSubmit(data: PostFormState) {
<VModal <VModal
v-if="shouldRender" v-if="shouldRender"
v-model:visible="visible" v-model:visible="visible"
title="文章设置" :title="$t('core.uc_post.setting_modal.title')"
:width="700" :width="700"
centered centered
@close="onClose" @close="onClose"

View File

@ -16,11 +16,11 @@ export default definePlugin({
name: "Posts", name: "Posts",
component: PostList, component: PostList,
meta: { meta: {
title: "core.post.title", title: "core.uc_post.title",
searchable: true, searchable: true,
permissions: ["uc:posts:manage"], permissions: ["uc:posts:manage"],
menu: { menu: {
name: "core.sidebar.menu.items.posts", name: "core.uc_sidebar.menu.items.posts",
group: "content", group: "content",
icon: markRaw(IconBookRead), icon: markRaw(IconBookRead),
priority: 0, priority: 0,
@ -33,7 +33,7 @@ export default definePlugin({
name: "PostEditor", name: "PostEditor",
component: PostEditor, component: PostEditor,
meta: { meta: {
title: "文章编辑", title: "core.post_editor.title",
searchable: true, searchable: true,
permissions: ["uc:posts:manage"], permissions: ["uc:posts:manage"],
}, },

View File

@ -56,7 +56,7 @@ const selectedNotification = computed(() => {
</script> </script>
<template> <template>
<VPageHeader :title="$t('core.notification.title')"> <VPageHeader :title="$t('core.uc_notification.title')">
<template #icon> <template #icon>
<IconNotificationBadgeLine class="mr-2 self-center" /> <IconNotificationBadgeLine class="mr-2 self-center" />
</template> </template>
@ -80,8 +80,8 @@ const selectedNotification = computed(() => {
v-model:active-id="activeTab" v-model:active-id="activeTab"
class="sticky top-0 z-10 !rounded-none" class="sticky top-0 z-10 !rounded-none"
:items="[ :items="[
{ id: 'unread', label: $t('core.notification.tabs.unread') }, { id: 'unread', label: $t('core.uc_notification.tabs.unread') },
{ id: 'read', label: $t('core.notification.tabs.read') }, { id: 'read', label: $t('core.uc_notification.tabs.read') },
]" ]"
type="outline" type="outline"
@change="selectedNotificationName = undefined" @change="selectedNotificationName = undefined"
@ -95,8 +95,8 @@ const selectedNotification = computed(() => {
<VEmpty <VEmpty
:title="`${ :title="`${
activeTab === 'unread' activeTab === 'unread'
? $t('core.notification.empty.titles.unread') ? $t('core.uc_notification.empty.titles.unread')
: $t('core.notification.empty.titles.read') : $t('core.uc_notification.empty.titles.read')
}`" }`"
> >
<template #actions> <template #actions>

View File

@ -7,8 +7,10 @@ import { useMutation, useQueryClient } from "@tanstack/vue-query";
import { Dialog, Toast, VStatusDot } from "@halo-dev/components"; import { Dialog, Toast, VStatusDot } from "@halo-dev/components";
import { watch } from "vue"; import { watch } from "vue";
import { ref } from "vue"; import { ref } from "vue";
import { useI18n } from "vue-i18n";
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { t } = useI18n();
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -43,8 +45,8 @@ const { mutate: handleMarkAsRead } = useMutation({
function handleDelete() { function handleDelete() {
Dialog.warning({ Dialog.warning({
title: "删除消息", title: t("core.uc_notification.operations.delete.title"),
description: "确定要删除该消息吗?", description: t("core.uc_notification.operations.delete.description"),
async onConfirm() { async onConfirm() {
await apiClient.notification.deleteSpecifiedNotification({ await apiClient.notification.deleteSpecifiedNotification({
name: props.notification.metadata.name, name: props.notification.metadata.name,
@ -53,7 +55,7 @@ function handleDelete() {
await queryClient.invalidateQueries({ queryKey: ["user-notifications"] }); await queryClient.invalidateQueries({ queryKey: ["user-notifications"] });
Toast.success("删除成功"); Toast.success(t("core.common.toast.delete_success"));
}, },
}); });
} }
@ -109,7 +111,7 @@ watch(
class="text-sm text-gray-600 hover:text-gray-900" class="text-sm text-gray-600 hover:text-gray-900"
@click.stop="handleMarkAsRead({ refetch: true })" @click.stop="handleMarkAsRead({ refetch: true })"
> >
{{ $t("core.notification.operations.mark_as_read.button") }} {{ $t("core.uc_notification.operations.mark_as_read.button") }}
</span> </span>
<span <span
class="text-sm text-red-600 hover:text-red-700" class="text-sm text-red-600 hover:text-red-700"

View File

@ -15,10 +15,10 @@ export default definePlugin({
name: "Notifications", name: "Notifications",
component: Notifications, component: Notifications,
meta: { meta: {
title: "消息", title: "core.uc_notification.title",
searchable: true, searchable: true,
menu: { menu: {
name: "消息", name: "core.uc_sidebar.menu.items.notification",
group: "dashboard", group: "dashboard",
icon: markRaw(IconNotificationBadgeLine), icon: markRaw(IconNotificationBadgeLine),
priority: 1, priority: 1,

View File

@ -63,19 +63,19 @@ provide<Ref<DetailedUser | undefined>>("user", user);
const tabs: UserTab[] = [ const tabs: UserTab[] = [
{ {
id: "detail", id: "detail",
label: t("core.user.detail.tabs.detail"), label: t("core.uc_profile.tabs.detail"),
component: markRaw(DetailTab), component: markRaw(DetailTab),
priority: 10, priority: 10,
}, },
{ {
id: "notification-preferences", id: "notification-preferences",
label: t("core.user.detail.tabs.notification-preferences"), label: t("core.uc_profile.tabs.notification-preferences"),
component: markRaw(NotificationPreferences), component: markRaw(NotificationPreferences),
priority: 20, priority: 20,
}, },
{ {
id: "pat", id: "pat",
label: t("core.user.detail.tabs.pat"), label: t("core.uc_profile.tabs.pat"),
component: markRaw(PersonalAccessTokensTab), component: markRaw(PersonalAccessTokensTab),
priority: 30, priority: 30,
}, },
@ -122,10 +122,10 @@ const activeTab = useRouteQuery<string>("tab", tabs[0].id, {
</VButton> </VButton>
<template #popper> <template #popper>
<VDropdownItem @click="editingModal = true"> <VDropdownItem @click="editingModal = true">
{{ $t("core.user.detail.actions.update_profile.title") }} {{ $t("core.uc_profile.actions.update_profile.title") }}
</VDropdownItem> </VDropdownItem>
<VDropdownItem @click="passwordChangeModal = true"> <VDropdownItem @click="passwordChangeModal = true">
{{ $t("core.user.detail.actions.change_password.title") }} {{ $t("core.uc_profile.actions.change_password.title") }}
</VDropdownItem> </VDropdownItem>
</template> </template>
</VDropdown> </VDropdown>

View File

@ -8,8 +8,10 @@ import { apiClient } from "@/utils/api-client";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import { useIntervalFn } from "@vueuse/shared"; import { useIntervalFn } from "@vueuse/shared";
import { computed } from "vue"; import { computed } from "vue";
import { useI18n } from "vue-i18n";
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { t } = useI18n();
const { currentUser, fetchCurrentUser } = useUserStore(); const { currentUser, fetchCurrentUser } = useUserStore();
@ -58,7 +60,11 @@ const { mutate: sendVerifyCode, isLoading: isSending } = useMutation({
mutationKey: ["send-verify-code"], mutationKey: ["send-verify-code"],
mutationFn: async () => { mutationFn: async () => {
if (!email.value) { if (!email.value) {
Toast.error("请输入电子邮箱"); Toast.error(
t(
"core.uc_profile.email_verify_modal.operations.send_code.toast_email_empty"
)
);
throw new Error("email is empty"); throw new Error("email is empty");
} }
return await apiClient.user.sendEmailVerificationCode({ return await apiClient.user.sendEmailVerificationCode({
@ -68,7 +74,9 @@ const { mutate: sendVerifyCode, isLoading: isSending } = useMutation({
}); });
}, },
onSuccess() { onSuccess() {
Toast.success("验证码已发送"); Toast.success(
t("core.uc_profile.email_verify_modal.operations.send_code.toast_success")
);
timer.value = 60; timer.value = 60;
resume(); resume();
}, },
@ -76,9 +84,16 @@ const { mutate: sendVerifyCode, isLoading: isSending } = useMutation({
const sendVerifyCodeButtonText = computed(() => { const sendVerifyCodeButtonText = computed(() => {
if (isSending.value) { if (isSending.value) {
return "发送中"; return t(
"core.uc_profile.email_verify_modal.operations.send_code.buttons.sending"
);
} }
return isActive.value ? `${timer.value} 秒后重发` : "发送验证码"; return isActive.value
? t(
"core.uc_profile.email_verify_modal.operations.send_code.buttons.countdown",
{ timer: timer.value }
)
: t("core.uc_profile.email_verify_modal.operations.send_code.buttons.send");
}); });
const { mutate: verifyEmail, isLoading: isVerifying } = useMutation({ const { mutate: verifyEmail, isLoading: isVerifying } = useMutation({
@ -91,7 +106,9 @@ const { mutate: verifyEmail, isLoading: isVerifying } = useMutation({
}); });
}, },
onSuccess() { onSuccess() {
Toast.success("验证成功"); Toast.success(
t("core.uc_profile.email_verify_modal.operations.verify.toast_success")
);
queryClient.invalidateQueries({ queryKey: ["user-detail"] }); queryClient.invalidateQueries({ queryKey: ["user-detail"] });
fetchCurrentUser(); fetchCurrentUser();
onClose(); onClose();
@ -107,7 +124,11 @@ function handleVerify(data: { code: string }) {
<VModal <VModal
v-if="shouldRender" v-if="shouldRender"
v-model:visible="visible" v-model:visible="visible"
:title="currentUser?.spec.emailVerified ? '修改电子邮箱' : '绑定电子邮箱'" :title="
currentUser?.spec.emailVerified
? $t('core.uc_profile.email_verify_modal.titles.modify')
: $t('core.uc_profile.email_verify_modal.titles.verify')
"
@close="onClose" @close="onClose"
> >
<FormKit <FormKit
@ -119,11 +140,20 @@ function handleVerify(data: { code: string }) {
<FormKit <FormKit
v-model="email" v-model="email"
type="email" type="email"
:label="currentUser?.spec.emailVerified ? '新电子邮箱' : '电子邮箱'" :label="
currentUser?.spec.emailVerified
? $t('core.uc_profile.email_verify_modal.fields.new_email.label')
: $t('core.uc_profile.email_verify_modal.fields.email.label')
"
name="email" name="email"
validation="required|email" validation="required|email"
></FormKit> ></FormKit>
<FormKit type="number" name="code" label="验证码" validation="required"> <FormKit
type="number"
name="code"
:label="$t('core.uc_profile.email_verify_modal.fields.code.label')"
validation="required"
>
<template #suffix> <template #suffix>
<VButton <VButton
:loading="isSending" :loading="isSending"
@ -143,9 +173,11 @@ function handleVerify(data: { code: string }) {
type="secondary" type="secondary"
@click="$formkit.submit('email-verify-form')" @click="$formkit.submit('email-verify-form')"
> >
验证 {{ $t("core.common.buttons.verify") }}
</VButton>
<VButton @click="emit('close')">
{{ $t("core.common.buttons.close_and_shortcut") }}
</VButton> </VButton>
<VButton @click="emit('close')"></VButton>
</VSpace> </VSpace>
</template> </template>
</VModal> </VModal>

View File

@ -85,7 +85,7 @@ const handleChangePassword = async () => {
<VModal <VModal
:visible="visible" :visible="visible"
:width="500" :width="500"
:title="$t('core.user.change_password_modal.title')" :title="$t('core.uc_profile.change_password_modal.title')"
@update:visible="onVisibleChange" @update:visible="onVisibleChange"
> >
<FormKit <FormKit
@ -99,7 +99,9 @@ const handleChangePassword = async () => {
> >
<FormKit <FormKit
id="passwordInput" id="passwordInput"
:label="$t('core.user.change_password_modal.fields.new_password.label')" :label="
$t('core.uc_profile.change_password_modal.fields.new_password.label')
"
name="password" name="password"
type="password" type="password"
validation="required:trim|length:5,100|matches:/^\S.*\S$/" validation="required:trim|length:5,100|matches:/^\S.*\S$/"
@ -109,7 +111,9 @@ const handleChangePassword = async () => {
></FormKit> ></FormKit>
<FormKit <FormKit
:label=" :label="
$t('core.user.change_password_modal.fields.confirm_password.label') $t(
'core.uc_profile.change_password_modal.fields.confirm_password.label'
)
" "
name="password_confirm" name="password_confirm"
type="password" type="password"

View File

@ -76,7 +76,7 @@ const {
setTimeout(() => { setTimeout(() => {
Dialog.info({ Dialog.info({
title: t("core.user.pat.operations.copy.title"), title: t("core.uc_profile.pat.operations.copy.title"),
description: data.metadata.annotations?.[patAnnotations.ACCESS_TOKEN], description: data.metadata.annotations?.[patAnnotations.ACCESS_TOKEN],
confirmType: "secondary", confirmType: "secondary",
confirmText: t("core.common.buttons.copy"), confirmText: t("core.common.buttons.copy"),
@ -102,7 +102,7 @@ const { copy } = useClipboard({
<VModal <VModal
v-model:visible="visible" v-model:visible="visible"
:width="700" :width="700"
:title="$t('core.user.pat.creation_modal.title')" :title="$t('core.uc_profile.pat.creation_modal.title')"
@close="emit('close')" @close="emit('close')"
> >
<div> <div>
@ -110,7 +110,7 @@ const { copy } = useClipboard({
<div class="md:col-span-1"> <div class="md:col-span-1">
<div class="sticky top-0"> <div class="sticky top-0">
<span class="text-base font-medium text-gray-900"> <span class="text-base font-medium text-gray-900">
{{ $t("core.user.pat.creation_modal.groups.general") }} {{ $t("core.uc_profile.pat.creation_modal.groups.general") }}
</span> </span>
</div> </div>
</div> </div>
@ -126,19 +126,27 @@ const { copy } = useClipboard({
validation="required" validation="required"
type="text" type="text"
name="name" name="name"
:label="$t('core.user.pat.creation_modal.fields.name.label')" :label="
$t('core.uc_profile.pat.creation_modal.fields.name.label')
"
></FormKit> ></FormKit>
<FormKit <FormKit
type="datetime-local" type="datetime-local"
name="expiresAt" name="expiresAt"
:label="$t('core.user.pat.creation_modal.fields.expiresAt.label')" :label="
:help="$t('core.user.pat.creation_modal.fields.expiresAt.help')" $t('core.uc_profile.pat.creation_modal.fields.expiresAt.label')
"
:help="
$t('core.uc_profile.pat.creation_modal.fields.expiresAt.help')
"
></FormKit> ></FormKit>
<FormKit <FormKit
type="textarea" type="textarea"
name="description" name="description"
:label=" :label="
$t('core.user.pat.creation_modal.fields.description.label') $t(
'core.uc_profile.pat.creation_modal.fields.description.label'
)
" "
></FormKit> ></FormKit>
</FormKit> </FormKit>
@ -154,7 +162,7 @@ const { copy } = useClipboard({
<div class="md:col-span-1"> <div class="md:col-span-1">
<div class="sticky top-0"> <div class="sticky top-0">
<span class="text-base font-medium text-gray-900"> <span class="text-base font-medium text-gray-900">
{{ $t("core.user.pat.creation_modal.groups.permissions") }} {{ $t("core.uc_profile.pat.creation_modal.groups.permissions") }}
</span> </span>
</div> </div>
</div> </div>

View File

@ -27,8 +27,8 @@ const { t } = useI18n();
function handleDelete() { function handleDelete() {
Dialog.warning({ Dialog.warning({
title: t("core.user.pat.operations.delete.title"), title: t("core.uc_profile.pat.operations.delete.title"),
description: t("core.user.pat.operations.delete.description"), description: t("core.uc_profile.pat.operations.delete.description"),
async onConfirm() { async onConfirm() {
await apiClient.pat.deletePat({ await apiClient.pat.deletePat({
name: props.token.metadata.name, name: props.token.metadata.name,
@ -42,14 +42,14 @@ function handleDelete() {
function handleRevoke() { function handleRevoke() {
Dialog.warning({ Dialog.warning({
title: t("core.user.pat.operations.revoke.title"), title: t("core.uc_profile.pat.operations.revoke.title"),
description: t("core.user.pat.operations.revoke.description"), description: t("core.uc_profile.pat.operations.revoke.description"),
async onConfirm() { async onConfirm() {
await apiClient.pat.revokePat({ await apiClient.pat.revokePat({
name: props.token.metadata.name, name: props.token.metadata.name,
}); });
Toast.success(t("core.user.pat.operations.revoke.toast_success")); Toast.success(t("core.uc_profile.pat.operations.revoke.toast_success"));
queryClient.invalidateQueries({ queryKey: ["personal-access-tokens"] }); queryClient.invalidateQueries({ queryKey: ["personal-access-tokens"] });
}, },
}); });
@ -58,19 +58,19 @@ function handleRevoke() {
async function handleRestore() { async function handleRestore() {
await apiClient.pat.restorePat({ name: props.token.metadata.name }); await apiClient.pat.restorePat({ name: props.token.metadata.name });
Toast.success(t("core.user.pat.operations.restore.toast_success")); Toast.success(t("core.uc_profile.pat.operations.restore.toast_success"));
queryClient.invalidateQueries({ queryKey: ["personal-access-tokens"] }); queryClient.invalidateQueries({ queryKey: ["personal-access-tokens"] });
} }
const statusText = computed(() => { const statusText = computed(() => {
const { expiresAt } = props.token.spec || {}; const { expiresAt } = props.token.spec || {};
if (expiresAt && new Date(expiresAt) < new Date()) { if (expiresAt && new Date(expiresAt) < new Date()) {
return t("core.user.pat.list.fields.status.expired"); return t("core.uc_profile.pat.list.fields.status.expired");
} }
return t( return t(
props.token.spec?.revoked props.token.spec?.revoked
? "core.user.pat.list.fields.status.revoked" ? "core.uc_profile.pat.list.fields.status.revoked"
: "core.user.pat.list.fields.status.normal" : "core.uc_profile.pat.list.fields.status.normal"
); );
}); });
@ -109,13 +109,13 @@ const statusTheme = computed(() => {
v-tooltip="formatDatetime(token.spec.expiresAt)" v-tooltip="formatDatetime(token.spec.expiresAt)"
> >
{{ {{
$t("core.user.pat.list.fields.expiresAt.dynamic", { $t("core.uc_profile.pat.list.fields.expiresAt.dynamic", {
expiresAt: relativeTimeTo(token.spec?.expiresAt), expiresAt: relativeTimeTo(token.spec?.expiresAt),
}) })
}} }}
</span> </span>
<span v-else> <span v-else>
{{ $t("core.user.pat.list.fields.expiresAt.forever") }} {{ $t("core.uc_profile.pat.list.fields.expiresAt.forever") }}
</span> </span>
</div> </div>
</template> </template>
@ -135,10 +135,10 @@ const statusTheme = computed(() => {
type="danger" type="danger"
@click="handleRevoke" @click="handleRevoke"
> >
{{ $t("core.user.pat.operations.revoke.button") }} {{ $t("core.uc_profile.pat.operations.revoke.button") }}
</VDropdownItem> </VDropdownItem>
<VDropdownItem v-else @click="handleRestore"> <VDropdownItem v-else @click="handleRestore">
{{ $t("core.user.pat.operations.restore.button") }} {{ $t("core.uc_profile.pat.operations.restore.button") }}
</VDropdownItem> </VDropdownItem>
<VDropdownDivider /> <VDropdownDivider />
<VDropdownItem type="danger" @click="handleDelete"> <VDropdownItem type="danger" @click="handleDelete">

View File

@ -114,7 +114,7 @@ async function onEmailVerifyModalClose() {
</script> </script>
<template> <template>
<VModal <VModal
:title="$t('core.user.editing_modal.titles.update')" :title="$t('core.uc_profile.editing_modal.title')"
:visible="visible" :visible="visible"
:width="700" :width="700"
@update:visible="onVisibleChange" @update:visible="onVisibleChange"
@ -131,7 +131,7 @@ async function onEmailVerifyModalClose() {
<div class="md:col-span-1"> <div class="md:col-span-1">
<div class="sticky top-0"> <div class="sticky top-0">
<span class="text-base font-medium text-gray-900"> <span class="text-base font-medium text-gray-900">
{{ $t("core.user.editing_modal.groups.general") }} {{ $t("core.uc_profile.editing_modal.groups.general") }}
</span> </span>
</div> </div>
</div> </div>
@ -140,21 +140,23 @@ async function onEmailVerifyModalClose() {
id="userNameInput" id="userNameInput"
v-model="formState.metadata.name" v-model="formState.metadata.name"
:disabled="true" :disabled="true"
:label="$t('core.user.editing_modal.fields.username.label')" :label="$t('core.uc_profile.editing_modal.fields.username.label')"
type="text" type="text"
name="name" name="name"
></FormKit> ></FormKit>
<FormKit <FormKit
id="displayNameInput" id="displayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
:label="$t('core.user.editing_modal.fields.display_name.label')" :label="
$t('core.uc_profile.editing_modal.fields.display_name.label')
"
type="text" type="text"
name="displayName" name="displayName"
validation="required|length:0,50" validation="required|length:0,50"
></FormKit> ></FormKit>
<FormKit <FormKit
v-model="formState.spec.email" v-model="formState.spec.email"
:label="$t('core.user.editing_modal.fields.email.label')" :label="$t('core.uc_profile.editing_modal.fields.email.label')"
type="email" type="email"
name="email" name="email"
readonly readonly
@ -165,20 +167,20 @@ async function onEmailVerifyModalClose() {
class="rounded-none border-y-0 border-l border-r-0" class="rounded-none border-y-0 border-l border-r-0"
@click="emailVerifyModal = true" @click="emailVerifyModal = true"
> >
修改 {{ $t("core.common.buttons.modify") }}
</VButton> </VButton>
</template> </template>
</FormKit> </FormKit>
<FormKit <FormKit
v-model="formState.spec.phone" v-model="formState.spec.phone"
:label="$t('core.user.editing_modal.fields.phone.label')" :label="$t('core.uc_profile.editing_modal.fields.phone.label')"
type="text" type="text"
name="phone" name="phone"
validation="length:0,20" validation="length:0,20"
></FormKit> ></FormKit>
<FormKit <FormKit
v-model="formState.spec.bio" v-model="formState.spec.bio"
:label="$t('core.user.editing_modal.fields.bio.label')" :label="$t('core.uc_profile.editing_modal.fields.bio.label')"
type="textarea" type="textarea"
name="bio" name="bio"
validation="length:0,2048" validation="length:0,2048"

View File

@ -17,10 +17,10 @@ export default definePlugin({
name: "Profile", name: "Profile",
component: Profile, component: Profile,
meta: { meta: {
title: "个人资料", title: "core.uc_profile.title",
searchable: true, searchable: true,
menu: { menu: {
name: "我的", name: "core.uc_sidebar.menu.items.profile",
group: "dashboard", group: "dashboard",
icon: markRaw(IconAccountCircleLine), icon: markRaw(IconAccountCircleLine),
priority: 0, priority: 0,

View File

@ -40,7 +40,7 @@ const availableAuthProviders = computed(() => {
const handleUnbindAuth = (authProvider: ListedAuthProvider) => { const handleUnbindAuth = (authProvider: ListedAuthProvider) => {
Dialog.warning({ Dialog.warning({
title: t("core.user.detail.operations.unbind.title", { title: t("core.uc_profile.detail.operations.unbind.title", {
display_name: authProvider.displayName, display_name: authProvider.displayName,
}), }),
confirmText: t("core.common.buttons.confirm"), confirmText: t("core.common.buttons.confirm"),
@ -74,29 +74,33 @@ const emailVerifyModal = ref(false);
<div class="border-t border-gray-100"> <div class="border-t border-gray-100">
<VDescription> <VDescription>
<VDescriptionItem <VDescriptionItem
:label="$t('core.user.detail.fields.display_name')" :label="$t('core.uc_profile.detail.fields.display_name')"
:content="user?.user.spec.displayName" :content="user?.user.spec.displayName"
class="!px-2" class="!px-2"
/> />
<VDescriptionItem <VDescriptionItem
:label="$t('core.user.detail.fields.username')" :label="$t('core.uc_profile.detail.fields.username')"
:content="user?.user.metadata.name" :content="user?.user.metadata.name"
class="!px-2" class="!px-2"
/> />
<VDescriptionItem <VDescriptionItem
:label="$t('core.user.detail.fields.email')" :label="$t('core.uc_profile.detail.fields.email')"
class="!px-2" class="!px-2"
> >
<div v-if="user" class="w-full xl:w-1/2"> <div v-if="user" class="w-full xl:w-1/2">
<VAlert <VAlert
v-if="!user.user.spec.email" v-if="!user.user.spec.email"
title="设置电子邮箱" :title="$t('core.uc_profile.detail.email_not_set.title')"
description="电子邮箱地址还未设置,点击下方按钮进行设置" :description="
$t('core.uc_profile.detail.email_not_set.description')
"
type="warning" type="warning"
:closable="false" :closable="false"
> >
<template #actions> <template #actions>
<VButton size="sm" @click="emailVerifyModal = true">设置</VButton> <VButton size="sm" @click="emailVerifyModal = true">
{{ $t("core.common.buttons.setting") }}
</VButton>
</template> </template>
</VAlert> </VAlert>
@ -104,14 +108,16 @@ const emailVerifyModal = ref(false);
<span>{{ user.user.spec.email }}</span> <span>{{ user.user.spec.email }}</span>
<div v-if="!user.user.spec.emailVerified" class="mt-3"> <div v-if="!user.user.spec.emailVerified" class="mt-3">
<VAlert <VAlert
title="验证电子邮箱" :title="$t('core.uc_profile.detail.email_not_verified.title')"
description="电子邮箱地址还未验证,点击下方按钮进行验证" :description="
$t('core.uc_profile.detail.email_not_verified.description')
"
type="warning" type="warning"
:closable="false" :closable="false"
> >
<template #actions> <template #actions>
<VButton size="sm" @click="emailVerifyModal = true"> <VButton size="sm" @click="emailVerifyModal = true">
验证 {{ $t("core.common.buttons.verify") }}
</VButton> </VButton>
</template> </template>
</VAlert> </VAlert>
@ -120,7 +126,7 @@ const emailVerifyModal = ref(false);
</div> </div>
</VDescriptionItem> </VDescriptionItem>
<VDescriptionItem <VDescriptionItem
:label="$t('core.user.detail.fields.roles')" :label="$t('core.uc_profile.detail.fields.roles')"
class="!px-2" class="!px-2"
> >
<VTag v-for="role in user?.roles" :key="role.metadata.name"> <VTag v-for="role in user?.roles" :key="role.metadata.name">
@ -134,18 +140,18 @@ const emailVerifyModal = ref(false);
</VTag> </VTag>
</VDescriptionItem> </VDescriptionItem>
<VDescriptionItem <VDescriptionItem
:label="$t('core.user.detail.fields.bio')" :label="$t('core.uc_profile.detail.fields.bio')"
:content="user?.user.spec?.bio || $t('core.common.text.none')" :content="user?.user.spec?.bio || $t('core.common.text.none')"
class="!px-2" class="!px-2"
/> />
<VDescriptionItem <VDescriptionItem
:label="$t('core.user.detail.fields.creation_time')" :label="$t('core.uc_profile.detail.fields.creation_time')"
:content="formatDatetime(user?.user.metadata?.creationTimestamp)" :content="formatDatetime(user?.user.metadata?.creationTimestamp)"
class="!px-2" class="!px-2"
/> />
<VDescriptionItem <VDescriptionItem
v-if="!isFetching && availableAuthProviders?.length" v-if="!isFetching && availableAuthProviders?.length"
:label="$t('core.user.detail.fields.identity_authentication')" :label="$t('core.uc_profile.detail.fields.identity_authentication')"
class="!px-2" class="!px-2"
> >
<ul class="space-y-2"> <ul class="space-y-2">
@ -171,7 +177,7 @@ const emailVerifyModal = ref(false);
size="sm" size="sm"
@click="handleUnbindAuth(authProvider)" @click="handleUnbindAuth(authProvider)"
> >
{{ $t("core.user.detail.operations.unbind.button") }} {{ $t("core.uc_profile.detail.operations.unbind.button") }}
</VButton> </VButton>
<VButton <VButton
v-else v-else
@ -179,7 +185,7 @@ const emailVerifyModal = ref(false);
type="secondary" type="secondary"
@click="handleBindAuth(authProvider)" @click="handleBindAuth(authProvider)"
> >
{{ $t("core.user.detail.operations.bind.button") }} {{ $t("core.uc_profile.detail.operations.unbind.button") }}
</VButton> </VButton>
</div> </div>
</div> </div>

View File

@ -101,7 +101,7 @@ const {
class="px-4 py-3 text-left text-sm font-semibold text-gray-900 sm:w-96" class="px-4 py-3 text-left text-sm font-semibold text-gray-900 sm:w-96"
scope="col" scope="col"
> >
{{ $t("core.user.notification-preferences.fields.type") }} {{ $t("core.uc_profile.notification-preferences.fields.type") }}
</th> </th>
<th <th
v-for="notifier in data?.notifiers" v-for="notifier in data?.notifiers"

View File

@ -65,8 +65,8 @@ function onCreationModalClose() {
<Transition v-else-if="!pats?.length" appear name="fade"> <Transition v-else-if="!pats?.length" appear name="fade">
<VEmpty <VEmpty
:message="$t('core.user.pat.list.empty.message')" :message="$t('core.uc_profile.pat.list.empty.message')"
:title="$t('core.user.pat.list.empty.title')" :title="$t('core.uc_profile.pat.list.empty.title')"
> >
<template #actions> <template #actions>
<VSpace> <VSpace>