feat: support filtering attachments in the library by file media type (#5893)

#### What type of PR is this?

/kind feature
/area core
/area ui

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

为 `/apis/api.console.halo.run/v1alpha1/attachments` 接口增加了 `accepts` 可选参数,用于根据附件的 `MediaType` 进行筛选。

为附件库增加通过文件的 MediaType 类型进行筛选的筛选项。

同时支持使用了 `CoreSelectorProvider` 组件的文件选择框的筛选。现在只会显示 `accepts` 所支持的文件。

#### How to test it?

测试 ui 端文件选择框的类型筛选是否正确有效。
测试使用了 `CoreSelectorProvider` 组件的 `accepts` 是否有效。

#### Which issue(s) this PR fixes:

Fixes #5054

#### Does this PR introduce a user-facing change?
```release-note
附件库支持按文件类型进行过滤
```
pull/5928/head
Takagi 2024-05-16 10:32:35 +08:00 committed by GitHub
parent 983e70d50d
commit e5bc699fb2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 372 additions and 81 deletions

View File

@ -1869,6 +1869,17 @@
"schema": { "schema": {
"type": "string" "type": "string"
} }
},
{
"description": "Acceptable media types.",
"in": "query",
"name": "accepts",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
} }
], ],
"responses": { "responses": {

View File

@ -2,6 +2,7 @@ package run.halo.app.core.extension.attachment.endpoint;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
import static org.springdoc.core.fn.builders.arrayschema.Builder.arraySchemaBuilder;
import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; import static org.springdoc.core.fn.builders.content.Builder.contentBuilder;
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder; import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder;
@ -15,11 +16,13 @@ import static run.halo.app.extension.index.query.QueryFactory.contains;
import static run.halo.app.extension.index.query.QueryFactory.in; import static run.halo.app.extension.index.query.QueryFactory.in;
import static run.halo.app.extension.index.query.QueryFactory.isNull; import static run.halo.app.extension.index.query.QueryFactory.isNull;
import static run.halo.app.extension.index.query.QueryFactory.not; import static run.halo.app.extension.index.query.QueryFactory.not;
import static run.halo.app.extension.index.query.QueryFactory.startsWith;
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions; import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions;
import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -32,6 +35,7 @@ import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.codec.multipart.FormFieldPart; import org.springframework.http.codec.multipart.FormFieldPart;
import org.springframework.http.codec.multipart.Part; import org.springframework.http.codec.multipart.Part;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.BodyExtractors; import org.springframework.web.reactive.function.BodyExtractors;
@ -49,6 +53,7 @@ import run.halo.app.core.extension.service.AttachmentService;
import run.halo.app.extension.ListOptions; import run.halo.app.extension.ListOptions;
import run.halo.app.extension.PageRequestImpl; import run.halo.app.extension.PageRequestImpl;
import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.extension.index.query.QueryFactory;
import run.halo.app.extension.router.IListRequest; import run.halo.app.extension.router.IListRequest;
import run.halo.app.extension.router.IListRequest.QueryListRequest; import run.halo.app.extension.router.IListRequest.QueryListRequest;
import run.halo.app.extension.router.QueryParamBuildUtil; import run.halo.app.extension.router.QueryParamBuildUtil;
@ -142,6 +147,14 @@ public class AttachmentEndpoint implements CustomEndpoint {
+ " parameter.") + " parameter.")
Optional<Boolean> getUngrouped(); Optional<Boolean> getUngrouped();
@ArraySchema(uniqueItems = true,
arraySchema = @Schema(name = "accepts",
description = "Acceptable media types."),
schema = @Schema(description = "like image/*, video/mp4, text/*",
implementation = String.class,
example = "image/*"))
List<String> getAccepts();
@ArraySchema(uniqueItems = true, @ArraySchema(uniqueItems = true,
arraySchema = @Schema(name = "sort", arraySchema = @Schema(name = "sort",
description = "Sort property and direction of the list result. Supported fields: " description = "Sort property and direction of the list result. Supported fields: "
@ -168,7 +181,21 @@ public class AttachmentEndpoint implements CustomEndpoint {
.name("keyword") .name("keyword")
.required(false) .required(false)
.description("Keyword for searching.") .description("Keyword for searching.")
.implementation(String.class)); .implementation(String.class))
.parameter(parameterBuilder()
.in(ParameterIn.QUERY)
.name("accepts")
.required(false)
.description("Acceptable media types.")
.array(
arraySchemaBuilder()
.uniqueItems(true)
.schema(schemaBuilder()
.implementation(String.class)
.example("image/*"))
)
.implementationArray(String.class)
);
} }
} }
@ -193,6 +220,11 @@ public class AttachmentEndpoint implements CustomEndpoint {
.map(ungroupedStr -> getSharedInstance().convert(ungroupedStr, Boolean.class)); .map(ungroupedStr -> getSharedInstance().convert(ungroupedStr, Boolean.class));
} }
@Override
public List<String> getAccepts() {
return queryParams.getOrDefault("accepts", Collections.emptyList());
}
@Override @Override
public Sort getSort() { public Sort getSort() {
var sort = SortResolver.defaultInstance.resolve(exchange); var sort = SortResolver.defaultInstance.resolve(exchange);
@ -220,9 +252,27 @@ public class AttachmentEndpoint implements CustomEndpoint {
fieldQuery = and(fieldQuery, not(in("spec.groupName", hiddenGroups))); fieldQuery = and(fieldQuery, not(in("spec.groupName", hiddenGroups)));
} }
if (hasAccepts()) {
var acceptFieldQueryOptional = getAccepts().stream()
.filter(StringUtils::hasText)
.map((accept -> accept.replace("/*", "/").toLowerCase()))
.distinct()
.map(accept -> startsWith("spec.mediaType", accept))
.reduce(QueryFactory::or);
if (acceptFieldQueryOptional.isPresent()) {
fieldQuery = and(fieldQuery, acceptFieldQueryOptional.get());
}
}
listOptions.setFieldSelector(listOptions.getFieldSelector().andQuery(fieldQuery)); listOptions.setFieldSelector(listOptions.getFieldSelector().andQuery(fieldQuery));
return listOptions; return listOptions;
} }
private boolean hasAccepts() {
return !CollectionUtils.isEmpty(getAccepts())
&& !getAccepts().contains("*")
&& !getAccepts().contains("*/*");
}
} }
@Schema(types = "object") @Schema(types = "object")

