From 2a3b5c0b8f511b3d50b8553172b26a8da4124af3 Mon Sep 17 00:00:00 2001 From: teable-bot Date: Fri, 9 Jan 2026 07:26:40 +0000 Subject: [PATCH] [sync] Merge pull request #1013 from teableio/fix/conditional-lookup-multivalue Synced from teableio/teable-ee@c08a4ef --- apps/nestjs-backend/package.json | 24 +- .../field-converting.service.ts | 44 ++- .../field-supplement.service.ts | 2 + .../field/open-api/field-open-api.service.ts | 25 +- .../notification/notification.service.ts | 16 +- .../record/query-builder/field-cte-visitor.ts | 31 +- .../query-builder/field-select-visitor.ts | 32 +- .../open-api/setting-open-api.controller.ts | 1 + .../src/types/i18n.generated.ts | 315 ++++++++++++++---- apps/nextjs-app/package.json | 4 +- .../public/images/layout/error-dark.png | Bin 0 -> 11463 bytes .../public/images/layout/error-light.png | Bin 0 -> 11785 bytes .../public/images/layout/not-found-dark.png | Bin 0 -> 16475 bytes .../public/images/layout/not-found-light.png | Bin 0 -> 16687 bytes .../public/images/layout/permission-dark.png | Bin 0 -> 11537 bytes .../public/images/layout/permission-light.png | Bin 0 -> 11609 bytes .../public/images/layout/upgrade-dark.png | Bin 0 -> 14273 bytes .../public/images/layout/upgrade-light.png | Bin 0 -> 14407 bytes .../app/blocks/admin/setting/SettingPage.tsx | 5 +- .../blocks/base/base-side-bar/BaseSideBar.tsx | 14 +- .../base-side-bar/BaseSidebarHeaderLeft.tsx | 216 +++++++++--- .../blocks/base/base-side-bar/QuickAction.tsx | 4 +- .../space-setting/SpaceInnerSettingModal.tsx | 42 ++- .../space/component/BaseListTrigger.tsx | 58 ---- .../space/component/SpaceActionTrigger.tsx | 29 +- .../space-side-bar/SpaceInnerSideBar.tsx | 43 ++- .../space/space-side-bar/SpaceSwitcher.tsx | 201 +++++++---- .../features/app/components/SideBarFooter.tsx | 4 +- .../features/app/components/billing/Level.tsx | 9 +- .../field-setting/SelectFieldType.tsx | 4 +- .../useUpdateConditionalLookupOptions.ts | 3 +- .../notifications/NotificationsManage.tsx | 2 +- .../app/components/sidebar/Sidebar.tsx | 199 ++++++----- .../app/components/sidebar/useSidebarStore.ts | 23 +- .../app/components/space/SpaceActionBar.tsx | 3 +- .../app/components/space/SpaceAvatar.tsx | 29 +- .../components/toggle-side-bar/constant.ts | 2 + .../app/hooks/useBillingLevelConfig.ts | 11 +- .../src/features/app/hooks/useSetting.ts | 2 + .../src/features/app/layouts/BaseLayout.tsx | 2 +- .../app/layouts/TemplateBaseLayout.tsx | 2 +- .../src/features/system/pages/ErrorPage.tsx | 46 ++- .../features/system/pages/ForbiddenPage.tsx | 34 +- .../system/pages/IllustrationPage.tsx | 63 ++++ .../features/system/pages/NotFoundPage.tsx | 34 +- .../features/system/pages/PaymentRequired.tsx | 42 ++- .../src/features/system/pages/index.ts | 2 + .../common-i18n/src/locales/de/common.json | 156 +++++++-- packages/common-i18n/src/locales/de/sdk.json | 32 +- .../common-i18n/src/locales/de/space.json | 4 + .../common-i18n/src/locales/de/system.json | 17 +- .../common-i18n/src/locales/en/common.json | 113 ++++++- packages/common-i18n/src/locales/en/sdk.json | 22 ++ .../common-i18n/src/locales/en/space.json | 4 + .../common-i18n/src/locales/en/system.json | 15 +- .../common-i18n/src/locales/es/common.json | 186 +++++++++-- packages/common-i18n/src/locales/es/sdk.json | 22 ++ .../common-i18n/src/locales/es/space.json | 4 + .../common-i18n/src/locales/es/system.json | 15 +- .../common-i18n/src/locales/fr/common.json | 206 ++++++++++-- packages/common-i18n/src/locales/fr/sdk.json | 22 ++ .../common-i18n/src/locales/fr/space.json | 4 + .../common-i18n/src/locales/fr/system.json | 15 +- .../common-i18n/src/locales/it/common.json | 113 +++++-- packages/common-i18n/src/locales/it/sdk.json | 22 ++ .../common-i18n/src/locales/it/space.json | 4 + .../common-i18n/src/locales/it/system.json | 15 +- .../common-i18n/src/locales/ja/common.json | 128 ++++++- packages/common-i18n/src/locales/ja/sdk.json | 22 ++ .../common-i18n/src/locales/ja/space.json | 4 + .../common-i18n/src/locales/ja/system.json | 15 +- .../common-i18n/src/locales/ru/common.json | 71 +++- packages/common-i18n/src/locales/ru/sdk.json | 22 ++ .../common-i18n/src/locales/ru/space.json | 4 + .../common-i18n/src/locales/ru/system.json | 15 +- .../common-i18n/src/locales/tr/common.json | 89 ++++- packages/common-i18n/src/locales/tr/sdk.json | 22 ++ .../common-i18n/src/locales/tr/space.json | 4 + .../common-i18n/src/locales/tr/system.json | 15 +- .../common-i18n/src/locales/uk/common.json | 58 +++- packages/common-i18n/src/locales/uk/sdk.json | 22 ++ .../common-i18n/src/locales/uk/space.json | 4 + .../common-i18n/src/locales/uk/system.json | 17 +- .../common-i18n/src/locales/zh/common.json | 113 ++++++- packages/common-i18n/src/locales/zh/sdk.json | 22 ++ .../common-i18n/src/locales/zh/space.json | 4 + .../common-i18n/src/locales/zh/system.json | 17 +- .../common-i18n/src/locales/zh/table.json | 12 +- packages/icons/src/components/Coins.tsx | 18 + packages/icons/src/components/Credits.tsx | 24 ++ packages/icons/src/components/GiftPerson.tsx | 141 ++++++++ .../icons/src/components/GiftPersonDark.tsx | 176 ++++++++++ packages/icons/src/components/LinkedIn.tsx | 32 ++ packages/icons/src/components/ShieldUser.tsx | 18 + packages/icons/src/components/Token.tsx | 22 ++ packages/icons/src/index.ts | 9 +- .../openapi/src/admin/setting/get-public.ts | 1 + packages/openapi/src/admin/setting/get.ts | 1 + .../openapi/src/admin/setting/key.enum.ts | 1 + packages/openapi/src/admin/setting/update.ts | 1 + packages/sdk/src/config/local-storage-keys.ts | 2 + pnpm-lock.yaml | 28 +- 102 files changed, 3057 insertions(+), 710 deletions(-) create mode 100644 apps/nextjs-app/public/images/layout/error-dark.png create mode 100644 apps/nextjs-app/public/images/layout/error-light.png create mode 100644 apps/nextjs-app/public/images/layout/not-found-dark.png create mode 100644 apps/nextjs-app/public/images/layout/not-found-light.png create mode 100644 apps/nextjs-app/public/images/layout/permission-dark.png create mode 100644 apps/nextjs-app/public/images/layout/permission-light.png create mode 100644 apps/nextjs-app/public/images/layout/upgrade-dark.png create mode 100644 apps/nextjs-app/public/images/layout/upgrade-light.png delete mode 100644 apps/nextjs-app/src/features/app/blocks/space/component/BaseListTrigger.tsx create mode 100644 apps/nextjs-app/src/features/system/pages/IllustrationPage.tsx create mode 100644 packages/icons/src/components/Coins.tsx create mode 100644 packages/icons/src/components/Credits.tsx create mode 100644 packages/icons/src/components/GiftPerson.tsx create mode 100644 packages/icons/src/components/GiftPersonDark.tsx create mode 100644 packages/icons/src/components/LinkedIn.tsx create mode 100644 packages/icons/src/components/ShieldUser.tsx create mode 100644 packages/icons/src/components/Token.tsx diff --git a/apps/nestjs-backend/package.json b/apps/nestjs-backend/package.json index 2573e405ad..51d419ea55 100644 --- a/apps/nestjs-backend/package.json +++ b/apps/nestjs-backend/package.json @@ -118,17 +118,17 @@ "webpack": "5.91.0" }, "dependencies": { - "@ai-sdk/amazon-bedrock": "4.0.0-beta.97", - "@ai-sdk/anthropic": "3.0.0-beta.87", - "@ai-sdk/azure": "3.0.0-beta.102", - "@ai-sdk/cohere": "3.0.0-beta.52", - "@ai-sdk/deepseek": "2.0.0-beta.54", - "@ai-sdk/google": "3.0.0-beta.77", - "@ai-sdk/mistral": "3.0.0-beta.53", - "@ai-sdk/openai": "3.0.0-beta.100", - "@ai-sdk/openai-compatible": "2.0.0-beta.52", - "@ai-sdk/togetherai": "2.0.0-beta.53", - "@ai-sdk/xai": "3.0.0-beta.60", + "@ai-sdk/amazon-bedrock": "4.0.9", + "@ai-sdk/anthropic": "3.0.7", + "@ai-sdk/azure": "3.0.7", + "@ai-sdk/cohere": "3.0.4", + "@ai-sdk/deepseek": "2.0.4", + "@ai-sdk/google": "3.0.5", + "@ai-sdk/mistral": "3.0.5", + "@ai-sdk/openai": "3.0.7", + "@ai-sdk/openai-compatible": "2.0.4", + "@ai-sdk/togetherai": "2.0.4", + "@ai-sdk/xai": "3.0.10", "@aws-sdk/client-s3": "3.609.0", "@aws-sdk/lib-storage": "3.609.0", "@aws-sdk/s3-request-presigner": "3.609.0", @@ -172,7 +172,7 @@ "@teable/openapi": "workspace:^", "@teamwork/websocket-json-stream": "2.0.0", "@valibot/to-json-schema": "1.3.0", - "ai": "6.0.0-beta.156", + "ai": "6.0.14", "ajv": "8.12.0", "archiver": "7.0.1", "axios": "1.7.7", diff --git a/apps/nestjs-backend/src/features/field/field-calculate/field-converting.service.ts b/apps/nestjs-backend/src/features/field/field-calculate/field-converting.service.ts index 6ba4d0eea3..31f537719d 100644 --- a/apps/nestjs-backend/src/features/field/field-calculate/field-converting.service.ts +++ b/apps/nestjs-backend/src/features/field/field-calculate/field-converting.service.ts @@ -249,6 +249,41 @@ export class FieldConvertingService { return ops.filter(Boolean) as IOtOperation[]; } + /** + * Update conditional lookup field - validate dependencies and clear/set hasError + */ + private updateConditionalLookupField(field: IFieldInstance, fieldMap: IFieldMap): IOtOperation[] { + const ops: IOtOperation[] = []; + + // Get referenced field IDs from the conditional lookup configuration + const referencedFieldIds = this.fieldSupplementService + .getFieldReferenceIds(field) + .filter((id) => !!id && id !== field.id); + + // Check if any referenced field is missing or has error + const missingFields = referencedFieldIds.filter((id) => !fieldMap[id]); + const erroredFields = referencedFieldIds.filter((id) => fieldMap[id]?.hasError); + + const hasMissingDependency = missingFields.length > 0; + const hasErroredDependency = erroredFields.length > 0; + + if (hasMissingDependency || hasErroredDependency) { + const op = this.buildOpAndMutateField(field, 'hasError', true); + if (op) { + ops.push(op); + } + return ops; + } + + // Clear error if all dependencies are valid + const clearErrorOp = this.buildOpAndMutateField(field, 'hasError', null); + if (clearErrorOp) { + ops.push(clearErrorOp); + } + + return ops; + } + private updateConditionalRollupField( field: ConditionalRollupFieldDto, fieldMap: IFieldMap @@ -326,6 +361,7 @@ export class FieldConvertingService { private async generateReferenceFieldOps(fields: IFieldInstance[]) { const fieldIds = fields.map((field) => field.id); + const topoOrdersContext = await this.fieldCalculationService.getTopoOrdersContext(fieldIds); const { fieldId2TableId, directedGraph } = topoOrdersContext; const fieldMap = { ...topoOrdersContext.fieldMap, ...keyBy(fields, 'id') }; @@ -362,7 +398,12 @@ export class FieldConvertingService { const tableId = fieldId2TableId[curField.id]; if (curField.isLookup) { - pushOpsMap(tableId, curField.id, this.updateLookupField(curField, fieldMap)); + // For conditional lookup fields, use the dedicated update method + if (curField.isConditionalLookup) { + pushOpsMap(tableId, curField.id, this.updateConditionalLookupField(curField, fieldMap)); + } else { + pushOpsMap(tableId, curField.id, this.updateLookupField(curField, fieldMap)); + } } else if (curField.type === FieldType.Formula) { pushOpsMap(tableId, curField.id, this.updateFormulaField(curField, fieldMap)); } else if (curField.type === FieldType.Rollup) { @@ -1554,6 +1595,7 @@ export class FieldConvertingService { ); const newField = createFieldInstanceByVo(newFieldVo); + const modifiedOps = await this.generateModifiedOps(tableId, newField, oldField); // 2. collect changes effect by the supplement(link) field diff --git a/apps/nestjs-backend/src/features/field/field-calculate/field-supplement.service.ts b/apps/nestjs-backend/src/features/field/field-calculate/field-supplement.service.ts index 29024f9313..608f91f79c 100644 --- a/apps/nestjs-backend/src/features/field/field-calculate/field-supplement.service.ts +++ b/apps/nestjs-backend/src/features/field/field-calculate/field-supplement.service.ts @@ -1037,6 +1037,8 @@ export class FieldSupplementService { isComputed: true, cellValueType, dbFieldType: this.getDbFieldType(field.type, cellValueType, true), + // Clear hasError since we validated all required fields exist + hasError: undefined, }; } diff --git a/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts b/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts index be04c4d884..4d5ae0a096 100644 --- a/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts +++ b/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts @@ -239,7 +239,7 @@ export class FieldOpenApiService { return false; } - return this.validateFilterFieldReferences(tableId, foreignTableId, meta?.filter); + return await this.validateFilterFieldReferences(tableId, foreignTableId, meta?.filter); } private async isFieldConfigurationValid( @@ -552,7 +552,10 @@ export class FieldOpenApiService { return references.every((reference) => { const referenceField = resolveReferenceField(reference); - return referenceField ? isFieldReferenceComparable(baseField, referenceField) : false; + if (!referenceField) { + return false; + } + return isFieldReferenceComparable(baseField, referenceField); }); } @@ -568,20 +571,28 @@ export class FieldOpenApiService { private async markError(tableId: string, field: IFieldInstance, hasError: boolean) { if (hasError) { - !field.hasError && (await this.fieldService.markError(tableId, [field.id], true)); + if (!field.hasError) { + await this.fieldService.markError(tableId, [field.id], true); + } } else { - field.hasError && (await this.fieldService.markError(tableId, [field.id], false)); + if (field.hasError) { + await this.fieldService.markError(tableId, [field.id], false); + } } } private async checkAndUpdateError(tableId: string, field: IFieldInstance) { const fieldReferenceIds = this.fieldSupplementService.getFieldReferenceIds(field); + // Deduplicate field IDs since the same field can appear multiple times + // (e.g., as lookupFieldId and in filter) + const uniqueFieldReferenceIds = [...new Set(fieldReferenceIds)]; + const refFields = await this.prismaService.txClient().field.findMany({ - where: { id: { in: fieldReferenceIds }, deletedTime: null }, + where: { id: { in: uniqueFieldReferenceIds }, deletedTime: null }, select: { id: true }, }); - if (refFields.length !== fieldReferenceIds.length) { + if (refFields.length !== uniqueFieldReferenceIds.length) { await this.markError(tableId, field, true); return; } @@ -591,7 +602,7 @@ export class FieldOpenApiService { toFieldId: field.id, }, }); - const missingReferenceIds = fieldReferenceIds.filter( + const missingReferenceIds = uniqueFieldReferenceIds.filter( (refId) => !curReference.find((ref) => ref.fromFieldId === refId) ); diff --git a/apps/nestjs-backend/src/features/notification/notification.service.ts b/apps/nestjs-backend/src/features/notification/notification.service.ts index b5d582266d..e6488faef2 100644 --- a/apps/nestjs-backend/src/features/notification/notification.service.ts +++ b/apps/nestjs-backend/src/features/notification/notification.service.ts @@ -12,9 +12,8 @@ import { } from '@teable/core'; import type { Prisma } from '@teable/db-main-prisma'; import { PrismaService } from '@teable/db-main-prisma'; +import { MailTransporterType, MailType } from '@teable/openapi'; import { - MailTransporterType, - MailType, type IGetNotifyListQuery, type INotificationUnreadCountVo, type INotificationVo, @@ -48,12 +47,11 @@ export class NotificationService { private readonly i18n: I18nService ) {} - private async getUserLang(userId: string) { - const user = await this.userService.getUserById(userId); - return user?.lang ?? I18nContext.current()?.lang; + getUserLang(lang?: string | null) { + return lang ?? I18nContext.current()?.lang; } - private getMessage(text: string | ILocalization, lang?: string) { + getMessage(text: string | ILocalization, lang?: string) { return typeof text === 'string' ? text : (this.i18n.t(text.i18nKey, { @@ -65,7 +63,7 @@ export class NotificationService { /** * notification message i18n use common prefix, so we need to remove it to save db */ - private getMessageI18n(localization: string | ILocalization) { + getMessageI18n(localization: string | ILocalization) { return typeof localization === 'string' ? undefined : JSON.stringify({ @@ -251,7 +249,7 @@ export class NotificationService { this.sendNotifyBySocket(toUser.id, socketNotification); if (emailConfig && toUser.notifyMeta && toUser.notifyMeta.email) { - const lang = await this.getUserLang(toUserId); + const lang = this.getUserLang(toUser.lang); const emailOptions = await this.mailSenderService.htmlEmailOptions({ ...emailConfig, title: this.getMessage(emailConfig.title, lang), @@ -340,7 +338,7 @@ export class NotificationService { this.sendNotifyBySocket(toUser.id, socketNotification); if (emailConfig && toUser.notifyMeta && toUser.notifyMeta.email) { - const lang = await this.getUserLang(toUserId); + const lang = this.getUserLang(toUser.lang); const emailOptions = await this.mailSenderService.commonEmailOptions({ ...emailConfig, title: this.getMessage(emailConfig.title, lang), diff --git a/apps/nestjs-backend/src/features/record/query-builder/field-cte-visitor.ts b/apps/nestjs-backend/src/features/record/query-builder/field-cte-visitor.ts index 4948f2ec07..811d78e6ce 100644 --- a/apps/nestjs-backend/src/features/record/query-builder/field-cte-visitor.ts +++ b/apps/nestjs-backend/src/features/record/query-builder/field-cte-visitor.ts @@ -425,6 +425,13 @@ class FieldCteSelectionVisitor implements IFieldVisitor { if (field.isConditionalLookup) { const cteName = this.fieldCteMap.get(field.id); if (!cteName) { + // Log warning when conditional lookup CTE is missing + const fieldCteMapKeys = Array.from(this.fieldCteMap.keys()); + console.warn( + `[ConditionalLookup] CTE not found for field ${field.id} (${field.name}). ` + + `Available CTEs: [${fieldCteMapKeys.join(', ')}]. ` + + `Returning NULL::${field.dbFieldType}` + ); return this.dialect.typedNullFor(field.dbFieldType); } return `"${cteName}"."conditional_lookup_${field.id}"`; @@ -1805,7 +1812,12 @@ export class FieldCteVisitor implements IFieldVisitor { field: FieldCore, options: IConditionalLookupOptions ): void { - if (field.hasError) return; + if (field.hasError) { + this.logger.warn( + `[ConditionalLookup] Skipping CTE generation for field ${field.id} (${field.name}): field.hasError=true` + ); + return; + } if (this.state.getFieldCteMap().has(field.id)) return; if (this.conditionalLookupGenerationStack.has(field.id)) return; @@ -1813,16 +1825,28 @@ export class FieldCteVisitor implements IFieldVisitor { try { const { foreignTableId, lookupFieldId, filter, sort, limit } = options; if (!foreignTableId || !lookupFieldId) { + this.logger.warn( + `[ConditionalLookup] Skipping CTE generation for field ${field.id} (${field.name}): ` + + `foreignTableId=${foreignTableId}, lookupFieldId=${lookupFieldId}` + ); return; } const foreignTable = this.tables.getTable(foreignTableId); if (!foreignTable) { + this.logger.warn( + `[ConditionalLookup] Skipping CTE generation for field ${field.id} (${field.name}): ` + + `foreignTable not found for foreignTableId=${foreignTableId}` + ); return; } const targetField = foreignTable.getField(lookupFieldId); if (!targetField) { + this.logger.warn( + `[ConditionalLookup] Skipping CTE generation for field ${field.id} (${field.name}): ` + + `targetField not found for lookupFieldId=${lookupFieldId} in foreignTable=${foreignTableId}` + ); return; } @@ -2135,6 +2159,11 @@ export class FieldCteVisitor implements IFieldVisitor { const options = field.getConditionalLookupOptions?.(); if (options) { this.generateConditionalLookupFieldCte(field, options); + } else { + this.logger.warn( + `[ConditionalLookup] getConditionalLookupOptions returned undefined for field ${field.id} (${field.name}). ` + + `isConditionalLookup=${field.isConditionalLookup}, lookupOptions=${JSON.stringify(field.lookupOptions)}` + ); } } } diff --git a/apps/nestjs-backend/src/features/record/query-builder/field-select-visitor.ts b/apps/nestjs-backend/src/features/record/query-builder/field-select-visitor.ts index f5e173e701..cd222cd5a8 100644 --- a/apps/nestjs-backend/src/features/record/query-builder/field-select-visitor.ts +++ b/apps/nestjs-backend/src/features/record/query-builder/field-select-visitor.ts @@ -207,18 +207,28 @@ export class FieldSelectVisitor implements IFieldVisitor { } // Conditional lookup CTEs are stored against the field itself. - if (field.isConditionalLookup && fieldCteMap.has(field.id)) { - const conditionalCteName = fieldCteMap.get(field.id)!; - if (!this.state.isCteJoined(conditionalCteName)) { - // If the CTE isn't joined in this scope, fall back to raw column access. + if (field.isConditionalLookup) { + if (!fieldCteMap.has(field.id)) { + console.warn( + `[ConditionalLookup] CTE not in fieldCteMap for field ${field.id} (${(field as unknown as { name?: string }).name}). ` + + `Available CTE keys: [${Array.from(fieldCteMap.keys()).join(', ')}]` + ); } else { - const column = - field.type === FieldType.ConditionalRollup - ? `conditional_rollup_${field.id}` - : `conditional_lookup_${field.id}`; - const rawExpression = this.qb.client.raw(`??."${column}"`, [conditionalCteName]); - this.state.setSelection(field.id, `"${conditionalCteName}"."${column}"`); - return rawExpression; + const conditionalCteName = fieldCteMap.get(field.id)!; + if (!this.state.isCteJoined(conditionalCteName)) { + // If the CTE isn't joined in this scope, fall back to raw column access. + console.warn( + `[ConditionalLookup] CTE ${conditionalCteName} for field ${field.id} (${(field as unknown as { name?: string }).name}) is not joined in current scope` + ); + } else { + const column = + field.type === FieldType.ConditionalRollup + ? `conditional_rollup_${field.id}` + : `conditional_lookup_${field.id}`; + const rawExpression = this.qb.client.raw(`??."${column}"`, [conditionalCteName]); + this.state.setSelection(field.id, `"${conditionalCteName}"."${column}"`); + return rawExpression; + } } } diff --git a/apps/nestjs-backend/src/features/setting/open-api/setting-open-api.controller.ts b/apps/nestjs-backend/src/features/setting/open-api/setting-open-api.controller.ts index 0666cd2c83..ae3e60fe01 100644 --- a/apps/nestjs-backend/src/features/setting/open-api/setting-open-api.controller.ts +++ b/apps/nestjs-backend/src/features/setting/open-api/setting-open-api.controller.ts @@ -73,6 +73,7 @@ export class SettingOpenApiController { SettingKey.AI_CONFIG, SettingKey.APP_CONFIG, SettingKey.WEB_SEARCH_CONFIG, + SettingKey.ENABLE_CREDIT_REWARD, ]); const { aiConfig, appConfig, webSearchConfig, ...rest } = setting; return { diff --git a/apps/nestjs-backend/src/types/i18n.generated.ts b/apps/nestjs-backend/src/types/i18n.generated.ts index 0309408c26..3febe6c837 100644 --- a/apps/nestjs-backend/src/types/i18n.generated.ts +++ b/apps/nestjs-backend/src/types/i18n.generated.ts @@ -194,6 +194,7 @@ export type I18nTranslations = { "doNotSave": string; "submit": string; "confirm": string; + "continue": string; "close": string; "edit": string; "fill": string; @@ -218,8 +219,11 @@ export type I18nTranslations = { "yesDelete": string; "rename": string; "duplicate": string; + "export": string; + "import": string; "change": string; "upgrade": string; + "upgradeToLevel": string; "search": string; "loadMore": string; "collapseSidebar": string; @@ -231,23 +235,22 @@ export type I18nTranslations = { "showAllRow": string; "hideNotMatchRow": string; "more": string; + "expand": string; + "view": string; + "preview": string; + "viewAndEdit": string; + "deleteTip": string; "move": string; "turnOn": string; "exit": string; "next": string; "previous": string; "select": string; - "view": string; - "preview": string; - "viewAndEdit": string; - "continue": string; - "export": string; - "import": string; - "expand": string; - "deleteTip": string; "refresh": string; "login": string; "useTemplate": string; + "backToSpace": string; + "switchBase": string; }; "quickAction": { "title": string; @@ -256,12 +259,13 @@ export type I18nTranslations = { "password": { "setInvalid": string; }; - "non": { - "share": string; - "copy": string; - }; "template": { + "non": { + "share": string; + "copy": string; + }; "aiTitle": string; + "aiGreeting": string; "aiSubTitle": string; "guideTitle": string; "watchVideo": string; @@ -285,11 +289,6 @@ export type I18nTranslations = { "guide7": string; }; }; - "non": { - "share": string; - "copy": string; - }; - "aiGreeting": string; "useTemplateDialog": { "title": string; "description": string; @@ -341,6 +340,20 @@ export type I18nTranslations = { "addPasswordSuccess": { "title": string; }; + "deleteAccount": { + "title": string; + "desc": string; + "error": { + "title": string; + "desc": string; + "spacesError": string; + }; + "confirm": { + "title": string; + "placeholder": string; + }; + "loading": string; + }; "changeEmail": { "title": string; "desc": string; @@ -361,20 +374,6 @@ export type I18nTranslations = { "sendSuccess": string; }; }; - "deleteAccount": { - "title": string; - "desc": string; - "error": { - "title": string; - "desc": string; - "spacesError": string; - }; - "confirm": { - "title": string; - "placeholder": string; - }; - "loading": string; - }; }; "notify": { "title": string; @@ -402,14 +401,6 @@ export type I18nTranslations = { }; "integration": { "title": string; - "description": string; - "lastUsed": string; - "revoke": string; - "owner": string; - "revokeTitle": string; - "revokeDesc": string; - "scopeTitle": string; - "scopeDesc": string; "thirdPartyIntegrations": { "title": string; "description": string; @@ -444,26 +435,16 @@ export type I18nTranslations = { "desc": string; }; }; + "description": string; + "lastUsed": string; + "revoke": string; + "owner": string; + "revokeTitle": string; + "revokeDesc": string; + "scopeTitle": string; + "scopeDesc": string; }; "templateAdmin": { - "header": { - "cover": string; - "name": string; - "description": string; - "markdownDescription": string; - "category": string; - "isSystem": string; - "source": string; - "status": string; - "publishSnapshot": string; - "snapshotTime": string; - "actions": string; - "featured": string; - "createdBy": string; - "userNonExistent": string; - "usage": string; - "preview": string; - }; "title": string; "noData": string; "importing": string; @@ -487,6 +468,24 @@ export type I18nTranslations = { "browseByCategory": string; }; }; + "header": { + "cover": string; + "name": string; + "description": string; + "markdownDescription": string; + "category": string; + "isSystem": string; + "source": string; + "status": string; + "publishSnapshot": string; + "snapshotTime": string; + "actions": string; + "featured": string; + "createdBy": string; + "userNonExistent": string; + "preview": string; + "usage": string; + }; "actions": { "title": string; "publish": string; @@ -550,10 +549,12 @@ export type I18nTranslations = { "free": string; "plus": string; "pro": string; - "enterprise": string; "business": string; + "enterprise": string; }; "noResult": string; + "allNodes": string; + "noDescription": string; "untitled": string; "name": string; "description": string; @@ -640,9 +641,9 @@ export type I18nTranslations = { }; "help": { "title": string; - "apiLink": string; "appLink": string; "mainLink": string; + "apiLink": string; }; "pagePermissionChangeTip": string; "listEmptyTips": string; @@ -653,6 +654,10 @@ export type I18nTranslations = { "unavailableInPlanTips": string; "unavailableConnectionTips": string; "levelTips": string; + "enterpriseFeature": string; + "automationRequiresUpgrade": string; + "authorityMatrixRequiresUpgrade": string; + "viewPricing": string; "billable": string; "billableByAuthorityMatrix": string; "licenseExpiredGracePeriod": string; @@ -671,13 +676,10 @@ export type I18nTranslations = { "paused": string; "seatLimitExceeded": string; }; - "enterpriseFeature": string; - "automationRequiresUpgrade": string; - "authorityMatrixRequiresUpgrade": string; - "viewPricing": string; }; "admin": { "setting": { + "instanceTitle": string; "description": string; "allowSignUp": string; "allowSignUpDescription": string; @@ -694,11 +696,11 @@ export type I18nTranslations = { "brandingSettings": { "title": string; "description": string; + "brandName": string; "logo": string; "logoDescription": string; "logoUpload": string; "logoUploadDescription": string; - "brandName": string; }; "ai": { "name": string; @@ -903,7 +905,6 @@ export type I18nTranslations = { "aiGatewayDescription": string; "aiGatewayApiKey": string; }; - "instanceTitle": string; }; "action": { "enterApiKey": string; @@ -1155,6 +1156,16 @@ export type I18nTranslations = { }; }; }; + "rewardRejected": { + "title": string; + "message": string; + "buttonText": string; + }; + "rewardApproved": { + "title": string; + "message": string; + "buttonText": string; + }; }; }; "title": string; @@ -1190,8 +1201,6 @@ export type I18nTranslations = { "base": { "deleteTip": string; }; - "allNodes": string; - "noDescription": string; "noPermissionToCreateBase": string; "app": { "title": string; @@ -1199,6 +1208,139 @@ export type I18nTranslations = { "previewAppError": string; "sendErrorToAI": string; }; + "credit": { + "title": string; + "leftAmount": string; + "winFreeCredits": string; + "getCredits": string; + "winCredit": { + "title": string; + "freeCredits": string; + "guidelinesTitle": string; + "tagTeableio": string; + "minCharacters": string; + "minFollowers": string; + "limitPerWeek": string; + "postOnX": string; + "postOnLinkedIn": string; + "preFilledDraft": string; + "claimTitle": string; + "userEmail": string; + "postUrlLabel": string; + "postUrlPlaceholder": string; + "invalidUrl": string; + "claiming": string; + "claimCredits": string; + "congratulations": string; + "claimSuccess": string; + "verifying": string; + "verifyingDescription": string; + "verifyFailed": string; + "tryAgain": string; + }; + "error": { + "verificationFailed": string; + }; + }; + "reward": { + "title": string; + "rewardCredits": string; + "minCharCount": string; + "minFollowerCount": string; + "mustMention": string; + "fetchSnapshotFailed": string; + "alreadyClaimedThisWeek": string; + "manage": { + "title": string; + "description": string; + "overview": string; + "records": string; + "searchSpace": string; + "searchRecords": string; + "dateRange": string; + "from": string; + "to": string; + "totalSpaces": string; + "totalRecords": string; + "space": string; + "allSpaces": string; + "user": string; + "creator": string; + "platform": string; + "allStatuses": string; + "allPlatforms": string; + "pendingCount": string; + "approvedCount": string; + "rejectedCount": string; + "approvedAmount": string; + "consumedAmount": string; + "availableAmount": string; + "expiringSoonAmount": string; + "amount": string; + "remainingAmount": string; + "createdTime": string; + "rewardTime": string; + "expiredTime": string; + "lastModified": string; + "viewDetails": string; + "details": string; + "basicInfo": string; + "amountInfo": string; + "timeInfo": string; + "socialInfo": string; + "verifyResult": string; + "uniqueKey": string; + "verify": string; + "valid": string; + "invalid": string; + "errors": string; + "copied": string; + "openPost": string; + "noData": string; + "page": string; + "status": { + "label": string; + "pending": string; + "approved": string; + "rejected": string; + }; + }; + }; + "clickToCopyTooltip": string; + "copiedTooltip": string; + "hiddenFieldCount_one": string; + "hiddenFieldCount_other": string; + "invalidFieldMapping": string; + "sourceFieldNotFoundMapping": string; + "targetFieldNotFoundMapping": string; + "fieldTypeNotSupportedMapping": string; + "fieldSettingsNotMatchMapping": string; + "fieldSettingsLookupNotMatch": string; + "fieldSettingsLinkTableNotMatch": string; + "fieldSettingsLinkViewNotMatch": string; + "fieldTypeDifferentMapping": string; + "fieldMappingSourceTip": string; + "fieldMappingTargetTip": string; + "reset": string; + "checkAll": string; + "uncheckAll": string; + "duplicateOptionsMapping": string; + "lookupFieldInvalidMapping": string; + "noMatchedOptions": string; + "needManualSelectionMapping": string; + "targetFieldIsComputed": string; + "targetFieldIsComputedTips": string; + "emptyOption": string; + "showEmptyTip": string; + "hideEmptyTip": string; + "hideText": string; + "showText": string; + "sourceTable": string; + "sourceView": string; + "non": { + "share": string; + "copy": string; + }; }; "dashboard": { "empty": { @@ -2561,6 +2703,7 @@ export type I18nTranslations = { "lookupFieldIdInvalid": string; "formulaExpressionParseError": string; "formulaReferenceNotFound": string; + "formulaReferenceNotFieldId": string; "rollupExpressionParseError": string; "choiceNameAlreadyExists": string; "symmetricFieldIdRequired": string; @@ -2584,14 +2727,16 @@ export type I18nTranslations = { "clickCountReachedMaxCount": string; "notSupportReset": string; }; - "formulaReferenceNotFieldId": string; }; "view": { "notFound": string; + "cannotDeleteLastView": string; "defaultViewNotFound": string; "propertyParseError": string; "primaryFieldCannotBeHidden": string; "filterUnsupportedFieldType": string; + "filterInvalidOperator": string; + "filterInvalidOperatorMode": string; "sortUnsupportedFieldType": string; "groupUnsupportedFieldType": string; "anchorNotFound": string; @@ -2599,9 +2744,6 @@ export type I18nTranslations = { "shareNotEnabled": string; "shareAlreadyEnabled": string; "shareAlreadyDisabled": string; - "cannotDeleteLastView": string; - "filterInvalidOperator": string; - "filterInvalidOperatorMode": string; }; "billing": { "insufficientCredit": string; @@ -2772,6 +2914,28 @@ export type I18nTranslations = { "noProjectOrVersionFound": string; "noDeploymentUrlAvailable": string; }; + "reward": { + "notFound": string; + "unsupportedSourceType": string; + "maxClaimsReached": string; + "verificationFailed": string; + "alreadyClaimedThisWeek": string; + "invalidPostUrl": string; + "postAlreadyUsed": string; + "unsupportedPlatformUrl": string; + "unsupportedPlatform": string; + "minCharCount": string; + "minFollowerCount": string; + "mustMention": string; + "fetchTweetFailed": string; + "tweetNotFound": string; + "fetchUserFailed": string; + "xUserNotFound": string; + "fetchLinkedInPostFailed": string; + "linkedInPostNotFound": string; + "linkedInAuthorNotFound": string; + "fetchLinkedInUserFailed": string; + }; }; }; "setting": { @@ -2836,6 +3000,10 @@ export type I18nTranslations = { "pin": string; "empty": string; }; + "tooltip": { + "noPermissionToCreateBase": string; + "creatingBase": string; + }; "tip": { "delete": string; "title": string; @@ -2971,6 +3139,7 @@ export type I18nTranslations = { "system": { "notFound": { "title": string; + "description": string; }; "links": { "backToHome": string; @@ -2983,6 +3152,10 @@ export type I18nTranslations = { "title": string; "description": string; }; + "error": { + "title": string; + "description": string; + }; }; "table": { "toolbar": { diff --git a/apps/nextjs-app/package.json b/apps/nextjs-app/package.json index 66a9012329..7b25a0f4ab 100644 --- a/apps/nextjs-app/package.json +++ b/apps/nextjs-app/package.json @@ -64,6 +64,7 @@ "@types/react-syntax-highlighter": "15.5.11", "@types/react-test-renderer": "18.0.7", "@types/sharedb": "3.3.10", + "@types/canvas-confetti": "1.9.0", "@vitejs/plugin-react-swc": "3.6.0", "@vitest/coverage-v8": "2.1.5", "autoprefixer": "10.4.19", @@ -129,11 +130,10 @@ "@teable/openapi": "workspace:^", "@teable/sdk": "workspace:^", "@teable/ui-lib": "workspace:^", - "@types/canvas-confetti": "1.9.0", + "canvas-confetti": "1.9.4", "allotment": "1.20.0", "axios": "1.7.7", "buffer": "6.0.3", - "canvas-confetti": "1.9.4", "class-variance-authority": "0.7.0", "date-fns": "4.1.0", "date-fns-tz": "3.2.0", diff --git a/apps/nextjs-app/public/images/layout/error-dark.png b/apps/nextjs-app/public/images/layout/error-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..2db90b5b822b9ee937b064440799c183473d067e GIT binary patch literal 11463 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 UZv8q={x_f`rzTq~Z5H~!0NwwYCjbBd literal 0 HcmV?d00001 diff --git a/apps/nextjs-app/public/images/layout/error-light.png b/apps/nextjs-app/public/images/layout/error-light.png new file mode 100644 index 0000000000000000000000000000000000000000..572ca5860d48e35445f2dda927e41fbcb661236d GIT binary patch literal 11785 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 literal 0 HcmV?d00001 diff --git a/apps/nextjs-app/public/images/layout/not-found-dark.png b/apps/nextjs-app/public/images/layout/not-found-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..b4746243b8fd305ee0e51121e382900dfee6e348 GIT binary patch literal 16475 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 literal 0 HcmV?d00001 diff --git a/apps/nextjs-app/public/images/layout/permission-dark.png b/apps/nextjs-app/public/images/layout/permission-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1c0dff1c694f2256315ec434b24562e38f85b1f9 GIT binary patch literal 11537 zcmb7qbyQSQ*Y}-a28JHGyF=-&p+pdn4rvgiq&o)z>5>#F5s+>HMPLM_8zqz&X^`%e zZ+xF;ee3<}TkAV(-F?o^^V@r$d*{wtH%>=ejS!C(4*&o{^@l2Y002h*yI@!ti42(( z31;fm(KJxS%y<9)V}E~tX=!O}Y^*(kR3JNkaGsEF%py%Lfox5di92 zz30NsHLAahfq-Nfq|v~9>~9xRlKzq*S=sjf&xyNWXq<52e^P8Y2u!6woJ1@9 z8$HKlkZWtLEcEuCttsQWk9VTkdoeTbkbN)SVPz@&C>{!1b*eNDLz5rR?0xG7l0pT1|D)=1O7Hsfd-@i?y+m0&!>pNIOLGjWi2@HO!WuyO+PXTVN zQ%*FlyP1`YpNsbn^%4YXEE%t;0jS<4VS#THzck&j;PW6hKY*O^EPI(WAA*#+@?{91 z0uPX|gRC$pJu_HyOUQ`Dh4+T&IWxSd6s^9#&NK;8P5?-l^F$r7d|>dKgrC4`qW*XU z5-o@L*z)<^;=cJlRlmeFrqD6tF#o|5R74V!Syz9roKyd~H{SJS^yUiE?C>$o2kMAL2nSV0He_(M z%DRio?(g`?%f7FAzU=E~^~AKb)!RtI-LJaaaEcimasuodxVEvApxWix1xhlp2ID){Eq1H_7AVu5m};Kbfya(?5BofCiuhZpVQjsKgi zCn>Dgc@PMs(~N!2?35e}6407)KQKm}L)lPyE#=H$at4QlRh)4kOb0f!?5e$Kp zzn=4}Ny;w3EOY!u5?22OczL$A69R$31Z%_l+R5LqZV~c=K)gS>%qb0!^)N9MhX}rO zYVAJ@9bvBTP!KCZfWD8If*CyAjVJiwL=YqB8|JJAN{iSQU(iA!{c2zW(gLGcOe4&h ztV3czgC@rAqt-svA=sD@UwaRe+4cLtJF4#vpGxz6*5pcP{lm0E4AY_MW5~N~{xbJ_ zMzc1T0tD*aI^;4ae15hu8Hh<+Z+*JZZ0HPgqI){3YPu3bO_Fr3o4QKqGpt6O$Wf_ zS(lYyF(x~EGc+0vXi5T0!l;v4u;}m%IX6L}HM`;ZHB`I&Ku81(PQ0Xjz#j6-P%EOn z=F|gtfV?|Z)Jh(ED>H`0Mvo-1W?QfG`ixrqd;P&!{cQ1N!Z#Ss$_C;1(Ydfe;6gjB ziCaFj&{qF$?QucworSgMd4)ll=i(Nkr%vebG~<>RsJ=$CdHY2UgQp#uubPTVa%-LZ_n8v`>Yw*^XSK zflLOPVUM{))FhwC}GNsg0U7Yl+w*Z06q=JU<3Jcca9>M zqm>$pQ@t_5CG<≫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 OQdiYhsa3Lm@qYkQz4s>o literal 0 HcmV?d00001 diff --git a/apps/nextjs-app/public/images/layout/permission-light.png b/apps/nextjs-app/public/images/layout/permission-light.png new file mode 100644 index 0000000000000000000000000000000000000000..48f0d118e215b2be15b1aeb143ab0bb252db440b GIT binary patch literal 11609 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 literal 0 HcmV?d00001 diff --git a/apps/nextjs-app/public/images/layout/upgrade-dark.png b/apps/nextjs-app/public/images/layout/upgrade-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..517746b08c3dcbdf2ecbae781cccef9a96a9e72a GIT binary patch literal 14273 zcmbumWl$T=6EK{F;1;B~yAz5_AvmQ#aVS!PQyhvGOK^%)iWVy_1=`|L0u(7woZ{{t z+~NKG-_OrHU!I-0*}L1l+nt@8*}d7_7;P<8LOdEg002PvQcX!0001HWH*hfi+mR-d zB>4|TX=~^!|A(Lc-{AQ8czJnwWMrhKrY0{h4}m}=B_(xqbim*L!x7}Y(txLZOPTR zR;$E+_y1qu*H@lOM53;}9T_8dZs-6ctCp9kh(-pYgjT}N%W>}=WLL;-56cNGK8Rbgc}iOQ+MRH6RX$ z%4YFgR=%?f&m&?rU*(=;KL1JFgi=0SSRBVPQ$9w$nk^}mysi@$uG z=+X8X7jwRMGQ@)^A;LpWC_=r(;H)Uyp&!Lb*!w;of5P;xO8sfire%6VM5Y`H`~9;V z`xTF$P>w?~`xspl86Afa?Po5IrbcT}K3wM1)Lc(hPqwE|Vgj1O5081rmjjoAKeEXc zc%^e@x1T9?WuC3=9yzjqi^N)T;X+@iG?A~SEh+6fJ5~L~SAOC9y_4+`ml1p!H`W5} zO|vzS9?2Jw#-8@I4wG|Nl7}#;&e?J-fByVFkZ77Znzg*ru-}4Vj52)Fu~{OhMI^t` z|BYlY_C-I6lI6qo1yEl8TBGxm77e<5qGruv#oWN;=ik)TCq13P_q^wOn{RJJx=aHL z(n^thukg6~wjJs?R%U{%w^B^rx`J0jaU={OxJ?_Z)vg0ZKNZg>z@A$&O^)2?$9=X? z_l|;uzuRNCQ||d9^BS!GghG}JH@XEyZ5glzHsPxv3f==>86rc}oY4Ef&bTu^%}!04 zP3XEk@4w~BCW2k;e8(NKGBW2R=*eM1kE-Cx;Q8?56q@?&7GUOLe3 zUt*W8f$6CIm~{JF(ujt}c~aaO#YKWIb57aRfgL84eTbSJSfxNy0ht zL4=Ia0E|B1=s4=q;Zp~nEmr2P^r zynP+0Ry%tcUGeIHc3SzF-#~3!<^_ZLZHv`CyDP`JLo59Eorm%6)G0`F^dA4dy3;pe zT*{3drM&hsF9vyIpKPbn6K}nvDxrvfW2bD4#g2-AX{DtIrUjkl4@YR`@%G3gbw#26 zso7e>_EM@@N(uo>d8E18j|fAsqg{=IM)v`(M1qfUs`sx+O8Q~a@TeWGU&YaMf5dwG zJUl2V5p&8$oBxh!&Dn5X?Fc{DwrnQRK@Di>46{B(KE=e>ftTaMVFULwuvpC{R$G0L z;}#bvjSe;!ysSwg-&81!#iN1)PMD2X$el1&4e>>vwPWFRy%^u`NAWD>D2_To2&5|> zTMfAIh`}~OEM}g1Gf;tGl-hN)TSggR10w33p3t~@7Itp^Si)UYIrWf^O3X|1egDe< z2jkVA2iLBO5D6yyT64+V{_9)R!c>sl7SHRK__3Q0yWB-1uk#qUKm4G<5^MMJp#x<$ zCvb9YFhj&72H{ zH(|jMpFj~kFE*r!Be6C6&qiUI=qf5P%LXpM{0N=!en=}l$zZi#qJUGlIfv-aj@((ui}ECK7YbBRV|lZVLYm`9Xr$FItk zQDaY3easC{$!C1ORwk@;zPLXws0^0^2Lkdhe^6iF6ESXtDOJw<)UOMOh|xj!Dvn}s z2C-=h8d`f#UN>ze{ViFUK{+qPxhC)uUe+uGt*IP3Y;pMQR||kX1}BZ2_?!8UlD}`w z=!50OXN~2~UYNSqv{2T@QMCVxjg@u2_qWL_TwTfDNIa7c!rswIsf3u@5# z`*5OKUW}t>(Voypf6E*bKeiPA5aX{;YLxx+Q6}(Q?Raeva;N3_Yer%Bu}Wj%pUEEd zMwjQ>-_HVZk098c<%C{2$O7tbx1iVcE!2Bpr6o~`yxQY0LtC=sTr#p|4EMu4e$wBO zEs4mqOk#z9G}7{s{I!=%-d54O zedp;+xBtSx|G1m=gcB_N8Tqub@R|N``O0ut7^rQH%D*iS^lKrpJE=k6mr9^eyI?j< zjLzI)FbrRskg?p357g6v@gxafnE+F!Lf>mjVnO!200)DLHt^{o-u!F(Og*aWccJ1= z8jRB)CkC0%^Z2ipIRoJ_8K&QZ`hu&>l7dC zGMkr(NozNcfV7KG<18|ET+is^a*jM}Yt?s`*^WWMJv`H@vrPeP-0-ng;i0y}j`cNa z7rz_#ae+8=lhzueJC8qg6PwKvfoM+g3+d}9_!r41Dd*0~=u`)MttJwdHf{J|dB%!4 zO7xZw+s3-445h7JB@Uwx4kH$>`m|}c#fNJgprw-AMtMdoGtW%B4hyefd4fGV?mgj6 zz)I2B&M3xMmtdyGJR)UOg`RxJ(9g?^eZXj`7R5uoNcqv3@-pLcaWPfDe406r$I zk7#L;fjWvPwe=D`X5yq@86FiPZg^g;y!kL1NfyTA{vrl}(s#qb@iFFoN$jp*sD}yT z6HK4LjaF(a6#tWq7~{{P@b?v$#B4C0z%w3&m~(yXKQ(`MaV<@i%G8RQAZ)b|FmjmF zLJ4dJFNA_5p1iSa=?fJJN8{3-^|LL+M=m<$f@^fQRtgc4Iaq}Z_ix9Nu&}K+=-^fq zSAzRw7gx)9Vbff8ucQ=%Rpf?-Qz%ws&U)!zD`tAqx5>-3mwejUvv~!XIBWa?(i&Vl z8;A(t3B8NH8H=F ze=Y1mxl_f}u!T+dx<_C&Ib%vF%gFxzJvA^tha6E(z5Ui;ruXEWjb8qVYU=0g%RwGx z0M|8V_aCzF3vt`=0lD~}-3u+>n~ff6(fi+Mm6i!jo8h5~{!m_?d~w#BdP6l*FzOLE zYX89N@!q^)WjwJ}kS8}&#ioIn(|&AVRl8Q<|B%^52B-G5_yy3x0oxwxhhFmCe)707V6;8~*_8bz z*n>)s=8?m%Bk57c{;MFH9reSB5tx{9h|K4gV|gAYPbvuCn&sR)qonf^urcQUcqJ~3 zZj7m%CpxB=nYQKB5h~|Kk4*tuKu=d=4SWa<{KFXI@zyv;S|92?nP(wHfEmT$trGi) z$9QG-XpS!IVoON^9xW?{&@H4^$vMOX7v~)zB+MeqnQ2KMJkTa}k6%~)$WP~^epJ;f zPW+p1ZV2?!>5^U13P$aFY&}bKj}lvfgx8lU$WcZkpWO&)m%Nxa#;HCfv81NE4nCgTpEMe> zyQaZA%++;Ml2BTpv_pjibN{6l!#+YGOUG#EU#n@8s}1VuP@_XGb@oo20D(5{aC}f+ z-=wQnXh*CMSCb$QhL6evzV#)!gS#+KE5>VZ7lJY!a)c(&#T$T`McI#{F;Ny1L~%P+ ziH!Y9dIPdG`T zrLoh1?osZD3(CkjRN{vk`Qg9-wF9|4;;yI$CKEmHeJMg1`d@J zy0L(A`Wdvwxo|et@&RkxqSe_18SMvE5$wa1?-{F$e2Oqn5bV+FFtYL@m%9X8!>!Ia>Q~7oXa;E zda$LZ3ZGXK2Cc?(Eh|;(A=_l?0!Zd`Y`glA@h0l8+Qe0RJ-m`*k^<0S$iH*P+2}i4 zdSgNxZ->s_i)&D%IBxEdsB5?L$10s?Sd?Uo>BFBJ`@CH_4MjM&m>_4eMuU>UnBd!JxjN?X6Fc8XB3{4SMDrmSLA3OoZZ}VlD=)6EGSb zCEN8aqfJR#`lB+(@{UV}s5k#+BMcRI2|w1+M);ZJO&~i3>%1`DrUSk|b`gt4T&f{^ z*Sv2u!EJ}NBsH(SR^IZLe&QJt#f9+pgd!>wSfb za8W509(w7%+%R8I$kd8~5q92Xrbjv+B)W3^hwPX5Px=WQH$qvwQ)wt$XZ?S)0sy}j z57fBmUy%aSDAh&hUh*^&32PKpMX)z-ljOhLCnlE=?1Vf~cG&+Gzb7L2Nv^i-*>7Mb z5esk%OfRYEtS2KK?d}tOD?VHNK`pdn(Zi@6^}=SKldm_a-QPXD5|54ep|I({0=nnp5XGq>PU1X~_q z$6?KGM~~>9Wx@{a$!B`rwaMdcc)}&B^_3)}(Wn=hYR9wo$0D+?3dFXlaeef>X$XGJ z2ehvH#fKlumw7@~KL^McWEE~*ymteO{H(cpn)$v;2C8}EY7Qq;>0rSOl zi*Eica2M7R#b7h@tC#g!6O}j;r~#?)|3%o`4`fF;Px8&51Bm6Gm7S9?9&@+T4Oe`s zM6{n<>DV(zzQFCx-z${c8CRj-?cCL=XiQSIkNdXkKQQV^OD6!$Qf&3R_L=!HhQE79qv~x^>o_xAYtVx05{E)#wZIouH!lJ}QH#mroof4D$hPYY_C zU7vAAxdiqKOGvBj^dQ-VcUn>;)rtr?aVMG}MVbVSQ9-okTb`74>lD*6048RD}+}xexk7Rj79TFNZHcOctH!48`zgDV6 zFoq#aCSPG`p@^5@HP(Ez(hqJn2}(5U%jX)_Y5)0RLoU4}BJ~-9yx}P0#{!VK_j-rif{W^o>C1AL9;)8K&Eq5{B->JN$3F_?Xc~xU$>DOl9%0 z1(ezZ#-ePuVHA4y{TtIC%DC)s-P`keZmZ_3U(exl!5pB->J?|Nk{ueSsD`5!&3%v> zha$oTSgU+Nj~Cu*@6{$rIFhsS;S)3L2LOik@rWvf3qc_e)MFv=;yny;*) z1k{etclyc_hi(P6Xq!#s9f^7CO@Gb}q0d|seiOuoi*Prpj`;}fiU;`+;3MC>6fat% z9u{N+Lii~uZbo-&EHh+(CrS$l$OQ!#YuW+Aogiy0aXTZ=&lk_E6Z+-zO@636spjmW zBJ0Rh&PxOS?Ft^y-|QyrNJHV-)BvYuEX&cn6TY*WYw8J0>I6gwb5B-WqS_X!i?Qf7 zRuf6IAYZ?MRr54(9c@Fzw=ljZh-IFFQF!-}HiBTrCRj;z9p(9iyzmWr7cF<>gWgmO zakt4n^!k8Q(=&GIoA_DCAV;b=F4Y#`^kQP9o^gih+41oVk)WsTjTi}V4L z^ugfTN01U1A(l(O>_GEygSp*7AOD#8d0MTA6Q$V(4(_XwTV{SJsL%+;OSz$Wi6T42 z`wWkK1Xb6G+}w8On607wS8)9)J86cm?KwW#x;aQOR+)8ghNea2-$dF=RzWNlLzh1Oj)7dYU z#ZoEcZTy_AoUn`&DFxUnWl9P2`VNum+QE(!09h82+X4%|6BWrn)!L$%`l$_Ea1i+5Z zU_Hi+X1%yr*EW)>jq30soFl`8tx`rlCs1_D7wdI6K)!Q7%&Y^Sg>eD!hzTMbevMVU z>b~&(D-53D{R-fcd2ZGt)Tla-xj$Ea;!v{pZ6~UX*`$vb4@nrZE184Tz5wD~n;GD^ zm|)^|5j$S>2=f;cCp8dRTkAB%>5Qrcf1!@%D;20?&kOjY>CJpop2d%m90{YZ=?fF> zxF5&TF!=AwW7u|xL%={sdTQN;1fJP2J*O$*>UuZPfA`JMOk@VJ`y6tzLaGR_Z-Y=p zYMoeqrGlnor&ED^U-fzTq2F?dWL3PrA=UB|6ao{KJEzKBGh^AHDmz+$uW;xnCoLCL zcKel#_%Mpl~Jmiw9Y*-_MsTR_9afzE`SSbXfY+Z=;L?w=6mc8hn zyU>4nO1t~d(meT>w)pOG+k^5vGR9AQ*f5>^@9fh+7lnK}T(z2Ee*igV#T+FUtj?t~ z_XTjZ27uQnxEB^u>&v0>aUDvo6`RfScUadc3Jevq+1Y=3YH#N%Fw5K)Q#(%y5xH`gq4Cj^dDHS#}3GFm6RUFCKIxO3Nq=C@k3yUF@=*)tu z27WBinK#X#mVx^_VT*S302Ti_Jkb{lvzxePgcvMTU}D_07Ex4*69#BYE{mO*#K(<6 z{Vt_tGOrQJu$FNy*DMylX0FSey0Z%r4Yj7_>W&PmIlDLQobDUfRy`0{yd>ac zVqt$L7(&FUh>5{BsD9b|)!gbf44C!@b@3Ss#j^*y7RF%t_Qr??AU-x+@(xSMRbct8 zJs?m*jS`MhpTt=H#OCyG`7;H)wsZ6on=<@im4fOWG3mxt{l{HFa!*VuXzDqWFIzOB zj`*6yCs3>6fhhZm16Tcj4kjh}3oa4GEg2ZZr*uI%i)PGZg20&}PYt7abbi?9V(bt6 z!tUny1R+^P=i);}05)xG0!}H62ju;9Zg{xM$tuF!C1sqEXyyF)B=PN``tqUUyB*?1 zXmUN*qR|HSLjfc7-qFb^@$vIvDCQq4(kaFk5}%HOI^8dO?b|}EjndE9;%7N4ew;KTEnh#4pNCd%Ef4`1#LEry`T|B+aQUezrzFPQHCj z{>u$Uz>eJZ9TUGWDyfuf!_3v!y6U|mklcAq-`%!IvropZKs{Ta7Q*cEP(b0(wnYhB z>OSNyN!SuhkJ%%p6>-sii>!WY>e6KWQ1B#p!)C@sEAa9A6Yt-)5;-@re~eV4ncmvQ zK%1sC{r1w1cPY0R)>3-c6cd}L&g&54?~l-@l6BFfD!n(z7zKDyM?1~KDlB}5{G5G- z3q1GgK{D))ScH4@X!3vS7W{_?HuhUZ3cD)3O++E2zc_vfoaY^qPL*MNeL{&sKDi~M|9f_0E!-B4P1hTVJYTUzg5{q1uq z+tK}>Q{hldwU(y8F;)j5R94PEh}c}ed8=650W&u8=Bpb@lsv}hQ4iycY!24gDULX8 zoOB)UY@a_sQN~~E6ycgP9mN?pHlI5vEqs(>qEPVEbPLqVW#W{G5hcLCw@&KL;_!x& zVEajEs2&VklHDf(1~kpiy=#i@2Ir>r;SDXhlK_snT`Cj{IW1FxU>Fk8|Ch9~%AN_3 z%jI%CzRK#XCWpbq{<`xs)w$&bH-N%}Qem%WhtOHA2DFlZ0l#&&RJ^4G@MFUW-Py6C zJa7;!`hO?>vnv3^6w&~cZ2F%w$!DgQ*jV`mb-_Xf=ysL7!5caUZBfRLrlrD@!UDQj zT*Lo;4jUs418^OO>BJgZgq^g2;QFz>uktTxG^hoObo63nTQB`fXeQxwQDn-K@%DBp zyI_r}X9a}{LmbG2j8(s^3D2?d*zQn2UFF#_u)uTq$E>l;9vL!#DAiaA%480Um{O^! zu)rKpr9TCyn#Y-M{_>diyH1bE5t`s-Ndx-Ap5KvHKqZuAubKIu$uHF z2ZPMUGP`an%yGgoxef4=c*nXmLTRPWP?*f$A<@=wU{>Ch8DH3Mj_SgXkOU+%%6}<3 z#3D}*YtXO{rPdj{Grj`ND-jWpjGI_%}$DZYs3S(GR+Z&fOzOe!%gfk(DrKQc}@0Zt%q zgmE=oNIgoS4O3ZHL-tpdS^$Q0ah7{{byHAxodRb$MWp%!>+{ktX~0&%>Ee zQ0%3e0!XBa*FVMPrH@Dc-b3E8Ld&N!LG>8Y!A}Vf7usZn`;C`v5u`E>K8kYwUuurs z`at&oDmv{`as#9v8BX4sV&l@IsGBzvf}daU9dyP%FQ9BJ2bMmMeM>m^keg6D(9*vv zo;}rg|8K+Yg?Lw;PUIj~<@z643RdUz!3b+WhOuiE?E@~u#r#ATBzfATGCV)bIje20 zo`6M!l*<9fD_sbu#dW0e@by`?V*v2aA7xMSZRzr-2Qq4=_sTel@ng zDh?K-QGsMLUGF8Pgy~AwEv8<^OW&o*NHcer8g|tiZ%))Kh*AVV(5ln87;nb$C21rq zzooPodKN>F7zii&eG`OzFBex460_=BRrTq)j(zB&6;?JG`iP<0m z_D^q}MQH>YJ6()rR9N>RWt;Ls<|Eno(-iFRs~m6~eXsQHWZ_?lXKh(XZ$)lS(nXJz z7R0*iGNW_(-L(|8edc2^HL=a+!oa)%;ba~ve=*DE$}L7HG6*F`Y+CAV@in?^=1i1e z(n@5f6xmJo_|8#`f6Tnb1Y+EGccj=2=dgylvn$>4)G&1Bi4iJf9 zu2I_sDSAn1OB9)7*0#EZ!R0qu%l;_i%Tiz3W!=9 z2|;Q+s7^g1?~snvB5U{iZ=)8R*IhPYxR7)`pDI*W<{&Q{9^n~o@iOSRWHB1uNO-lp zQR`GcP%XaU_Vj*0#i%+sz&{x4_YlQ3-v|@KVk9Bm$CfB*g(IU{722Dg=mT83`nCg% zVG6%_6IKwTUwz#{@z1kEwo5XVAa|=L*)8?Rh_*;L`17qJ(Pkm69!@)S2xmEp?O` zMl1`~UuB)Fg+~$kL3~oCR&xW18)l9n1gB6JO6|H)+`_1iC60Yog17MDT`62$ANf$L zIiY@9KM{7!B)|6lYu{9B4yg{8o&N$1U(ca$#s+@WO5;h;Si(1pD$HHCV;#IKP*s9D zQepn1bmGBHmMud*#{!~K6lNR?0nx~p4>~cI^Q-w)V^%kQ&ZDz!${VUJ%XTV21SPdE z)q#CTJ)uAomeHsOPGrvXU>_m#U8~ENGj{_&63w`^gw?ivDAkgQ-9tvWQ=Ez{AE`*s z_AeJ3#(D1OoG%7`SW4ryHlsMVbM?zC-x&XDBMslM?KsXJW__t@9P?R^MZ0dqMPf>m zKJCuAx?4YRsmHY|`2;Y~9QAqBCcZ=p&cwe4x~p*$#O!YNKC)8>5X9M)kWi~na~EI!n!@>6DZX)dRNlu(tiG>D z(sH1Pc2KvVfo28Ao3os|29lm#lpRSienz+;=U?2IM&9KSnu{Z1rGqzqVTgCCTykuQ z2RLR({Ic#((92Ireyyhu&f@2U!k2iHH>|a;aHKEgWj8Jw#QGk%k7kQ|CL;1O{Sc== zb_9ntqG=%py#qR#M{RL`#1l2cLcrX&t37}e*N!o*Asnw!ijzw>&h>F z%A|P!P^FF$>rGedcAwcm=Yd<}1KVTxQr5G39*#gd7Xn$P&+R!FH4f+5%)55>-XTkm zYy8|o7oe?GYVsIRoE-7QFA|@^o4>`e(s6QMJ3L*91>jmh2Xgqmf5s)NrTCg1vHPnG zU}Ag6hgfczu~2*m{EuA3WW#tO%Lw9@S&RjLB6Eqm!Z&!I!mmJfN!au>V|ol&*`&^_ zB8y)z%+}6)zFN1Oq3geSKqOg!r@5z4E*$G@lv^U~-^z*K=|>^-!at?j$TFg68y&AE z%5N?hlZW4UO>6!lYrn#V+Mf_2z9vPUXc{Z zP#Ks@h-7A7KLq2{^zSCkL45Zu!>l07ff83J86)dEwVnqk7iu-#i^;(|my$oQF>5S& zTiMJsrmGd_)B_h9wZ2*0$U6+eV{WDO^_TW5C98>T^7#~t_GhzIwGH)?G zIs_`*5At=IqqupNcM(BVM6jgJMqhKD6ukt#CJ1#?^K1vD+w00^gq4d_w)kMC)ch`r`3Ff=| zxpV%eqTODN8KHph5F>D-6|Pv?+i<$$fsh^U_$e&OzR>E98z~>4m9}7)IZQ?!JKUgs zlcP4L@tKzvWms~%5n_yD&DeoLd(~hJBPErB7-eqpt}1O5mwr|*=R|U_EDYkyJPZyn zliY+4M!k4k5jVN~-0MjAXSaX7tK5%zovEcSOsDe=OkR|284J`9p+H)aE@Bw4^BN~A z=*q^rOL$Ac?AZZ`^t0l2fv^kmwS(%RZ2Z&|bCc&i@8ANxd5s?5?^P@Qu;C5psiMvH z``uT8z*Z^nadlannwo@WB_xVWbBHJ-$}YlZ~4_q8D}Ce3<1V zPMc*6v9}JL>qk|k>2@5!B=8Oz5@>oq)IIrlvW8>apdH=4SONN_TZ3bpvtdrdaWK4( zv+F>1KcaIse6r?uylYgz+9VoS%uFn&y?Ru|DEGKr~?P-81ebRqB1adeH#Gf%IA0IddW*?;(&{+(hC zEQ;Y~Y!xKd%~mGcL71S2$Y7io6j=J?VyvW^&l)>7KtEMdsw6T}^gVhROO*%aOlFox zAKpi7`g@kZxWQAkey@O*gS+V0#q~@NFHC=hHF#n&2;7?*)5&H?zX$SEBU01KL5-_t za?rYqzwjFi;zHwAcnp2{^PBHK%{P$(@R#Al%E6~;^_(9~=I0UCtFm1p1iCBZi#@&c zkq%|_sz%YT!pu>5#LCnDS=#t$5x1fjLt0f<6inAsBT2H>9CM4;2}eh4qnH}2HA%V# z$~=CotL$%>ofbb{+;aA+<5)>FAzuYvtZS;cjYZ&l1F6$C=`wWx@Qmm(OBDWu4l8Fp z`&{+Pr5nfzZ83p{>a3Bv^~Ok3$1j%I@(Qd>MIry01nCV5I$kK3*Ei&hmXlor7X9h< z=FwV5HuyloDBU1kLlMp7RlO%QqAsQ-4c zq6RZro3Mqq_RF)`c60Pm8H7?hZV^;CHRof1?-A8GO%rJm*VN*#7W5Mp+iKO?h>vNk zM^+nGbr9VNde^Z}QawZ%2nouv6MCj4*2|9KZ}Kqc|2#@!3|G@UZ)I3*;qHv%a?>Yx zv+7wi1NI{>-(W#u@_nsEEiSR0gO%Bp^gI@C(#2!TeT4A;t6q5rW0r_PffSK-(|0W* zwuk$~*;-HJK#srWF#0e|tj2fq_0nOfspe#_i-3nOX8tkM0N%W()DFeWbtYefFqy3c zQEQoryB@!>l4O1k3|)5ynW03m@Z)sUIzZ$`RB&qD*-qDR2TWru8z8mp%{$TG*O*){ zuU|~?<^MQq$;WW@wI+!L7@XzM4Y(jn|3MV7>3B#U3F3(SavqU~6v+k(+K3-FO709X z|0z?h3fy9A6O6#&=9le|B7<>&fL2Epjnzg38psE$Md~Ui$@?s z^rL1A#TrHaNj)`NY8?}5uD6XEDSJS|?dlE0h*omxaMATeH$^CWzdSrrxfQ%3i<$*4+;;?Own7uyTs z=+IB^jS3AsoOc$N4sjuKQrw%RgPf_~MOolfZTqhfOX_ZwK|XU~U8@0Fg#NPt05W6PZUdXfm(0 zxdVeaDOUE^yBR{(7tB}=b^NjpZOqVt<30hYv(6omM%&XMQ#QF?&6u|D1n246(4S2s z8Ag?N`#r96iD-b?k&aGt^V{H=^Rf*}|6Kb}$@biGf#}Yl-eQRIP|es0^hfzFZ4M1G>7E7b%SKH=d(1=R>UWwuwxwQ@T9Dn&+`+@ zE)pFMU$}SfKHV8n(LFMyy$qAP6Qv*hJdgRslj`0}>IpCC!iwtmPO4g?&*LE_>lC9A z)n$q{mVnxgd`h}ut5iO|5&Zcs)UWmF_wwTvOzCafy9nmsv={vY4Bdo81eH6?!RQ2 zPM_Q?kuQg_+&n7wu~V8jvpgu$4Y4wzM!&rh}(pIif)-T_zl?)DIu?nF`+F{9?>5N_9{44{uV)q~Hc-A4nZb^l6iJjJjMp5y zGnA0d=#2@N&BMK|TQxIPT|BtDyZG?XFdtNYwz|4&nt2#G@Ly7OYH;24>caf;?x8p6 z!>q+YQLS!L*yNX2187on!Z>-WaJ@krfrsyV431o8wbbO-g*u_kNtFkX5((L#ll)58gt|^kB zuHKk2{`JwOcErH#V-T_Wx2O4m+~VZ{n{RZ;%EE<|s(xPX{V=JxoXiuex(eQe2UE>E z6q&8PU8F;T8TM4So!yV5mg|#h=f}5G6<_#|uc?#Is=VJA9Ty0D@v815N4t$5WMAFm z`=bd%aP*zNK}3Twov@2f^#);{jK|a|c%7Mrc=xfZ&&z_>h;IHK=LtPn*bL#|?8cip z?@$=CjJKss&63-t81!xDG(-Nbh{Hl~@?rKtF|XdgeSvmuej7&MA!DyHO)B%d`DIW2S8wNz3;NxB~fwuB(~Pn6K#$_tZ?Z<%=LHM@%<#PCE$+%g0;6 zkm3%neO6<)=*jBjOGq1g#!Qp@KjY4bO8Vm^1q4&{)b2qixd9q z(Aw(yivRlmb$R?>m7}AhrKP2jk&&vZs@&XMBodjFl+@nd{%;xx1Og6+^YimFFfhPi zFjrSsZEbCHbMt?C5)%_$TwH>KgY)w8{zq+fb@jhNfcLH3KS{W!uBIL!_>mt5cSW=x zF(l?LX^$ZDlB!?~aD*#Tn?JXG=`rzW#5~yLf21ED|L>scKO`ydu{sx@APfKy{i~`V ztM3ck|D))=4u`=z^y_8@2mjtziOu4rN>+7H)Ony6{s!c`ZGj*bY87cmUb5Xb{gX?&hf-A(Y$`v=O{zHaF1@6ymQ>Nma+9ULt1Ial(% z39X)ZJ+Cz;HJ`FTHr1gh^iy~FYIpzP=49pYQL@K;*WTz*kuV|G<@4D)@Z#rR-@f&?Qo9P*ynPIwgc|dP?EusX__ro5-8GjQ z>x&GF+pn-uOG2_UDGq*wpU=WMW4`H5d>BSOcD6lWcgpOz{iuxNtoTa3)gdhU+_y&X zm>#Pyrjrh94dva)nO5hGueDNuI&-^;Vr#p7P8?=)wfm{6ZBR7ha+BwUiG-u95dSd& zVCh##-m#<%v#(%FsYK$hLiv?TVCErm|l!AL;HJ zW8h#(Gmi;KeJ*X?iLV0s7SaW(Gg`@<3KCRPXkjac{93k`rQQ0Iiq$zS!+1JA5=u=G ziWG@8^_T+Yy7;cIRZV=n?M55dv4$LPJX>Nqy`RN4k^tao!}L6RUxRt)hsT?yYl{+8 z>!d=CC#TzkZx8ANK|!XZ)q2u)CU}72G^c(bMO%U#zX3@Dg-u8`{df`5<0&$eNd$8V zufdfIt+xzD*X3CKqnu4*&k%7E=&J&iJDeL_dFpHIuO#**pg5fuzeKkWg)~27WKsC4 z6#Kz#<4)aSYbFXL zDTdl(az~GeV6IxRVckOWRQKwjv%K@dp9A2^IThS9FR}kk%?0rMFUORdRr3q$kCk!q z==9FI9q&{ujutt9{ca61F{Oe$+sT(m)F;U8Iw%vnGYDuK-A{O2+a=^X%^Sb9yQ#bZ zv2fV51C&X2zh3Z_jC7dYVE+(_=AJR#{I{nIR5KV=X5WU%6j$U|1X-69*iHYf8lwf% zXvHmHeAdcB{j-<5Bq!!er>K=)1&9ULqE3t7;R)l8H06`L&m@Pt0ryll5u#!P|42$C zMj&MQ52j*ZO93O#a8k^LFl2kF{s{TQ5@Jj}RBPHtNZ9b~UelNVHAFBk#0^|Xi&Yc!TRUZhf zV}nUWnMZ-nuy>kg;y2&l$n?N1Osq|-z~H@jD@Zm?JP(uCW8fY?$s!SRB%uZMB8wsS zPT9+po4%zk7BGV(VB4rS_V}RQo&L%7l&z03;?#P0yO z=6c?4+a=`Ho*KdQLccU&7Qz`)4^NBIj+PR>cX_m1Bj(f$ahYN852kZ@xUw^+yrI}K zd4L&HaqQf@fN2}~%Lt-`1P4T+!83sz1O2Q-HAq=fSk7s~XM4a5$Y^0?-s(#je`Za< zh`XqiE6l8tx+Geve2UM4OcLO|vE4m?*XR7BgIF9g2N z26b*{9+(98b*6vAqWE4yf@gt|_!dE$z2?I4X1E54gOrc^Nd_#`+!ZIZa909PSpIqL zxI8;|XN!Z6HyD{VcCcFne8fI6nO}ZRWgA+5xK5;f{^pt{=jR_24bJJpHHz)C4yzxS zrjO>Xxt@G^8u+c!o0k0@?=rGU3UZ%1w5YdkE(iG8f;~o{Q%J)dR`vM9@iuR~dI8RE z7Y87>)-nlq+~Scf{Wx!gQ~(VaPZ>d|Nu?;m&?L6G^Ac>>8iNO5=9_l2bnz>B<+mTw zEaiz+3~jQ_I}La4!dJyx8wFP0W`F(vad`M6XqHyTOrl1fEG=N`mHDg@tAR{p9)o%~7j|Puk z)KTK27rS4P#!F1eXLkB((%MHGqBk&wjuTu=17gFPxyu$s+}ib1o}mE|vmaQi7NOwR`18PH_ZB-wPQYUeZig1}z@1)f!wJ%>TK|ql zkQ!(!4iEv=eyb?Lx_Wk*hBZ#{E(+E&7yUQ@Xyr!B-|MKq%$No*6DL(b^w=zZ zwKiuN9ZIfmiX6WD>hLTrWBTVeuqUc#dsD=tbd|>~rL{R`A?#TT&lvVA+j5Epu~~|f z)K#(RKH535I%0yx_g@`SRxx6m6I*hb$Ni@AX@)hp$F+UOkn7?MPvvuwAHUnPv zehN9Fy0QKEtykkw6NG4~{qP|S&36Y9K9<|vwlXDGy`I2H$5cfXPUPwJ;OBsRh_PX+ zJUFgNR35CQz@H_+=RI2Cc6}c~3e1%jNiBi8ar_sr{vMv{Et7K91D@njJcsl4?+FUQ z1;jWkewiRBz1#no(#F=^O=MlV%_N22o40NcS_F3!zKYu%frrgK>pG0jgj9)3U2&jk zZqPae531nL9X~1lO2aL@?i=>Rg87z0eE>z-RiQ1)LA`&BbzUF^UFJ*eIK+T(_oAKl%2aJwx2YY!F9;**~xpSz|m^t!+K4xlMSgbgM9 zU>ORD5t=qVNMIaot3iyH%Y4ZoMo{`xIf#(c>^V)R8L&n?<=vUiUC}~X&EK;VF5CO) zPYK~BX%)y&`sC`r2qXd~zfi|JI*Yqm<3MBW@myyGQvoXzdNzm_t+dX2^)pEBDa)nf z0fx`aj}E=l&+)POPfBElL2=uBZuWG?iMi&%3qbb}fJVT5f5Yt+X#G#M7&qJzS*j4+ z@<~ldM8-bnQ<4k38VssXvGM$mX)AmQ!yIVEfL(g>@XwMR_2PS4q%nDoFR>o7tIdnI(r#p(+Ycuw$aCZ?kn%=OA@?pH#i?-2G#VNt% z*ULuSc@IP)T2u)Rj}O>gi&G=2hJbF+V8Yge20rp<>APe>mX2rgHuxq-L!XEdPag)Z zc`>sxIU^V`8)dATq8xHQtikZv@r)!Lw=$8VKqrR?g4fYs16AEhz8;ZTTsy++LCdKd zP$OKimmaKE4VaA%7-$mMYnsd#UfR}0hR2%tDBQKf?96(w`FA`q1&dn!?HiE5w-0X+ z$95y1GqFY8VzdRtj*Go^YmeEj%?)>Xtkg=E6vR;fGA88XL!q$E3{3+Z^HAw%piDlb z09`#l@)Z2gnyC9M7>eeCV)E)N-=|OfRXvs|$c8yurvOdBkCy6cDCj4hYubiqFu$e- zmgRpTe2@}l6i**6)lb0HNHv%^=69*#TP8AjaYx=$A(q)B07Vz7S!5d&td$Jq#(%cwvoLTV;I1xf^D5ElCs;Cf@vSr^hVxAelyQWjK-J1 zCV7QYd($1V{C)%_b;tIHe)spQt)Sd}Q>%fS>SxE8&@OZ8gV}eT-lRWBCs*pTYUhpH3|1XRE?^Qu*?_1R&ujp$*Wk?J&!oZOnBYr(+X2CNB%`}4JORnW)D)Ei_(V2J%; z&`4U2!uQ;a9GLj4A>--Bty~CoVHQ6gagFVQEV48-Pm5i)a(-ibNl|3W^(~B0@s$^v!^W)^UHpZ)Z7pa;3Yldp+fJv=!gb$mPmxmjY7hWK6({ zPTbQg<4WpJudHyE7u(caxd47v*R{TGIQD#uHixu&;)Cg!)i8_8qW?D{D&eQ!=D{mL zQlG(v=G)<3;21#k!yU0_KCMn3=T6g|I%6ew31JnV=Q7Ulm!zkI$q*xe+^a+4?P6bt zSS7u{wpDwkgQ~rL8nLvegO(WSZ=93}tkV~Y%Hjiyl{@TcDC~E_jdh81@9fY^m|9oE z@MoHYrgqypNlPdJY|YQ))+i9Sovv&?6VH$~mVzLdZ@;qG6>+>$w~5uj;zI?@w7Aa) z-Lh^^nwSnmwVz1v59=m1(#Te=-m!qxcV1Jm)DB6oAj;W=D!Bj-1;s#BM6giUOe<1lh55aWmwPzzl$m7ji_#AvH zuK&_bw|&1<`Hq&t1J;O*-%YR?1h zujBW_fAYC(=-lYu)RYlJwnaSO1oY<063Bq=p9{x0hk;EJ{9&bC`s3{b>YBcd6P~Iw z_*};~_d1?K8~7C|!eHJvf}oV{Tak@>|CQn$dnkqL%EC=6aaBiyzZac?4q0PMK3$>7yn~4$K;$h-D@3Bi>&^B@f&3#dccWX7J16#SXiyd=Y+%r4CjKR;%q%M{#rL)-i8s*N|&=dd|;^ z)sJa?=FrNO7Y+MZ99G+k3*i(L=yac6;_D)rz@5VFa-yZUwun&OU!$>2Pf8KE8Q+Rc zpz?J~2T6&{uXG6653c^Brhcsq z`718n*r@LJ*ypy}1@q`{*1oP9xI$2`i zxgl^?Wi$r%D3JbD_Cd$oST+*zkp?J^Xu{=1z8_};FI_rrX!cSB^D6&y38&`@!I+x! zu2-Kec7p%SP}xKJ7$q-V5T5(z}3bAXVa|58>o+}A-WkcATWL&h0K6do6& zUJ^)c=9G?;;~8w(uIYY5O|cY~3+H#Q+P?+`uqib{n;h1ej){zULqfkTLK|?T0hXDg zH{+~zm06tdrWeP~rZ{r54MpTh9Z1F}1u~8TwQT8k?vbQDIv~^f??%tc{u-(BA+-60 zDd;Pg9nV$9tgMW;>~!`$_H+c9F(_C7n?Kr^AqX$!glB0h4aBB4N;v!~fNp4%99v<; zn|lBdS8U^}fDiRebfQjW7Y01^G=;n)|BL{6Ux5=OOn(`9R<*kQd*ERAq*Sirf`DS&X@&xswT3No zfic`jD@l+vQBUT3a~&EntVg^unUtYX)RT(TfWp1@pFxUl%dq)~$=p*vO?>r3t~Q_m zLg zXuflJ!Y}DFEdBKjDUi5~PG$;O6Ezd(gIK`{dSh&}awN6ZT(r8*48*>${;~Dtlul>{ z$ghVg#ci?FUZ687iNKxl+&SVmJAFkXrVsY4?0j>!N^VzZ)>l}BR!w`zK|rkLP=*Bs zV^GJIOz0(UKBZ&}UDNq=9G^sj4+13`(VfPiOh2fX_K-zK?;#cE`5&epJ}~GBRli7U z*&cz2d8Urh8sz|b)ACNXwns3>%;j7ze=-59^*^i$(kcZX#+@yBP~6LMR=p3&0bD+X z9%h&aS2El%zsxw{jA~J$0%s?YtA@1Poc;Kn96wEeuuipw2K~drf4lya8PDLBATB=3 zr+J6RK5Dh%Mv)(}(pxwx_pIYQGMk{kPl*C`h#jMdpBBQYC{xUAV8EumB~RLp#o@tG zSf@2@i?W*A$-QeM*qWSThFf`CL0O#Kko^LHj$bZ8a|1xR` z9EOVwpFsRPWA!6VTJ}U-yY2T0Y#$H-z{e^Bjbo)NuVZG*pIn>BGrYh?=6^txPk_{C z-ljB>+o4 zGTo{GT$hfNOhV(!)5Mt-f__$j;Mb&q75`xU2AZWO$fO(I=59PG2uMPw;%t9|+ z6lG9U1+}lVu?DZyM!G1Y&VdmjIpx-J(iI`VyAKh|qZz5dTfk?0y)t79OgaUnB>H~% zTk(r5lhekud6xIF)Yh4^nSsnS(Tf#$LH6mp0{>oAF0{5J$tGXgnFNLGk_ z`$yp`uR-(HX}v=f4=dOj59Key40Q?p3dDH?Y6~KG>-d}7^o2Z`xKQ-7_u8&0dEt0G ze@9*;DM^=qV8R6uZK;saNhXMqWqt&G)3kPzc4PB5bOS5a=vWYj*;7Bjx?LyHltdiL z`!A@wz*N8vRDkP(p)>5B%7_(X)k%9C_*uRPv3>1k1>(|5XUitpYGp zZ@fz+Ay5{p)36mSGE(iNhD!?(4fe4w7znm7J1#(-}a5y5-LJA8{6QGoF& z;Er|RSZ+0*Kk;hp+hf%0LYvPrjmTTL|6O)|7g_P{5Au7}XSk|7y8a1w3ce)pPcWy0s}IdIVchI{wA>NbJMr>n9V=rI>Jq+u?f6p--1-1VWR! zj-$dsE2P^M4z(7l=g+ntWCT{i9^DAJHq(B4{yXL~Y97K&u7(!*zJa0;Je>Yo!IuT? zl$RJFmV`$yaps;mSh~)A|80FEJ-EXt0!RG^Eb69wvr1+KlL50G4lZUK)xJ08IU`6d zg6r{)AnmYzCW$ekXMXNNHN$y|N)TM$3MIld>Wti2B zku39$D+Gh>+iSsDPSDf3+Ns@*T6!$Qx$(O41B+rKLGV@KjuwmU<|ouB>$s2Qn zIV%Wy?XNLA;W5~`u1<}jJ720T^-+wAAA<;xi&%VHHu<6YTJ2vB&J3~q-o0i{kBg1O zOcxjPYwdFg4)uyN-mHb`*Is4u#l{Q9URw_VBbo-w0%J zM;BjY81Et=D?unlTivLBn^D5=O>Ik^T?>7trn)f9SSF{JprePFzF?o@PZHwT3Y8rS zwm6QKUpmSqkZwX$ECB0)vJQq~(z^PS^Gg6s0i_#SQ_bzEhHR$Xc6rN@N;ODF7IA}d zX9>NLxHZt8iTmdZK>=Y)EK^o%a{n$5b_6k^Qntmk*4jE;a%vb@82SH-xI%!LzJ`p{ zd8+dtNf{fVWWdV$-YcID39A*036W}}bYRo(}GN21ktn z4q58KND!pT$fZT9V?_c;H)^ORB%J$9r!O!ou}Y^eJQD7|r9{XotR=A5KX zCZ@;2+9Pz4En_d?6(TWpPjtezc z32V5n3n#Bj=8!?aD38#pUm0=gyoh}yES@YsI~C4Z1tbs^jie%7+41lANTtguLSs`p zucpjTC`{Vp^@0mfFJL0gq4fbN7xxx4VlRIw1%Ei_H@>>P@vd^RA(LC|b2`k6jW_LD z;rx~OdfuA3?bjf?$d5UmmOO_^MX0j(^y9B1x~9f7rF7V|tKAR(7WbGAti2&?MLGcU z^RqJQOULDuUh1dqOb%J!u@RVmwl;E8qf0Fv*^=aOY5eg+ljzOq7HTPRFbnM`{v7wzt2Pm)N7+#m&hAke*?2Y(op5(BsWkD^=bYAW82UqrIIBGvPz%-TJVsC|`Tg zE@jdh7;(AhkY*34Uox5OkVedtVH&_f{%TF)NJXV-C{qz!}SKw9zpwzVi z`eAWc)r0ctzEscgrQDm*Q^{r`DWY8s_=eP&UqwHC_%KMS)x1uq=k1vtQaORqw>Gqg zz@N{{?OvSvb-Ed^tA|0wef0V#yGySh);iiY^jbN9xa9!rZ&+EAcF?K!hjY2KwOmCu zdTr#V!`npodX+N#9YG8IJx8BB3GUV>#2qcG8Rte;t;V1Hb~;sq-N5yo&A?lcWV+Yb zcG6`4%+5t($x{3~*J{tI>Bv*M2FfZFNkN`*uX}|#b^2Gs?2o}%!e5V>bxJNdYj8O5 zCI5;L-Kf&|en`4aozQq+CgU4K&7@Y%XOsErf?1E7K2&4fRvSdGgA{%;78tECmiqE+ zARUuWWuBd{b3a65{a9xU=lLR!s`-P;CFjuGsyZ;*sk&@8g4Xx8(Qw@Mvr^h|OoO}> z&5`Si0(8sw)U*%tz68o;7MN|f^YK_RlUHXZls**(JyMLp_ivu4EKItX|7{1JtfE^b zAtnTIbQH1HA+(J3)4c+-VMkPOot6mlI5AhgJw!Yf+o|o2d-CwGGKv2amt5R!nJ&}M zK)Y^~e$ZAy5yTWXFTVEE57?h zVa{ZtL~@S0nMi?g2{D~4|iBPX|UA=s6Xwv%oD|aq3NJHfJlSJg59sk!X zd`seI`(2N{izyt>V!0Nc=5#n%7S5z_)szCTou^EeZrdl1-Uel@QCjfh;YjtDTGhFP zikE2Rnkl%)la)sn%WfTat0_Nkv*yHNC{ZD^<7e2X4HdG2<2=WgoqgBpCx)eP)vzv3 zU^o_Q>qq8;`^D^UpbO)od1U;@4##y7IPA-nX?=Xyyr%5_dc`)r3U3=Zws1(B)>o6$ zJZhzZ-8eH4!(3(KNt z=y48^MarqIP+PRl&$Ndim%__hZRKDU1fV?60%kFAZ~;WUnqZk)XSHsubm^0@EI~{3 z^q3FRz5T5tMKH97+DB37?!e@5PLsw*5}sG~9Ooo%(GaYb2ianY;R1g;oIb9h}l!(Ep(KV?rT3ANvyS|q`` zEUTNOz<)wlcTPzum&K+Osyiz1JM46XWfecI_%KJ`A7pYK#O+E(#F6*qgy{#S69e(m zU*u#32+fCxbGsNI4=AfOAP)r|z4jGKZEp=A+-@3Wxxxudz@uo)yh2JP$7_+oSF&&^ zF3_s!@7DSrO>mww>%dJJh+DXoF~yEOB%2iIAq;BOxFCT0IW)}6x40=RL03X7*yWT& zr8h^DVs0&xkl&4dqtGQDrg6v3le)rUyuMDX1wMpDXG{p3-hrtBQk!nMzQdod7x5)y zg%-(MygxYHNa~_87EE6-k~#@~pdx_!w+ zC^y*ciS^u6-~(;l6K}Aa$U7D(3sp3w0wQTKv3|BLirjmQ+#@NuC56K$;P(>tK|E5K z;SR2FPuXB!6A;(AJ%AZoV}L_xq>%c+0^;qsV)KUJoVbnyC|6UAPxo%}a2LWi^ z%1E+#f@n+6vD9tyd|!EU4R<{LY(wctF4Q?SV((6wcabJ!3XptFNyev_z*U zR7lA@n?F@G62m_DX`~^C3nygWZVY`wdoSuBblpTKv9F1%zrxr{c@aQE#bEXVK{VKP zYv3mpHX9LMXEWK5vAdQWO}LnvfoZAALe2c+Nu<_~Q>!=e5vI{lf+y^29>byAJUGP+ z&B#|16FJc5t|lCr{B({LCx}IU+QT+>YCNsF@P-&}U^qwnT;xxO>dfTjW_D_aGI`gv zEA!L_iKfM1OGbQh2jjBzqH%)vTGDB4odm9B^2asG8?0ZbHBFzm@sF`EGN0jRQ1-Tr zbpNu&V|?pK@~a1p0S&YsK+NMr_&TrPso^Y!n=cppB6FI^EuOHU!y=c*SC6FC7o^Pw z&m$_6p8}oEo_#*Xe+|(r(!*riAN~YrEYvs-#@otX>j^m8;VWTosJ%5j4ZZ@#l!C_} zZ_J71T=bo&WjmB#*YI?|^u)fRg?uy~YrV7-awAK_q@&!XQ|~R8^(9-iEQ7>lj(p3) zyk)3e(z=7jBAy%J;f5^ zyHM5BpiG>n^=%Y>tBBbPdJ_DMj4SWN|AX{D&M%PSKgKU}`&}m{@FX?7;UfodU?45I zz4U$Km+!NXdSF7he}X73L)Yi#*iZ>P0V9b`gQ(aYqGK1no(VgeXu`ZzPuS&X_KYhV z!}c!ojLq-U`S_#5!-Oaz{-431kBTWhuke`6KE8eDq!euyY-At@FhJp&c6=F`i8Ct* zD|`XRwh||IG+uw1+5L)(^A%&tZ@1)^?_TRhZ;_$0>^lH`M25aX_%1?J%{l`*EQq5n zG=*M3-mq3lEb)ss>ipPjq$r1fyF*6WfZ}qsq>ZMMt?-_NvP7cIrs@T z;OaR@#DyJtp{AIIgov!Ktk3u-3FN$8-rXyU2&pALgU}g>CP4H%S^!K*ljIhRe*#Re^m&LwU>(IFTnIQb|)mme9yt=w3@5SP&4 z$+Daf`EfR$VC5<@8cw5o2H?1)t2|JdIibd4^jsU^!8j5B(RxxLt$!vWOSPJ3dnM$E zrU5r#Z{kEBa=Q>>eOKnOi^3r6E2dOSu2hZ@AkM;*yH1dDQT+Ft^!YU9cmuRwO zi_3Ds3HkE#eLGgS`;j6%0yz8^p*n?C=$}qaPLNw`Sg(8EX28|vLGD~uO~D@| z%tx1DO+8;M7G7We!-c1dg3iR!wZ=#@8AmmKa9tQsF(%-oum(T5Do}`bmz#iR? z%WCoU7t_twN8E~-?oH=%cJ`B_VPP~?vQ^E{TWAD1r@q@+ z(v1a>+^43w{t32`9!s7Av11z=R9b(5CDn>DWL(^@&cb1*en;qvEm&D#iao>xDim39 zlag!a>`;jE)E0OfI`F=M@R+V*J&pk=L`LX4`zh@3m2@y3ZIbT?YO(WcqoVBZ}!|M>;tKpso^xFdjn+9 zSOL)|7eG|K?G~Ly^b6Pd$k;+0MG2G@GYNsjom`8*WembD@rNvD>Hg_(hSWj0v3c{l zpN-@*{$vMwA=azCl=jWca=5fF`T&$?Ymm&d7MsMVK6C)@RA%kIulD+P~ z-qF#?;tA|Upt!|oTQa5vqtUjDek{u-3&KjQq(k5LN6RDp{j79Gdq^qYKm;6+}qc|c}Pw8g0t8V)e(8{ z&8o&CFOci%;c7yzg>clnmQsO<3WfASzY_}a#iLrkF~BZCb(}#n>ld+Xo3J>rU9=?h zU=(`u0)G-%bDT!e>tj4bqrx@mKs4Q%61qSwH%b7@sP2d{L%gnXu2!A&A{8nA1q;`% znh!Mfnk)r|oq;so+r;PP($(@60ixHN%o&Z|01zLcw@e6D1pyHttwcYOsNp1c*Y^Y! zbypPAcy=oiDg%G8)V_{4IGGu34#35LeSy^82(BK9AD062YDO%F^7ccIGrd9^r6T< zwZetv$E;p98K>J_C%VDF@$iqF@I|)^SAMhN;N_j)ts}v>{nmOnf`CKw7Vkz6GQQRU9Hy>P?Om3d@ln4_pLlrH(Q zL;UBtRO64{+xJX#tus8Glyt~)7-h=r!+BS6FOv+T#<+som)(_ihKL_Wt&a*=$rA~e zp7xcBNj;SZ$MQE`#G`+bk3T`zA|~kYuCch@*DEM^;GxUqsqb-k{Fttg0S~kB9(dqJ)S-V^&@+&LDTM(%S8gcNykQPTwcfC7=x%t^Z&)NIut+G1<|= z@3AAjaDjW>4dmuPAHN)UaOaa-uQJ1~>$B&sT%s_Rpc~&w}Yokn7#M*Ln(^g6lSofp9*8wcP#untphuE!)`ZDn<*NNa$MV+nxoo36MYl^u1@Sv z_#Sn&oR_IH=w#~{gRd;RhsY$7`{d2O&68IUOnU)~SP5zmo;}dqH?2C7PH&`mHr`<3 zQb*9d5Y$f4b-XOy8bbcg+Nd-fT;n8Ur5~*ec88^ETfSxCedynvZN&xRF|0(cx-xAz zd&qQpj*ZKjDo0GOG=d$oHfryiM9+zuK$v*%q1=SA?{y^nysZB4%0gNu`%pvFQP6H^EjX;dkJdesZZWyDPPbvrh8ompRk9 z`_&zML1Uq*imy5Mm#Ahj=>$?N+Yw7NjqH>BOiC-;z#M;+2x&cQ3-52eQZRY2{fsW2P91tE0!T2zR0$K*!& zF}H>J5j~wN@bEZjgai2e%-s!E4_A7wS>9q_%U@Vzzv#0XLI?E%ceg|O;D&*!8+F-I z$4-sXp^z2d5#4i)cTpb9K>~UuE#+45UiuSkt&)*5Rh;0wOV`#|^Fh+xM&7|MQ@<^L z&hXjMe#yV;;e)=6aPqmm7m$oHAEb#qCdNGZ7h$fAJ2#ufEk*dX-=J@Z=Lq(t zZy|~K@Vm)^D6FmFXaAqLGXarF)ZM}CM)35l{xm0FQee1X&P;7t zyKjNcu!Dm+<;33KJCFDGlDpLzdUjv72g;o1evIXpm9^{L!2f)Ptr}6_$I<-1KdmVx Wxsm7lnO(R1$D*pJsZc402>CyJ>G7rj literal 0 HcmV?d00001 diff --git a/apps/nextjs-app/src/features/app/blocks/admin/setting/SettingPage.tsx b/apps/nextjs-app/src/features/app/blocks/admin/setting/SettingPage.tsx index 3ade690afd..a4f182a640 100644 --- a/apps/nextjs-app/src/features/app/blocks/admin/setting/SettingPage.tsx +++ b/apps/nextjs-app/src/features/app/blocks/admin/setting/SettingPage.tsx @@ -26,10 +26,11 @@ import { scrollToTarget } from './utils'; export interface ISettingPageProps { settingServerData?: ISettingVo; + rewardManage?: React.ReactNode; } export const SettingPage = (props: ISettingPageProps) => { - const { settingServerData } = props; + const { settingServerData, rewardManage } = props; const queryClient = useQueryClient(); const { t } = useTranslation('common'); @@ -264,6 +265,8 @@ export const SettingPage = (props: ISettingPageProps) => { )} + {rewardManage} + {/* email config */}

{t('email.config')}

diff --git a/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSideBar.tsx b/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSideBar.tsx index 546de1c643..77be45dd68 100644 --- a/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSideBar.tsx +++ b/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSideBar.tsx @@ -1,13 +1,23 @@ // import { TableList } from '../../table-list/TableList'; +import { CollaboratorType } from '@teable/openapi'; +import { useBase } from '@teable/sdk/hooks'; import { BaseNodeTree } from './BaseNodeTree'; import { BasePageRouter } from './BasePageRouter'; -export const BaseSideBar = () => { +export const BaseSideBar = (props: { + renderWinFreeCredit?: (spaceId: string) => React.ReactNode; +}) => { + const { renderWinFreeCredit } = props; + const base = useBase(); + const isSpaceCollaborator = base.collaboratorType === CollaboratorType.Space; return ( <> {/* */} - +
+ +
+ {isSpaceCollaborator && renderWinFreeCredit && renderWinFreeCredit(base.spaceId)} ); }; diff --git a/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSidebarHeaderLeft.tsx b/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSidebarHeaderLeft.tsx index 333fa254ed..3d6a9db273 100644 --- a/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSidebarHeaderLeft.tsx +++ b/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/BaseSidebarHeaderLeft.tsx @@ -1,19 +1,166 @@ -import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { hasPermission } from '@teable/core'; -import { ChevronsLeft, ChevronDown, Menu } from '@teable/icons'; -import { CollaboratorType, deleteBase, permanentDeleteBase, updateBase } from '@teable/openapi'; +import { ChevronsLeft, ChevronDown, Database, HelpCircle, Pencil } from '@teable/icons'; +import { CollaboratorType, getBaseList, getSharedBase, updateBase } from '@teable/openapi'; import { ReactQueryKeys } from '@teable/sdk/config'; import { useBase } from '@teable/sdk/hooks'; import { useIsTemplate } from '@teable/sdk/hooks/use-is-template'; -import { Button, cn, Input } from '@teable/ui-lib'; +import { + cn, + DropdownMenu, + DropdownMenuItem, + DropdownMenuContent, + DropdownMenuTrigger, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + Input, + DropdownMenuSeparator, +} from '@teable/ui-lib'; +import { ArrowLeft, Send } from 'lucide-react'; +import Link from 'next/link'; import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; import { useRef, useState } from 'react'; import { TeableLogo } from '@/components/TeableLogo'; import { Emoji } from '@/features/app/components/emoji/Emoji'; -import { BaseActionTrigger } from '../../space/component/BaseActionTrigger'; -import { BaseListTrigger } from '../../space/component/BaseListTrigger'; +import { useIsCloud } from '@/features/app/hooks/useIsCloud'; +import { tableConfig } from '@/features/i18n/table.config'; +import { PublishBaseDialog } from '../../table/table-header/publish-base/PublishBaseDialog'; -export const BaseSidebarHeaderLeft = () => { +const BaseDropdownMenu = ({ + children, + showRename, + onRename, + backSpace, + creditUsage, + spaceId, + collaboratorType, + currentBaseId, + disabled, +}: { + children: React.ReactNode; + showRename: boolean; + onRename: () => void; + backSpace: () => void; + spaceId: string; + creditUsage?: React.ReactNode; + collaboratorType?: CollaboratorType; + currentBaseId: string; + disabled?: boolean; +}) => { + const { t } = useTranslation(tableConfig.i18nNamespaces); + const isCloud = useIsCloud(); + const [open, setOpen] = useState(false); + + const isSpaceCollaborator = collaboratorType === CollaboratorType.Space; + const { data: spaceBases } = useQuery({ + queryKey: ReactQueryKeys.baseList(spaceId), + queryFn: ({ queryKey }) => getBaseList({ spaceId: queryKey[1] }).then((res) => res.data), + enabled: open && isSpaceCollaborator, + }); + + const { data: sharedBases } = useQuery({ + queryKey: ReactQueryKeys.getSharedBase(), + queryFn: () => getSharedBase().then((res) => res.data), + enabled: open && collaboratorType === CollaboratorType.Base, + }); + + const bases = spaceBases || sharedBases; + + return ( + + + {children} + + e.stopPropagation()} + > + +
+ + {t('common:actions.backToSpace')} +
+
+ + {isCloud && isSpaceCollaborator && creditUsage && ( + <> +
{creditUsage}
+ + + )} + + +
+ + {t('common:actions.switchBase')} +
+
+ + {bases?.map((base) => ( + + + + {base.icon ? ( + + ) : ( + + )} + + + {base.name} + + + + ))} + +
+ {showRename && ( + +
+ + {t('actions.rename')} +
+
+ )} + setOpen(false)} closeOnSuccess={false}> + e.preventDefault()}> +
+ + {t('space:publishBase.publishToCommunity')} +
+
+
+ + + + + + {t('help.title')} + + +
+
+ ); +}; + +export const BaseSidebarHeaderLeft = ({ creditUsage }: { creditUsage?: React.ReactNode }) => { const base = useBase(); const router = useRouter(); const [renaming, setRenaming] = useState(); @@ -30,17 +177,6 @@ export const BaseSidebarHeaderLeft = () => { }, }); - const { mutate: deleteBaseMutator } = useMutation({ - mutationFn: ({ baseId, permanent }: { baseId: string; permanent?: boolean }) => - permanent ? permanentDeleteBase(baseId) : deleteBase(baseId), - onSuccess: () => { - router.push({ - pathname: '/space/[spaceId]', - query: { spaceId: base.spaceId }, - }); - }, - }); - const toggleRenameBase = async () => { if (baseName && baseName !== base.name) { await updateBaseMutator({ @@ -57,8 +193,6 @@ export const BaseSidebarHeaderLeft = () => { }; const hasUpdatePermission = hasPermission(base.role, 'base|update'); - const hasDeletePermission = hasPermission(base.role, 'base|delete'); - const hasMovePermission = hasPermission(base.role, 'space|create'); const backSpace = () => { if (isTemplate) { @@ -126,35 +260,29 @@ export const BaseSidebarHeaderLeft = () => { /> ) : ( -

- {base.name} -

- )} - {!isTemplate && ( - deleteBaseMutator({ baseId: base.id, permanent })} onRename={onRename} - align="start" + spaceId={base.spaceId} + creditUsage={creditUsage} + collaboratorType={base.collaboratorType} + currentBaseId={base.id} + disabled={isTemplate} > - - +
+ + {base.name} + + {!isTemplate && } +
+ )}
- {!isTemplate && ( - - - - )} ); }; diff --git a/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/QuickAction.tsx b/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/QuickAction.tsx index be80d0c56e..e57a35eed4 100644 --- a/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/QuickAction.tsx +++ b/apps/nextjs-app/src/features/app/blocks/base/base-side-bar/QuickAction.tsx @@ -62,9 +62,9 @@ export const QuickAction = ({ children }: React.PropsWithChildren) => { variant="outline" onClick={() => setOpen(true)} > - {children} + {children} {isHydrated && ( - + {modKeyStr} K diff --git a/apps/nextjs-app/src/features/app/blocks/space-setting/SpaceInnerSettingModal.tsx b/apps/nextjs-app/src/features/app/blocks/space-setting/SpaceInnerSettingModal.tsx index 0c9940d2fc..dcb2f022e4 100644 --- a/apps/nextjs-app/src/features/app/blocks/space-setting/SpaceInnerSettingModal.tsx +++ b/apps/nextjs-app/src/features/app/blocks/space-setting/SpaceInnerSettingModal.tsx @@ -9,28 +9,55 @@ import { } from '@teable/ui-lib/shadcn'; import { Settings, Users } from 'lucide-react'; import { useTranslation } from 'next-i18next'; -import { useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { spaceConfig } from '@/features/i18n/space.config'; import { CollaboratorPage } from './collaborator'; import { GeneralPage } from './general'; interface ISpaceInnerSettingModalProps { + open?: boolean; + setOpen?: (open: boolean) => void; + defaultTab?: SettingTab; children: React.ReactNode; } -enum SettingTab { +export enum SettingTab { General = 'general', Collaborator = 'collaborator', } export const SpaceInnerSettingModal = (props: ISpaceInnerSettingModalProps) => { - const { children } = props; + const { + children, + open: controlledOpen, + setOpen: controlledSetOpen, + defaultTab = SettingTab.General, + } = props; const { t } = useTranslation(spaceConfig.i18nNamespaces); - const [open, setOpen] = useState(false); + const [internalOpen, setInternalOpen] = useState(false); + const isControlled = controlledOpen !== undefined; + const open = isControlled ? controlledOpen : internalOpen; + const setOpen = useCallback( + (value: boolean) => { + if (controlledSetOpen) { + controlledSetOpen(value); + } + if (!isControlled) { + setInternalOpen(value); + } + }, + [controlledSetOpen, isControlled, setInternalOpen] + ); + + const [tab, setTab] = useState(defaultTab); + useEffect(() => { + if (open) { + setTab(defaultTab); + } + }, [open, defaultTab]); - const [tab, setTab] = useState(SettingTab.General); const tabList = useMemo(() => { return [ { @@ -79,7 +106,10 @@ export const SpaceInnerSettingModal = (props: ISpaceInnerSettingModalProps) => { return ( {children} - + e.preventDefault()} + > {content} diff --git a/apps/nextjs-app/src/features/app/blocks/space/component/BaseListTrigger.tsx b/apps/nextjs-app/src/features/app/blocks/space/component/BaseListTrigger.tsx deleted file mode 100644 index 47e27d68cd..0000000000 --- a/apps/nextjs-app/src/features/app/blocks/space/component/BaseListTrigger.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { Database } from '@teable/icons'; -import { CollaboratorType, getBaseList, getSharedBase } from '@teable/openapi'; -import { ReactQueryKeys } from '@teable/sdk/config'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@teable/ui-lib/shadcn'; -import Link from 'next/link'; -import React from 'react'; - -export const BaseListTrigger = ({ - collaboratorType, - spaceId, - children, -}: { - collaboratorType?: CollaboratorType; - spaceId: string; - children: React.ReactNode; -}) => { - const { data: spaceBases } = useQuery({ - queryKey: ReactQueryKeys.baseList(spaceId), - queryFn: ({ queryKey }) => getBaseList({ spaceId: queryKey[1] }).then((res) => res.data), - enabled: collaboratorType !== CollaboratorType.Base, - }); - - const { data: sharedBases } = useQuery({ - queryKey: ReactQueryKeys.getSharedBase(), - queryFn: () => getSharedBase().then((res) => res.data), - enabled: collaboratorType === CollaboratorType.Base, - }); - - const bases = spaceBases || sharedBases; - - if (!bases) return null; - - return ( - - {children} - - {bases.map((base) => ( - - - {base.icon ? base.icon : } - {base.name} - - - ))} - - - ); -}; diff --git a/apps/nextjs-app/src/features/app/blocks/space/component/SpaceActionTrigger.tsx b/apps/nextjs-app/src/features/app/blocks/space/component/SpaceActionTrigger.tsx index a1a0d9af14..58906e9cb6 100644 --- a/apps/nextjs-app/src/features/app/blocks/space/component/SpaceActionTrigger.tsx +++ b/apps/nextjs-app/src/features/app/blocks/space/component/SpaceActionTrigger.tsx @@ -1,4 +1,4 @@ -import { Pencil, Trash2, Import } from '@teable/icons'; +import { Trash2, Import, Settings, Pencil } from '@teable/icons'; import type { IGetSpaceVo } from '@teable/openapi'; import { DropdownMenu, @@ -8,15 +8,17 @@ import { DropdownMenuTrigger, } from '@teable/ui-lib/shadcn'; import { useTranslation } from 'next-i18next'; -import React from 'react'; +import React, { useCallback, useState } from 'react'; import { DeleteSpaceConfirm } from '@/features/app/components/space/DeleteSpaceConfirm'; import { spaceConfig } from '@/features/i18n/space.config'; +import { SpaceInnerSettingModal, SettingTab } from '../../space-setting/SpaceInnerSettingModal'; interface ISpaceActionTrigger { space: IGetSpaceVo; showRename?: boolean; showDelete?: boolean; showImportBase?: boolean; + showSettings?: boolean; onRename?: () => void; onDelete?: () => void; onPermanentDelete?: () => void; @@ -37,6 +39,7 @@ export const SpaceActionTrigger: React.FC { + setOpen?.(false); + setSettingModalOpen(true); + }, [setOpen, setSettingModalOpen]); + + if (!showDelete && !showRename && !showSettings) { return null; } + return ( <> @@ -64,6 +74,12 @@ export const SpaceActionTrigger: React.FC )} + {showSettings && ( + + + {t('space:spaceSetting.title')} + + )} {showDelete && ( <> @@ -83,6 +99,13 @@ export const SpaceActionTrigger: React.FC + + + ); }; diff --git a/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceInnerSideBar.tsx b/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceInnerSideBar.tsx index 33501f0769..faf6f20e5a 100644 --- a/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceInnerSideBar.tsx +++ b/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceInnerSideBar.tsx @@ -5,6 +5,12 @@ import { createBase, getSpaceById } from '@teable/openapi'; import { ReactQueryKeys } from '@teable/sdk/config'; import { cn } from '@teable/ui-lib/shadcn'; import { Button } from '@teable/ui-lib/shadcn/ui/button'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@teable/ui-lib/shadcn/ui/tooltip'; import Link from 'next/link'; import { useParams } from 'next/navigation'; import { useRouter } from 'next/router'; @@ -18,8 +24,9 @@ import { PinList } from './PinList'; export const SpaceInnerSideBar = (props: { renderSettingModal?: (children: React.ReactNode) => React.ReactNode; + renderWinFreeCredit?: (spaceId: string) => React.ReactNode; }) => { - const { renderSettingModal } = props; + const { renderSettingModal, renderWinFreeCredit } = props; const router = useRouter(); const { t } = useTranslation(spaceConfig.i18nNamespaces); const { spaceId } = useParams<{ spaceId: string }>(); @@ -70,16 +77,29 @@ export const SpaceInnerSideBar = (props: {
{space && (
- + + + + + + {(!canCreateBase || createBaseLoading) && ( + + {!canCreateBase + ? t('space:tooltip.noPermissionToCreateBase') + : t('space:tooltip.creatingBase')} + + )} + +
)}
    @@ -149,6 +169,7 @@ export const SpaceInnerSideBar = (props: {
    + {renderWinFreeCredit && renderWinFreeCredit(spaceId)} ); }; diff --git a/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceSwitcher.tsx b/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceSwitcher.tsx index 5a54e7e12d..5568c86e68 100644 --- a/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceSwitcher.tsx +++ b/apps/nextjs-app/src/features/app/blocks/space/space-side-bar/SpaceSwitcher.tsx @@ -1,6 +1,6 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { getUniqName } from '@teable/core'; -import { Admin, Check, ChevronDown, Database, Plus, Settings, Trash2 } from '@teable/icons'; +import { Check, ChevronDown, Database, Plus, Settings, ShieldUser, Trash2 } from '@teable/icons'; import { createSpace, getSubscriptionSummaryList, @@ -26,27 +26,61 @@ import { PopoverContent, PopoverTrigger, } from '@teable/ui-lib/shadcn'; +import { Building2 } from 'lucide-react'; import Link from 'next/link'; import { useParams } from 'next/navigation'; import { useRouter } from 'next/router'; import { useTranslation } from 'next-i18next'; -import { useMemo, useState } from 'react'; +import type { ReactNode } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { useIsCloud } from '@/features/app/hooks/useIsCloud'; import { spaceConfig } from '@/features/i18n/space.config'; import { Level } from '../../../components/billing/Level'; import { SpaceAvatar } from '../../../components/space/SpaceAvatar'; +import { SpaceInnerSettingModal as SpaceInnerSettingModalComponent } from '../../space-setting'; +import { SettingTab } from '../../space-setting/SpaceInnerSettingModal'; import { useSpaceList } from '../hooks'; import { usePinMap } from '../usePinMap'; import { StarButton } from './StarButton'; -export const SpaceSwitcher = () => { +interface ISpaceSwitcherProps { + open?: boolean; + setOpen?: (open: boolean) => void; + upgradeTip?: ReactNode; + creditUsage?: ReactNode; + spaceInnerSettingModal?: ReactNode; +} + +export const SpaceSwitcher = (props: ISpaceSwitcherProps) => { + const { + open: controlledOpen, + setOpen: controlledSetOpen, + upgradeTip, + creditUsage, + spaceInnerSettingModal, + } = props; const router = useRouter(); const { t } = useTranslation(spaceConfig.i18nNamespaces); const { user } = useSession(); const isCloud = useIsCloud(); const queryClient = useQueryClient(); - const [open, setOpen] = useState(false); + const [internalOpen, setInternalOpen] = useState(false); + const isControlled = controlledOpen !== undefined; + const open = isControlled ? controlledOpen : internalOpen; + const setOpen = useCallback( + (value: boolean) => { + if (controlledSetOpen) { + controlledSetOpen(value); + } + if (!isControlled) { + setInternalOpen(value); + } + }, + [controlledSetOpen, isControlled, setInternalOpen] + ); + + const [settingModalOpen, setSettingModalOpen] = useState(false); const [showCreateDialog, setShowCreateDialog] = useState(false); const [spaceName, setSpaceName] = useState(''); const [highlightedValue, setHighlightedValue] = useState(); @@ -73,6 +107,13 @@ export const SpaceSwitcher = () => { return spaceList?.find((space) => space.id === currentSpaceId); }, [spaceList, currentSpaceId]); + const sortedSpaceList = useMemo(() => { + if (!spaceList || !currentSpaceId) return spaceList; + const currentSpaceItem = spaceList.find((s) => s.id === currentSpaceId); + if (!currentSpaceItem) return spaceList; + return [currentSpaceItem, ...spaceList.filter((s) => s.id !== currentSpaceId)]; + }, [spaceList, currentSpaceId]); + const organization = user?.organization; const { mutate: addSpace, isLoading } = useMutation({ @@ -133,7 +174,11 @@ export const SpaceSwitcher = () => { - + e.preventDefault()} + > { return 0; }} > -
    -

    - {t('space:allSpaces')} ({spaceList?.length || 0}) -

    - -
    + {isCloud && (upgradeTip || creditUsage) && ( +
    + {upgradeTip} + {creditUsage} +
    + )} - - {t('common:noResult')} +
    +
    + +
    - - {spaceList?.map((space) => { - const isSelected = space.id === currentSpaceId; - const subscription = subscriptionMap.get(space.id); - const isPinned = pinMap?.[space.id]; + + {t('common:noResult')} - return ( - handleSelectSpace(space)} - className={cn('group flex items-center gap-2 rounded-md h-10')} - > -
    - - {space.name} - {isCloud && } - -
    + + {sortedSpaceList?.map((space) => { + const isSelected = space.id === currentSpaceId; + const subscription = subscriptionMap.get(space.id); + const spaceIsPinned = pinMap?.[space.id]; -
    - {isSelected && } -
    -
    - ); - })} -
    - + return ( + handleSelectSpace(space)} + className={cn('group flex items-center gap-2 rounded-md h-10')} + > +
    + + {space.name} + + {isCloud && } +
    -
    - +
    + {isSelected && } +
    + + ); + })} + + + +
    + +
    @@ -214,21 +264,22 @@ export const SpaceSwitcher = () => { target="_blank" rel="noopener noreferrer" onClick={() => setOpen(false)} - className="flex h-9 items-center gap-2 rounded-md p-2 hover:bg-accent" + className="flex h-8 items-center gap-2 rounded-md px-2 hover:bg-accent" > - {t('space:sharedBase.title')} + {t('space:sharedBase.title')} + {user?.isAdmin && ( setOpen(false)} - className="flex h-9 items-center gap-2 rounded-md p-2 hover:bg-accent" + className="flex h-8 items-center gap-2 rounded-md px-2 hover:bg-accent" > - - {t('common:noun.adminPanel')} + + {t('common:noun.adminPanel')} )} @@ -238,10 +289,10 @@ export const SpaceSwitcher = () => { target="_blank" rel="noopener noreferrer" onClick={() => setOpen(false)} - className="flex h-9 items-center gap-2 rounded-md p-2 hover:bg-accent" + className="flex h-8 items-center gap-2 rounded-md px-2 hover:bg-accent" > - - {t('common:noun.organizationPanel')} + + {t('common:noun.organizationPanel')} )} @@ -250,10 +301,10 @@ export const SpaceSwitcher = () => { target="_blank" rel="noopener noreferrer" onClick={() => setOpen(false)} - className="flex h-9 items-center gap-2 rounded-md p-2 hover:bg-accent" + className="flex h-8 items-center gap-2 rounded-md p-2 hover:bg-accent" > - {t('common:trash.spaceTrash')} + {t('common:trash.spaceTrash')}
    @@ -292,6 +343,18 @@ export const SpaceSwitcher = () => {
} /> + + {spaceInnerSettingModal ? ( + spaceInnerSettingModal + ) : ( + + + + )} ); }; diff --git a/apps/nextjs-app/src/features/app/components/SideBarFooter.tsx b/apps/nextjs-app/src/features/app/components/SideBarFooter.tsx index 019c3ed7ad..2a80b45b1e 100644 --- a/apps/nextjs-app/src/features/app/components/SideBarFooter.tsx +++ b/apps/nextjs-app/src/features/app/components/SideBarFooter.tsx @@ -47,13 +47,13 @@ export const SideBarFooter: React.FC = () => { } return ( -
+
diff --git a/apps/nextjs-app/src/features/app/components/sidebar/Sidebar.tsx b/apps/nextjs-app/src/features/app/components/sidebar/Sidebar.tsx index 9277967c23..ffe15ba7d6 100644 --- a/apps/nextjs-app/src/features/app/components/sidebar/Sidebar.tsx +++ b/apps/nextjs-app/src/features/app/components/sidebar/Sidebar.tsx @@ -1,15 +1,18 @@ import { ChevronsLeft } from '@teable/icons'; -import { useIsMobile, useIsTemplate } from '@teable/sdk'; +import { useIsHydrated, useIsMobile, useIsTemplate } from '@teable/sdk'; import { Button, cn } from '@teable/ui-lib'; +import { Resizable } from 're-resizable'; import type { FC, PropsWithChildren, ReactNode } from 'react'; -import { useEffect, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; -import { useMedia } from 'react-use'; -import { SIDE_BAR_WIDTH } from '../toggle-side-bar/constant'; +import { + MAX_SIDE_BAR_WIDTH, + MIN_SIDE_BAR_WIDTH, + SIDE_BAR_WIDTH, +} from '../toggle-side-bar/constant'; import { HoverWrapper } from '../toggle-side-bar/HoverWrapper'; import { SheetWrapper } from '../toggle-side-bar/SheetWrapper'; import { SidebarHeader } from './SidebarHeader'; -import { useChatPanelStore } from './useChatPanelStore'; import { useSidebarStore } from './useSidebarStore'; interface ISidebarProps { @@ -17,90 +20,132 @@ interface ISidebarProps { className?: string; } +const useSidebar = () => { + const isTemplate = useIsTemplate(); + const [isVisible, setVisible] = useState(true); + const [width, setWidth] = useState(SIDE_BAR_WIDTH); + const storedSidebarStore = useSidebarStore(); + return useMemo(() => { + if (isTemplate) { + return { + isVisible, + setVisible, + setWidth, + width, + }; + } + return storedSidebarStore; + }, [isVisible, setVisible, setWidth, width, isTemplate, storedSidebarStore]); +}; + export const Sidebar: FC> = (props) => { const { headerLeft, children, className } = props; const isMobile = useIsMobile(); - const [leftVisible, setLeftVisible] = useState(true); - const isTemplate = useIsTemplate(); - const isLargeScreen = useMedia('(min-width: 1024px)'); - const { setVisible } = useSidebarStore(); + const { isVisible, setVisible, setWidth, width } = useSidebar(); + const isHydrated = useIsHydrated(); - const { status } = useChatPanelStore(); + const toggleSidebar = useCallback(() => { + setVisible(!isVisible); + }, [isVisible, setVisible]); - const isExpanded = status === 'expanded'; + useHotkeys('meta+b', toggleSidebar, [toggleSidebar]); - useHotkeys(`meta+b`, () => { - setVisible(!leftVisible); - }); + const sidebarClassName = cn( + 'group/sidebar flex size-full flex-col overflow-hidden bg-background', + className + ); - useEffect(() => { - setVisible(leftVisible); - }, [leftVisible, setVisible]); + const sidebarContent = useMemo( + () => ( + <> + + {children} + + ), + [headerLeft, children, toggleSidebar] + ); - useEffect(() => { - if (!isTemplate) { - setLeftVisible(isLargeScreen); - } - }, [isLargeScreen, isTemplate]); + if (isMobile) { + return ( + +
+ + {children} +
+
+ ); + } - return ( - <> - {isMobile ? ( - -
+ // Collapsed state: show trigger button with hover panel + if (!isVisible) { + return ( + + + + + +
e.preventDefault()}> {children}
- - ) : ( -
e.preventDefault()} - > -
- setLeftVisible(!leftVisible)} /> - {leftVisible && children} -
-
- )} +
+
+ ); + } - {!isMobile && !leftVisible && ( - - - - - -
e.preventDefault()} - > - - {children} -
-
-
- )} - + if (!isHydrated) { + return ( +
e.preventDefault()} + > +
{sidebarContent}
+
+ ); + } + + return ( + { + const newWidth = parseInt(ref.style.width, 10); + if (!isNaN(newWidth)) { + if (newWidth <= MIN_SIDE_BAR_WIDTH) { + setVisible(false); + } else { + setWidth(newWidth); + } + } + }} + handleClasses={{ right: 'group' }} + handleStyles={{ + right: { + width: '6px', + right: '-6px', + }, + }} + handleComponent={{ + right: ( +
+ ), + }} + > +
e.preventDefault()}> + {sidebarContent} +
+ ); }; diff --git a/apps/nextjs-app/src/features/app/components/sidebar/useSidebarStore.ts b/apps/nextjs-app/src/features/app/components/sidebar/useSidebarStore.ts index cf52aec65f..2ca00ef903 100644 --- a/apps/nextjs-app/src/features/app/components/sidebar/useSidebarStore.ts +++ b/apps/nextjs-app/src/features/app/components/sidebar/useSidebarStore.ts @@ -1,10 +1,25 @@ +import { LocalStorageKeys } from '@teable/sdk'; import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; +import { SIDE_BAR_WIDTH } from '../toggle-side-bar/constant'; + interface ISidebarState { isVisible: boolean; setVisible: (isVisible: boolean) => void; + width: number; + setWidth: (width: number) => void; } -export const useSidebarStore = create()((set) => ({ - isVisible: false, - setVisible: (isVisible: boolean) => set({ isVisible }), -})); +export const useSidebarStore = create()( + persist( + (set) => ({ + isVisible: true, + width: SIDE_BAR_WIDTH, + setVisible: (isVisible: boolean) => set((state) => ({ ...state, isVisible })), + setWidth: (width: number) => set((state) => ({ ...state, width })), + }), + { + name: LocalStorageKeys.Sidebar, + } + ) +); diff --git a/apps/nextjs-app/src/features/app/components/space/SpaceActionBar.tsx b/apps/nextjs-app/src/features/app/components/space/SpaceActionBar.tsx index 3f63b9f90c..4db9323d04 100644 --- a/apps/nextjs-app/src/features/app/components/space/SpaceActionBar.tsx +++ b/apps/nextjs-app/src/features/app/components/space/SpaceActionBar.tsx @@ -103,7 +103,8 @@ export const SpaceActionBar: React.FC = (props) => { { - let hash = 0; - for (let i = 0; i < str.length; i++) { - hash = str.charCodeAt(i) + ((hash << 5) - hash); - } - return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length]; -}; - interface ISpaceAvatarProps { name: string; className?: string; } export const SpaceAvatar = ({ name, className }: ISpaceAvatarProps) => { - const bgColor = getColorFromString(name); const initial = name?.charAt(0).toUpperCase() || '?'; return ( - + {initial} diff --git a/apps/nextjs-app/src/features/app/components/toggle-side-bar/constant.ts b/apps/nextjs-app/src/features/app/components/toggle-side-bar/constant.ts index 22f111dbeb..abb124cb83 100644 --- a/apps/nextjs-app/src/features/app/components/toggle-side-bar/constant.ts +++ b/apps/nextjs-app/src/features/app/components/toggle-side-bar/constant.ts @@ -1 +1,3 @@ export const SIDE_BAR_WIDTH = 288; +export const MIN_SIDE_BAR_WIDTH = 150; +export const MAX_SIDE_BAR_WIDTH = 480; diff --git a/apps/nextjs-app/src/features/app/hooks/useBillingLevelConfig.ts b/apps/nextjs-app/src/features/app/hooks/useBillingLevelConfig.ts index 481b97a350..ce1d129cab 100644 --- a/apps/nextjs-app/src/features/app/hooks/useBillingLevelConfig.ts +++ b/apps/nextjs-app/src/features/app/hooks/useBillingLevelConfig.ts @@ -11,20 +11,21 @@ export const useBillingLevelConfig = (productLevel?: BillingProductLevel) => { [BillingProductLevel.Free]: { name: t('level.free'), description: t('billing.levelTips', { level: t('level.free') }), - tagCls: 'bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-white', - upgradeTagCls: 'border border-gray-200 dark:border-gray-700 text-gray-600 dark:text-white', + tagCls: 'bg-gray-900/10 dark:bg-white/10 text-gray-600 dark:text-white/80', + upgradeTagCls: + 'border border-gray-900/10 dark:border-white/10 text-gray-600 dark:text-white', }, [BillingProductLevel.Pro]: { name: t('level.pro'), description: t('billing.levelTips', { level: t('level.pro') }), - tagCls: 'bg-emerald-200 dark:bg-emerald-700 text-emerald-600 dark:text-white', + tagCls: 'bg-emerald-100 dark:bg-emerald-500/20 text-emerald-600 dark:text-emerald-400', upgradeTagCls: 'border border-emerald-200 dark:border-emerald-700 text-emerald-600', }, [BillingProductLevel.Business]: { name: t('level.business'), description: t('billing.levelTips', { level: t('level.business') }), - tagCls: 'bg-emerald-200 dark:bg-emerald-700 text-emerald-600 dark:text-white', - upgradeTagCls: 'border border-emerald-200 dark:border-emerald-700 text-emerald-600', + tagCls: 'bg-blue-100 dark:bg-blue-500/20 text-blue-600 dark:text-blue-400', + upgradeTagCls: 'border border-blue-200 dark:border-blue-700 text-blue-600', }, [BillingProductLevel.Enterprise]: { name: t('level.enterprise'), diff --git a/apps/nextjs-app/src/features/app/hooks/useSetting.ts b/apps/nextjs-app/src/features/app/hooks/useSetting.ts index 5666718bf8..d4c65a5df8 100644 --- a/apps/nextjs-app/src/features/app/hooks/useSetting.ts +++ b/apps/nextjs-app/src/features/app/hooks/useSetting.ts @@ -18,6 +18,7 @@ export const useSetting = () => { webSearchEnabled = false, appGenerationEnabled = false, createdTime, + enableCreditReward = false, } = setting ?? {}; return { @@ -28,6 +29,7 @@ export const useSetting = () => { webSearchEnabled, appGenerationEnabled, createdTime, + enableCreditReward, }; }; diff --git a/apps/nextjs-app/src/features/app/layouts/BaseLayout.tsx b/apps/nextjs-app/src/features/app/layouts/BaseLayout.tsx index 5a0b40b2f0..213324331f 100644 --- a/apps/nextjs-app/src/features/app/layouts/BaseLayout.tsx +++ b/apps/nextjs-app/src/features/app/layouts/BaseLayout.tsx @@ -56,7 +56,7 @@ export const BaseLayout: React.FC<{
}> -
+
diff --git a/apps/nextjs-app/src/features/app/layouts/TemplateBaseLayout.tsx b/apps/nextjs-app/src/features/app/layouts/TemplateBaseLayout.tsx index 6185240adb..bfd16181be 100644 --- a/apps/nextjs-app/src/features/app/layouts/TemplateBaseLayout.tsx +++ b/apps/nextjs-app/src/features/app/layouts/TemplateBaseLayout.tsx @@ -86,7 +86,7 @@ export const TemplateBaseLayout = ({
}> -
+
diff --git a/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx b/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx index 1b1b700a9f..88323282cb 100644 --- a/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx +++ b/apps/nextjs-app/src/features/system/pages/ErrorPage.tsx @@ -1,5 +1,7 @@ -import Head from 'next/head'; +import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; +import { systemConfig } from '@/features/i18n/system.config'; +import { IllustrationPage } from './IllustrationPage'; type Props = { statusCode?: number | null; @@ -11,26 +13,36 @@ type Props = { export const ErrorPage: FC = (props) => { const { error, errorId, message, statusCode } = props; + const { t } = useTranslation(systemConfig.i18nNamespaces); return ( - <> - - Error {statusCode} - -
-
-

Woops !

-

- Something went wrong. Please try again later. -

+
+ +
+
+ Code: + {statusCode}
-
-

Code: {statusCode}

-

Message: {message}

-

Error id: {errorId}

-

ErrorMessage: {error?.message}

+
+ Message: + {message} +
+
+ Error id: + {errorId} +
+
+ ErrorMessage: + {error?.message}
- +
); }; diff --git a/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx b/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx index 78140a9fb5..afb8653328 100644 --- a/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx +++ b/apps/nextjs-app/src/features/system/pages/ForbiddenPage.tsx @@ -1,32 +1,26 @@ -import { Button } from '@teable/ui-lib/shadcn'; -import Head from 'next/head'; import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; import { systemConfig } from '@/features/i18n/system.config'; +import type { IButtonConfig } from './IllustrationPage'; +import { IllustrationPage } from './IllustrationPage'; -type Props = { +type ForbiddenPageProps = { title?: string; - children?: never; + description?: string; + button?: IButtonConfig; }; -export const ForbiddenPage: FC = (props) => { +export const ForbiddenPage: FC = ({ title, description, button }) => { const { t } = useTranslation(systemConfig.i18nNamespaces); - const title = props.title ?? t('system:forbidden.title'); return ( - <> - - {title} - -
-

- {title} -

-

{t('system:forbidden.description')}

- -
- + ); }; diff --git a/apps/nextjs-app/src/features/system/pages/IllustrationPage.tsx b/apps/nextjs-app/src/features/system/pages/IllustrationPage.tsx new file mode 100644 index 0000000000..6f1d53b172 --- /dev/null +++ b/apps/nextjs-app/src/features/system/pages/IllustrationPage.tsx @@ -0,0 +1,63 @@ +import { useTheme } from '@teable/next-themes'; +import { Button } from '@teable/ui-lib/shadcn'; +import Head from 'next/head'; +import Image from 'next/image'; +import type { FC } from 'react'; + +export interface IButtonConfig { + label: string; + href: string; + variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'link' | 'destructive'; +} + +export interface IIllustrationPageProps { + /** Light theme image path */ + imageLightSrc: string; + /** Dark theme image path */ + imageDarkSrc: string; + /** Image alt text */ + imageAlt?: string; + /** Page title (also used for document title) */ + title: string; + /** Page description */ + description?: string; + /** Button config */ + button: IButtonConfig; +} + +export const IllustrationPage: FC = ({ + imageLightSrc, + imageDarkSrc, + imageAlt = 'Illustration', + title, + description, + button, +}) => { + const { resolvedTheme } = useTheme(); + + const imageSrc = resolvedTheme === 'dark' ? imageDarkSrc : imageLightSrc; + + return ( + <> + + {title} + +
+ {imageAlt} +
+

+ {title} +

+ {description && ( +

+ {description} +

+ )} +
+ +
+ + ); +}; diff --git a/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx b/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx index cfefb553cd..666f3ac6ae 100644 --- a/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx +++ b/apps/nextjs-app/src/features/system/pages/NotFoundPage.tsx @@ -1,32 +1,26 @@ -import { Button } from '@teable/ui-lib/shadcn'; -import Head from 'next/head'; import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; - import { systemConfig } from '@/features/i18n/system.config'; +import type { IButtonConfig } from './IllustrationPage'; +import { IllustrationPage } from './IllustrationPage'; -type Props = { +type NotFoundPageProps = { title?: string; - children?: never; + description?: string; + button?: IButtonConfig; }; -export const NotFoundPage: FC = (props) => { +export const NotFoundPage: FC = ({ title, description, button }) => { const { t } = useTranslation(systemConfig.i18nNamespaces); - const title = props.title ?? t('system:notFound.title'); return ( - <> - - {title} - -
-

- {title} -

- -
- + ); }; diff --git a/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx b/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx index f5cb803827..545c307922 100644 --- a/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx +++ b/apps/nextjs-app/src/features/system/pages/PaymentRequired.tsx @@ -1,34 +1,30 @@ -import { Button } from '@teable/ui-lib/shadcn'; -import Head from 'next/head'; -import { Trans, useTranslation } from 'next-i18next'; +import { useTranslation } from 'next-i18next'; import type { FC } from 'react'; import { systemConfig } from '@/features/i18n/system.config'; +import type { IButtonConfig } from './IllustrationPage'; +import { IllustrationPage } from './IllustrationPage'; -type Props = { +type PaymentRequiredPageProps = { title?: string; - children?: never; + description?: string; + button?: IButtonConfig; }; -export const PaymentRequiredPage: FC = (props) => { +export const PaymentRequiredPage: FC = ({ + title, + description, + button, +}) => { const { t } = useTranslation(systemConfig.i18nNamespaces); - const title = props.title ?? t('system:paymentRequired.title'); return ( - <> - - {title} - -
-

- {title} -

-

- }} /> -

- -
- + ); }; diff --git a/apps/nextjs-app/src/features/system/pages/index.ts b/apps/nextjs-app/src/features/system/pages/index.ts index 5ec79ffb4e..fdc14142a8 100644 --- a/apps/nextjs-app/src/features/system/pages/index.ts +++ b/apps/nextjs-app/src/features/system/pages/index.ts @@ -1,3 +1,5 @@ +export { IllustrationPage } from './IllustrationPage'; +export type { IButtonConfig, IIllustrationPageProps } from './IllustrationPage'; export { NotFoundPage } from './NotFoundPage'; export { ErrorPage } from './ErrorPage'; export { ForbiddenPage } from './ForbiddenPage'; diff --git a/packages/common-i18n/src/locales/de/common.json b/packages/common-i18n/src/locales/de/common.json index 6c40ce2f88..fce89d391b 100644 --- a/packages/common-i18n/src/locales/de/common.json +++ b/packages/common-i18n/src/locales/de/common.json @@ -6,6 +6,7 @@ "doNotSave": "Nicht speichern", "submit": "Abschicken", "confirm": "Bestätigen", + "continue": "Fortfahren", "close": "Schließen", "edit": "Bearbeiten", "fill": "Ausfüllen", @@ -30,8 +31,11 @@ "yesDelete": "Ja, lösche", "rename": "Umbenennen", "duplicate": "Duplizieren", + "export": "Exportieren", + "import": "Importieren", "change": "Ändern", "upgrade": "Upgrade", + "upgradeToLevel": "Upgrade auf {{level}}", "search": "Suche", "loadMore": "Mehr laden", "collapseSidebar": "Seitenleiste einklappen", @@ -43,15 +47,22 @@ "showAllRow": "Zeige alle Reihen", "hideNotMatchRow": "Nicht übereinstimmende Zeile ausblenden", "more": "Mehr", + "expand": "Erweitern", + "view": "Ansehen", + "preview": "Vorschau", + "viewAndEdit": "Ansehen und bearbeiten", + "deleteTip": "Möchten Sie \"{{name}}\" wirklich löschen?", "move": "Verschieben nach", "turnOn": "Einschalten", "exit": "Ausloggen", "next": "Nächste", "previous": "Vorherige", "select": "Auswählen", - "view": "Ansehen", - "preview": "Vorschau", - "viewAndEdit": "Ansehen und bearbeiten" + "refresh": "Aktualisieren", + "login": "Anmelden", + "useTemplate": "Vorlage verwenden", + "backToSpace": "Zurück zum Space", + "switchBase": "Base wechseln" }, "quickAction": { "title": "Schnelle Aktionen...", @@ -60,12 +71,13 @@ "password": { "setInvalid": "Das Passwort ist ungültig, besteht aus mindestens 8 Zeichen und muss mindestens einen Buchstaben und eine Zahl enthalten." }, - "non": { - "share": "Teilen", - "copy": "Kopiert" - }, "template": { + "non": { + "share": "Teilen", + "copy": "Kopiert" + }, "aiTitle": "Lass uns zusammen bauen", + "aiGreeting": "Wie kann ich Ihnen helfen, {{name}}", "aiSubTitle": "Die erste KI-Plattform, auf der Teams gemeinsam an Daten arbeiten und Produktions-Apps erstellen", "guideTitle": "Beginnen Sie mit Ihrem Szenario", "watchVideo": "Video ansehen", @@ -88,10 +100,14 @@ "guide6": "Erstellen Sie einen Content-Planer mit Beiträgen und Veröffentlichungsdaten", "guide7": "Lebensläufe einfügen → Teable bitten, Kandidaten zu organisieren und vorzusortieren" } + }, + "useTemplateDialog": { + "title": "Space auswählen", + "description": "Bitte wählen Sie einen Space für die Vorlage aus" } }, "settings": { - "title": "Einstellungen", + "title": "Instanzeinstellungen", "personal": { "title": "Persönliche Einstellungen" }, @@ -134,6 +150,20 @@ "addPasswordSuccess": { "title": "🎉 Passwort erfolgreich hinzugefügt." }, + "deleteAccount": { + "title": "Konto löschen", + "desc": "Diese Aktion ist unwiderruflich. Es wird Ihr Konto und alle zugehörigen Daten dauerhaft löschen.", + "error": { + "title": "Konto kann nicht gelöscht werden", + "desc": "Sie müssen zuerst die folgenden Abhängigkeiten behandeln:", + "spacesError": "Bevor Sie Ihr Konto löschen, müssen Sie zuerst Ihre Spaces verlassen (oder löschen und dann in den Papierkorb verschieben)." + }, + "confirm": { + "title": "Bitte geben Sie DELETE zur Bestätigung ein", + "placeholder": "DELETE" + }, + "loading": "Lösche..." + }, "changeEmail": { "title": "E-Mail-Adresse ändern", "desc": "Bitte verifizieren Sie Ihr Passwort und bestätigen Sie Ihre neue E-Mail-Adresse", @@ -161,9 +191,9 @@ "desc": "Sie erhalten E-Mails, wenn Sie Kommentare, Erwähnungen, Seiteneinladungen, Erinnerungen, Zugriffsanfragen und Eigentumsänderungen erhalten." }, "setting": { - "title": "Meine Einstellungen", - "theme": "Theme", - "themeDesc": "Wählen Sie das Theme für die App.", + "title": "Einstellungen", + "theme": "Benutzeroberflächen-Theme", + "themeDesc": "Wählen Sie Ihr Farbschema für die Benutzeroberfläche", "dark": "Dunkel", "light": "Hell", "system": "System", @@ -181,16 +211,65 @@ }, "integration": { "title": "Integrationen", - "description": "Sie haben {{count}} Anwendungen Zugriff auf Ihr Konto gewährt.", - "lastUsed": "Zuletzt verwendet am {{date}}", - "revoke": "Widerrufen", - "owner": "Im Besitz von {{user}}", - "revokeTitle": "Sind Sie sicher, dass Sie die Genehmigung widerrufen wollen?", - "revokeDesc": "{{name}} wird nicht mehr auf die Teable-API zugreifen können. Sie können diese Aktion nicht rückgängig machen.", - "scopeTitle": "Berechtigungen", - "scopeDesc": "Diese Anwendung wird die folgenden Bereiche abrufen können:" + "thirdPartyIntegrations": { + "title": "Drittanbieter-Integrationen", + "description": "Sie haben {{count}} Anwendungen Zugriff auf Ihr Konto gewährt.", + "lastUsed": "Zuletzt verwendet am {{date}}", + "revoke": "Widerrufen", + "owner": "Im Besitz von {{user}}", + "revokeTitle": "Sind Sie sicher, dass Sie die Genehmigung widerrufen wollen?", + "revokeDesc": "{{name}} wird nicht mehr auf die Teable-API zugreifen können. Sie können diese Aktion nicht rückgängig machen.", + "scopeTitle": "Berechtigungen", + "scopeDesc": "Diese Anwendung wird die folgenden Bereiche abrufen können:" + }, + "userIntegration": { + "title": "Verbundene Konten", + "description": "Verbinden Sie externe Konten, um Teable den Zugriff auf Ihre Ressourcen zu ermöglichen.", + "emptyDescription": "Keine verbundenen Konten", + "actions": { + "reconnect": "Erneut verbinden" + }, + "slack": { + "user": "Slack-Benutzer", + "workspace": "Slack-Arbeitsbereich" + }, + "deleteTitle": "Verbundenes Konto entfernen", + "deleteDesc": "Möchten Sie {{name}} wirklich entfernen?", + "create": "Neues Konto verbinden", + "manage": "Verbundene Konten verwalten", + "searchPlaceholder": "Verbundene Konten suchen", + "defaultName": "{{name}} Integration", + "callback": { + "error": "Autorisierung fehlgeschlagen", + "title": "Autorisierung erfolgreich", + "desc": "Sie können dieses Fenster jetzt schließen." + } + } }, "templateAdmin": { + "title": "Vorlagenverwaltung", + "noData": "Keine Daten", + "importing": "Importiere...", + "usageCount": "Nutzungsanzahl: {{count}}", + "useTemplate": "Diese Vorlage verwenden", + "createdBy": "von {{user}}", + "backToTemplateList": "Zurück zur Vorlagenliste", + "tips": { + "errorCategoryName": "Kategorie existiert nicht oder wurde gelöscht", + "needSnapshot": "Bitte erstellen Sie einen Snapshot vor der Veröffentlichung, und der Vorlagenname und die Beschreibung dürfen nicht leer sein", + "needPublish": "Bitte veröffentlichen Sie die Vorlage, bevor Sie sie hervorheben", + "needBaseSource": "Bitte wählen Sie eine Base-Quelle, bevor Sie einen Snapshot erstellen", + "forbiddenUpdateSystemTemplate": "Systemvorlagen können nicht geändert werden", + "addCategoryTips": "Bitte geben Sie zuerst einen Kategorienamen in das Suchfeld ein." + }, + "category": { + "menu": { + "getStarted": "Erste Schritte", + "recommended": "Empfohlen", + "all": "Alle", + "browseByCategory": "Nach Kategorie durchsuchen" + } + }, "header": { "cover": "Umschlag", "name": "Name", @@ -206,7 +285,32 @@ "featured": "Hervorgehoben", "createdBy": "Erstellt von", "userNonExistent": "Benutzer existiert nicht", + "preview": "Vorschau", "usage": "Nutzung" + }, + "actions": { + "title": "Aktionen", + "publish": "Veröffentlichen", + "delete": "Löschen", + "duplicate": "Duplizieren", + "preview": "Vorschau", + "use": "Verwenden", + "pinTop": "Oben anheften", + "addCategory": "Kategorie hinzufügen", + "selectCategory": "Kategorie auswählen", + "viewTemplate": "Vorlage anzeigen" + }, + "relatedTemplates": "Verwandte Vorlagen", + "noImage": "Kein Bild", + "baseSelectPanel": { + "title": "Vorlagenquelle auswählen", + "description": "Wählen Sie eine Base als Vorlage", + "confirm": "Bestätigen", + "search": "Suchen...", + "cancel": "Abbrechen", + "selectBase": "Base auswählen", + "createTemplate": "Vorlage erstellen", + "abnormalBase": "Base existiert nicht oder wurde gelöscht" } } }, @@ -240,15 +344,19 @@ "folder": "Ordner", "newAutomation": "Neue Automatisierung", "newApp": "Neue App", - "newFolder": "Neuer Ordner" + "newFolder": "Neuer Ordner", + "template": "Vorlage" }, "level": { "free": "Free", "plus": "Plus", "pro": "Pro", + "business": "Business", "enterprise": "Enterprise" }, "noResult": "Kein Ergebnis.", + "allNodes": "Alle Knoten", + "noDescription": "Keine Beschreibung", "untitled": "Ohne Titel", "name": "Name", "description": "Beschreibung", @@ -313,6 +421,8 @@ }, "help": { "title": "Hilfe", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "Die Berechtigungen für die Seite wurden aktualisiert. Bitte aktualisieren Sie die Seite, um den neuesten Inhalt zu sehen.", @@ -324,6 +434,10 @@ "unavailableInPlanTips": "Der aktuelle Abonnementplan unterstützt diese Funktion nicht", "unavailableConnectionTips": "Die Datenbankverbindungsfunktion wird in Zukunft entfernt und ist nur in der Enterprise-Edition von öffentlicher Cloud und selbstgehosteten Versionen verfügbar.", "levelTips": "Dieser Space befindet sich derzeit auf dem {{level}} Plan", + "enterpriseFeature": "Enterprise-Funktion", + "automationRequiresUpgrade": "Upgrade auf Enterprise Edition (EE) um Automatisierung zu aktivieren", + "authorityMatrixRequiresUpgrade": "Upgrade auf Enterprise Edition (EE) um Berechtigungsmatrix zu aktivieren", + "viewPricing": "Preise anzeigen", "billable": "Abrechenbar", "billableByAuthorityMatrix": "Abrechnung durch Berechtigungsmatrix generiert", "licenseExpiredGracePeriod": "Ihre Self-Hosted-Lizenz ist abgelaufen und wird am {{expiredTime}} auf den kostenlosen Plan herabgestuft. Bitte aktualisieren Sie Ihre Lizenz umgehend, um Zugriff auf Premium-Funktionen zu behalten.", @@ -345,6 +459,7 @@ }, "admin": { "setting": { + "instanceTitle": "Instanzeinstellungen", "description": "Ändern Sie die Einstellungen für Ihre aktuelle Instanz", "allowSignUp": "Erstellen neuer Konten zulassen", "allowSignUpDescription": "Wenn Sie diese Option deaktivieren, werden neue Benutzerregistrierungen verhindert, und die Schaltfläche „Registrieren“ wird nicht mehr auf der Anmeldeseite angezeigt.", @@ -361,6 +476,7 @@ "brandingSettings": { "title": "Branding-Einstellungen", "description": "Nur in der Enterprise Edition verfügbar", + "brandName": "Markenname", "logo": "Logo", "logoDescription": "Das Logo ist Ihre Markenidentität in Teable.", "logoUpload": "Logo hochladen", diff --git a/packages/common-i18n/src/locales/de/sdk.json b/packages/common-i18n/src/locales/de/sdk.json index 4e8267913f..7af11ffc2b 100644 --- a/packages/common-i18n/src/locales/de/sdk.json +++ b/packages/common-i18n/src/locales/de/sdk.json @@ -1100,7 +1100,8 @@ "deniedByEnabledAuthorityMatrix": "Berechtigung durch aktivierte Berechtigungsmatrix verweigert", "invalidRequestPath": "Anfragepfad ist nicht gültig", "notAllowedOperation": "Sie haben keine Berechtigung, diese Operation auszuführen", - "notAllowedDepartment": "Sie haben keine Berechtigung, auf diese Abteilung zuzugreifen" + "notAllowedDepartment": "Sie haben keine Berechtigung, auf diese Abteilung zuzugreifen", + "templateHeaderInvalid": "Vorlagen-Header ist ungültig" }, "authorityMatrix": { "defaultRoleNotFound": "Standardrolle nicht gefunden", @@ -1149,6 +1150,7 @@ "lookupFieldIdInvalid": "Nachschlagefeld {{lookupFieldId}} ungültig", "formulaExpressionParseError": "Formelausdrucks-Parsefehler", "formulaReferenceNotFound": "Formelreferenzfeld {{fieldIds}} nicht gefunden", + "formulaReferenceNotFieldId": "Formelreferenzen {{fieldIds}} nicht gefunden. Formeln müssen Feld-IDs (fldXXXXXXXXXXXXXXXX Format) verwenden, nicht Feldnamen.", "rollupExpressionParseError": "Rollup-Ausdrucks-Parsefehler", "choiceNameAlreadyExists": "Auswahlname {{name}} existiert bereits", "symmetricFieldIdRequired": "Symmetrische Feld-ID ist erforderlich", @@ -1175,10 +1177,13 @@ }, "view": { "notFound": "Ansicht nicht gefunden", + "cannotDeleteLastView": "Die letzte Ansicht in einer Tabelle kann nicht gelöscht werden. Eine Tabelle muss mindestens eine Ansicht haben.", "defaultViewNotFound": "Standardansicht nicht gefunden", "propertyParseError": "Fehler beim Parsen der Ansichtseigenschaft", "primaryFieldCannotBeHidden": "Primärfeld kann nicht ausgeblendet werden", "filterUnsupportedFieldType": "Filter unterstützt Feldtyp nicht", + "filterInvalidOperator": "Filter hat ungültigen Operator für diesen Feldtyp", + "filterInvalidOperatorMode": "Filter hat ungültige Operator- und Modus-Kombination", "sortUnsupportedFieldType": "Sortierung unterstützt Feldtyp nicht", "groupUnsupportedFieldType": "Gruppierung unterstützt Feldtyp nicht", "anchorNotFound": "Anker-Ansicht nicht gefunden", @@ -1283,7 +1288,8 @@ "domainVerification": { "notFound": "Kein Domain-Verifizierungscode gefunden", "invalidCode": "Ungültiger Verifizierungscode", - "resendCooldown": "Bitte warten Sie 1 Minute bevor Sie einen neuen Code anfordern" + "resendCooldown": "Bitte warten Sie 1 Minute bevor Sie einen neuen Code anfordern", + "alreadyVerified": "Domain bereits verifiziert" }, "organization": { "notFound": "Organisation nicht gefunden", @@ -1354,6 +1360,28 @@ "cannotDeployAppBeforeInitialization": "App kann vor der Initialisierung nicht bereitgestellt werden", "noProjectOrVersionFound": "Kein Projekt oder Version gefunden", "noDeploymentUrlAvailable": "Keine Bereitstellungs-URL verfügbar" + }, + "reward": { + "notFound": "Belohnung nicht gefunden", + "unsupportedSourceType": "Nicht unterstützter Belohnungsquellentyp", + "maxClaimsReached": "Sie haben die maximale Anzahl an Belohnungsansprüchen (2) für diese Woche erreicht", + "verificationFailed": "Verifizierung fehlgeschlagen: {{errors}}", + "alreadyClaimedThisWeek": "Sie haben bereits eine Belohnung für dieses Konto in dieser Woche beansprucht", + "invalidPostUrl": "Ungültiges Beitrags-URL-Format", + "postAlreadyUsed": "Dieser Beitrag wurde bereits verwendet, um eine Belohnung zu beanspruchen", + "unsupportedPlatformUrl": "Nicht unterstützte Social-Media-Plattform-URL", + "unsupportedPlatform": "Nicht unterstützte Plattform: {{platform}}", + "minCharCount": "Beitrag muss mindestens {{count}} Zeichen haben", + "minFollowerCount": "Konto muss mindestens {{count}} Follower haben", + "mustMention": "Beitrag muss {{mention}} erwähnen", + "fetchTweetFailed": "Abrufen des X-Tweets fehlgeschlagen: {{error}}", + "tweetNotFound": "X-Tweet nicht gefunden: {{postId}}", + "fetchUserFailed": "Abrufen des X-Benutzers fehlgeschlagen: {{error}}", + "xUserNotFound": "X-Benutzer nicht gefunden: {{username}}", + "fetchLinkedInPostFailed": "Abrufen des LinkedIn-Beitrags fehlgeschlagen: {{error}}", + "linkedInPostNotFound": "LinkedIn-Beitrag nicht gefunden: {{postId}}", + "linkedInAuthorNotFound": "LinkedIn-Autor nicht gefunden: {{postId}}", + "fetchLinkedInUserFailed": "Abrufen des LinkedIn-Benutzers fehlgeschlagen: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/de/space.json b/packages/common-i18n/src/locales/de/space.json index ed65a7c5f5..187a865f26 100644 --- a/packages/common-i18n/src/locales/de/space.json +++ b/packages/common-i18n/src/locales/de/space.json @@ -41,6 +41,10 @@ "pin": "Pin", "empty": "Ihre gepinnten Bases und Spaces werden hier erscheinen" }, + "tooltip": { + "noPermissionToCreateBase": "Sie haben keine Berechtigung, eine Base zu erstellen", + "creatingBase": "Base wird erstellt..." + }, "tip": { "delete": "Sind Sie sicher, dass Sie <0/> löschen wollen?", "title": "Tipps", diff --git a/packages/common-i18n/src/locales/de/system.json b/packages/common-i18n/src/locales/de/system.json index 9793e9523f..6724c32cb3 100644 --- a/packages/common-i18n/src/locales/de/system.json +++ b/packages/common-i18n/src/locales/de/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Seite wurde nicht gefunden" + "title": "Seite nicht gefunden", + "description": "Der Link, dem Sie gefolgt sind, ist möglicherweise fehlerhaft oder die Seite wurde verschoben." }, "links": { - "backToHome": "Zurück zum Anfang" + "backToHome": "Zurück zur Startseite" }, "forbidden": { - "title": "403 - Verboten", - "description": "Sie haben keine Berechtigung, auf diese Seite zuzugreifen." + "title": "Zugriff eingeschränkt", + "description": "Sie benötigen eine Berechtigung, um auf diese Ressource zuzugreifen.\nBitte wenden Sie sich an Ihren Administrator." }, "paymentRequired": { - "title": "402 - Upgrade des Abonnements erforderlich", - "description": "Your current subscription does not support access to this feature.

Please upgrade your subscription to continue." + "title": "Premium-Funktion freischalten", + "description": "Diese Funktion ist in erweiterten Plänen verfügbar.\nUpgraden Sie, um Ihre Möglichkeiten zu erweitern." + }, + "error": { + "title": "Etwas ist schief gelaufen", + "description": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut." } } diff --git a/packages/common-i18n/src/locales/en/common.json b/packages/common-i18n/src/locales/en/common.json index 5988932cca..d239e49cb9 100644 --- a/packages/common-i18n/src/locales/en/common.json +++ b/packages/common-i18n/src/locales/en/common.json @@ -35,6 +35,7 @@ "import": "Import", "change": "Change", "upgrade": "Upgrade", + "upgradeToLevel": "Upgrade to {{level}}", "search": "Search", "loadMore": "Load more", "collapseSidebar": "Collapse sidebar", @@ -59,7 +60,9 @@ "select": "Select", "refresh": "Refresh", "login": "Login", - "useTemplate": "Use template" + "useTemplate": "Use template", + "backToSpace": "Back to space", + "switchBase": "Switch base" }, "quickAction": { "title": "Quick actions...", @@ -951,6 +954,16 @@ "unknown": "AI task for table \"{{tableName}}\" was cancelled. Error: {{errorMessage}}" } } + }, + "rewardRejected": { + "title": "Reward Claim Rejected", + "message": "Your {{spaceName}} reward claim has been rejected for the following reason(s): {{errorMessages}}, Please review and submit again.", + "buttonText": "View Space" + }, + "rewardApproved": { + "title": "Reward Claim Approved", + "message": "Congratulations! Your {{spaceName}} reward claim has been approved. {{amount}} credits have been added, valid for {{expiredDays}} days.", + "buttonText": "View Space" } } } @@ -988,5 +1001,103 @@ "description": "Configure the v0 API Key to enable App builder capabilities. Access v0 setting to obtain your API Key", "previewAppError": "App running error", "sendErrorToAI": "Send error to AI" + }, + "credit": { + "title": "Credit", + "leftAmount": "Credits left", + "winFreeCredits": "Win free credits", + "getCredits": "Get 1000 credits", + "winCredit": { + "title": "Share a positive review to earn", + "freeCredits": "1000 free credits", + "guidelinesTitle": "Sharing checklist", + "tagTeableio": "Tag @teableio", + "minCharacters": "Write 100+ characters review", + "minFollowers": "Have 10+ followers", + "limitPerWeek": "500 credits per post, up to 2 posts weekly (X + LinkedIn)", + "postOnX": "Post on X", + "postOnLinkedIn": "Post on LinkedIn", + "preFilledDraft": "🌟 Pre-filled draft ready for you!", + "claimTitle": "Paste post URL to claim your credits", + "userEmail": "User email", + "postUrlLabel": "Post URL (X or LinkedIn)", + "postUrlPlaceholder": "Paste the link to your post here", + "invalidUrl": "Please enter a valid X or LinkedIn post URL", + "claiming": "Claiming...", + "claimCredits": "Claim credits", + "congratulations": "Congratulations!", + "claimSuccess": "You have claimed 500 credits!", + "verifying": "Verifying your post...", + "verifyingDescription": "We're checking your post content, this usually takes a few seconds", + "verifyFailed": "Verification failed", + "tryAgain": "Try Again" + }, + "error": { + "verificationFailed": "Verification failed" + } + }, + "reward": { + "title": "Reward", + "rewardCredits": "Reward credits", + "minCharCount": "Post must have at least {{count}} characters", + "minFollowerCount": "Account must have at least {{count}} followers", + "mustMention": "Post must mention {{mention}}", + "fetchSnapshotFailed": "Failed to fetch post snapshot", + "alreadyClaimedThisWeek": "You have already claimed a reward for this account this week", + "manage": { + "title": "Reward Management", + "description": "View and manage reward records across all spaces", + "overview": "Overview", + "records": "Records", + "searchSpace": "Search space...", + "searchRecords": "Search postUrl/userId...", + "dateRange": "Select date range", + "from": "From", + "to": "To", + "totalSpaces": "Total: {{count}} spaces", + "totalRecords": "Total: {{count}} records", + "space": "Space", + "allSpaces": "All Spaces", + "user": "User", + "creator": "Creator", + "platform": "Platform", + "allStatuses": "All Statuses", + "allPlatforms": "All Platforms", + "pendingCount": "Pending Count", + "approvedCount": "Approved Count", + "rejectedCount": "Rejected Count", + "approvedAmount": "Approved Amount", + "consumedAmount": "Consumed Amount", + "availableAmount": "Available Amount", + "expiringSoonAmount": "Expiring Soon Amount (7d)", + "amount": "Amount", + "remainingAmount": "Remaining Amount", + "createdTime": "Created Time", + "rewardTime": "Rewarded Time", + "expiredTime": "Expired Time", + "lastModified": "Last Modified", + "viewDetails": "View Details", + "details": "Reward Details", + "basicInfo": "Basic Info", + "amountInfo": "Amount Info", + "timeInfo": "Time Info", + "socialInfo": "Social Info", + "verifyResult": "Verification Result", + "uniqueKey": "Unique Key", + "verify": "Verify", + "valid": "Valid", + "invalid": "Invalid", + "errors": "Errors", + "copied": "{{label}} copied", + "openPost": "Open post", + "noData": "No data", + "page": "Page {{current}} of {{total}}", + "status": { + "label": "Status", + "pending": "Pending", + "approved": "Approved", + "rejected": "Rejected" + } + } } } diff --git a/packages/common-i18n/src/locales/en/sdk.json b/packages/common-i18n/src/locales/en/sdk.json index 1cb2fb9e9d..00d4bc5f53 100644 --- a/packages/common-i18n/src/locales/en/sdk.json +++ b/packages/common-i18n/src/locales/en/sdk.json @@ -1360,6 +1360,28 @@ "cannotDeployAppBeforeInitialization": "Cannot deploy app before initialization", "noProjectOrVersionFound": "No project or version found", "noDeploymentUrlAvailable": "No deployment URL available" + }, + "reward": { + "notFound": "Reward not found", + "unsupportedSourceType": "Unsupported reward source type", + "maxClaimsReached": "You have reached the maximum reward claims (2) for this week", + "verificationFailed": "Verification failed: {{errors}}", + "alreadyClaimedThisWeek": "You have already claimed a reward for this account this week", + "invalidPostUrl": "Invalid post URL format", + "postAlreadyUsed": "This post has already been used to claim a reward", + "unsupportedPlatformUrl": "Unsupported social platform URL", + "unsupportedPlatform": "Unsupported platform: {{platform}}", + "minCharCount": "Post must have at least {{count}} characters", + "minFollowerCount": "Account must have at least {{count}} followers", + "mustMention": "Post must mention {{mention}}", + "fetchTweetFailed": "Failed to fetch X tweet: {{error}}", + "tweetNotFound": "X tweet not found: {{postId}}", + "fetchUserFailed": "Failed to fetch X user: {{error}}", + "xUserNotFound": "X user not found: {{username}}", + "fetchLinkedInPostFailed": "Failed to fetch LinkedIn post: {{error}}", + "linkedInPostNotFound": "LinkedIn post not found: {{postId}}", + "linkedInAuthorNotFound": "LinkedIn author not found: {{postId}}", + "fetchLinkedInUserFailed": "Failed to fetch LinkedIn user: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/en/space.json b/packages/common-i18n/src/locales/en/space.json index d28fcb285c..b9fd24d2d5 100644 --- a/packages/common-i18n/src/locales/en/space.json +++ b/packages/common-i18n/src/locales/en/space.json @@ -45,6 +45,10 @@ "pin": "Pin", "empty": "Your pined bases and space will appear here" }, + "tooltip": { + "noPermissionToCreateBase": "You don't have permission to create base", + "creatingBase": "Creating base..." + }, "tip": { "delete": "Are you sure you want to delete <0/>?", "title": "Tips", diff --git a/packages/common-i18n/src/locales/en/system.json b/packages/common-i18n/src/locales/en/system.json index ed78ed585c..54a91c6f3d 100644 --- a/packages/common-i18n/src/locales/en/system.json +++ b/packages/common-i18n/src/locales/en/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Page not found" + "title": "Page not found", + "description": "The link you followed may be broken, or the page has been moved." }, "links": { "backToHome": "Back to home" }, "forbidden": { - "title": "403 - Forbidden", - "description": "You don't have permission to access this page." + "title": "Access restricted", + "description": "You need permission to access this resource.\nPlease contact your admin." }, "paymentRequired": { - "title": "402 - Subscription upgrade required", - "description": "Your current subscription does not support access to this feature.

Please upgrade your subscription to continue." + "title": "Unlock premium feature", + "description": "This feature is available on advanced plans.\nUpgrade to expand your capabilities." + }, + "error": { + "title": "Something went wrong", + "description": "An unexpected issue occurred. Please try again later." } } diff --git a/packages/common-i18n/src/locales/es/common.json b/packages/common-i18n/src/locales/es/common.json index 080e83ef27..4df1c1e64c 100644 --- a/packages/common-i18n/src/locales/es/common.json +++ b/packages/common-i18n/src/locales/es/common.json @@ -32,6 +32,7 @@ "duplicate": "Duplicar", "change": "Cambiar", "upgrade": "Actualizar", + "upgradeToLevel": "Actualizar a {{level}}", "search": "Buscar", "loadMore": "Cargar más", "collapseSidebar": "Colapsar barra lateral", @@ -51,7 +52,17 @@ "select": "Seleccionar", "view": "Ver", "preview": "Vista previa", - "viewAndEdit": "Ver y editar" + "viewAndEdit": "Ver y editar", + "deleteTip": "¿Está seguro de que desea eliminar \"{{name}}\"?", + "refresh": "Actualizar", + "login": "Iniciar sesión", + "useTemplate": "Usar plantilla", + "backToSpace": "Volver al Espacio", + "switchBase": "Cambiar Base", + "continue": "Continuar", + "export": "Exportar", + "import": "Importar", + "expand": "Expandir" }, "quickAction": { "title": "Acciones Rápidas...", @@ -60,12 +71,13 @@ "password": { "setInvalid": "La contraseña no es válida, debe tener al menos 8 caracteres y contener al menos una letra y un número." }, - "non": { - "share": "Compartir", - "copy": "Copiado" - }, "template": { + "non": { + "share": "Compartir", + "copy": "Copiado" + }, "aiTitle": "Construyamos juntos", + "aiGreeting": "¿En qué puedo ayudarte, {{name}}?", "aiSubTitle": "La primera plataforma de IA donde los equipos colaboran en datos y generan aplicaciones de producción", "guideTitle": "Comienza desde tu escenario", "watchVideo": "Ver video", @@ -76,6 +88,10 @@ "loadMore": "Cargar Más", "allTemplatesLoaded": "Todas las plantillas cargadas", "createTemplate": "Crear Plantilla", + "useTemplateDialog": { + "title": "Seleccionar espacio", + "description": "Por favor seleccione un espacio para la plantilla" + }, "promptBox": { "placeholder": "Construye tu aplicación empresarial con Teable", "start": "Iniciar", @@ -91,7 +107,7 @@ } }, "settings": { - "title": "Configuración", + "title": "Configuración de instancia", "personal": { "title": "Configuración personal" }, @@ -134,6 +150,20 @@ "addPasswordSuccess": { "title": "🎉 Agregue la contraseña con éxito." }, + "deleteAccount": { + "title": "Eliminar cuenta", + "desc": "Esta acción es irreversible. Eliminará permanentemente su cuenta y todos los datos asociados.", + "error": { + "title": "No se puede eliminar la cuenta", + "desc": "Debe manejar las siguientes dependencias primero:", + "spacesError": "Antes de eliminar su cuenta, primero debe salir (o eliminar, luego mover a la papelera) de sus Espacios." + }, + "confirm": { + "title": "Por favor escriba DELETE para confirmar", + "placeholder": "DELETE" + }, + "loading": "Eliminando..." + }, "changeEmail": { "title": "Cambiar dirección de correo", "desc": "Verifica tu contraseña y confirma tu nueva dirección de correo", @@ -162,13 +192,17 @@ }, "setting": { "title": "Mis Ajustes", - "theme": "Tema", - "themeDesc": "Selecciona el tema para la aplicación.", + "theme": "Tema de interfaz", + "themeDesc": "Selecciona tu esquema de colores de interfaz", "dark": "Oscuro", "light": "Claro", "system": "Sistema", "version": "Versión de la aplicación", - "language": "Idioma" + "language": "Idioma", + "interactionMode": "Modo de interacción", + "mouseMode": "Modo de cursor", + "touchMode": "Modo táctil", + "systemMode": "Seguir configuración del sistema" }, "nav": { "settings": "Configuración", @@ -176,13 +210,66 @@ "contactSupport": "Contactar con soporte" }, "integration": { - "title": "Integración", - "revoke": "Revocar", - "revokeTitle": "¿Estás seguro de que quieres revocar la autorización?", - "scopeTitle": "Permisos", - "scopeDesc": "Esta aplicación podrá obtener los siguientes ámbitos:" + "title": "Integraciones", + "thirdPartyIntegrations": { + "title": "Integraciones de terceros", + "description": "Ha otorgado acceso a {{count}} aplicaciones a su cuenta.", + "lastUsed": "Último uso {{date}}", + "revoke": "Revocar", + "owner": "Propiedad de {{user}}", + "revokeTitle": "¿Está seguro de que desea revocar la autorización?", + "revokeDesc": "{{name}} ya no podrá acceder a la API de Teable. No puede deshacer esta acción.", + "scopeTitle": "Permisos", + "scopeDesc": "Esta aplicación podrá obtener los siguientes ámbitos:" + }, + "userIntegration": { + "title": "Cuentas conectadas", + "description": "Conecte cuentas externas para permitir que Teable acceda a sus recursos.", + "emptyDescription": "Sin cuentas conectadas", + "actions": { + "reconnect": "Reconectar" + }, + "slack": { + "user": "Usuario de Slack", + "workspace": "Espacio de trabajo de Slack" + }, + "deleteTitle": "Eliminar cuenta conectada", + "deleteDesc": "¿Está seguro de que desea eliminar {{name}}?", + "create": "Conectar nueva cuenta", + "manage": "Administrar cuentas conectadas", + "searchPlaceholder": "Buscar cuentas conectadas", + "defaultName": "Integración de {{name}}", + "callback": { + "error": "Autorización fallida", + "title": "Autorización exitosa", + "desc": "Puede cerrar esta ventana ahora." + } + } }, "templateAdmin": { + "title": "Administración de plantillas", + "noData": "Sin datos", + "importing": "Importando...", + "usageCount": "Recuento de uso: {{count}}", + "useTemplate": "Usar esta plantilla", + "createdBy": "por {{user}}", + "backToTemplateList": "Volver a la lista de plantillas", + "tips": { + "errorCategoryName": "La categoría no existe o fue eliminada", + "needSnapshot": "Por favor cree una instantánea antes de publicar, y el nombre y descripción de la plantilla no pueden estar vacíos", + "needPublish": "Por favor publique la plantilla antes de destacarla", + "needBaseSource": "Por favor seleccione una fuente Base antes de crear la instantánea", + "forbiddenUpdateSystemTemplate": "Las plantillas del sistema no se pueden modificar", + "addCategoryTips": "Por favor ingrese primero un nombre de categoría en el cuadro de búsqueda." + }, + "category": { + "menu": { + "getStarted": "Comenzar", + "recommended": "Recomendado", + "all": "Todos", + "browseByCategory": "Explorar por categoría" + } + }, "header": { "cover": "Portada", "name": "Nombre", @@ -198,7 +285,32 @@ "featured": "Destacado", "createdBy": "Creado por", "userNonExistent": "Usuario no existe", + "preview": "Vista previa", "usage": "Uso" + }, + "actions": { + "title": "Acciones", + "publish": "Publicar", + "delete": "Eliminar", + "duplicate": "Duplicar", + "preview": "Vista previa", + "use": "Usar", + "pinTop": "Fijar arriba", + "addCategory": "Agregar categoría", + "selectCategory": "Seleccionar categoría", + "viewTemplate": "Ver plantilla" + }, + "relatedTemplates": "Plantillas relacionadas", + "noImage": "Sin imagen", + "baseSelectPanel": { + "title": "Seleccionar fuente de plantilla", + "description": "Seleccione una Base como plantilla", + "confirm": "Confirmar", + "search": "Buscar...", + "cancel": "Cancelar", + "selectBase": "Seleccionar Base", + "createTemplate": "Crear plantilla", + "abnormalBase": "La base no existe o fue eliminada" } } }, @@ -232,20 +344,25 @@ "folder": "Carpeta", "newAutomation": "Nueva automatización", "newApp": "Nueva aplicación", - "newFolder": "Nueva carpeta" + "newFolder": "Nueva carpeta", + "template": "Plantilla" }, "level": { "free": "Gratis", - "plus": "Más", + "plus": "Plus", "pro": "Pro", - "enterprise": "Empresa" + "business": "Business", + "enterprise": "Enterprise" }, "noResult": "Sin resultado.", - "untitled": "Intitulado", + "allNodes": "Todos los nodos", + "noDescription": "Sin descripción", + "untitled": "Sin título", "name": "Nombre", "description": "Descripción", "required": "Requerido", "characters": "caracteres", + "atLeastOne": "Reserve al menos un {{noun}}", "guide": { "prev": "Anterior", "next": "Siguiente", @@ -272,6 +389,9 @@ "poweredBy": "Alimentado por <0> ", "invite": { "dialog": { + "title": "Compartir espacio {{spaceName}}", + "desc_one": "Este espacio tiene {{count}} colaborador. Agregar un colaborador de espacio le da acceso a todas las Bases en este espacio.", + "desc_other": "Este espacio tiene {{count}} colaboradores. Agregar un colaborador de espacio les da acceso a todas las Bases en este espacio.", "tabEmail": "Invitar por correo electrónico", "emailPlaceholder": "Introduce las direcciones de correo electrónico, separadas por Enter", "tabLink": "Invitar por enlace", @@ -280,14 +400,19 @@ "linkSend": "Crear enlace", "spaceTitle": "Colaboradores espaciales", "collaboratorSearchPlaceholder": "Encuentra un colaborador espacial por nombre o correo electrónico", + "collaboratorJoin": "se unió {{joinTime}}", "collaboratorRemove": "Eliminar el colaborador", - "linkTitle": "Invitar enlaces", + "linkTitle": "Enlaces de invitación", + "linkCreatedTime": "creado {{createdTime}}", "linkCopySuccess": "Enlace copiado", "linkRemove": "Eliminar enlace" }, "base": { - "baseTitle": "Colaboradores base", - "collaboratorSearchPlaceholder": "Encuentre un colaborador base por nombre o correo electrónico" + "title": "Compartir {{baseName}}", + "desc_one": "Esta Base se comparte con {{count}} colaborador.", + "desc_other": "Esta Base se comparte con {{count}} colaboradores.", + "baseTitle": "Colaboradores de Base", + "collaboratorSearchPlaceholder": "Encuentre un colaborador de Base por nombre o correo electrónico" }, "addOrgCollaborator": { "title": "Agregar colaborador de organización", @@ -296,6 +421,8 @@ }, "help": { "title": "Ayuda", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "Los permisos de la página se han actualizado. ", @@ -306,6 +433,11 @@ "userLimitExceededDescription": "La instancia actual ha alcanzado el número máximo de usuarios permitidos por tu licencia. Por favor, desactiva algunos usuarios o actualiza la licencia.", "unavailableInPlanTips": "El plan de suscripción actual no admite esta función", "unavailableConnectionTips": "La función de conexión de base de datos se eliminará en el futuro y solo estará disponible en la edición Enterprise y en versiones autohospedadas.", + "levelTips": "Este espacio se encuentra actualmente en el plan {{level}}", + "enterpriseFeature": "Función Enterprise", + "automationRequiresUpgrade": "Actualice a Enterprise Edition (EE) para habilitar la automatización", + "authorityMatrixRequiresUpgrade": "Actualice a Enterprise Edition (EE) para habilitar la matriz de autoridad", + "viewPricing": "Ver precios", "billable": "Facturable", "billableByAuthorityMatrix": "Facturación generada por la matriz de permisos", "licenseExpiredGracePeriod": "Su licencia autohospedada ha caducado y se degradará al plan gratuito el {{expiredTime}}. Actualice su licencia de inmediato para mantener el acceso a las funciones premium.", @@ -327,6 +459,7 @@ }, "admin": { "setting": { + "instanceTitle": "Configuración de instancia", "description": "Cambie la configuración de su instancia actual", "allowSignUp": "Permitir crear nuevas cuentas", "allowSignUpDescription": "Deshabilitar esta opción prohibirá los registros de nuevos usuarios, y el botón de registro ya no aparecerá en la página de inicio de sesión.", @@ -339,10 +472,14 @@ "enableWaitlist": "Habilitar lista de espera", "enableWaitlistDescription": "Habilitar esta opción permitirá que los usuarios se registren solo con un código de invitación.", "generalSettings": "Configuración general", - "aiSettings": "Configuración de AI", + "aiSettings": { + "title": "Configuración de IA", + "description": "Configurar los ajustes de IA para esta instancia" + }, "brandingSettings": { "title": "Configuración de marca", "description": "Solo disponible en la Edición Enterprise", + "brandName": "Nombre de marca", "logo": "Logo", "logoDescription": "El logo es su identidad de marca en Teable.", "logoUpload": "Subir logo", @@ -493,9 +630,12 @@ "notification": { "title": "Notificaciones", "unread": "No leído", - "read": "Leer", + "read": "Leído", + "markAs": "Marcar esta notificación como {{status}}", "markAllAsRead": "Marcar todo como leído", + "noUnread": "No hay notificaciones con estado: {{status}}", "changeSetting": "Cambiar la configuración de notificación de página", + "new": "{{count}} nueva(s)", "showMore": "Mostrar más" }, "role": { diff --git a/packages/common-i18n/src/locales/es/sdk.json b/packages/common-i18n/src/locales/es/sdk.json index ae0fd8a637..d93ef2a2b5 100644 --- a/packages/common-i18n/src/locales/es/sdk.json +++ b/packages/common-i18n/src/locales/es/sdk.json @@ -1366,6 +1366,28 @@ "cannotDeployAppBeforeInitialization": "No se puede implementar la aplicación antes de la inicialización", "noProjectOrVersionFound": "No se encontró proyecto o versión", "noDeploymentUrlAvailable": "No hay URL de implementación disponible" + }, + "reward": { + "notFound": "Recompensa no encontrada", + "unsupportedSourceType": "Tipo de fuente de recompensa no soportado", + "maxClaimsReached": "Ha alcanzado el máximo de reclamaciones de recompensa (2) para esta semana", + "verificationFailed": "Verificación fallida: {{errors}}", + "alreadyClaimedThisWeek": "Ya ha reclamado una recompensa para esta cuenta esta semana", + "invalidPostUrl": "Formato de URL de publicación inválido", + "postAlreadyUsed": "Esta publicación ya ha sido utilizada para reclamar una recompensa", + "unsupportedPlatformUrl": "URL de plataforma social no soportada", + "unsupportedPlatform": "Plataforma no soportada: {{platform}}", + "minCharCount": "La publicación debe tener al menos {{count}} caracteres", + "minFollowerCount": "La cuenta debe tener al menos {{count}} seguidores", + "mustMention": "La publicación debe mencionar {{mention}}", + "fetchTweetFailed": "Error al obtener el tweet de X: {{error}}", + "tweetNotFound": "Tweet de X no encontrado: {{postId}}", + "fetchUserFailed": "Error al obtener el usuario de X: {{error}}", + "xUserNotFound": "Usuario de X no encontrado: {{username}}", + "fetchLinkedInPostFailed": "Error al obtener la publicación de LinkedIn: {{error}}", + "linkedInPostNotFound": "Publicación de LinkedIn no encontrada: {{postId}}", + "linkedInAuthorNotFound": "Autor de LinkedIn no encontrado: {{postId}}", + "fetchLinkedInUserFailed": "Error al obtener el usuario de LinkedIn: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/es/space.json b/packages/common-i18n/src/locales/es/space.json index b41766981a..6024d31750 100644 --- a/packages/common-i18n/src/locales/es/space.json +++ b/packages/common-i18n/src/locales/es/space.json @@ -41,6 +41,10 @@ "pin": "Fijar", "empty": "Tus bases y espacios fijados aparecerán aquí" }, + "tooltip": { + "noPermissionToCreateBase": "No tienes permiso para crear una base", + "creatingBase": "Creando base..." + }, "tip": { "delete": "¿Estás seguro de que quieres eliminar <0/>?", "title": "Consejos", diff --git a/packages/common-i18n/src/locales/es/system.json b/packages/common-i18n/src/locales/es/system.json index 5cea9b9d36..5e63d398e6 100644 --- a/packages/common-i18n/src/locales/es/system.json +++ b/packages/common-i18n/src/locales/es/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Página No Encontrada" + "title": "Página no encontrada", + "description": "El enlace que seguiste puede estar roto o la página ha sido movida." }, "links": { "backToHome": "Volver al inicio" }, "forbidden": { - "title": "403 - Acceso Denegado", - "description": "No tienes permiso para acceder a esta página." + "title": "Acceso restringido", + "description": "Necesitas permiso para acceder a este recurso.\nPor favor, contacta con tu administrador." }, "paymentRequired": { - "title": "402 - Se Requiere Actualizar la Suscripción", - "description": "Tu suscripción actual no permite acceder a esta función.

Por favor, actualiza tu suscripción para continuar." + "title": "Desbloquear función Premium", + "description": "Esta función está disponible en planes avanzados.\nActualiza para ampliar tus capacidades." + }, + "error": { + "title": "Algo salió mal", + "description": "Ocurrió un error inesperado. Por favor, inténtalo de nuevo más tarde." } } diff --git a/packages/common-i18n/src/locales/fr/common.json b/packages/common-i18n/src/locales/fr/common.json index 07e7bba60e..b5f6d18132 100644 --- a/packages/common-i18n/src/locales/fr/common.json +++ b/packages/common-i18n/src/locales/fr/common.json @@ -1,6 +1,7 @@ { "actions": { - "title": "Fonctionner", + "title": "Actions", + "add": "Ajouter", "save": "Sauvegarder", "doNotSave": "Ne pas sauvegarder", "submit": "Soumettre", @@ -15,6 +16,7 @@ "zoomIn": "Zoomer", "zoomOut": "Dézoomer", "back": "Retour", + "remove": "Supprimer", "removeConfig": "Supprimer la configuration", "saveSucceed": "Sauvegarde réussie !", "submitSucceed": "Soumission réussie !", @@ -30,12 +32,19 @@ "duplicate": "Dupliquer", "change": "Changer", "upgrade": "Mettre à niveau", + "upgradeToLevel": "Passer à {{level}}", "search": "Rechercher", "loadMore": "Charger plus", "collapseSidebar": "Réduire la barre latérale", "restore": "Récupérer", "permanentDelete": "Suppression permanente", + "globalSearch": "Recherche globale", + "fieldSearch": "Recherche par champ", + "tableIndex": "Index", + "showAllRow": "Afficher toutes les lignes", + "hideNotMatchRow": "Masquer les lignes non correspondantes", "more": "Plus", + "expand": "Développer", "move": "Déplacer vers", "turnOn": "Activer", "exit": "Déconnexion", @@ -44,7 +53,16 @@ "select": "Sélectionner", "view": "Voir", "preview": "Aperçu", - "viewAndEdit": "Voir et modifier" + "viewAndEdit": "Voir et modifier", + "deleteTip": "Êtes-vous sûr de vouloir supprimer \"{{name}}\" ?", + "refresh": "Actualiser", + "login": "Se connecter", + "useTemplate": "Utiliser le modèle", + "backToSpace": "Retour à l'espace", + "switchBase": "Changer de base", + "continue": "Continuer", + "export": "Exporter", + "import": "Importer" }, "quickAction": { "title": "Actions rapides...", @@ -53,12 +71,13 @@ "password": { "setInvalid": "Le mot de passe n'est pas valide, il doit contenir au moins 8 caractères et au moins une lettre et un chiffre." }, - "non": { - "share": "Partager", - "copy": "Copié" - }, "template": { + "non": { + "share": "Partager", + "copy": "Copié" + }, "aiTitle": "Construisons ensemble", + "aiGreeting": "Comment puis-je vous aider, {{name}} ?", "aiSubTitle": "La première plateforme IA où les équipes collaborent sur les données et génèrent des applications de production", "guideTitle": "Commencez à partir de votre scénario", "watchVideo": "Regarder la vidéo", @@ -69,6 +88,10 @@ "loadMore": "Charger Plus", "allTemplatesLoaded": "Tous les modèles chargés", "createTemplate": "Créer un Modèle", + "useTemplateDialog": { + "title": "Sélectionner un espace", + "description": "Veuillez sélectionner un espace pour le modèle" + }, "promptBox": { "placeholder": "Créez votre application métier avec Teable", "start": "Démarrer", @@ -84,7 +107,7 @@ } }, "settings": { - "title": "Paramètres", + "title": "Paramètres d'instance", "personal": { "title": "Paramètres personnels" }, @@ -129,6 +152,20 @@ "addPasswordSuccess": { "title": "🎉 Mot de passe ajouté avec succès." }, + "deleteAccount": { + "title": "Supprimer le compte", + "desc": "Cette action est irréversible. Elle supprimera définitivement votre compte et toutes les données associées.", + "error": { + "title": "Impossible de supprimer le compte", + "desc": "Vous devez d'abord gérer les dépendances suivantes :", + "spacesError": "Avant de supprimer votre compte, vous devez d'abord quitter (ou supprimer, puis déplacer vers la corbeille) vos Espaces." + }, + "confirm": { + "title": "Veuillez taper DELETE pour confirmer", + "placeholder": "DELETE" + }, + "loading": "Suppression en cours..." + }, "changeEmail": { "title": "Changer l'adresse e-mail", "desc": "Veuillez vérifier votre mot de passe et confirmer votre nouvelle adresse e-mail", @@ -176,16 +213,65 @@ }, "integration": { "title": "Intégrations", - "description": "Vous avez accordé l'accès à {{count}} applications à votre compte.", - "lastUsed": "Dernière utilisation à {{date}}", - "revoke": "Révoquer", - "owner": "Propriétaire par {{user}}", - "revokeTitle": "Êtes-vous sûr de vouloir révoquer l'autorisation ?", - "revokeDesc": "{{name}} ne pourra plus accéder à l'API Teable. Vous ne pouvez pas annuler cette action.", - "scopeTitle": "Autorisations", - "scopeDesc": "Cette application pourra obtenir les autorisations suivantes :" + "thirdPartyIntegrations": { + "title": "Intégrations tierces", + "description": "Vous avez accordé l'accès à {{count}} applications à votre compte.", + "lastUsed": "Dernière utilisation {{date}}", + "revoke": "Révoquer", + "owner": "Propriété de {{user}}", + "revokeTitle": "Êtes-vous sûr de vouloir révoquer l'autorisation ?", + "revokeDesc": "{{name}} ne pourra plus accéder à l'API Teable. Vous ne pouvez pas annuler cette action.", + "scopeTitle": "Autorisations", + "scopeDesc": "Cette application pourra obtenir les autorisations suivantes :" + }, + "userIntegration": { + "title": "Comptes connectés", + "description": "Connectez des comptes externes pour permettre à Teable d'accéder à vos ressources.", + "emptyDescription": "Aucun compte connecté", + "actions": { + "reconnect": "Reconnecter" + }, + "slack": { + "user": "Utilisateur Slack", + "workspace": "Espace de travail Slack" + }, + "deleteTitle": "Supprimer le compte connecté", + "deleteDesc": "Êtes-vous sûr de vouloir supprimer {{name}} ?", + "create": "Connecter un nouveau compte", + "manage": "Gérer les comptes connectés", + "searchPlaceholder": "Rechercher les comptes connectés", + "defaultName": "Intégration {{name}}", + "callback": { + "error": "Échec de l'autorisation", + "title": "Autorisation réussie", + "desc": "Vous pouvez maintenant fermer cette fenêtre." + } + } }, "templateAdmin": { + "title": "Administration des modèles", + "noData": "Aucune donnée", + "importing": "Importation...", + "usageCount": "Nombre d'utilisations: {{count}}", + "useTemplate": "Utiliser ce modèle", + "createdBy": "par {{user}}", + "backToTemplateList": "Retour à la liste des modèles", + "tips": { + "errorCategoryName": "La catégorie n'existe pas ou a été supprimée", + "needSnapshot": "Veuillez créer un instantané avant de publier, et le nom et la description du modèle ne peuvent pas être vides", + "needPublish": "Veuillez publier le modèle avant de le mettre en vedette", + "needBaseSource": "Veuillez sélectionner une source Base avant de créer l'instantané", + "forbiddenUpdateSystemTemplate": "Les modèles système ne peuvent pas être modifiés", + "addCategoryTips": "Veuillez d'abord saisir un nom de catégorie dans la zone de recherche." + }, + "category": { + "menu": { + "getStarted": "Commencer", + "recommended": "Recommandé", + "all": "Tous", + "browseByCategory": "Parcourir par catégorie" + } + }, "header": { "cover": "Couverture", "name": "Nom", @@ -201,7 +287,32 @@ "featured": "En vedette", "createdBy": "Créé par", "userNonExistent": "Utilisateur inexistant", + "preview": "Aperçu", "usage": "Utilisation" + }, + "actions": { + "title": "Actions", + "publish": "Publier", + "delete": "Supprimer", + "duplicate": "Dupliquer", + "preview": "Aperçu", + "use": "Utiliser", + "pinTop": "Épingler en haut", + "addCategory": "Ajouter une catégorie", + "selectCategory": "Sélectionner une catégorie", + "viewTemplate": "Voir le modèle" + }, + "relatedTemplates": "Modèles associés", + "noImage": "Aucune image", + "baseSelectPanel": { + "title": "Sélectionner la source du modèle", + "description": "Sélectionnez une Base comme modèle", + "confirm": "Confirmer", + "search": "Rechercher...", + "cancel": "Annuler", + "selectBase": "Sélectionner une Base", + "createTemplate": "Créer un modèle", + "abnormalBase": "La base n'existe pas ou a été supprimée" } } }, @@ -235,20 +346,25 @@ "folder": "Dossier", "newAutomation": "Nouvelle automatisation", "newApp": "Nouvelle application", - "newFolder": "Nouveau dossier" + "newFolder": "Nouveau dossier", + "template": "Modèle" }, "level": { "free": "Gratuit", "plus": "Plus", "pro": "Pro", - "enterprise": "Entreprise" + "business": "Business", + "enterprise": "Enterprise" }, "noResult": "Aucun résultat.", + "allNodes": "Tous les nœuds", + "noDescription": "Pas de description", "untitled": "Sans titre", "name": "Nom", "description": "Description", "required": "Requis", "characters": "caractères", + "atLeastOne": "Conservez au moins un {{noun}}", "guide": { "prev": "Précédent", "next": "Suivant", @@ -275,7 +391,7 @@ "poweredBy": "Propulsé par <0>", "invite": { "dialog": { - "title": "Partage de l'espace {{spaceName}}", + "title": "Partager l'espace {{spaceName}}", "desc_one": "Cet espace a {{count}} collaborateur. Ajouter un collaborateur à l'espace lui donnera accès à toutes les bases au sein de cet espace.", "desc_other": "Cet espace a {{count}} collaborateurs. Ajouter un collaborateur à l'espace lui donnera accès à toutes les bases au sein de cet espace.", "tabEmail": "Inviter par email", @@ -292,10 +408,23 @@ "linkCreatedTime": "créé {{createdTime}}", "linkCopySuccess": "Lien copié", "linkRemove": "Supprimer le lien" + }, + "base": { + "title": "Partager {{baseName}}", + "desc_one": "Cette Base est partagée avec {{count}} collaborateur.", + "desc_other": "Cette Base est partagée avec {{count}} collaborateurs.", + "baseTitle": "Collaborateurs de la Base", + "collaboratorSearchPlaceholder": "Trouver un collaborateur de Base par nom ou email" + }, + "addOrgCollaborator": { + "title": "Ajouter un collaborateur d'organisation", + "placeholder": "Sélectionner un membre ou département de l'organisation" } }, "help": { "title": "Aide", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "Les autorisations de la page ont été mises à jour. Veuillez rafraîchir la page pour voir le contenu le plus récent.", @@ -307,6 +436,10 @@ "unavailableInPlanTips": "Le plan d'abonnement actuel ne prend pas en charge cette fonctionnalité", "unavailableConnectionTips": "La fonctionnalité de connexion de base de données sera supprimée et ne sera disponible que dans la version Entreprise et les versions auto-hébergées.", "levelTips": "Cet espace est actuellement sur le plan {{level}}", + "enterpriseFeature": "Fonctionnalité Enterprise", + "automationRequiresUpgrade": "Passez à Enterprise Edition (EE) pour activer l'automatisation", + "authorityMatrixRequiresUpgrade": "Passez à Enterprise Edition (EE) pour activer la matrice d'autorité", + "viewPricing": "Voir les tarifs", "billable": "Facturable", "billableByAuthorityMatrix": "Facturation générée par la matrice d'autorités", "licenseExpiredGracePeriod": "Votre licence auto-hébergée a expiré et sera rétrogradée au forfait gratuit le {{expiredTime}}. Veuillez mettre à jour votre licence rapidement pour conserver l'accès aux fonctionnalités premium.", @@ -328,6 +461,7 @@ }, "admin": { "setting": { + "instanceTitle": "Paramètres d'instance", "description": "Modifier les paramètres de votre instance actuelle", "allowSignUp": "Autoriser la création de nouveaux comptes", "allowSignUpDescription": "Désactiver cette option interdira les nouvelles inscriptions d'utilisateur, et le bouton d'inscription n'apparaîtra plus sur la page de connexion.", @@ -340,10 +474,14 @@ "enableWaitlist": "Activer la liste d'attente", "enableWaitlistDescription": "Activer cette option permettra aux utilisateurs de s'inscrire uniquement avec un code d'invitation.", "generalSettings": "Paramètres généraux", - "aiSettings": "Paramètres AI", + "aiSettings": { + "title": "Paramètres IA", + "description": "Configurer les paramètres IA pour cette instance" + }, "brandingSettings": { "title": "Paramètres de marque", "description": "Disponible uniquement dans l'Édition Enterprise", + "brandName": "Nom de marque", "logo": "Logo", "logoDescription": "Le logo est votre identité de marque dans Teable.", "logoUpload": "Télécharger le logo", @@ -502,8 +640,24 @@ "new": "nouveau {{count}}", "showMore": "Voir plus" }, + "role": { + "title": { + "owner": "Propriétaire", + "creator": "Créateur", + "editor": "Éditeur", + "commenter": "Commentateur", + "viewer": "Lecteur" + }, + "description": { + "owner": "Peut entièrement configurer et modifier les bases, automatisations, matrices d'autorité et gérer les paramètres et la facturation de l'espace", + "creator": "Peut entièrement configurer et modifier les bases, automatisations et matrices d'autorité", + "editor": "Peut modifier les enregistrements et les vues, mais ne peut pas configurer les tables ou les champs", + "commenter": "Peut commenter les enregistrements", + "viewer": "Ne peut pas modifier ou commenter" + } + }, "trash": { - "spaceTrash": "Corbeille d'espace", + "spaceTrash": "Corbeille de l'espace", "type": "Type", "resetTrash": "Vider", "deletedBy": "Supprimé par", @@ -514,8 +668,18 @@ "addToTrash": "Déplacer dans la corbeille", "description": "Les données dans la corbeille occupent toujours un espace d'utilisation de records et d'utilisation de pièces jointes." }, + "pluginCenter": { + "pluginUrlEmpty": "Le plugin n'a pas d'URL", + "install": "Installer", + "publisher": "Éditeur", + "lastUpdated": "Dernière mise à jour", + "pluginNotFound": "Plugin introuvable", + "pluginEmpty": { + "title": "Pas encore de plugins" + } + }, "automation": { - "turnOnTip": "Voulez-vous activer l'automatisation actuelle?" + "turnOnTip": "Voulez-vous activer l'automatisation actuelle ?" }, "email": { "send": "Envoyer", diff --git a/packages/common-i18n/src/locales/fr/sdk.json b/packages/common-i18n/src/locales/fr/sdk.json index a016c58a6d..072c55364a 100644 --- a/packages/common-i18n/src/locales/fr/sdk.json +++ b/packages/common-i18n/src/locales/fr/sdk.json @@ -1354,6 +1354,28 @@ "cannotDeployAppBeforeInitialization": "Impossible de déployer l'application avant l'initialisation", "noProjectOrVersionFound": "Aucun projet ou version trouvé", "noDeploymentUrlAvailable": "Aucune URL de déploiement disponible" + }, + "reward": { + "notFound": "Récompense non trouvée", + "unsupportedSourceType": "Type de source de récompense non pris en charge", + "maxClaimsReached": "Vous avez atteint le maximum de réclamations de récompenses (2) pour cette semaine", + "verificationFailed": "Vérification échouée : {{errors}}", + "alreadyClaimedThisWeek": "Vous avez déjà réclamé une récompense pour ce compte cette semaine", + "invalidPostUrl": "Format d'URL de publication invalide", + "postAlreadyUsed": "Cette publication a déjà été utilisée pour réclamer une récompense", + "unsupportedPlatformUrl": "URL de plateforme sociale non prise en charge", + "unsupportedPlatform": "Plateforme non prise en charge : {{platform}}", + "minCharCount": "La publication doit contenir au moins {{count}} caractères", + "minFollowerCount": "Le compte doit avoir au moins {{count}} abonnés", + "mustMention": "La publication doit mentionner {{mention}}", + "fetchTweetFailed": "Échec de la récupération du tweet X : {{error}}", + "tweetNotFound": "Tweet X non trouvé : {{postId}}", + "fetchUserFailed": "Échec de la récupération de l'utilisateur X : {{error}}", + "xUserNotFound": "Utilisateur X non trouvé : {{username}}", + "fetchLinkedInPostFailed": "Échec de la récupération de la publication LinkedIn : {{error}}", + "linkedInPostNotFound": "Publication LinkedIn non trouvée : {{postId}}", + "linkedInAuthorNotFound": "Auteur LinkedIn non trouvé : {{postId}}", + "fetchLinkedInUserFailed": "Échec de la récupération de l'utilisateur LinkedIn : {{error}}" } } } diff --git a/packages/common-i18n/src/locales/fr/space.json b/packages/common-i18n/src/locales/fr/space.json index cee249cee6..80d766ea3e 100644 --- a/packages/common-i18n/src/locales/fr/space.json +++ b/packages/common-i18n/src/locales/fr/space.json @@ -41,6 +41,10 @@ "pin": "Épingler", "empty": "Vos bases et espaces favoris apparaîtront ici" }, + "tooltip": { + "noPermissionToCreateBase": "Vous n'avez pas la permission de créer une base", + "creatingBase": "Création de la base..." + }, "tip": { "delete": "Êtes-vous sûr de vouloir supprimer <0/> ?", "title": "Conseils", diff --git a/packages/common-i18n/src/locales/fr/system.json b/packages/common-i18n/src/locales/fr/system.json index d78f84bbe0..a94fad65d8 100644 --- a/packages/common-i18n/src/locales/fr/system.json +++ b/packages/common-i18n/src/locales/fr/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Page non trouvée" + "title": "Page non trouvée", + "description": "Le lien que vous avez suivi est peut-être rompu ou la page a été déplacée." }, "links": { "backToHome": "Retour à l'accueil" }, "forbidden": { - "title": "403 - Accès interdit", - "description": "Vous n'avez pas la permission d'accéder à cette page." + "title": "Accès restreint", + "description": "Vous avez besoin d'une autorisation pour accéder à cette ressource.\nVeuillez contacter votre administrateur." }, "paymentRequired": { - "title": "402 - Mise à niveau de l'abonnement requise", - "description": "Votre abonnement actuel ne permet pas d'accéder à cette fonctionnalité.

Veuillez mettre à niveau votre abonnement pour continuer." + "title": "Débloquer la fonctionnalité Premium", + "description": "Cette fonctionnalité est disponible dans les forfaits avancés.\nPassez à un forfait supérieur pour étendre vos capacités." + }, + "error": { + "title": "Une erreur s'est produite", + "description": "Une erreur inattendue s'est produite. Veuillez réessayer plus tard." } } diff --git a/packages/common-i18n/src/locales/it/common.json b/packages/common-i18n/src/locales/it/common.json index d1d290f777..a50b111445 100644 --- a/packages/common-i18n/src/locales/it/common.json +++ b/packages/common-i18n/src/locales/it/common.json @@ -32,6 +32,7 @@ "duplicate": "Duplica", "change": "Cambia", "upgrade": "Aggiorna", + "upgradeToLevel": "Aggiorna a {{level}}", "search": "Cerca", "loadMore": "Carica altro", "collapseSidebar": "Comprimi barra laterale", @@ -51,7 +52,17 @@ "select": "Seleziona", "view": "Visualizza", "preview": "Anteprima", - "viewAndEdit": "Visualizza e modifica" + "viewAndEdit": "Visualizza e modifica", + "deleteTip": "Sei sicuro di voler eliminare \"{{name}}\"?", + "refresh": "Aggiorna", + "login": "Accedi", + "useTemplate": "Usa modello", + "backToSpace": "Torna allo Spazio", + "switchBase": "Cambia Base", + "continue": "Continua", + "export": "Esporta", + "import": "Importa", + "expand": "Espandi" }, "quickAction": { "title": "Azioni rapide...", @@ -60,12 +71,13 @@ "password": { "setInvalid": "La password non è valida, deve contenere almeno 8 caratteri e almeno una lettera e un numero." }, - "non": { - "share": "Condividi", - "copy": "Copiato" - }, "template": { + "non": { + "share": "Condividi", + "copy": "Copiato" + }, "aiTitle": "Costruiamo insieme", + "aiGreeting": "Come posso aiutarti, {{name}}?", "aiSubTitle": "La prima piattaforma AI dove i team collaborano sui dati e generano app di produzione", "guideTitle": "Inizia dal tuo scenario", "watchVideo": "Guarda il video", @@ -76,6 +88,10 @@ "loadMore": "Carica Altro", "allTemplatesLoaded": "Tutti i modelli caricati", "createTemplate": "Crea Modello", + "useTemplateDialog": { + "title": "Seleziona spazio", + "description": "Seleziona uno spazio per il modello" + }, "promptBox": { "placeholder": "Costruisci la tua app aziendale con Teable", "start": "Inizia", @@ -91,7 +107,7 @@ } }, "settings": { - "title": "Impostazioni", + "title": "Impostazioni dell'istanza", "personal": { "title": "Impostazioni personali" }, @@ -134,6 +150,20 @@ "addPasswordSuccess": { "title": "🎉 Aggiunta password riuscita." }, + "deleteAccount": { + "title": "Elimina account", + "desc": "Questa azione è irreversibile. Eliminerà permanentemente il tuo account e tutti i dati associati.", + "error": { + "title": "Impossibile eliminare l'account", + "desc": "Devi prima gestire le seguenti dipendenze:", + "spacesError": "Prima di eliminare il tuo account, devi prima uscire (o eliminare, poi spostare nel cestino) dai tuoi Spazi." + }, + "confirm": { + "title": "Digita DELETE per confermare", + "placeholder": "DELETE" + }, + "loading": "Eliminazione in corso..." + }, "changeEmail": { "title": "Modifica indirizzo email", "desc": "Verifica la tua password e conferma il tuo nuovo indirizzo email", @@ -162,13 +192,17 @@ }, "setting": { "title": "Le mie impostazioni", - "theme": "Tema", - "themeDesc": "Seleziona il tema per l'app.", + "theme": "Tema interfaccia", + "themeDesc": "Seleziona lo schema di colori dell'interfaccia", "dark": "Scuro", "light": "Chiaro", "system": "Sistema", "version": "Versione dell'app", - "language": "Lingua" + "language": "Lingua", + "interactionMode": "Modalità di interazione", + "mouseMode": "Modalità cursore", + "touchMode": "Modalità touch", + "systemMode": "Segui le impostazioni di sistema" }, "nav": { "settings": "Impostazioni", @@ -177,14 +211,40 @@ }, "integration": { "title": "Integrazioni", - "description": "Hai concesso l'accesso al tuo account a {{count}} applicazioni.", - "lastUsed": "Ultimo utilizzo il {{date}}", - "revoke": "Revoca", - "owner": "Proprietario di {{user}}", - "revokeTitle": "Sei sicuro di voler revocare l'autorizzazione?", - "revokeDesc": "{{name}} non sarà più in grado di accedere all'API di Teable. Non puoi annullare questa azione.", - "scopeTitle": "Permessi", - "scopeDesc": "Questa applicazione sarà in grado di ottenere i seguenti ambiti:" + "thirdPartyIntegrations": { + "title": "Integrazioni di terze parti", + "description": "Hai concesso l'accesso al tuo account a {{count}} applicazioni.", + "lastUsed": "Ultimo utilizzo {{date}}", + "revoke": "Revoca", + "owner": "Di proprietà di {{user}}", + "revokeTitle": "Sei sicuro di voler revocare l'autorizzazione?", + "revokeDesc": "{{name}} non sarà più in grado di accedere all'API di Teable. Non puoi annullare questa azione.", + "scopeTitle": "Permessi", + "scopeDesc": "Questa applicazione sarà in grado di ottenere i seguenti ambiti:" + }, + "userIntegration": { + "title": "Account connessi", + "description": "Connetti account esterni per consentire a Teable di accedere alle tue risorse.", + "emptyDescription": "Nessun account connesso", + "actions": { + "reconnect": "Riconnetti" + }, + "slack": { + "user": "Utente Slack", + "workspace": "Area di lavoro Slack" + }, + "deleteTitle": "Rimuovi account connesso", + "deleteDesc": "Sei sicuro di voler rimuovere {{name}}?", + "create": "Connetti nuovo account", + "manage": "Gestisci account connessi", + "searchPlaceholder": "Cerca account connessi", + "defaultName": "Integrazione {{name}}", + "callback": { + "error": "Autorizzazione fallita", + "title": "Autorizzazione riuscita", + "desc": "Puoi chiudere questa finestra ora." + } + } }, "templateAdmin": { "header": { @@ -236,15 +296,19 @@ "folder": "Cartella", "newAutomation": "Nuova automazione", "newApp": "Nuova applicazione", - "newFolder": "Nuova cartella" + "newFolder": "Nuova cartella", + "template": "Modello" }, "level": { "free": "Gratuito", "plus": "Plus", "pro": "Pro", + "business": "Business", "enterprise": "Enterprise" }, "noResult": "Nessun risultato.", + "allNodes": "Tutti i nodi", + "noDescription": "Nessuna descrizione", "untitled": "Senza titolo", "name": "Nome", "description": "Descrizione", @@ -309,6 +373,8 @@ }, "help": { "title": "Aiuto", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "I permessi della pagina sono stati aggiornati. Si prega di aggiornare la pagina per vedere il contenuto più recente.", @@ -320,6 +386,10 @@ "unavailableInPlanTips": "Il piano di abbonamento attuale non supporta questa funzione", "unavailableConnectionTips": "La funzione di connessione al database verrà rimossa in futuro e sarà disponibile solo nella versione Enterprise e nelle versioni self-hosted.", "levelTips": "Questo spazio è attualmente sul piano {{level}}", + "enterpriseFeature": "Funzionalità Enterprise", + "automationRequiresUpgrade": "Aggiorna a Enterprise Edition (EE) per abilitare l'automazione", + "authorityMatrixRequiresUpgrade": "Aggiorna a Enterprise Edition (EE) per abilitare la matrice di autorità", + "viewPricing": "Visualizza prezzi", "billable": "Fatturabile", "billableByAuthorityMatrix": "Fatturazione generata dalla matrice dei permessi", "licenseExpiredGracePeriod": "La tua licenza self-hosted è scaduta e verrà declassata al piano gratuito il {{expiredTime}}. Aggiorna la tua licenza tempestivamente per mantenere l'accesso alle funzionalità premium.", @@ -341,6 +411,7 @@ }, "admin": { "setting": { + "instanceTitle": "Impostazioni dell'istanza", "description": "Modifica le impostazioni per la tua istanza corrente", "allowSignUp": "Consenti la creazione di nuovi account", "allowSignUpDescription": "Disabilitando questa opzione si proibiranno le nuove registrazioni degli utenti e il pulsante di registrazione non apparirà più nella pagina di accesso.", @@ -353,10 +424,14 @@ "enableWaitlist": "Abilita la lista d'attesa", "enableWaitlistDescription": "Abilitando questa opzione si consentirà agli utenti di registrarsi solo con un codice di invito.", "generalSettings": "Impostazioni generali", - "aiSettings": "Impostazioni AI", + "aiSettings": { + "title": "Impostazioni AI", + "description": "Configura le impostazioni AI per questa istanza" + }, "brandingSettings": { "title": "Impostazioni di branding", "description": "Disponibile solo nell'Edizione Enterprise", + "brandName": "Nome del marchio", "logo": "Logo", "logoDescription": "Il logo è la tua identità di marca in Teable.", "logoUpload": "Carica logo", diff --git a/packages/common-i18n/src/locales/it/sdk.json b/packages/common-i18n/src/locales/it/sdk.json index 394bcd138d..0c71260666 100644 --- a/packages/common-i18n/src/locales/it/sdk.json +++ b/packages/common-i18n/src/locales/it/sdk.json @@ -1354,6 +1354,28 @@ "cannotDeployAppBeforeInitialization": "Impossibile distribuire l'app prima dell'inizializzazione", "noProjectOrVersionFound": "Nessun progetto o versione trovato", "noDeploymentUrlAvailable": "Nessun URL di distribuzione disponibile" + }, + "reward": { + "notFound": "Premio non trovato", + "unsupportedSourceType": "Tipo di fonte premio non supportato", + "maxClaimsReached": "Hai raggiunto il massimo di richieste premio (2) per questa settimana", + "verificationFailed": "Verifica fallita: {{errors}}", + "alreadyClaimedThisWeek": "Hai già richiesto un premio per questo account questa settimana", + "invalidPostUrl": "Formato URL del post non valido", + "postAlreadyUsed": "Questo post è già stato utilizzato per richiedere un premio", + "unsupportedPlatformUrl": "URL della piattaforma social non supportato", + "unsupportedPlatform": "Piattaforma non supportata: {{platform}}", + "minCharCount": "Il post deve avere almeno {{count}} caratteri", + "minFollowerCount": "L'account deve avere almeno {{count}} follower", + "mustMention": "Il post deve menzionare {{mention}}", + "fetchTweetFailed": "Impossibile recuperare il tweet X: {{error}}", + "tweetNotFound": "Tweet X non trovato: {{postId}}", + "fetchUserFailed": "Impossibile recuperare l'utente X: {{error}}", + "xUserNotFound": "Utente X non trovato: {{username}}", + "fetchLinkedInPostFailed": "Impossibile recuperare il post LinkedIn: {{error}}", + "linkedInPostNotFound": "Post LinkedIn non trovato: {{postId}}", + "linkedInAuthorNotFound": "Autore LinkedIn non trovato: {{postId}}", + "fetchLinkedInUserFailed": "Impossibile recuperare l'utente LinkedIn: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/it/space.json b/packages/common-i18n/src/locales/it/space.json index 5f175eeb69..9be234302d 100644 --- a/packages/common-i18n/src/locales/it/space.json +++ b/packages/common-i18n/src/locales/it/space.json @@ -41,6 +41,10 @@ "pin": "Preferiti", "empty": "Le tue basi e spazi preferiti appariranno qui" }, + "tooltip": { + "noPermissionToCreateBase": "Non hai il permesso di creare una base", + "creatingBase": "Creazione della base in corso..." + }, "tip": { "delete": "Sei sicuro di voler eliminare <0/>?", "title": "Suggerimenti", diff --git a/packages/common-i18n/src/locales/it/system.json b/packages/common-i18n/src/locales/it/system.json index e547ff7a78..4e89ecc1cd 100644 --- a/packages/common-i18n/src/locales/it/system.json +++ b/packages/common-i18n/src/locales/it/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Pagina Non Trovata" + "title": "Pagina non trovata", + "description": "Il link che hai seguito potrebbe essere non valido o la pagina è stata spostata." }, "links": { "backToHome": "Torna alla home" }, "forbidden": { - "title": "403 - Accesso negato", - "description": "Non hai il permesso di accedere a questa pagina." + "title": "Accesso limitato", + "description": "Hai bisogno dell'autorizzazione per accedere a questa risorsa.\nContatta il tuo amministratore." }, "paymentRequired": { - "title": "402 - Richiesto Aggiornamento del tuo Abbonamento", - "description": "Il tuo abbonamento attuale non supporta l'accesso a questa funzione.

Per favore, aggiorna il tuo abbonamento per continuare." + "title": "Sblocca funzionalità Premium", + "description": "Questa funzionalità è disponibile nei piani avanzati.\nEffettua l'upgrade per espandere le tue capacità." + }, + "error": { + "title": "Qualcosa è andato storto", + "description": "Si è verificato un errore imprevisto. Riprova più tardi." } } diff --git a/packages/common-i18n/src/locales/ja/common.json b/packages/common-i18n/src/locales/ja/common.json index cf475da148..ea7f174c65 100644 --- a/packages/common-i18n/src/locales/ja/common.json +++ b/packages/common-i18n/src/locales/ja/common.json @@ -1,5 +1,7 @@ { "actions": { + "title": "アクション", + "add": "追加", "save": "保存", "doNotSave": "保存しない", "submit": "送信", @@ -14,6 +16,7 @@ "zoomIn": "ズームイン", "zoomOut": "ズームアウト", "back": "戻る", + "remove": "削除", "removeConfig": "設定を削除", "saveSucceed": "保存成功!", "submitSucceed": "送信成功!", @@ -29,12 +32,19 @@ "duplicate": "複製", "change": "変更", "upgrade": "アップグレード", + "upgradeToLevel": "{{level}}にアップグレード", "search": "検索", "loadMore": "されに読み込む", "collapseSidebar": "サイドバーを折りたたむ", "restore": "復元", "permanentDelete": "永久削除", + "globalSearch": "グローバル検索", + "fieldSearch": "フィールドで検索", + "tableIndex": "インデックス", + "showAllRow": "すべての行を表示", + "hideNotMatchRow": "一致しない行を非表示", "more": "もっと", + "expand": "展開", "move": "移動先", "turnOn": "有効にする", "exit": "ログアウト", @@ -43,7 +53,16 @@ "select": "選択", "view": "表示", "preview": "プレビュー", - "viewAndEdit": "表示と編集" + "viewAndEdit": "表示と編集", + "deleteTip": "\"{{name}}\"を削除してもよろしいですか?", + "refresh": "更新", + "login": "ログイン", + "useTemplate": "テンプレートを使用", + "backToSpace": "スペースに戻る", + "switchBase": "ベースを切り替え", + "continue": "続行", + "export": "エクスポート", + "import": "インポート" }, "quickAction": { "title": "クイックアクション...", @@ -52,12 +71,13 @@ "password": { "setInvalid": "パスワードが無効です。少なくとも8文字で、少なくとも1つの文字と1つの数字を含める必要があります。" }, - "non": { - "share": "共有", - "copy": "コピーされました" - }, "template": { + "non": { + "share": "共有", + "copy": "コピーされました" + }, "aiTitle": "一緒に構築しましょう", + "aiGreeting": "{{name}}さん、何かお手伝いできますか?", "aiSubTitle": "チームがデータで協力し、本番アプリを生成する最初のAIプラットフォーム", "guideTitle": "シナリオから始める", "watchVideo": "動画を見る", @@ -68,6 +88,10 @@ "loadMore": "さらに読み込む", "allTemplatesLoaded": "すべてのテンプレートが読み込まれました", "createTemplate": "テンプレートを作成", + "useTemplateDialog": { + "title": "スペースを選択", + "description": "テンプレート用のスペースを選択してください" + }, "promptBox": { "placeholder": "Teableでビジネスアプリを構築", "start": "開始", @@ -83,7 +107,7 @@ } }, "settings": { - "title": "設定", + "title": "インスタンス設定", "personal": { "title": "個人設定" }, @@ -128,6 +152,20 @@ "addPasswordSuccess": { "title": "🎉 パスワードの追加に成功しました。" }, + "deleteAccount": { + "title": "アカウントを削除", + "desc": "このアクションは元に戻せません。アカウントとすべての関連データが完全に削除されます。", + "error": { + "title": "アカウントを削除できません", + "desc": "まず以下の依存関係を処理する必要があります:", + "spacesError": "アカウントを削除する前に、まずスペースを退出(または削除してゴミ箱に移動)する必要があります。" + }, + "confirm": { + "title": "確認するにはDELETEと入力してください", + "placeholder": "DELETE" + }, + "loading": "削除中..." + }, "changeEmail": { "title": "メールアドレスの変更", "desc": "パスワードを認証し、新しいメールアドレスを確認してください", @@ -175,14 +213,40 @@ }, "integration": { "title": "統合", - "description": "は{{count}}のアプリケーションにアカウントへのアクセスを許可しました。", - "lastUsed": "最終使用日:{{date}}", - "revoke": "取り消す", - "owner": "所有者:{{user}}", - "revokeTitle": "本当に承認を取り消しますか?", - "revokeDesc": "{{name}}はTeable APIにアクセスできなくなります。この操作を元に戻すことはできません。", - "scopeTitle": "権限", - "scopeDesc": "このアプリケーションは、次のスコープを取得できます:" + "thirdPartyIntegrations": { + "title": "サードパーティ統合", + "description": "{{count}}個のアプリケーションにアカウントへのアクセスを許可しました。", + "lastUsed": "最終使用日:{{date}}", + "revoke": "取り消す", + "owner": "所有者:{{user}}", + "revokeTitle": "本当に承認を取り消しますか?", + "revokeDesc": "{{name}}はTeable APIにアクセスできなくなります。この操作を元に戻すことはできません。", + "scopeTitle": "権限", + "scopeDesc": "このアプリケーションは、次のスコープを取得できます:" + }, + "userIntegration": { + "title": "接続されたアカウント", + "description": "外部アカウントを接続して、Teableがあなたのリソースにアクセスできるようにします。", + "emptyDescription": "接続されたアカウントがありません", + "actions": { + "reconnect": "再接続" + }, + "slack": { + "user": "Slackユーザー", + "workspace": "Slackワークスペース" + }, + "deleteTitle": "接続されたアカウントを削除", + "deleteDesc": "{{name}}を削除してもよろしいですか?", + "create": "新しいアカウントを接続", + "manage": "接続されたアカウントを管理", + "searchPlaceholder": "接続されたアカウントを検索", + "defaultName": "{{name}}統合", + "callback": { + "error": "認証に失敗しました", + "title": "認証に成功しました", + "desc": "このウィンドウを閉じることができます。" + } + } }, "templateAdmin": { "header": { @@ -234,20 +298,25 @@ "folder": "フォルダ", "newAutomation": "新しいオートメーション", "newApp": "新しいアプリ", - "newFolder": "新しいフォルダ" + "newFolder": "新しいフォルダ", + "template": "テンプレート" }, "level": { "free": "無料", "plus": "プラス", "pro": "プロ", + "business": "ビジネス", "enterprise": "エンタープライズ" }, "noResult": "結果なし。", + "allNodes": "すべてのノード", + "noDescription": "説明なし", "untitled": "無題", "name": "名称", "description": "説明", "required": "必須", "characters": "文字", + "atLeastOne": "少なくとも1つの{{noun}}を保持してください", "guide": { "prev": "前へ", "next": "次へ", @@ -298,10 +367,16 @@ "desc_other": "このベースは{{count}}人の共同作業者と共有されています。", "baseTitle": "ベースの共同作業者", "collaboratorSearchPlaceholder": "名前またはメールアドレスでベースの共同作業者を探す" + }, + "addOrgCollaborator": { + "title": "組織の共同作業者を追加", + "placeholder": "組織のメンバーまたは部門を選択" } }, "help": { "title": "ヘルプ", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "ページの権限が更新されました。最新のコンテンツを表示するにはページを更新してください。", @@ -312,7 +387,11 @@ "userLimitExceededDescription": "現在のインスタンスは、ライセンスで許可されている最大ユーザー数に達しました。一部のユーザーを非アクティブ化するか、ライセンスをアップグレードしてください。", "unavailableInPlanTips": "現在契約中のプランではこの機能はサポートされていません", "unavailableConnectionTips": "データベース接続機能は将来削除され、Enterpriseプランと自己ホストバージョンでのみ利用可能になります。", - "levelTips": "このスペースは現在{{level}}プランにです", + "levelTips": "このスペースは現在{{level}}プランです", + "enterpriseFeature": "エンタープライズ機能", + "automationRequiresUpgrade": "オートメーションを有効にするにはEnterprise Edition(EE)にアップグレードしてください", + "authorityMatrixRequiresUpgrade": "権限マトリックスを有効にするにはEnterprise Edition(EE)にアップグレードしてください", + "viewPricing": "料金を見る", "billable": "課金対象", "billableByAuthorityMatrix": "権限マトリックスによって生成された課金", "licenseExpiredGracePeriod": "セルフホスト版ライセンスの有効期限が切れました。{{expiredTime}}に無料プランへダウングレードされ、プレミアム機能が利用できなくなります。完全な機能を維持するため、速やかにライセンスを更新してください。", @@ -334,6 +413,7 @@ }, "admin": { "setting": { + "instanceTitle": "インスタンス設定", "description": "現在のインスタンスの設定を変更する", "allowSignUp": "新しいアカウントの作成を許可する", "allowSignUpDescription": "このオプションを無効にすると、新規ユーザーの登録が禁止され、ログインページに登録ボタンが表示されなくなります。", @@ -346,10 +426,14 @@ "enableWaitlist": "待機リストを有効にする", "enableWaitlistDescription": "このオプションを有効にすると、ユーザーは招待コードを使用して新規アカウントの作成が可能になります。", "generalSettings": "一般設定", - "aiSettings": "AI設定", + "aiSettings": { + "title": "AI設定", + "description": "このインスタンスのAI設定を構成する" + }, "brandingSettings": { "title": "ブランディング設定", "description": "エンタープライズエディションでのみ利用可能", + "brandName": "ブランド名", "logo": "ロゴ", "logoDescription": "ロゴはTeableでのあなたのブランドアイデンティティです。", "logoUpload": "ロゴをアップロード", @@ -524,6 +608,16 @@ "viewer": "編集もコメントもできません" } }, + "pluginCenter": { + "pluginUrlEmpty": "プラグインにURLがありません", + "install": "インストール", + "publisher": "発行者", + "lastUpdated": "最終更新", + "pluginNotFound": "プラグインが見つかりません", + "pluginEmpty": { + "title": "プラグインがまだありません" + } + }, "trash": { "spaceTrash": "スペースのゴミ箱", "type": "タイプ", diff --git a/packages/common-i18n/src/locales/ja/sdk.json b/packages/common-i18n/src/locales/ja/sdk.json index b09f1edda5..df89618d46 100644 --- a/packages/common-i18n/src/locales/ja/sdk.json +++ b/packages/common-i18n/src/locales/ja/sdk.json @@ -1354,6 +1354,28 @@ "cannotDeployAppBeforeInitialization": "初期化前にアプリをデプロイできません", "noProjectOrVersionFound": "プロジェクトまたはバージョンが見つかりません", "noDeploymentUrlAvailable": "デプロイURLが利用できません" + }, + "reward": { + "notFound": "リワードが見つかりません", + "unsupportedSourceType": "サポートされていないリワードソースタイプです", + "maxClaimsReached": "今週のリワード請求上限(2回)に達しました", + "verificationFailed": "検証に失敗しました: {{errors}}", + "alreadyClaimedThisWeek": "今週すでにこのアカウントのリワードを請求しています", + "invalidPostUrl": "投稿URLの形式が無効です", + "postAlreadyUsed": "この投稿はすでにリワードの請求に使用されています", + "unsupportedPlatformUrl": "サポートされていないソーシャルプラットフォームのURLです", + "unsupportedPlatform": "サポートされていないプラットフォーム: {{platform}}", + "minCharCount": "投稿は少なくとも{{count}}文字必要です", + "minFollowerCount": "アカウントには少なくとも{{count}}人のフォロワーが必要です", + "mustMention": "投稿には{{mention}}へのメンションが必要です", + "fetchTweetFailed": "Xツイートの取得に失敗しました: {{error}}", + "tweetNotFound": "Xツイートが見つかりません: {{postId}}", + "fetchUserFailed": "Xユーザーの取得に失敗しました: {{error}}", + "xUserNotFound": "Xユーザーが見つかりません: {{username}}", + "fetchLinkedInPostFailed": "LinkedIn投稿の取得に失敗しました: {{error}}", + "linkedInPostNotFound": "LinkedIn投稿が見つかりません: {{postId}}", + "linkedInAuthorNotFound": "LinkedIn投稿者が見つかりません: {{postId}}", + "fetchLinkedInUserFailed": "LinkedInユーザーの取得に失敗しました: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/ja/space.json b/packages/common-i18n/src/locales/ja/space.json index df2b22301d..d86820aba0 100644 --- a/packages/common-i18n/src/locales/ja/space.json +++ b/packages/common-i18n/src/locales/ja/space.json @@ -41,6 +41,10 @@ "pin": "ピン", "empty": "ピン留めしたベースとスペースがここに表示されます" }, + "tooltip": { + "noPermissionToCreateBase": "ベースを作成する権限がありません", + "creatingBase": "ベースを作成中..." + }, "tip": { "delete": "<0/> を削除してもよろしいですか?", "title": "ヒント", diff --git a/packages/common-i18n/src/locales/ja/system.json b/packages/common-i18n/src/locales/ja/system.json index 618f0a4747..a179458267 100644 --- a/packages/common-i18n/src/locales/ja/system.json +++ b/packages/common-i18n/src/locales/ja/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - ページが見つかりません" + "title": "ページが見つかりません", + "description": "お探しのリンクは無効であるか、ページが移動された可能性があります。" }, "links": { "backToHome": "ホームへ戻る" }, "forbidden": { - "title": "403 - Forbidden", - "description": "このページにアクセスする権限がありません。" + "title": "アクセス制限", + "description": "このリソースにアクセスするには権限が必要です。\n管理者にお問い合わせください。" }, "paymentRequired": { - "title": "402 - 契約プランのアップグレードが必要です", - "description": "現在の契約プランではこの機能にアクセスできません。

続行するには契約プランをアップグレードしてください。" + "title": "プレミアム機能のロック解除", + "description": "この機能は上位プランでご利用いただけます。\nアップグレードして機能を拡張しましょう。" + }, + "error": { + "title": "エラーが発生しました", + "description": "予期しないエラーが発生しました。後でもう一度お試しください。" } } diff --git a/packages/common-i18n/src/locales/ru/common.json b/packages/common-i18n/src/locales/ru/common.json index 83ce77e253..7c7dd04b52 100644 --- a/packages/common-i18n/src/locales/ru/common.json +++ b/packages/common-i18n/src/locales/ru/common.json @@ -1,6 +1,7 @@ { "actions": { - "title": "действия", + "title": "Действия", + "add": "Добавить", "save": "Сохранить", "doNotSave": "Не сохранять", "submit": "Отправить", @@ -15,6 +16,7 @@ "zoomIn": "Увеличить", "zoomOut": "Уменьшить", "back": "Назад", + "remove": "Удалить", "removeConfig": "Удалить конфигурацию", "saveSucceed": "Сохранение успешно!", "submitSucceed": "Отправка успешно!", @@ -30,12 +32,19 @@ "duplicate": "Дублировать", "change": "Изменить", "upgrade": "Обновить", + "upgradeToLevel": "Обновить до {{level}}", "search": "Поиск", "loadMore": "Загрузить больше", "collapseSidebar": "Свернуть боковую панель", "restore": "Восстановить", "permanentDelete": "Удалить навсегда", + "globalSearch": "Глобальный поиск", + "fieldSearch": "Поиск по полю", + "tableIndex": "Индекс", + "showAllRow": "Показать все строки", + "hideNotMatchRow": "Скрыть несоответствующие строки", "more": "Больше", + "expand": "Развернуть", "move": "Переместить в", "turnOn": "Включить", "exit": "Выйти", @@ -44,7 +53,16 @@ "select": "Выбрать", "view": "Просмотр", "preview": "Предпросмотр", - "viewAndEdit": "Просмотр и редактирование" + "viewAndEdit": "Просмотр и редактирование", + "deleteTip": "Вы уверены, что хотите удалить \"{{name}}\"?", + "refresh": "Обновить", + "login": "Войти", + "useTemplate": "Использовать шаблон", + "backToSpace": "Вернуться в пространство", + "switchBase": "Переключить базу", + "continue": "Продолжить", + "export": "Экспорт", + "import": "Импорт" }, "quickAction": { "title": "Быстрые действия...", @@ -53,12 +71,13 @@ "password": { "setInvalid": "Пароль недействителен, должен содержать не менее 8 символов и хотя бы одну букву и одну цифру." }, - "non": { - "share": "Поделиться", - "copy": "Скопировано" - }, "template": { + "non": { + "share": "Поделиться", + "copy": "Скопировано" + }, "aiTitle": "Давайте создадим вместе", + "aiGreeting": "Чем я могу помочь, {{name}}?", "aiSubTitle": "Первая AI-платформа, где команды сотрудничают над данными и создают производственные приложения", "guideTitle": "Начните со своего сценария", "watchVideo": "Смотреть видео", @@ -69,6 +88,10 @@ "loadMore": "Загрузить Больше", "allTemplatesLoaded": "Все шаблоны загружены", "createTemplate": "Создать Шаблон", + "useTemplateDialog": { + "title": "Выберите пространство", + "description": "Выберите пространство для шаблона" + }, "promptBox": { "placeholder": "Создайте бизнес-приложение с Teable", "start": "Начать", @@ -84,7 +107,7 @@ } }, "settings": { - "title": "Настройки", + "title": "Настройки экземпляра", "personal": { "title": "Личные настройки" }, @@ -129,6 +152,20 @@ "addPasswordSuccess": { "title": "🎉 Пароль успешно добавлен." }, + "deleteAccount": { + "title": "Удалить учетную запись", + "desc": "Это действие необратимо. Ваша учетная запись и все связанные данные будут удалены навсегда.", + "error": { + "title": "Невозможно удалить учетную запись", + "desc": "Сначала необходимо обработать следующие зависимости:", + "spacesError": "Перед удалением учетной записи необходимо сначала выйти (или удалить, а затем переместить в корзину) из ваших пространств." + }, + "confirm": { + "title": "Введите DELETE для подтверждения", + "placeholder": "DELETE" + }, + "loading": "Удаление..." + }, "changeEmail": { "title": "Сменить адрес электронной почты", "desc": "Пожалуйста, подтвердите пароль и новый адрес электронной почты", @@ -235,20 +272,25 @@ "folder": "Папка", "newAutomation": "Новая автоматизация", "newApp": "Новое приложение", - "newFolder": "Новая папка" + "newFolder": "Новая папка", + "template": "Шаблон" }, "level": { "free": "Бесплатно", "plus": "Плюс", "pro": "Профи", + "business": "Бизнес", "enterprise": "Предприятие" }, "noResult": "Нет результата.", + "allNodes": "Все узлы", + "noDescription": "Нет описания", "untitled": "Без названия", "name": "Имя", "description": "Описание", "required": "Обязательно", "characters": "символов", + "atLeastOne": "Сохраните хотя бы один {{noun}}", "guide": { "prev": "Назад", "next": "Далее", @@ -303,6 +345,8 @@ }, "help": { "title": "Помощь", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "Разрешения страницы были обновлены. Пожалуйста, обновите страницу, чтобы увидеть последние изменения.", @@ -314,6 +358,10 @@ "unavailableInPlanTips": "Текущий тарифный план не поддерживает эту функцию", "unavailableConnectionTips": "Функция подключения к базе данных будет удалена в будущем и будет доступна только в тарифном плане Enterprise и в самохостинг версии.", "levelTips": "Это пространство сейчас на тарифе {{level}}", + "enterpriseFeature": "Функция Enterprise", + "automationRequiresUpgrade": "Обновитесь до Enterprise Edition (EE) чтобы включить автоматизацию", + "authorityMatrixRequiresUpgrade": "Обновитесь до Enterprise Edition (EE) чтобы включить матрицу полномочий", + "viewPricing": "Посмотреть цены", "billable": "Платный", "billableByAuthorityMatrix": "Биллинг, созданный матрицей полномочий", "licenseExpiredGracePeriod": "Срок действия вашей лицензии для самостоятельного размещения истек и будет понижена до бесплатного плана {{expiredTime}}. Пожалуйста, обновите лицензию, чтобы сохранить доступ к премиум-функциям.", @@ -335,6 +383,7 @@ }, "admin": { "setting": { + "instanceTitle": "Настройки экземпляра", "description": "Измените настройки для текущего экземпляра", "allowSignUp": "Разрешить создание новых аккаунтов", "allowSignUpDescription": "Отключение этой опции запретит регистрацию новых пользователей, и кнопка регистрации больше не будет отображаться на странице входа.", @@ -347,10 +396,14 @@ "enableWaitlist": "Включить список ожидания", "enableWaitlistDescription": "Включение этой опции позволит пользователям регистрироваться только с помощью приглашения.", "generalSettings": "Общие настройки", - "aiSettings": "AI настройки", + "aiSettings": { + "title": "AI настройки", + "description": "Настроить AI параметры для этого экземпляра" + }, "brandingSettings": { "title": "Настройки брендинга", "description": "Доступно только в корпоративной версии", + "brandName": "Название бренда", "logo": "Логотип", "logoDescription": "Логотип - это ваша фирменная идентичность в Teable.", "logoUpload": "Загрузить логотип", diff --git a/packages/common-i18n/src/locales/ru/sdk.json b/packages/common-i18n/src/locales/ru/sdk.json index 76fddcaa5b..efee59791f 100644 --- a/packages/common-i18n/src/locales/ru/sdk.json +++ b/packages/common-i18n/src/locales/ru/sdk.json @@ -1354,6 +1354,28 @@ "cannotDeployAppBeforeInitialization": "Невозможно развернуть приложение до инициализации", "noProjectOrVersionFound": "Проект или версия не найдены", "noDeploymentUrlAvailable": "URL развертывания недоступен" + }, + "reward": { + "notFound": "Награда не найдена", + "unsupportedSourceType": "Неподдерживаемый тип источника награды", + "maxClaimsReached": "Вы достигли максимального количества запросов наград (2) на этой неделе", + "verificationFailed": "Ошибка проверки: {{errors}}", + "alreadyClaimedThisWeek": "Вы уже запросили награду для этого аккаунта на этой неделе", + "invalidPostUrl": "Неверный формат URL публикации", + "postAlreadyUsed": "Эта публикация уже использовалась для получения награды", + "unsupportedPlatformUrl": "Неподдерживаемый URL социальной платформы", + "unsupportedPlatform": "Неподдерживаемая платформа: {{platform}}", + "minCharCount": "Публикация должна содержать не менее {{count}} символов", + "minFollowerCount": "Аккаунт должен иметь не менее {{count}} подписчиков", + "mustMention": "Публикация должна упоминать {{mention}}", + "fetchTweetFailed": "Не удалось получить твит X: {{error}}", + "tweetNotFound": "Твит X не найден: {{postId}}", + "fetchUserFailed": "Не удалось получить пользователя X: {{error}}", + "xUserNotFound": "Пользователь X не найден: {{username}}", + "fetchLinkedInPostFailed": "Не удалось получить публикацию LinkedIn: {{error}}", + "linkedInPostNotFound": "Публикация LinkedIn не найдена: {{postId}}", + "linkedInAuthorNotFound": "Автор LinkedIn не найден: {{postId}}", + "fetchLinkedInUserFailed": "Не удалось получить пользователя LinkedIn: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/ru/space.json b/packages/common-i18n/src/locales/ru/space.json index 3ed4ff4bbe..048dd2b6e8 100644 --- a/packages/common-i18n/src/locales/ru/space.json +++ b/packages/common-i18n/src/locales/ru/space.json @@ -41,6 +41,10 @@ "pin": "Закрепить", "empty": "Ваши закрепленные базы и пространства появятся здесь" }, + "tooltip": { + "noPermissionToCreateBase": "У вас нет разрешения на создание базы", + "creatingBase": "Создание базы..." + }, "tip": { "delete": "Вы уверены, что хотите удалить <0/>?", "title": "Советы", diff --git a/packages/common-i18n/src/locales/ru/system.json b/packages/common-i18n/src/locales/ru/system.json index 87ce370538..a6dcc60e1f 100644 --- a/packages/common-i18n/src/locales/ru/system.json +++ b/packages/common-i18n/src/locales/ru/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Страница не найдена" + "title": "Страница не найдена", + "description": "Ссылка, по которой вы перешли, может быть недействительной, или страница была перемещена." }, "links": { "backToHome": "Вернуться на главную" }, "forbidden": { - "title": "403 - Доступ запрещен", - "description": "У вас нет разрешения для доступа к этой странице." + "title": "Доступ ограничен", + "description": "Для доступа к этому ресурсу требуется разрешение.\nПожалуйста, обратитесь к администратору." }, "paymentRequired": { - "title": "402 - Требуется обновление подписки", - "description": "Ваша текущая подписка не поддерживает доступ к этой функции.

Пожалуйста, обновите подписку, чтобы продолжить." + "title": "Разблокировать премиум-функцию", + "description": "Эта функция доступна в расширенных тарифах.\nОбновите план, чтобы расширить возможности." + }, + "error": { + "title": "Что-то пошло не так", + "description": "Произошла непредвиденная ошибка. Пожалуйста, попробуйте позже." } } diff --git a/packages/common-i18n/src/locales/tr/common.json b/packages/common-i18n/src/locales/tr/common.json index dfeeeab730..251d6dd06c 100644 --- a/packages/common-i18n/src/locales/tr/common.json +++ b/packages/common-i18n/src/locales/tr/common.json @@ -1,6 +1,7 @@ { "actions": { - "title": "işlemler", + "title": "İşlemler", + "add": "Ekle", "save": "Kaydet", "doNotSave": "Kaydetme", "submit": "Gönder", @@ -15,6 +16,7 @@ "zoomIn": "Yakınlaştır", "zoomOut": "Uzaklaştır", "back": "Geri", + "remove": "Kaldır", "removeConfig": "Yapılandırmayı sil", "saveSucceed": "Başarıyla Kaydedildi!", "submitSucceed": "Başarıyla Gönderildi!", @@ -30,6 +32,7 @@ "duplicate": "Çoğalt", "change": "Değiştir", "upgrade": "Yükselt", + "upgradeToLevel": "{{level}}'e yükselt", "search": "Ara", "loadMore": "Daha Fazla Yükle", "collapseSidebar": "Kenar Çubuğunu Daralt", @@ -39,6 +42,9 @@ "fieldSearch": "Alan Ara", "showAllRow": "Tüm satırları göster", "hideNotMatchRow": "Eşleşmeyen satırları gizle", + "more": "Daha Fazla", + "expand": "Genişlet", + "tableIndex": "Dizin", "move": "Taşı", "turnOn": "Aç", "exit": "Çıkış", @@ -47,7 +53,16 @@ "select": "Seç", "view": "Görüntüle", "preview": "Önizleme", - "viewAndEdit": "Görüntüle ve düzenle" + "viewAndEdit": "Görüntüle ve düzenle", + "deleteTip": "\"{{name}}\" öğesini silmek istediğinizden emin misiniz?", + "refresh": "Yenile", + "login": "Giriş Yap", + "useTemplate": "Şablon Kullan", + "backToSpace": "Alana Dön", + "switchBase": "Veritabanı Değiştir", + "continue": "Devam Et", + "export": "Dışa Aktar", + "import": "İçe Aktar" }, "quickAction": { "title": "Hızlı İşlemler...", @@ -56,12 +71,13 @@ "password": { "setInvalid": "Şifre geçersiz, en az 8 karakter olmalı ve en az bir harf ve bir rakam içermelidir." }, - "non": { - "share": "Paylaş", - "copy": "Kopyalandı" - }, "template": { + "non": { + "share": "Paylaş", + "copy": "Kopyalandı" + }, "aiTitle": "Birlikte inşa edelim", + "aiGreeting": "Size nasıl yardımcı olabilirim, {{name}}?", "aiSubTitle": "Ekiplerin veriler üzerinde işbirliği yaptığı ve üretim uygulamaları oluşturduğu ilk AI platformu", "guideTitle": "Senaryonuzdan başlayın", "watchVideo": "Video izle", @@ -72,6 +88,10 @@ "loadMore": "Daha Fazla Yükle", "allTemplatesLoaded": "Tüm şablonlar yüklendi", "createTemplate": "Şablon Oluştur", + "useTemplateDialog": { + "title": "Alan Seçin", + "description": "Şablon için bir alan seçin" + }, "promptBox": { "placeholder": "Teable ile iş uygulamanızı oluşturun", "start": "Başlat", @@ -87,7 +107,7 @@ } }, "settings": { - "title": "Ayarlar", + "title": "Örnek Ayarları", "personal": { "title": "Kişisel ayarlar" }, @@ -132,6 +152,20 @@ "addPasswordSuccess": { "title": "🎉 Şifre başarıyla eklendi." }, + "deleteAccount": { + "title": "Hesabı Sil", + "desc": "Bu işlem geri alınamaz. Hesabınız ve tüm ilişkili veriler kalıcı olarak silinecektir.", + "error": { + "title": "Hesap silinemedi", + "desc": "Önce aşağıdaki bağımlılıkları çözmeniz gerekiyor:", + "spacesError": "Hesabınızı silmeden önce, Alanlarınızdan çıkmanız (veya silip çöp kutusuna taşımanız) gerekiyor." + }, + "confirm": { + "title": "Onaylamak için DELETE yazın", + "placeholder": "DELETE" + }, + "loading": "Siliniyor..." + }, "changeEmail": { "title": "E-posta adresini değiştir", "desc": "Lütfen şifrenizi doğrulayın ve yeni e-posta adresinizi onaylayın", @@ -238,15 +272,19 @@ "folder": "Klasör", "newAutomation": "Yeni otomasyon", "newApp": "Yeni uygulama", - "newFolder": "Yeni klasör" + "newFolder": "Yeni klasör", + "template": "Şablon" }, "level": { "free": "Ücretsiz", "plus": "Plus", "pro": "Pro", + "business": "İş", "enterprise": "Kurumsal" }, "noResult": "Sonuç Bulunamadı.", + "allNodes": "Tüm Düğümler", + "noDescription": "Açıklama yok", "untitled": "Başlıksız", "name": "İsim", "description": "Açıklama", @@ -307,6 +345,8 @@ }, "help": { "title": "Yardım", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "Sayfa izinleri güncellendi. En son içeriği görmek için lütfen sayfayı yenileyin.", @@ -724,5 +764,36 @@ }, "base": { "deleteTip": "\"{{name}}\" veritabanını silmek istediğinizden emin misiniz?" - } + }, + "clickToCopyTooltip": "Panoya kopyalamak için tıklayın", + "copiedTooltip": "Kopyalandı!", + "hiddenFieldCount_one": "{{count}} gizli alan", + "hiddenFieldCount_other": "{{count}} gizli alan", + "invalidFieldMapping": "Geçersiz alan eşlemesi", + "sourceFieldNotFoundMapping": "Kaynak alan bulunamadı", + "targetFieldNotFoundMapping": "Hedef alan bulunamadı", + "fieldTypeNotSupportedMapping": "Alan türü desteklenmiyor", + "fieldSettingsNotMatchMapping": "Alan ayarları eşleşmiyor", + "fieldSettingsLookupNotMatch": "Arama alan ayarları eşleşmiyor", + "fieldSettingsLinkTableNotMatch": "Bağlantı tablosu eşleşmiyor", + "fieldSettingsLinkViewNotMatch": "Bağlantı görünümü eşleşmiyor", + "fieldTypeDifferentMapping": "Alan türleri farklı", + "fieldMappingSourceTip": "Kaynak alanları hedef alanlarla eşleyin", + "fieldMappingTargetTip": "Alanları hedefle eşleştirme", + "reset": "Sıfırla", + "checkAll": "Tümünü seç", + "uncheckAll": "Seçimi kaldır", + "duplicateOptionsMapping": "Yinelenen seçenekler", + "lookupFieldInvalidMapping": "Arama alanı geçersiz", + "noMatchedOptions": "Eşleşen seçenek yok", + "needManualSelectionMapping": "Manuel seçim gerekli", + "targetFieldIsComputed": "Hedef alan hesaplanmış", + "targetFieldIsComputedTips": "Hedef alan hesaplanmış ve değiştirilemez", + "emptyOption": "(boş)", + "showEmptyTip": "Boş seçenekleri göster", + "hideEmptyTip": "Boş seçenekleri gizle", + "hideText": "Metni Gizle", + "showText": "Metni Göster", + "sourceTable": "Kaynak Tablo", + "sourceView": "Kaynak Görünüm" } diff --git a/packages/common-i18n/src/locales/tr/sdk.json b/packages/common-i18n/src/locales/tr/sdk.json index 591ee74090..748856d956 100644 --- a/packages/common-i18n/src/locales/tr/sdk.json +++ b/packages/common-i18n/src/locales/tr/sdk.json @@ -1354,6 +1354,28 @@ "cannotDeployAppBeforeInitialization": "Başlatmadan önce uygulama dağıtılamaz", "noProjectOrVersionFound": "Proje veya sürüm bulunamadı", "noDeploymentUrlAvailable": "Dağıtım URL'si mevcut değil" + }, + "reward": { + "notFound": "Ödül bulunamadı", + "unsupportedSourceType": "Desteklenmeyen ödül kaynak türü", + "maxClaimsReached": "Bu hafta için maksimum ödül talebine (2) ulaştınız", + "verificationFailed": "Doğrulama başarısız: {{errors}}", + "alreadyClaimedThisWeek": "Bu hesap için bu hafta zaten bir ödül talep ettiniz", + "invalidPostUrl": "Geçersiz gönderi URL formatı", + "postAlreadyUsed": "Bu gönderi zaten bir ödül talep etmek için kullanıldı", + "unsupportedPlatformUrl": "Desteklenmeyen sosyal platform URL'si", + "unsupportedPlatform": "Desteklenmeyen platform: {{platform}}", + "minCharCount": "Gönderi en az {{count}} karakter içermelidir", + "minFollowerCount": "Hesapta en az {{count}} takipçi olmalıdır", + "mustMention": "Gönderi {{mention}} kişisinden bahsetmelidir", + "fetchTweetFailed": "X tweeti alınamadı: {{error}}", + "tweetNotFound": "X tweeti bulunamadı: {{postId}}", + "fetchUserFailed": "X kullanıcısı alınamadı: {{error}}", + "xUserNotFound": "X kullanıcısı bulunamadı: {{username}}", + "fetchLinkedInPostFailed": "LinkedIn gönderisi alınamadı: {{error}}", + "linkedInPostNotFound": "LinkedIn gönderisi bulunamadı: {{postId}}", + "linkedInAuthorNotFound": "LinkedIn yazarı bulunamadı: {{postId}}", + "fetchLinkedInUserFailed": "LinkedIn kullanıcısı alınamadı: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/tr/space.json b/packages/common-i18n/src/locales/tr/space.json index aeacfb3d85..482d2132f6 100644 --- a/packages/common-i18n/src/locales/tr/space.json +++ b/packages/common-i18n/src/locales/tr/space.json @@ -41,6 +41,10 @@ "pin": "Sabitle", "empty": "Sabitlediğiniz veritabanları ve alanlar burada görünecek" }, + "tooltip": { + "noPermissionToCreateBase": "Veritabanı oluşturma izniniz yok", + "creatingBase": "Veritabanı oluşturuluyor..." + }, "tip": { "delete": "<0/> silmek istediğinizden emin misiniz?", "title": "İpuçları", diff --git a/packages/common-i18n/src/locales/tr/system.json b/packages/common-i18n/src/locales/tr/system.json index d39ba695b3..c569f42d09 100644 --- a/packages/common-i18n/src/locales/tr/system.json +++ b/packages/common-i18n/src/locales/tr/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Sayfa Bulunamadı" + "title": "Sayfa bulunamadı", + "description": "Takip ettiğiniz bağlantı bozuk olabilir veya sayfa taşınmış olabilir." }, "links": { "backToHome": "Ana sayfaya dön" }, "forbidden": { - "title": "403 - Erişim Yasak", - "description": "Bu sayfaya erişim izniniz yok." + "title": "Erişim kısıtlı", + "description": "Bu kaynağa erişmek için izne ihtiyacınız var.\nLütfen yöneticinizle iletişime geçin." }, "paymentRequired": { - "title": "402 - Abonelik Yükseltmesi Gerekli", - "description": "Mevcut aboneliğiniz bu özelliğe erişimi desteklemiyor.

Devam etmek için lütfen aboneliğinizi yükseltin." + "title": "Premium özelliğin kilidini aç", + "description": "Bu özellik gelişmiş planlarda kullanılabilir.\nYeteneklerinizi genişletmek için yükseltin." + }, + "error": { + "title": "Bir şeyler yanlış gitti", + "description": "Beklenmeyen bir hata oluştu. Lütfen daha sonra tekrar deneyin." } } diff --git a/packages/common-i18n/src/locales/uk/common.json b/packages/common-i18n/src/locales/uk/common.json index 2dd396b6f9..28ae8f70df 100644 --- a/packages/common-i18n/src/locales/uk/common.json +++ b/packages/common-i18n/src/locales/uk/common.json @@ -30,6 +30,7 @@ "duplicate": "Дублювати", "change": "Змінити", "upgrade": "Оновити", + "upgradeToLevel": "Оновити до {{level}}", "search": "Пошук", "loadMore": "Завантажити більше", "collapseSidebar": "Згорнути бічну панель", @@ -84,7 +85,7 @@ } }, "settings": { - "title": "Налаштування", + "title": "Приклад налаштувань", "personal": { "title": "Особисті налаштування" }, @@ -127,6 +128,20 @@ "addPasswordSuccess": { "title": "🎉 Пароль додано успішно." }, + "deleteAccount": { + "title": "Видалити обліковий запис", + "desc": "Цю дію неможливо скасувати. Ваш обліковий запис і всі пов'язані дані будуть назавжди видалені.", + "error": { + "title": "Не вдалося видалити обліковий запис", + "desc": "Вам потрібно спочатку вирішити наступні залежності:", + "spacesError": "Перш ніж видалити обліковий запис, вам потрібно вийти з просторів (або видалити та перемістити в кошик)." + }, + "confirm": { + "title": "Введіть DELETE для підтвердження", + "placeholder": "DELETE" + }, + "loading": "Видалення..." + }, "changeEmail": { "title": "Змінити адресу електронної пошти", "desc": "Будь ласка, перевірте пароль і підтвердьте нову адресу електронної пошти", @@ -233,15 +248,19 @@ "folder": "Папка", "newAutomation": "Нова автоматизація", "newApp": "Новий додаток", - "newFolder": "Нова папка" + "newFolder": "Нова папка", + "template": "Шаблон" }, "level": { "free": "Безкоштовно", "plus": "Плюс", "pro": "Профі", + "business": "Бізнес", "enterprise": "Підприємство" }, "noResult": "Немає результату.", + "allNodes": "Усі вузли", + "noDescription": "Без опису", "untitled": "Без назви", "name": "Назва", "description": "Опис", @@ -306,6 +325,8 @@ }, "help": { "title": "Допомога", + "appLink": "https://app.teable.ai", + "mainLink": "https://help.teable.ai", "apiLink": "https://help.teable.ai/en/api-doc/token" }, "pagePermissionChangeTip": "Дозволи сторінки оновлено. Будь ласка, оновіть сторінку, щоб побачити найновіший вміст.", @@ -723,5 +744,36 @@ }, "base": { "deleteTip": "Ви впевнені, що хочете видалити \"{{name}}\" базу?" - } + }, + "clickToCopyTooltip": "Клацніть, щоб скопіювати в буфер обміну", + "copiedTooltip": "Скопійовано!", + "hiddenFieldCount_one": "{{count}} приховане поле", + "hiddenFieldCount_other": "{{count}} прихованих полів", + "invalidFieldMapping": "Недійсне зіставлення поля", + "sourceFieldNotFoundMapping": "Поле джерела не знайдено", + "targetFieldNotFoundMapping": "Цільове поле не знайдено", + "fieldTypeNotSupportedMapping": "Тип поля не підтримується", + "fieldSettingsNotMatchMapping": "Налаштування поля не збігаються", + "fieldSettingsLookupNotMatch": "Налаштування поля пошуку не збігаються", + "fieldSettingsLinkTableNotMatch": "Зв'язана таблиця не збігається", + "fieldSettingsLinkViewNotMatch": "Зв'язаний вигляд не збігається", + "fieldTypeDifferentMapping": "Типи полів різні", + "fieldMappingSourceTip": "Зіставте поля джерела з цільовими полями", + "fieldMappingTargetTip": "Зіставте поля з ціллю", + "reset": "Скинути", + "checkAll": "Вибрати все", + "uncheckAll": "Скасувати вибір", + "duplicateOptionsMapping": "Повторювані варіанти", + "lookupFieldInvalidMapping": "Поле пошуку недійсне", + "noMatchedOptions": "Немає відповідних варіантів", + "needManualSelectionMapping": "Потрібен ручний вибір", + "targetFieldIsComputed": "Цільове поле обчислюване", + "targetFieldIsComputedTips": "Цільове поле обчислюване і не може бути змінене", + "emptyOption": "(порожньо)", + "showEmptyTip": "Показати порожні варіанти", + "hideEmptyTip": "Приховати порожні варіанти", + "hideText": "Приховати текст", + "showText": "Показати текст", + "sourceTable": "Таблиця джерела", + "sourceView": "Вигляд джерела" } diff --git a/packages/common-i18n/src/locales/uk/sdk.json b/packages/common-i18n/src/locales/uk/sdk.json index 9ad030533c..7f1006639b 100644 --- a/packages/common-i18n/src/locales/uk/sdk.json +++ b/packages/common-i18n/src/locales/uk/sdk.json @@ -1354,6 +1354,28 @@ "cannotDeployAppBeforeInitialization": "Неможливо розгорнути додаток до ініціалізації", "noProjectOrVersionFound": "Проект або версію не знайдено", "noDeploymentUrlAvailable": "URL розгортання недоступний" + }, + "reward": { + "notFound": "Нагороду не знайдено", + "unsupportedSourceType": "Непідтримуваний тип джерела нагороди", + "maxClaimsReached": "Ви досягли максимальної кількості запитів нагород (2) на цьому тижні", + "verificationFailed": "Помилка перевірки: {{errors}}", + "alreadyClaimedThisWeek": "Ви вже запитали нагороду для цього акаунту на цьому тижні", + "invalidPostUrl": "Недійсний формат URL публікації", + "postAlreadyUsed": "Ця публікація вже використовувалась для отримання нагороди", + "unsupportedPlatformUrl": "Непідтримуваний URL соціальної платформи", + "unsupportedPlatform": "Непідтримувана платформа: {{platform}}", + "minCharCount": "Публікація повинна містити щонайменше {{count}} символів", + "minFollowerCount": "Акаунт повинен мати щонайменше {{count}} підписників", + "mustMention": "Публікація повинна згадувати {{mention}}", + "fetchTweetFailed": "Не вдалося отримати твіт X: {{error}}", + "tweetNotFound": "Твіт X не знайдено: {{postId}}", + "fetchUserFailed": "Не вдалося отримати користувача X: {{error}}", + "xUserNotFound": "Користувача X не знайдено: {{username}}", + "fetchLinkedInPostFailed": "Не вдалося отримати публікацію LinkedIn: {{error}}", + "linkedInPostNotFound": "Публікацію LinkedIn не знайдено: {{postId}}", + "linkedInAuthorNotFound": "Автора LinkedIn не знайдено: {{postId}}", + "fetchLinkedInUserFailed": "Не вдалося отримати користувача LinkedIn: {{error}}" } } } diff --git a/packages/common-i18n/src/locales/uk/space.json b/packages/common-i18n/src/locales/uk/space.json index b7db947f7f..ee3a3d3e85 100644 --- a/packages/common-i18n/src/locales/uk/space.json +++ b/packages/common-i18n/src/locales/uk/space.json @@ -41,6 +41,10 @@ "pin": "Закріпити", "empty": "Тут з'являться ваші закріплені бази та простори" }, + "tooltip": { + "noPermissionToCreateBase": "У вас немає дозволу створювати базу", + "creatingBase": "Створення бази..." + }, "tip": { "delete": "Ви впевнені, що хочете видалити <0/>?", "title": "Поради", diff --git a/packages/common-i18n/src/locales/uk/system.json b/packages/common-i18n/src/locales/uk/system.json index b0bd8d195d..18c74b688a 100644 --- a/packages/common-i18n/src/locales/uk/system.json +++ b/packages/common-i18n/src/locales/uk/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - Сторінку не знайдено" + "title": "Сторінку не знайдено", + "description": "Посилання, за яким ви перейшли, може бути недійсним, або сторінку переміщено." }, "links": { - "backToHome": "Додому" + "backToHome": "Повернутися на головну" }, "forbidden": { - "title": "403 - Заборонено.", - "description": "Ви не маєте дозволу на доступ до цієї сторінки." + "title": "Доступ обмежено", + "description": "Вам потрібен дозвіл для доступу до цього ресурсу.\nБудь ласка, зверніться до адміністратора." }, "paymentRequired": { - "title": "402 - Необхідно оновити підписку", - "description": "Ваша поточна підписка не підтримує доступ до цієї функції.

Оновіть свою підписку, щоб продовжити." + "title": "Розблокувати преміум-функцію", + "description": "Ця функція доступна в розширених тарифах.\nОновіть план, щоб розширити можливості." + }, + "error": { + "title": "Щось пішло не так", + "description": "Сталася неочікувана помилка. Будь ласка, спробуйте пізніше." } } diff --git a/packages/common-i18n/src/locales/zh/common.json b/packages/common-i18n/src/locales/zh/common.json index d403673a72..84e39e60d8 100644 --- a/packages/common-i18n/src/locales/zh/common.json +++ b/packages/common-i18n/src/locales/zh/common.json @@ -35,6 +35,7 @@ "import": "导入", "change": "变更", "upgrade": "升级", + "upgradeToLevel": "升级到{{level}}", "search": "搜索", "loadMore": "加载更多", "collapseSidebar": "折叠侧边栏", @@ -59,7 +60,9 @@ "select": "选择", "refresh": "刷新", "login": "登录", - "useTemplate": "使用模版" + "useTemplate": "使用模版", + "backToSpace": "返回空间", + "switchBase": "切换数据库" }, "quickAction": { "title": "快捷搜索...", @@ -948,6 +951,16 @@ "unknown": "表 \"{{tableName}}\" 的 AI 任务已取消。错误:{{errorMessage}}" } } + }, + "rewardRejected": { + "title": "奖励领取被拒绝", + "message": "您的 {{spaceName}} 奖励申请因以下原因被拒绝:{{errorMessages}},请检查后重新提交。", + "buttonText": "查看空间" + }, + "rewardApproved": { + "title": "奖励领取成功", + "message": "恭喜!您的 {{spaceName}} 奖励申请已通过。{{amount}} 算力已添加,有效期 {{expiredDays}} 天。", + "buttonText": "查看空间" } } } @@ -985,5 +998,103 @@ "description": "配置 v0 API 密钥以启用应用构建器功能,访问 v0 设置 获取 API 密钥", "previewAppError": "应用运行报错", "sendErrorToAI": "将错误发送给 AI" + }, + "credit": { + "title": "算力", + "leftAmount": "剩余算力", + "winFreeCredits": "获取免费算力", + "getCredits": "获取 1000 算力", + "winCredit": { + "title": "分享正面评价即可获得", + "freeCredits": "1000 免费算力", + "guidelinesTitle": "分享要求", + "tagTeableio": "标记 @teableio", + "minCharacters": "撰写 100+ 字符的评价", + "minFollowers": "拥有 10+ 粉丝数", + "limitPerWeek": "每个帖子 500 算力,每周最多 2 次(X + LinkedIn)", + "postOnX": "发布到 X", + "postOnLinkedIn": "发布到 LinkedIn", + "preFilledDraft": "🌟 已为您准备好预填草稿!", + "claimTitle": "粘贴帖子链接领取算力", + "userEmail": "用户邮箱", + "postUrlLabel": "帖子链接 (X 或 LinkedIn)", + "postUrlPlaceholder": "在此粘贴您的帖子链接", + "invalidUrl": "请输入有效的 X 或 LinkedIn 帖子链接", + "claiming": "领取中...", + "claimCredits": "领取算力", + "congratulations": "恭喜!", + "claimSuccess": "您已成功领取 500 算力!", + "verifying": "正在验证您的帖子...", + "verifyingDescription": "我们正在检查您的帖子内容,通常需要几秒钟", + "verifyFailed": "验证失败", + "tryAgain": "重试" + }, + "error": { + "verificationFailed": "验证失败" + } + }, + "reward": { + "title": "奖励", + "rewardCredits": "算力奖励", + "minCharCount": "帖子内容至少需要 {{count}} 个字符", + "minFollowerCount": "账户至少需要 {{count}} 位粉丝", + "mustMention": "帖子必须提及 {{mention}}", + "fetchSnapshotFailed": "获取帖子快照失败", + "alreadyClaimedThisWeek": "您本周已为此账户领取过奖励", + "manage": { + "title": "奖励管理", + "description": "查看和管理所有空间的奖励记录", + "overview": "概览", + "records": "记录", + "searchSpace": "搜索空间...", + "searchRecords": "搜索帖子链接/用户ID...", + "dateRange": "选择日期范围", + "from": "从", + "to": "至", + "totalSpaces": "共 {{count}} 个空间", + "totalRecords": "共 {{count}} 条记录", + "space": "空间", + "allSpaces": "全部空间", + "user": "用户", + "creator": "创建者", + "platform": "平台", + "allStatuses": "全部状态", + "allPlatforms": "全部平台", + "pendingCount": "待处理个数", + "approvedCount": "通过个数", + "rejectedCount": "拒绝个数", + "approvedAmount": "通过数量", + "consumedAmount": "已消耗数量", + "availableAmount": "可用数量", + "expiringSoonAmount": "即将过期数量 (7天)", + "amount": "数量", + "remainingAmount": "剩余数量", + "createdTime": "创建时间", + "rewardTime": "奖励时间", + "expiredTime": "过期时间", + "lastModified": "最后修改", + "viewDetails": "查看详情", + "details": "奖励详情", + "basicInfo": "基本信息", + "amountInfo": "金额信息", + "timeInfo": "时间信息", + "socialInfo": "社交信息", + "verifyResult": "验证结果", + "uniqueKey": "唯一标识", + "verify": "验证", + "valid": "有效", + "invalid": "无效", + "errors": "错误", + "copied": "{{label}} 已复制", + "openPost": "打开帖子", + "noData": "暂无数据", + "page": "第 {{current}} / {{total}} 页", + "status": { + "label": "状态", + "pending": "待处理", + "approved": "已通过", + "rejected": "已拒绝" + } + } } } diff --git a/packages/common-i18n/src/locales/zh/sdk.json b/packages/common-i18n/src/locales/zh/sdk.json index 3f8ddafa70..0f9ce22b6d 100644 --- a/packages/common-i18n/src/locales/zh/sdk.json +++ b/packages/common-i18n/src/locales/zh/sdk.json @@ -1360,6 +1360,28 @@ "cannotDeployAppBeforeInitialization": "无法在初始化前部署应用", "noProjectOrVersionFound": "没有找到项目或版本", "noDeploymentUrlAvailable": "没有可用的部署 URL" + }, + "reward": { + "notFound": "奖励记录不存在", + "unsupportedSourceType": "不支持的奖励来源类型", + "maxClaimsReached": "您本周已达到最大奖励领取次数 (2 次)", + "verificationFailed": "验证失败:{{errors}}", + "alreadyClaimedThisWeek": "您本周已为此账户领取过奖励", + "invalidPostUrl": "帖子链接格式无效", + "postAlreadyUsed": "此帖子已被用于领取奖励", + "unsupportedPlatformUrl": "不支持的社交平台链接", + "unsupportedPlatform": "不支持的平台:{{platform}}", + "minCharCount": "帖子内容至少需要 {{count}} 个字符", + "minFollowerCount": "账户至少需要 {{count}} 位粉丝", + "mustMention": "帖子必须提及 {{mention}}", + "fetchTweetFailed": "获取 X 推文失败:{{error}}", + "tweetNotFound": "未找到 X 推文:{{postId}}", + "fetchUserFailed": "获取 X 用户失败:{{error}}", + "xUserNotFound": "未找到 X 用户:{{username}}", + "fetchLinkedInPostFailed": "获取 LinkedIn 帖子失败:{{error}}", + "linkedInPostNotFound": "未找到 LinkedIn 帖子:{{postId}}", + "linkedInAuthorNotFound": "未找到 LinkedIn 作者:{{postId}}", + "fetchLinkedInUserFailed": "获取 LinkedIn 用户失败:{{error}}" } } } diff --git a/packages/common-i18n/src/locales/zh/space.json b/packages/common-i18n/src/locales/zh/space.json index 3b1f08a952..d19a45fe15 100644 --- a/packages/common-i18n/src/locales/zh/space.json +++ b/packages/common-i18n/src/locales/zh/space.json @@ -45,6 +45,10 @@ "pin": "收藏", "empty": "您收藏的数据库和空间将显示在这里" }, + "tooltip": { + "noPermissionToCreateBase": "您没有权限创建数据库", + "creatingBase": "正在创建数据库..." + }, "tip": { "delete": "确定要删除 \"<0/>\" 空间吗?", "title": "提示", diff --git a/packages/common-i18n/src/locales/zh/system.json b/packages/common-i18n/src/locales/zh/system.json index f0c3e79a1a..b90c910ff3 100644 --- a/packages/common-i18n/src/locales/zh/system.json +++ b/packages/common-i18n/src/locales/zh/system.json @@ -1,16 +1,21 @@ { "notFound": { - "title": "404 - 找不到页面" + "title": "页面未找到", + "description": "您访问的链接可能已失效或已被移动。" }, "links": { - "backToHome": "返回主页" + "backToHome": "返回首页" }, "forbidden": { - "title": "403 - 禁止访问", - "description": "您没有权限访问此页面" + "title": "访问受限", + "description": "您需要权限才能访问此资源。\n请联系管理员。" }, "paymentRequired": { - "title": "402 - 需要升级订阅", - "description": "您当前的订阅计划不支持访问此功能,请升级您的订阅以继续使用" + "title": "解锁高级功能", + "description": "此功能仅在高级计划中可用。\n升级以扩展您的能力。" + }, + "error": { + "title": "出错了", + "description": "发生了意外错误,请稍后重试。" } } diff --git a/packages/common-i18n/src/locales/zh/table.json b/packages/common-i18n/src/locales/zh/table.json index 7b7b985536..7b04e8513c 100644 --- a/packages/common-i18n/src/locales/zh/table.json +++ b/packages/common-i18n/src/locales/zh/table.json @@ -93,13 +93,13 @@ "hide": "隐藏", "default": { "singleLineText": { - "title": "标题" + "title": "单行文本" }, "longText": { - "title": "描述" + "title": "长文本" }, "number": { - "title": "计数", + "title": "数字", "formatType": "格式类型", "currencySymbol": "货币符号", "defaultSymbol": "¥", @@ -109,7 +109,7 @@ "percentExample": "百分比 (20%)" }, "singleSelect": { - "title": "状态", + "title": "单选", "options": { "todo": "待开始", "inProgress": "进行中", @@ -117,7 +117,7 @@ } }, "multipleSelect": { - "title": "标签" + "title": "多选" }, "attachment": { "title": "附件" @@ -146,7 +146,7 @@ "noDisplay": "不显示" }, "autoNumber": { - "title": "自动编号" + "title": "自增数字" }, "createdTime": { "title": "创建时间" diff --git a/packages/icons/src/components/Coins.tsx b/packages/icons/src/components/Coins.tsx new file mode 100644 index 0000000000..5b1dbb2464 --- /dev/null +++ b/packages/icons/src/components/Coins.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import type { SVGProps } from 'react'; +const Coins = (props: SVGProps) => ( + + + +); +export default Coins; diff --git a/packages/icons/src/components/Credits.tsx b/packages/icons/src/components/Credits.tsx new file mode 100644 index 0000000000..d9158a3daa --- /dev/null +++ b/packages/icons/src/components/Credits.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import type { SVGProps } from 'react'; +const Credits = (props: SVGProps) => ( + + + + +); +export default Credits; diff --git a/packages/icons/src/components/GiftPerson.tsx b/packages/icons/src/components/GiftPerson.tsx new file mode 100644 index 0000000000..29cbbfece5 --- /dev/null +++ b/packages/icons/src/components/GiftPerson.tsx @@ -0,0 +1,141 @@ +import * as React from 'react'; +import type { SVGProps } from 'react'; +const GiftPerson = (props: SVGProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); +export default GiftPerson; diff --git a/packages/icons/src/components/GiftPersonDark.tsx b/packages/icons/src/components/GiftPersonDark.tsx new file mode 100644 index 0000000000..4f81b54def --- /dev/null +++ b/packages/icons/src/components/GiftPersonDark.tsx @@ -0,0 +1,176 @@ +import * as React from 'react'; +import type { SVGProps } from 'react'; +const GiftPerson = (props: SVGProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); +export default GiftPerson; diff --git a/packages/icons/src/components/LinkedIn.tsx b/packages/icons/src/components/LinkedIn.tsx new file mode 100644 index 0000000000..2b0d8a06be --- /dev/null +++ b/packages/icons/src/components/LinkedIn.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import type { SVGProps } from 'react'; + +interface LinkedInProps extends SVGProps { + bgFill?: string; + fgFill?: string; +} + +const LinkedIn = ({ bgFill = '#007EBB', fgFill = 'white', ...props }: LinkedInProps) => ( + + + + +); +export default LinkedIn; diff --git a/packages/icons/src/components/ShieldUser.tsx b/packages/icons/src/components/ShieldUser.tsx new file mode 100644 index 0000000000..30c57567d9 --- /dev/null +++ b/packages/icons/src/components/ShieldUser.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import type { SVGProps } from 'react'; +const ShieldUser = (props: SVGProps) => ( + + + +); +export default ShieldUser; diff --git a/packages/icons/src/components/Token.tsx b/packages/icons/src/components/Token.tsx new file mode 100644 index 0000000000..e29c0282cf --- /dev/null +++ b/packages/icons/src/components/Token.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import type { SVGProps } from 'react'; + +const Token = (props: SVGProps) => { + return ( + + + + ); +}; + +export default Token; diff --git a/packages/icons/src/index.ts b/packages/icons/src/index.ts index 02c82a403b..1cef5efa08 100644 --- a/packages/icons/src/index.ts +++ b/packages/icons/src/index.ts @@ -42,14 +42,16 @@ export { default as Clock4 } from './components/Clock4'; export { default as Code } from './components/Code'; export { default as Code2 } from './components/Code2'; export { default as Cohere } from './components/Cohere'; +export { default as Coins } from './components/Coins'; export { default as Component } from './components/Component'; export { default as Condition } from './components/Condition'; export { default as ConditionalLookup } from './components/ConditionalLookup'; export { default as ConditionalRollup } from './components/ConditionalRollup'; export { default as Copy } from './components/Copy'; -export { default as CreditCard } from './components/CreditCard'; export { default as Cuppy } from './components/Cuppy'; export { default as CuppyLoader } from './components/CuppyLoader'; +export { default as Credits } from './components/Credits'; +export { default as CreditCard } from './components/CreditCard'; export { default as Database } from './components/Database'; export { default as DeepThinking } from './components/DeepThinking'; export { default as Deepseek } from './components/Deepseek'; @@ -95,6 +97,8 @@ export { default as Flame } from './components/Flame'; export { default as FreezeColumn } from './components/FreezeColumn'; export { default as Frown } from './components/Frown'; export { default as Gauge } from './components/Gauge'; +export { default as GiftPerson } from './components/GiftPerson'; +export { default as GiftPersonDark } from './components/GiftPersonDark'; export { default as Github } from './components/Github'; export { default as GithubLogo } from './components/GithubLogo'; export { default as GoogleLogo } from './components/GoogleLogo'; @@ -115,6 +119,7 @@ export { default as LayoutGrid } from './components/LayoutGrid'; export { default as LayoutList } from './components/LayoutList'; export { default as LayoutTemplate } from './components/LayoutTemplate'; export { default as License } from './components/License'; +export { default as LinkedIn } from './components/LinkedIn'; export { default as Line1 } from './components/Line1'; export { default as Line2 } from './components/Line2'; export { default as Line3 } from './components/Line3'; @@ -164,6 +169,7 @@ export { default as Settings } from './components/Settings'; export { default as Share2 } from './components/Share2'; export { default as Sheet } from './components/Sheet'; export { default as ShieldCheck } from './components/ShieldCheck'; +export { default as ShieldUser } from './components/ShieldUser'; export { default as Slack } from './components/Slack'; export { default as Sidebar } from './components/Sidebar'; export { default as SortAsc } from './components/SortAsc'; @@ -176,6 +182,7 @@ export { default as Table2 } from './components/Table2'; export { default as Teable } from './components/Teable'; export { default as TeableNew } from './components/TeableNew'; export { default as ThumbsUp } from './components/ThumbsUp'; +export { default as Token } from './components/Token'; export { default as Translation } from './components/Translation'; export { default as Trash } from './components/Trash'; export { default as Trash2 } from './components/Trash2'; diff --git a/packages/openapi/src/admin/setting/get-public.ts b/packages/openapi/src/admin/setting/get-public.ts index f2fe274e0e..598b293c04 100644 --- a/packages/openapi/src/admin/setting/get-public.ts +++ b/packages/openapi/src/admin/setting/get-public.ts @@ -46,6 +46,7 @@ export const publicSettingVoSchema = settingVoSchema changeEmailSendCodeMailRate: z.number().optional(), resetPasswordSendMailRate: z.number().optional(), signupVerificationSendCodeMailRate: z.number().optional(), + enableCreditReward: z.boolean().optional(), }); export type IPublicSettingVo = z.infer; diff --git a/packages/openapi/src/admin/setting/get.ts b/packages/openapi/src/admin/setting/get.ts index 2f18435171..0f78abfa90 100644 --- a/packages/openapi/src/admin/setting/get.ts +++ b/packages/openapi/src/admin/setting/get.ts @@ -20,6 +20,7 @@ export const settingVoSchema = z.object({ automationMailTransportConfig: mailTransportConfigSchema.nullable().optional(), appConfig: appConfigSchema.nullable().optional(), webSearchConfig: webSearchConfigSchema.nullable().optional(), + enableCreditReward: z.boolean().optional(), createdTime: z.string().optional(), }); diff --git a/packages/openapi/src/admin/setting/key.enum.ts b/packages/openapi/src/admin/setting/key.enum.ts index bc8103cd3f..a30da47fc1 100644 --- a/packages/openapi/src/admin/setting/key.enum.ts +++ b/packages/openapi/src/admin/setting/key.enum.ts @@ -13,4 +13,5 @@ export enum SettingKey { WEB_SEARCH_CONFIG = 'webSearchConfig', NOTIFY_MAIL_TRANSPORT_CONFIG = 'notifyMailTransportConfig', AUTOMATION_MAIL_TRANSPORT_CONFIG = 'automationMailTransportConfig', + ENABLE_CREDIT_REWARD = 'enableCreditReward', } diff --git a/packages/openapi/src/admin/setting/update.ts b/packages/openapi/src/admin/setting/update.ts index abe0219f3e..107f017964 100644 --- a/packages/openapi/src/admin/setting/update.ts +++ b/packages/openapi/src/admin/setting/update.ts @@ -151,6 +151,7 @@ export const updateSettingRoSchema = z.object({ enableWaitlist: z.boolean().optional(), appConfig: appConfigSchema.optional(), webSearchConfig: webSearchConfigSchema.optional(), + enableCreditReward: z.boolean().optional(), brandName: z.string().optional(), }); diff --git a/packages/sdk/src/config/local-storage-keys.ts b/packages/sdk/src/config/local-storage-keys.ts index 00640245de..bef6ad416b 100644 --- a/packages/sdk/src/config/local-storage-keys.ts +++ b/packages/sdk/src/config/local-storage-keys.ts @@ -24,4 +24,6 @@ export enum LocalStorageKeys { ChatPanel = 'ls_chat_panel', Chat = 'ls_chat', BaseNodeTreeExpandedItems = 'ls_base_node_tree_expanded_items', + WinCreditTriggerVisible = 'ls_win_credit_trigger_visible', + Sidebar = 'ls_sidebar', } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7a4e01ce0b..179f523706 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -739,9 +739,6 @@ importers: '@teable/ui-lib': specifier: workspace:^ version: link:../../packages/ui-lib - '@types/canvas-confetti': - specifier: 1.9.0 - version: 1.9.0 allotment: specifier: 1.20.0 version: 1.20.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -947,6 +944,9 @@ importers: '@testing-library/user-event': specifier: 14.5.2 version: 14.5.2(@testing-library/dom@9.3.4) + '@types/canvas-confetti': + specifier: 1.9.0 + version: 1.9.0 '@types/cors': specifier: 2.8.17 version: 2.8.17 @@ -1278,7 +1278,7 @@ importers: version: 9.1.0(eslint@8.57.0) eslint-import-resolver-typescript: specifier: 3.6.1 - version: 3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + version: 3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: specifier: 2.29.1 version: 2.29.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -1780,7 +1780,7 @@ importers: version: 5.4.3 vite-plugin-svgr: specifier: 4.2.0 - version: 4.2.0(rollup@4.28.1)(typescript@5.4.3)(vite@5.4.11(@types/node@22.18.0)(terser@5.37.0)) + version: 4.2.0(rollup@2.79.2)(typescript@5.4.3)(vite@5.4.11(@types/node@22.18.0)(terser@5.37.0)) vite-tsconfig-paths: specifier: 4.3.2 version: 4.3.2(typescript@5.4.3)(vite@5.4.11(@types/node@22.18.0)(terser@5.37.0)) @@ -23681,6 +23681,14 @@ snapshots: optionalDependencies: rollup: 2.78.0 + '@rollup/pluginutils@5.1.4(rollup@2.79.2)': + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + optionalDependencies: + rollup: 2.79.2 + '@rollup/pluginutils@5.1.4(rollup@4.28.1)': dependencies: '@types/estree': 1.0.6 @@ -29652,7 +29660,7 @@ snapshots: '@typescript-eslint/parser': 7.3.1(eslint@8.57.0)(typescript@5.4.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.1(eslint@8.57.0) @@ -29675,7 +29683,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 4.4.0 enhanced-resolve: 5.17.1 @@ -29720,7 +29728,7 @@ snapshots: '@typescript-eslint/parser': 7.3.1(eslint@8.57.0)(typescript@5.4.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -38292,9 +38300,9 @@ snapshots: - supports-color - typescript - vite-plugin-svgr@4.2.0(rollup@4.28.1)(typescript@5.4.3)(vite@5.4.11(@types/node@22.18.0)(terser@5.37.0)): + vite-plugin-svgr@4.2.0(rollup@2.79.2)(typescript@5.4.3)(vite@5.4.11(@types/node@22.18.0)(terser@5.37.0)): dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.28.1) + '@rollup/pluginutils': 5.1.4(rollup@2.79.2) '@svgr/core': 8.1.0(typescript@5.4.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.3)) vite: 5.4.11(@types/node@22.18.0)(terser@5.37.0)