View File

@ -390,6 +390,13 @@ public class SchemeInitializer implements ApplicationListener<ApplicationContext
return StringUtils.isBlank(group) ? null : group; return StringUtils.isBlank(group) ? null : group;
})) }))
); );
indexSpecs.add(new IndexSpec()
.setName("spec.mediaType")
.setIndexFunc(simpleAttribute(Attachment.class, attachment -> {
var mediaType = attachment.getSpec().getMediaType();
return StringUtils.isBlank(mediaType) ? null : mediaType;
}))
);
indexSpecs.add(new IndexSpec() indexSpecs.add(new IndexSpec()
.setName("spec.ownerName") .setName("spec.ownerName")
.setIndexFunc(simpleAttribute(Attachment.class, .setIndexFunc(simpleAttribute(Attachment.class,

View File

@ -63,12 +63,14 @@ const size = useRouteQuery<number>("size", 60, {
const selectedPolicy = useRouteQuery<string | undefined>("policy"); const selectedPolicy = useRouteQuery<string | undefined>("policy");
const selectedUser = useRouteQuery<string | undefined>("user"); const selectedUser = useRouteQuery<string | undefined>("user");
const selectedSort = useRouteQuery<string | undefined>("sort"); const selectedSort = useRouteQuery<string | undefined>("sort");
const selectedAccepts = useRouteQuery<string | undefined>("accepts");
watch( watch(
() => [ () => [
selectedPolicy.value, selectedPolicy.value,
selectedUser.value, selectedUser.value,
selectedSort.value, selectedSort.value,
selectedAccepts.value,
keyword.value, keyword.value,
], ],
() => { () => {
@ -77,13 +79,19 @@ watch(
); );
const hasFilters = computed(() => { const hasFilters = computed(() => {
return selectedPolicy.value || selectedUser.value || selectedSort.value; return (
selectedPolicy.value ||
selectedUser.value ||
selectedSort.value ||
selectedAccepts.value
);
}); });
function handleClearFilters() { function handleClearFilters() {
selectedPolicy.value = undefined; selectedPolicy.value = undefined;
selectedUser.value = undefined; selectedUser.value = undefined;
selectedSort.value = undefined; selectedSort.value = undefined;
selectedAccepts.value = undefined;
} }
const { const {
@ -110,6 +118,12 @@ const {
); );
}), }),
user: selectedUser, user: selectedUser,
accepts: computed(() => {
if (!selectedAccepts.value) {
return [];
}
return selectedAccepts.value.split(",");
}),
keyword: keyword, keyword: keyword,
sort: selectedSort, sort: selectedSort,
page: page, page: page,
@ -348,6 +362,31 @@ onMounted(() => {
}) || []), }) || []),
]" ]"
/> />
<FilterDropdown
v-model="selectedAccepts"
:label="$t('core.attachment.filters.accept.label')"
:items="[
{
label: t('core.common.filters.item_labels.all'),
},
{
label: t('core.attachment.filters.accept.items.image'),
value: 'image/*',
},
{
label: t('core.attachment.filters.accept.items.audio'),
value: 'audio/*',
},
{
label: t('core.attachment.filters.accept.items.video'),
value: 'video/*',
},
{
label: t('core.attachment.filters.accept.items.file'),
value: 'text/*,application/*',
},
]"
/>
<HasPermission :permissions="['system:users:view']"> <HasPermission :permissions="['system:users:view']">
<UserFilterDropdown <UserFilterDropdown
v-model="selectedUser" v-model="selectedUser"

View File

@ -22,6 +22,7 @@ import AttachmentUploadModal from "../AttachmentUploadModal.vue";
import AttachmentDetailModal from "../AttachmentDetailModal.vue"; import AttachmentDetailModal from "../AttachmentDetailModal.vue";
import AttachmentGroupList from "../AttachmentGroupList.vue"; import AttachmentGroupList from "../AttachmentGroupList.vue";
import { matchMediaTypes } from "@/utils/media-type"; import { matchMediaTypes } from "@/utils/media-type";
import { computed } from "vue";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@ -59,7 +60,14 @@ const {
handleSelectNext, handleSelectNext,
handleReset, handleReset,
isChecked, isChecked,
} = useAttachmentControl({ group: selectedGroup, page, size }); } = useAttachmentControl({
group: selectedGroup,
accepts: computed(() => {
return props.accepts;
}),
page,
size,
});
const uploadVisible = ref(false); const uploadVisible = ref(false);
const detailVisible = ref(false); const detailVisible = ref(false);

View File

@ -30,6 +30,7 @@ export function useAttachmentControl(filterOptions: {
policy?: Ref<Policy | undefined>; policy?: Ref<Policy | undefined>;
group?: Ref<Group | undefined>; group?: Ref<Group | undefined>;
user?: Ref<string | undefined>; user?: Ref<string | undefined>;
accepts?: Ref<string[]>;
keyword?: Ref<string | undefined>; keyword?: Ref<string | undefined>;
sort?: Ref<string | undefined>; sort?: Ref<string | undefined>;
page: Ref<number>; page: Ref<number>;
@ -37,7 +38,8 @@ export function useAttachmentControl(filterOptions: {
}): useAttachmentControlReturn { }): useAttachmentControlReturn {
const { t } = useI18n(); const { t } = useI18n();
const { user, policy, group, keyword, sort, page, size } = filterOptions; const { user, policy, group, keyword, sort, page, size, accepts } =
filterOptions;
const selectedAttachment = ref<Attachment>(); const selectedAttachment = ref<Attachment>();
const selectedAttachments = ref<Set<Attachment>>(new Set<Attachment>()); const selectedAttachments = ref<Set<Attachment>>(new Set<Attachment>());
@ -48,7 +50,17 @@ export function useAttachmentControl(filterOptions: {
const hasNext = ref(false); const hasNext = ref(false);
const { data, isLoading, isFetching, refetch } = useQuery<Attachment[]>({ const { data, isLoading, isFetching, refetch } = useQuery<Attachment[]>({
queryKey: ["attachments", policy, keyword, group, user, page, size, sort], queryKey: [
"attachments",
policy,
keyword,
group,
user,
accepts,
page,
size,
sort,
],
queryFn: async () => { queryFn: async () => {
const isUnGrouped = group?.value?.metadata.name === "ungrouped"; const isUnGrouped = group?.value?.metadata.name === "ungrouped";
@ -71,6 +83,7 @@ export function useAttachmentControl(filterOptions: {
page: page.value, page: page.value,
size: size.value, size: size.value,
ungrouped: isUnGrouped, ungrouped: isUnGrouped,
accepts: accepts?.value,
keyword: keyword?.value, keyword: keyword?.value,
sort: [sort?.value as string].filter(Boolean), sort: [sort?.value as string].filter(Boolean),
}); });

View File

@ -40,10 +40,11 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiAxiosParamCreator = function
* @param {Array<string>} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. * @param {Array<string>} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.
* @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter. * @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter.
* @param {string} [keyword] Keyword for searching. * @param {string} [keyword] Keyword for searching.
* @param {Array<string>} [accepts] Acceptable media types.
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
searchAttachments: async (page?: number, size?: number, labelSelector?: Array<string>, fieldSelector?: Array<string>, sort?: Array<string>, ungrouped?: boolean, keyword?: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => { searchAttachments: async (page?: number, size?: number, labelSelector?: Array<string>, fieldSelector?: Array<string>, sort?: Array<string>, ungrouped?: boolean, keyword?: string, accepts?: Array<string>, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/apis/api.console.halo.run/v1alpha1/attachments`; const localVarPath = `/apis/api.console.halo.run/v1alpha1/attachments`;
// use dummy base URL string because the URL constructor only accepts absolute URLs. // use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
@ -92,6 +93,10 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiAxiosParamCreator = function
localVarQueryParameter['keyword'] = keyword; localVarQueryParameter['keyword'] = keyword;
} }
if (accepts) {
localVarQueryParameter['accepts'] = accepts;
}
setSearchParams(localVarUrlObj, localVarQueryParameter); setSearchParams(localVarUrlObj, localVarQueryParameter);
@ -182,11 +187,12 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiFp = function(configuration?:
* @param {Array<string>} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. * @param {Array<string>} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.
* @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter. * @param {boolean} [ungrouped] Filter attachments without group. This parameter will ignore group parameter.
* @param {string} [keyword] Keyword for searching. * @param {string} [keyword] Keyword for searching.
* @param {Array<string>} [accepts] Acceptable media types.
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async searchAttachments(page?: number, size?: number, labelSelector?: Array<string>, fieldSelector?: Array<string>, sort?: Array<string>, ungrouped?: boolean, keyword?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AttachmentList>> { async searchAttachments(page?: number, size?: number, labelSelector?: Array<string>, fieldSelector?: Array<string>, sort?: Array<string>, ungrouped?: boolean, keyword?: string, accepts?: Array<string>, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AttachmentList>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.searchAttachments(page, size, labelSelector, fieldSelector, sort, ungrouped, keyword, options); const localVarAxiosArgs = await localVarAxiosParamCreator.searchAttachments(page, size, labelSelector, fieldSelector, sort, ungrouped, keyword, accepts, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0; const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1AttachmentApi.searchAttachments']?.[localVarOperationServerIndex]?.url; const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1AttachmentApi.searchAttachments']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
@ -222,7 +228,7 @@ export const ApiConsoleHaloRunV1alpha1AttachmentApiFactory = function (configura
* @throws {RequiredError} * @throws {RequiredError}
*/ */
searchAttachments(requestParameters: ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise<AttachmentList> { searchAttachments(requestParameters: ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise<AttachmentList> {
return localVarFp.searchAttachments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.ungrouped, requestParameters.keyword, options).then((request) => request(axios, basePath)); return localVarFp.searchAttachments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.ungrouped, requestParameters.keyword, requestParameters.accepts, options).then((request) => request(axios, basePath));
}, },
/** /**
* *
@ -290,6 +296,13 @@ export interface ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments * @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments
*/ */
readonly keyword?: string readonly keyword?: string
/**
* Acceptable media types.
* @type {Array<string>}
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachments
*/
readonly accepts?: Array<string>
} }
/** /**
@ -335,7 +348,7 @@ export class ApiConsoleHaloRunV1alpha1AttachmentApi extends BaseAPI {
* @memberof ApiConsoleHaloRunV1alpha1AttachmentApi * @memberof ApiConsoleHaloRunV1alpha1AttachmentApi
*/ */
public searchAttachments(requestParameters: ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest = {}, options?: RawAxiosRequestConfig) { public searchAttachments(requestParameters: ApiConsoleHaloRunV1alpha1AttachmentApiSearchAttachmentsRequest = {}, options?: RawAxiosRequestConfig) {
return ApiConsoleHaloRunV1alpha1AttachmentApiFp(this.configuration).searchAttachments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.ungrouped, requestParameters.keyword, options).then((request) => request(this.axios, this.basePath)); return ApiConsoleHaloRunV1alpha1AttachmentApiFp(this.configuration).searchAttachments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.ungrouped, requestParameters.keyword, requestParameters.accepts, options).then((request) => request(this.axios, this.basePath));
} }
/** /**

View File

@ -569,6 +569,13 @@ core:
items: items:
grid: Grid Mode grid: Grid Mode
list: List Mode list: List Mode
accept:
label: Type
items:
image: Image
audio: Audio
video: Video
file: File
detail_modal: detail_modal:
title: "Attachment: {display_name}" title: "Attachment: {display_name}"
fields: fields:

View File

@ -9,7 +9,9 @@ core:
operations: operations:
submit: submit:
toast_success: Inicio de sesión exitoso toast_success: Inicio de sesión exitoso
toast_failed: Error en el inicio de sesión, nombre de usuario o contraseña incorrectos toast_failed: >-
Error en el inicio de sesión, nombre de usuario o contraseña
incorrectos
toast_csrf: Token CSRF no válido, por favor inténtalo de nuevo toast_csrf: Token CSRF no válido, por favor inténtalo de nuevo
signup: signup:
label: No tienes una cuenta label: No tienes una cuenta
@ -40,7 +42,9 @@ core:
title: Vinculación de cuentas title: Vinculación de cuentas
common: common:
toast: toast:
mounted: El método de inicio de sesión actual no está vinculado a una cuenta. Por favor, vincula o registra una nueva cuenta primero. mounted: >-
El método de inicio de sesión actual no está vinculado a una cuenta.
Por favor, vincula o registra una nueva cuenta primero.
operations: operations:
login_and_bind: login_and_bind:
button: Iniciar sesión y vincular button: Iniciar sesión y vincular
@ -48,7 +52,9 @@ core:
button: Registrarse y vincular button: Registrarse y vincular
bind: bind:
toast_success: Vinculación exitosa toast_success: Vinculación exitosa
toast_failed: Vinculación fallida, no se encontró ningún método de inicio de sesión habilitado. toast_failed: >-
Vinculación fallida, no se encontró ningún método de inicio de sesión
habilitado.
sidebar: sidebar:
search: search:
placeholder: Buscar placeholder: Buscar
@ -124,7 +130,9 @@ core:
refresh_search_engine: refresh_search_engine:
title: Actualizar Motor de Búsqueda title: Actualizar Motor de Búsqueda
dialog_title: ¿Deseas actualizar el índice del motor de búsqueda? dialog_title: ¿Deseas actualizar el índice del motor de búsqueda?
dialog_content: Esta operación recreará los índices del motor de búsqueda para todas las publicaciones publicadas. dialog_content: >-
Esta operación recreará los índices del motor de búsqueda para
todas las publicaciones publicadas.
success_message: Índice del motor de búsqueda actualizado exitosamente. success_message: Índice del motor de búsqueda actualizado exitosamente.
evict_page_cache: evict_page_cache:
title: Actualizar Caché de Página title: Actualizar Caché de Página
@ -149,10 +157,14 @@ core:
operations: operations:
delete: delete:
title: ¿Estás seguro de que deseas eliminar esta publicación? title: ¿Estás seguro de que deseas eliminar esta publicación?
description: Esta operación moverá la publicación a la papelera de reciclaje, y podrá ser restaurada desde la papelera de reciclaje posteriormente. description: >-
Esta operación moverá la publicación a la papelera de reciclaje, y
podrá ser restaurada desde la papelera de reciclaje posteriormente.
delete_in_batch: delete_in_batch:
title: ¿Estás seguro de que deseas eliminar las publicaciones seleccionadas? title: ¿Estás seguro de que deseas eliminar las publicaciones seleccionadas?
description: Esta operación moverá las publicaciones a la papelera de reciclaje, y podrán ser restauradas desde la papelera de reciclaje posteriormente. description: >-
Esta operación moverá las publicaciones a la papelera de reciclaje, y
podrán ser restauradas desde la papelera de reciclaje posteriormente.
filters: filters:
status: status:
items: items:
@ -198,7 +210,9 @@ core:
label: Título label: Título
slug: slug:
label: Slug label: Slug
help: Usualmente usado para generar el enlace permanente a las publicaciones help: >-
Usualmente usado para generar el enlace permanente a las
publicaciones
refresh_message: Regenerar slug basado en el título. refresh_message: Regenerar slug basado en el título.
categories: categories:
label: Categorías label: Categorías
@ -230,14 +244,20 @@ core:
title: ¿Estás seguro de que deseas eliminar permanentemente esta publicación? title: ¿Estás seguro de que deseas eliminar permanentemente esta publicación?
description: Después de la eliminación, no será posible recuperarla. description: Después de la eliminación, no será posible recuperarla.
delete_in_batch: delete_in_batch:
title: ¿Estás seguro de que deseas eliminar permanentemente las publicaciones seleccionadas? title: >-
¿Estás seguro de que deseas eliminar permanentemente las publicaciones
seleccionadas?
description: Después de la eliminación, no será posible recuperarlas. description: Después de la eliminación, no será posible recuperarlas.
recovery: recovery:
title: ¿Quieres restaurar esta publicación? title: ¿Quieres restaurar esta publicación?
description: Esta operación restaurará la publicación a su estado antes de la eliminación. description: >-
Esta operación restaurará la publicación a su estado antes de la
eliminación.
recovery_in_batch: recovery_in_batch:
title: ¿Estás seguro de que deseas restaurar las publicaciones seleccionadas? title: ¿Estás seguro de que deseas restaurar las publicaciones seleccionadas?
description: Esta operación restaurará las publicaciones a su estado antes de la eliminación. description: >-
Esta operación restaurará las publicaciones a su estado antes de la
eliminación.
post_editor: post_editor:
title: Edición de publicación title: Edición de publicación
untitled: Publicación sin título untitled: Publicación sin título
@ -251,7 +271,9 @@ core:
operations: operations:
delete: delete:
title: ¿Estás seguro de que deseas eliminar esta etiqueta? title: ¿Estás seguro de que deseas eliminar esta etiqueta?
description: Después de eliminar esta etiqueta, se eliminará la asociación con el artículo correspondiente. Esta operación no se puede deshacer. description: >-
Después de eliminar esta etiqueta, se eliminará la asociación con el
artículo correspondiente. Esta operación no se puede deshacer.
editing_modal: editing_modal:
titles: titles:
update: Actualizar etiqueta de publicación update: Actualizar etiqueta de publicación
@ -264,7 +286,9 @@ core:
label: Nombre para mostrar label: Nombre para mostrar
slug: slug:
label: Slug label: Slug
help: Usualmente utilizado para generar el enlace permanente de las etiquetas help: >-
Usualmente utilizado para generar el enlace permanente de las
etiquetas
refresh_message: Regenerar slug basado en el nombre para mostrar. refresh_message: Regenerar slug basado en el nombre para mostrar.
color: color:
label: Color label: Color
@ -282,7 +306,9 @@ core:
operations: operations:
delete: delete:
title: ¿Estás seguro de que deseas eliminar esta categoría? title: ¿Estás seguro de que deseas eliminar esta categoría?
description: Después de eliminar esta categoría, se eliminará la asociación con los artículos correspondientes. Esta operación no se puede deshacer. description: >-
Después de eliminar esta categoría, se eliminará la asociación con los
artículos correspondientes. Esta operación no se puede deshacer.
add_sub_category: add_sub_category:
button: Agregar subcategoría button: Agregar subcategoría
editing_modal: editing_modal:
@ -299,7 +325,9 @@ core:
label: Nombre para mostrar label: Nombre para mostrar
slug: slug:
label: Slug label: Slug
help: Usualmente utilizado para generar el enlace permanente de las categorías help: >-
Usualmente utilizado para generar el enlace permanente de las
categorías
refresh_message: Regenerar slug basado en el nombre para mostrar. refresh_message: Regenerar slug basado en el nombre para mostrar.
template: template:
label: Plantilla personalizada label: Plantilla personalizada
@ -319,10 +347,14 @@ core:
operations: operations:
delete: delete:
title: ¿Estás seguro de que deseas eliminar esta página? title: ¿Estás seguro de que deseas eliminar esta página?
description: Esta operación moverá la página a la papelera de reciclaje, y podrá ser restaurada desde la papelera de reciclaje posteriormente. description: >-
Esta operación moverá la página a la papelera de reciclaje, y podrá
ser restaurada desde la papelera de reciclaje posteriormente.
delete_in_batch: delete_in_batch:
title: ¿Estás seguro de que deseas eliminar las páginas seleccionadas? title: ¿Estás seguro de que deseas eliminar las páginas seleccionadas?
description: Esta operación moverá las páginas a la papelera de reciclaje, y podrá ser restaurada desde la papelera de reciclaje posteriormente. description: >-
Esta operación moverá las páginas a la papelera de reciclaje, y podrá
ser restaurada desde la papelera de reciclaje posteriormente.
filters: filters:
status: status:
items: items:
@ -358,7 +390,9 @@ core:
label: Título label: Título
slug: slug:
label: Slug label: Slug
help: Usualmente utilizado para generar el enlace permanente de las páginas help: >-
Usualmente utilizado para generar el enlace permanente de las
páginas
refresh_message: Regenerar slug basado en el título. refresh_message: Regenerar slug basado en el título.
auto_generate_excerpt: auto_generate_excerpt:
label: Generar Extracto Automáticamente label: Generar Extracto Automáticamente
@ -386,14 +420,20 @@ core:
title: ¿Estás seguro de que deseas eliminar permanentemente esta página? title: ¿Estás seguro de que deseas eliminar permanentemente esta página?
description: Después de la eliminación, no será posible recuperarla. description: Después de la eliminación, no será posible recuperarla.
delete_in_batch: delete_in_batch:
title: ¿Estás seguro de que deseas eliminar permanentemente las páginas seleccionadas? title: >-
¿Estás seguro de que deseas eliminar permanentemente las páginas
seleccionadas?
description: Después de la eliminación, no será posible recuperarlas. description: Después de la eliminación, no será posible recuperarlas.
recovery: recovery:
title: ¿Quieres restaurar esta página? title: ¿Quieres restaurar esta página?
description: Esta operación restaurará la página a su estado antes de la eliminación. description: >-
Esta operación restaurará la página a su estado antes de la
eliminación.
recovery_in_batch: recovery_in_batch:
title: ¿Estás seguro de que deseas restaurar las páginas seleccionadas? title: ¿Estás seguro de que deseas restaurar las páginas seleccionadas?
description: Esta operación restaurará las páginas a su estado antes de la eliminación. description: >-
Esta operación restaurará las páginas a su estado antes de la
eliminación.
page_editor: page_editor:
title: Edición de Página title: Edición de Página
untitled: Página Sin Título untitled: Página Sin Título
@ -409,16 +449,24 @@ core:
operations: operations:
delete_comment: delete_comment:
title: ¿Estás seguro de que deseas eliminar este comentario? title: ¿Estás seguro de que deseas eliminar este comentario?
description: Todas las respuestas bajo los comentarios se eliminarán al mismo tiempo, y esta operación no se puede deshacer. description: >-
Todas las respuestas bajo los comentarios se eliminarán al mismo
tiempo, y esta operación no se puede deshacer.
delete_comment_in_batch: delete_comment_in_batch:
title: ¿Estás seguro de que deseas eliminar los comentarios seleccionados? title: ¿Estás seguro de que deseas eliminar los comentarios seleccionados?
description: Todas las respuestas bajo los comentarios se eliminarán al mismo tiempo, y esta operación no se puede deshacer. description: >-
Todas las respuestas bajo los comentarios se eliminarán al mismo
tiempo, y esta operación no se puede deshacer.
approve_comment_in_batch: approve_comment_in_batch:
button: Aprobar button: Aprobar
title: ¿Estás seguro de que deseas aprobar los comentarios seleccionados para su revisión? title: >-
¿Estás seguro de que deseas aprobar los comentarios seleccionados para
su revisión?
approve_applies_in_batch: approve_applies_in_batch:
button: Aprobar todas las respuestas button: Aprobar todas las respuestas
title: ¿Estás seguro de que deseas aprobar todas las respuestas a este comentario para su revisión? title: >-
¿Estás seguro de que deseas aprobar todas las respuestas a este
comentario para su revisión?
delete_reply: delete_reply:
title: ¿Estás seguro de que deseas eliminar esta respuesta? title: ¿Estás seguro de que deseas eliminar esta respuesta?
approve_reply: approve_reply:
@ -467,7 +515,9 @@ core:
storage_policies: Políticas de Almacenamiento storage_policies: Políticas de Almacenamiento
empty: empty:
title: No hay adjuntos en el grupo actual. title: No hay adjuntos en el grupo actual.
message: El grupo actual no tiene adjuntos, puedes intentar actualizar o cargar adjuntos. message: >-
El grupo actual no tiene adjuntos, puedes intentar actualizar o cargar
adjuntos.
actions: actions:
upload: Cargar Adjunto upload: Cargar Adjunto
operations: operations:
@ -497,6 +547,13 @@ core:
items: items:
grid: Modo Cuadrícula grid: Modo Cuadrícula
list: Modo Lista list: Modo Lista
accept:
label: Tipo
items:
image: Imagen
audio: Audio
video: Video
file: Archivo
detail_modal: detail_modal:
title: "Adjunto: {display_name}" title: "Adjunto: {display_name}"
fields: fields:
@ -530,18 +587,26 @@ core:
delete: delete:
button: Y mover adjunto a sin grupo button: Y mover adjunto a sin grupo
title: ¿Estás seguro de que deseas eliminar este grupo? title: ¿Estás seguro de que deseas eliminar este grupo?
description: El grupo se eliminará, y los adjuntos bajo el grupo se moverán a sin grupo. Esta operación no se puede deshacer. description: >-
El grupo se eliminará, y los adjuntos bajo el grupo se moverán a sin
grupo. Esta operación no se puede deshacer.
toast_success: Eliminación exitosa, {total} adjuntos se han movido a sin grupo toast_success: Eliminación exitosa, {total} adjuntos se han movido a sin grupo
delete_with_attachments: delete_with_attachments:
button: También eliminar adjuntos button: También eliminar adjuntos
title: ¿Estás seguro de que deseas eliminar este grupo? title: ¿Estás seguro de que deseas eliminar este grupo?
description: Al eliminar el grupo y todos los adjuntos dentro de él, esta acción no se puede deshacer. description: >-
toast_success: Eliminación exitosa, {total} adjuntos se han eliminado simultáneamente Al eliminar el grupo y todos los adjuntos dentro de él, esta acción
no se puede deshacer.
toast_success: >-
Eliminación exitosa, {total} adjuntos se han eliminado
simultáneamente
policies_modal: policies_modal:
title: Políticas de Almacenamiento title: Políticas de Almacenamiento
empty: empty:
title: Actualmente no hay estrategias de almacenamiento disponibles. title: Actualmente no hay estrategias de almacenamiento disponibles.
message: No hay políticas de almacenamiento disponibles en este momento. Puedes intentar actualizar o crear una nueva política. message: >-
No hay políticas de almacenamiento disponibles en este momento. Puedes
intentar actualizar o crear una nueva política.
operations: operations:
delete: delete:
title: ¿Estás seguro de que deseas eliminar esta política? title: ¿Estás seguro de que deseas eliminar esta política?
@ -565,7 +630,9 @@ core:
label: "Seleccionar política de almacenamiento:" label: "Seleccionar política de almacenamiento:"
empty: empty:
title: Sin política de almacenamiento title: Sin política de almacenamiento
description: Antes de cargar, es necesario crear una nueva política de almacenamiento. description: >-
Antes de cargar, es necesario crear una nueva política de
almacenamiento.
not_select: Por favor, selecciona una política de almacenamiento primero not_select: Por favor, selecciona una política de almacenamiento primero
select_modal: select_modal:
title: Seleccionar adjunto title: Seleccionar adjunto
@ -574,7 +641,7 @@ core:
label: Adjuntos label: Adjuntos
operations: operations:
select: select:
result: "({count} elementos seleccionados)" result: ({count} elementos seleccionados)
theme: theme:
title: Temas title: Temas
common: common:
@ -594,22 +661,35 @@ core:
title: ¿Estás seguro de activar el tema actual? title: ¿Estás seguro de activar el tema actual?
toast_success: Tema activado exitosamente toast_success: Tema activado exitosamente
reset: reset:
title: ¿Estás seguro de que deseas restablecer todas las configuraciones del tema? title: >-
description: Esta operación eliminará la configuración guardada y la restablecerá a los ajustes predeterminados. ¿Estás seguro de que deseas restablecer todas las configuraciones del
tema?
description: >-
Esta operación eliminará la configuración guardada y la restablecerá a
los ajustes predeterminados.
toast_success: Configuración restablecida exitosamente toast_success: Configuración restablecida exitosamente
reload: reload:
button: Recargar button: Recargar
title: ¿Estás seguro de que deseas recargar todas las configuraciones del tema? title: >-
description: Esta operación solo recargará la configuración del tema y la definición del formulario de ajustes, y no eliminará ninguna configuración guardada. ¿Estás seguro de que deseas recargar todas las configuraciones del
tema?
description: >-
Esta operación solo recargará la configuración del tema y la
definición del formulario de ajustes, y no eliminará ninguna
configuración guardada.
toast_success: Recarga de configuración exitosa toast_success: Recarga de configuración exitosa
uninstall: uninstall:
title: ¿Estás seguro de que deseas desinstalar este tema? title: ¿Estás seguro de que deseas desinstalar este tema?
uninstall_and_delete_config: uninstall_and_delete_config:
button: Desinstalar y eliminar configuración button: Desinstalar y eliminar configuración
title: ¿Estás seguro de que deseas desinstalar este tema y su configuración correspondiente? title: >-
¿Estás seguro de que deseas desinstalar este tema y su configuración
correspondiente?
remote_download: remote_download:
title: Se ha detectado una dirección de descarga remota, ¿deseas descargar? title: Se ha detectado una dirección de descarga remota, ¿deseas descargar?
description: "Por favor, verifica cuidadosamente si esta dirección es confiable: {url}" description: >-
Por favor, verifica cuidadosamente si esta dirección es confiable:
{url}
upload_modal: upload_modal:
titles: titles:
install: Instalar tema install: Instalar tema
@ -633,7 +713,9 @@ core:
not_installed: No Instalados not_installed: No Instalados
empty: empty:
title: No hay temas instalados actualmente. title: No hay temas instalados actualmente.
message: No hay temas instalados actualmente, puedes intentar actualizar o instalar un nuevo tema. message: >-
No hay temas instalados actualmente, puedes intentar actualizar o
instalar un nuevo tema.
not_installed_empty: not_installed_empty:
title: No hay temas actualmente no instalados. title: No hay temas actualmente no instalados.
preview_model: preview_model:
@ -668,11 +750,15 @@ core:
button: Establecer como menú principal button: Establecer como menú principal
toast_success: Configuración exitosa toast_success: Configuración exitosa
delete_menu: delete_menu:
title: "¿Estás seguro de que deseas eliminar este menú?" title: ¿Estás seguro de que deseas eliminar este menú?
description: Todos los elementos de menú de este menú se eliminarán al mismo tiempo y esta operación no se puede deshacer. description: >-
Todos los elementos de menú de este menú se eliminarán al mismo tiempo
y esta operación no se puede deshacer.
delete_menu_item: delete_menu_item:
title: "¿Estás seguro de que deseas eliminar este elemento de menú?" title: ¿Estás seguro de que deseas eliminar este elemento de menú?
description: Todos los subelementos de menú se eliminarán al mismo tiempo y no se pueden restaurar después de la eliminación. description: >-
Todos los subelementos de menú se eliminarán al mismo tiempo y no se
pueden restaurar después de la eliminación.
add_sub_menu_item: add_sub_menu_item:
button: Agregar subelemento de menú button: Agregar subelemento de menú
list: list:
@ -699,7 +785,7 @@ core:
placeholder: Selecciona el elemento de menú padre placeholder: Selecciona el elemento de menú padre
ref_kind: ref_kind:
label: Tipo label: Tipo
placeholder: "Por favor selecciona {label}" placeholder: Por favor selecciona {label}
options: options:
custom: Personalizado custom: Personalizado
post: Publicación post: Publicación
@ -723,21 +809,29 @@ 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?
uninstall_and_delete_config: 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_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: change_status:
active_title: Are you sure you want to active this plugin? active_title: Are you sure you want to active this plugin?
inactive_title: Are you sure you want to inactive this plugin? inactive_title: Are you sure you want to inactive this plugin?
@ -772,7 +866,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:
@ -801,7 +897,9 @@ core:
identity_authentication: Autenticación de Identidad identity_authentication: Autenticación de Identidad
empty: empty:
title: Actualmente no hay usuarios que cumplan con los criterios de filtrado. title: Actualmente no hay usuarios que cumplan con los criterios de filtrado.
message: No hay usuarios que coincidan con los criterios de filtrado en este momento. Puedes intentar actualizar o crear un nuevo usuario. message: >-
No hay usuarios que coincidan con los criterios de filtrado en este
momento. Puedes intentar actualizar o crear un nuevo usuario.
operations: operations:
delete: delete:
title: ¿Estás seguro de que deseas eliminar a este usuario? title: ¿Estás seguro de que deseas eliminar a este usuario?
@ -869,7 +967,9 @@ core:
button: Vincular button: Vincular
unbind: unbind:
button: Desvincular button: Desvincular
title: ¿Estás seguro de que deseas desvincular el método de inicio de sesión para {display_name}? title: >-
¿Estás seguro de que deseas desvincular el método de inicio de
sesión para {display_name}?
fields: fields:
display_name: Nombre para mostrar display_name: Nombre para mostrar
username: Nombre de usuario username: Nombre de usuario
@ -906,7 +1006,9 @@ core:
operations: operations:
delete: delete:
title: ¿Estás seguro de que deseas eliminar este rol? title: ¿Estás seguro de que deseas eliminar este rol?
description: Una vez eliminado el rol, se eliminarán las asignaciones de rol de los usuarios asociados y esta operación no se puede deshacer. description: >-
Una vez eliminado el rol, se eliminarán las asignaciones de rol de los
usuarios asociados y esta operación no se puede deshacer.
create_based_on_this_role: create_based_on_this_role:
button: Crear basado en este rol button: Crear basado en este rol
detail: detail:
@ -923,7 +1025,9 @@ core:
creation_time: Fecha de creación creation_time: Fecha de creación
permissions_detail: permissions_detail:
system_reserved_alert: system_reserved_alert:
description: El rol reservado del sistema no admite modificaciones. Se recomienda crear un nuevo rol basado en este. description: >-
El rol reservado del sistema no admite modificaciones. Se recomienda
crear un nuevo rol basado en este.
editing_modal: editing_modal:
titles: titles:
create: Crear rol create: Crear rol
@ -940,11 +1044,17 @@ core:
setting: Configuración setting: Configuración
operations: operations:
enable: enable:
title: ¿Estás seguro de que deseas habilitar este método de autenticación de identidad? title: >-
¿Estás seguro de que deseas habilitar este método de autenticación de
identidad?
disable: disable:
title: ¿Estás seguro de que deseas deshabilitar este método de autenticación de identidad? title: >-
¿Estás seguro de que deseas deshabilitar este método de autenticación
de identidad?
disable_privileged: disable_privileged:
tooltip: El método de autenticación reservado por el sistema no se puede deshabilitar tooltip: >-
El método de autenticación reservado por el sistema no se puede
deshabilitar
detail: detail:
title: Detalle de la autenticación de identidad title: Detalle de la autenticación de identidad
fields: fields:
@ -985,7 +1095,11 @@ core:
database: "Base de datos: {database}" database: "Base de datos: {database}"
os: "Sistema operativo: {os}" os: "Sistema operativo: {os}"
alert: alert:
external_url_invalid: La URL de acceso externo detectada no coincide con la URL de acceso actual, lo que podría causar que algunos enlaces no se redirijan correctamente. Por favor, verifica la configuración de la URL de acceso externo. external_url_invalid: >-
La URL de acceso externo detectada no coincide con la URL de acceso
actual, lo que podría causar que algunos enlaces no se redirijan
correctamente. Por favor, verifica la configuración de la URL de acceso
externo.
backup: backup:
title: Copia de Seguridad y Restauración title: Copia de Seguridad y Restauración
tabs: tabs:
@ -998,14 +1112,19 @@ core:
create: create:
button: Crear copia de seguridad button: Crear copia de seguridad
title: Crear copia de seguridad title: Crear copia de seguridad
description: ¿Estás seguro de que deseas crear una copia de seguridad? Esta operación puede tomar un tiempo. description: >-
¿Estás seguro de que deseas crear una copia de seguridad? Esta
operación puede tomar un tiempo.
toast_success: Solicitud de creación de copia de seguridad realizada toast_success: Solicitud de creación de copia de seguridad realizada
delete: delete:
title: Eliminar copia de seguridad title: Eliminar copia de seguridad
description: ¿Estás seguro de que deseas eliminar esta copia de seguridad? description: ¿Estás seguro de que deseas eliminar esta copia de seguridad?
restore: restore:
title: Restauración exitosa title: Restauración exitosa
description: Después de una restauración exitosa, necesitas reiniciar Halo para cargar los recursos del sistema normalmente. Después de hacer clic en OK, reiniciaremos automáticamente Halo. description: >-
Después de una restauración exitosa, necesitas reiniciar Halo para
cargar los recursos del sistema normalmente. Después de hacer clic en
OK, reiniciaremos automáticamente Halo.
restart: restart:
toast_success: Solicitud de reinicio realizada toast_success: Solicitud de reinicio realizada
list: list:
@ -1018,9 +1137,15 @@ core:
expiresAt: Expira el {expiresAt} expiresAt: Expira el {expiresAt}
restore: restore:
tips: tips:
first: 1. El proceso de restauración puede tomar un tiempo, por favor no actualices la página durante este período. first: >-
second: 2. Durante el proceso de restauración, aunque los datos existentes no se eliminarán, si hay un conflicto, los datos se sobrescribirán. 1. El proceso de restauración puede tomar un tiempo, por favor no
third: 3. Después de completar la restauración, necesitas reiniciar Halo para cargar los recursos del sistema normalmente. actualices la página durante este período.
second: >-
2. Durante el proceso de restauración, aunque los datos existentes no
se eliminarán, si hay un conflicto, los datos se sobrescribirán.
third: >-
3. Después de completar la restauración, necesitas reiniciar Halo para
cargar los recursos del sistema normalmente.
complete: Restauración completada, esperando reinicio... complete: Restauración completada, esperando reinicio...
start: Iniciar Restauración start: Iniciar Restauración
exception: exception:
@ -1132,7 +1257,7 @@ core:
extensions: extensions:
placeholder: placeholder:
options: options:
placeholder: "Ingresa / para seleccionar el tipo de entrada." placeholder: Ingresa / para seleccionar el tipo de entrada.
toolbox: toolbox:
attachment: Adjunto attachment: Adjunto
global_search: global_search:
@ -1158,7 +1283,9 @@ core:
social_auth_providers: social_auth_providers:
title: Inicio de sesión de terceros title: Inicio de sesión de terceros
app_download_alert: app_download_alert:
description: "Los temas y complementos para Halo se pueden descargar en las siguientes direcciones:" description: >-
Los temas y complementos para Halo se pueden descargar en las siguientes
direcciones:
sources: sources:
app_store: "Tienda de aplicaciones oficial: {url}" app_store: "Tienda de aplicaciones oficial: {url}"
github: "GitHub: {url}" github: "GitHub: {url}"
@ -1167,9 +1294,9 @@ core:
toast_recovered: Contenido no guardado recuperado de la caché toast_recovered: Contenido no guardado recuperado de la caché
formkit: formkit:
category_select: category_select:
creation_label: "Crear categoría {text}" creation_label: Crear categoría {text}
tag_select: tag_select:
creation_label: "Crear etiqueta {text}" creation_label: Crear etiqueta {text}
validation: validation:
trim: Por favor, elimina los espacios al inicio y al final trim: Por favor, elimina los espacios al inicio y al final
common: common:
@ -1206,7 +1333,7 @@ core:
detail: Detalle detail: Detalle
radio: radio:
"yes": "yes":
"no": No "no": "No"
select: select:
public: Público public: Público
private: Privado private: Privado
@ -1228,10 +1355,10 @@ core:
copy_success: Copiado exitosamente copy_success: Copiado exitosamente
operation_failed: Fallo en la operación operation_failed: Fallo en la operación
download_failed: Fallo en la descarga download_failed: Fallo en la descarga
save_failed_and_retry: "Fallo al guardar, por favor intenta nuevamente" save_failed_and_retry: Fallo al guardar, por favor intenta nuevamente
publish_failed_and_retry: "Fallo al publicar, por favor intenta nuevamente" publish_failed_and_retry: Fallo al publicar, por favor intenta nuevamente
network_error: "Error de red, por favor verifica tu conexión" network_error: Error de red, por favor verifica tu conexión
login_expired: "Sesión expirada, por favor inicia sesión nuevamente" login_expired: Sesión expirada, por favor inicia sesión nuevamente
forbidden: Acceso denegado forbidden: Acceso denegado
not_found: Recurso no encontrado not_found: Recurso no encontrado
server_internal_error: Error interno del servidor server_internal_error: Error interno del servidor
@ -1242,7 +1369,9 @@ core:
warning: Advertencia warning: Advertencia
descriptions: descriptions:
cannot_be_recovered: Esta operación es irreversible. cannot_be_recovered: Esta operación es irreversible.
editor_not_found: No se encontró ningún editor que coincida con el formato {raw_type}. Por favor verifica si el complemento del editor ha sido instalado. editor_not_found: >-
No se encontró ningún editor que coincida con el formato {raw_type}.
Por favor verifica si el complemento del editor ha sido instalado.
filters: filters:
results: results:
keyword: "Palabra clave: {keyword}" keyword: "Palabra clave: {keyword}"

View File

@ -557,6 +557,13 @@ core:
items: items:
grid: 网格模式 grid: 网格模式
list: 列表模式 list: 列表模式
accept:
label: 类型
items:
image: 图片
audio: 音频
video: 视频
file: 文件
detail_modal: detail_modal:
title: 附件:{display_name} title: 附件:{display_name}
fields: fields:

View File

@ -537,6 +537,13 @@ core:
items: items:
grid: 網格模式 grid: 網格模式
list: 列表模式 list: 列表模式
accept:
label: 類型
items:
image: 圖片
audio: 音頻
video: 視頻
file: 文件
detail_modal: detail_modal:
title: 附件:{display_name} title: 附件:{display_name}
fields: fields: