mirror of
https://github.com/langgenius/dify.git
synced 2026-11-10 21:35:45 +08:00
feat(web): show billing error prompts by console error code (#45192)
This commit is contained in:
94 files changed
+687
-151
No files matched your search
Generated
-20
@@ -1922,11 +1922,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/app/components/billing/billing-page/index.tsx": {
|
||||
"better-tailwindcss/enforce-logical-properties": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/app/components/billing/plan/assets/index.tsx": {
|
||||
"no-barrel-files/no-barrel-files": {
|
||||
"count": 3
|
||||
@@ -1942,11 +1937,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/app/components/billing/pricing/plans/cloud-plan-item/index.tsx": {
|
||||
"better-tailwindcss/enforce-logical-properties": {
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"web/app/components/billing/pricing/plans/self-hosted-plan-item/index.tsx": {
|
||||
"better-tailwindcss/enforce-logical-properties": {
|
||||
"count": 2
|
||||
@@ -2950,11 +2940,6 @@
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"web/app/components/header/account-menu/compliance.tsx": {
|
||||
"better-tailwindcss/enforce-logical-properties": {
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"web/app/components/header/account-menu/workplace-selector/index.tsx": {
|
||||
"better-tailwindcss/enforce-logical-properties": {
|
||||
"count": 2
|
||||
@@ -6322,11 +6307,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/app/education/apply/application-form.tsx": {
|
||||
"better-tailwindcss/enforce-logical-properties": {
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"web/app/education/apply/applied-education-content.tsx": {
|
||||
"better-tailwindcss/enforce-logical-properties": {
|
||||
"count": 2
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { GetBillingSubscriptionData } from '@dify/contracts/api/console/billing/types.gen'
|
||||
import type { CloudPlan } from '@dify/contracts/api/console/features/types.gen'
|
||||
import { ORPCError } from '@orpc/client'
|
||||
import { act, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { ALL_PLANS } from '@/app/components/billing/config'
|
||||
@@ -95,11 +96,33 @@ describe('Cloud plan payment flow', () => {
|
||||
if (interval === 'year') expect(screen.getByText(`$${price * 12}`)).toBeInTheDocument()
|
||||
await user.click(screen.getByRole('button', { name: `billing.plansCommon.${label}` }))
|
||||
await waitFor(() => expect(window.location.href).toBe('https://pay.example.com/checkout'))
|
||||
expect(mockGetSubscription).toHaveBeenCalledExactlyOnceWith({ query: { plan, interval } })
|
||||
expect(mockGetSubscription).toHaveBeenCalledExactlyOnceWith(
|
||||
{ query: { plan, interval } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
expect(mockGetInvoices).not.toHaveBeenCalled()
|
||||
},
|
||||
)
|
||||
|
||||
it('explains a failed checkout and keeps the user on the plan', async () => {
|
||||
const user = userEvent.setup()
|
||||
const startUrl = window.location.href
|
||||
mockGetSubscription.mockRejectedValueOnce(
|
||||
new ORPCError('billing_request_in_progress', {
|
||||
defined: true,
|
||||
status: 429,
|
||||
message: 'Backend text',
|
||||
}),
|
||||
)
|
||||
renderPlan()
|
||||
const button = screen.getByRole('button', { name: 'billing.plansCommon.startBuilding' })
|
||||
await user.click(button)
|
||||
expect(await screen.findByText('billing.errors.requestInProgress')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Backend text')).not.toBeInTheDocument()
|
||||
expect(window.location.href).toBe(startUrl)
|
||||
expect(button).toBeEnabled()
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ currentPlan: 'sandbox', plan: 'sandbox', label: 'currentPlan' },
|
||||
{ currentPlan: 'professional', plan: 'sandbox', label: 'startForFree' },
|
||||
@@ -136,10 +159,13 @@ describe('Cloud plan payment flow', () => {
|
||||
|
||||
it('closes the pending portal and reports its URL request failure', async () => {
|
||||
const user = userEvent.setup()
|
||||
mockGetInvoices.mockRejectedValueOnce(new Error('Billing unavailable'))
|
||||
mockGetInvoices.mockRejectedValueOnce(
|
||||
new ORPCError('billing_unavailable', { defined: true, status: 503, message: 'Backend text' }),
|
||||
)
|
||||
renderPlan({ currentPlan: 'professional', plan: 'professional' })
|
||||
await user.click(screen.getByRole('button', { name: 'billing.plansCommon.currentPlan' }))
|
||||
expect(await screen.findByText('Billing unavailable')).toBeInTheDocument()
|
||||
expect(await screen.findByText('billing.errors.unavailable')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Backend text')).not.toBeInTheDocument()
|
||||
expect(popup.close).toHaveBeenCalledOnce()
|
||||
expect(popup.location.href).toBe('')
|
||||
})
|
||||
|
||||
@@ -252,9 +252,10 @@ describe('Pricing Modal Flow', () => {
|
||||
await user.click(screen.getByRole('button', { name: 'billing.plansCommon.startBuilding' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockGetSubscription).toHaveBeenCalledWith({
|
||||
query: { plan: 'professional', interval: 'month' },
|
||||
})
|
||||
expect(mockGetSubscription).toHaveBeenCalledWith(
|
||||
{ query: { plan: 'professional', interval: 'month' } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
expect(navigateToCheckout).toHaveBeenCalledWith('https://pay.example.com')
|
||||
})
|
||||
})
|
||||
@@ -273,9 +274,10 @@ describe('Pricing Modal Flow', () => {
|
||||
await user.click(screen.getByRole('button', { name: 'education.useEducationDiscount' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockGetSubscription).toHaveBeenCalledWith({
|
||||
query: { plan: 'professional', interval: 'year' },
|
||||
})
|
||||
expect(mockGetSubscription).toHaveBeenCalledWith(
|
||||
{ query: { plan: 'professional', interval: 'year' } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
expect(navigateToCheckout).toHaveBeenCalledWith('https://pay.example.com')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ORPCError } from '@orpc/client'
|
||||
import { billingErrorMessageKey } from '../billing-error'
|
||||
|
||||
describe('billingErrorMessageKey', () => {
|
||||
it.each([
|
||||
['billing_unavailable', 503, 'errors.unavailable'],
|
||||
['billing_request_in_progress', 429, 'errors.requestInProgress'],
|
||||
['billing_operation_failed', 502, 'errors.operationFailed'],
|
||||
])('maps the declared %s code', (code, status, key) => {
|
||||
expect(billingErrorMessageKey(new ORPCError(code, { defined: true, status }))).toBe(key)
|
||||
})
|
||||
|
||||
it('treats undeclared errors as a generic billing failure', () => {
|
||||
expect(billingErrorMessageKey(new ORPCError('billing_unavailable', { status: 503 }))).toBe(
|
||||
'errors.operationFailed',
|
||||
)
|
||||
expect(
|
||||
billingErrorMessageKey(new ORPCError('account_not_found', { defined: true, status: 400 })),
|
||||
).toBe('errors.operationFailed')
|
||||
expect(billingErrorMessageKey(new Error('Failed to open new window'))).toBe(
|
||||
'errors.operationFailed',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,28 @@
|
||||
import type {
|
||||
BillingOperationFailedError,
|
||||
BillingRequestInProgressError,
|
||||
BillingUnavailableError,
|
||||
} from '@dify/contracts/api/console/compliance/types.gen'
|
||||
import { isDefinedError, ORPCError } from '@orpc/client'
|
||||
|
||||
type BillingErrorCode = (
|
||||
| BillingOperationFailedError
|
||||
| BillingRequestInProgressError
|
||||
| BillingUnavailableError
|
||||
)['code']
|
||||
|
||||
const billingErrorMessageKeyByCode = {
|
||||
billing_operation_failed: 'errors.operationFailed',
|
||||
billing_request_in_progress: 'errors.requestInProgress',
|
||||
billing_unavailable: 'errors.unavailable',
|
||||
} as const satisfies Record<BillingErrorCode, string>
|
||||
|
||||
function isBillingErrorCode(code: string): code is BillingErrorCode {
|
||||
return Object.hasOwn(billingErrorMessageKeyByCode, code)
|
||||
}
|
||||
|
||||
export function billingErrorMessageKey(error: unknown) {
|
||||
if (error instanceof ORPCError && isDefinedError(error) && isBillingErrorCode(error.code))
|
||||
return billingErrorMessageKeyByCode[error.code]
|
||||
return billingErrorMessageKeyByCode.billing_operation_failed
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ORPCError } from '@orpc/client'
|
||||
import { act, screen } from '@testing-library/react'
|
||||
import { consoleQuery } from '@/service/console'
|
||||
import { createConsoleQueryClient, createConsoleQueryWrapper } from '@/test/console/query-data'
|
||||
@@ -10,8 +11,20 @@ let deploymentEdition: 'CLOUD' | 'COMMUNITY' = 'CLOUD'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
request: vi.fn(() => new Promise(() => {})),
|
||||
getInvoices: vi.fn(() => new Promise(() => {})),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/console', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/service/console')>()
|
||||
const { withConsoleResponses } = await import('@/test/console/service-responses')
|
||||
return {
|
||||
...actual,
|
||||
consoleQuery: withConsoleResponses(actual.consoleQuery, {
|
||||
'billing.invoices.get': mocks.getInvoices,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/service/base', () => ({
|
||||
request: mocks.request,
|
||||
sseGeneratorPost: vi.fn(),
|
||||
@@ -81,4 +94,42 @@ describe('Billing', () => {
|
||||
expect(link).toHaveAttribute('target', '_blank')
|
||||
expect(link).toHaveAttribute('rel', 'noopener noreferrer')
|
||||
})
|
||||
|
||||
it('explains why the billing link is unavailable', async () => {
|
||||
currentBillingUrl = undefined
|
||||
mocks.getInvoices.mockRejectedValueOnce(
|
||||
new ORPCError('billing_unavailable', { defined: true, status: 503, message: 'Backend text' }),
|
||||
)
|
||||
|
||||
renderBilling()
|
||||
|
||||
expect(await screen.findByText('billing.errors.unavailable')).toBeInTheDocument()
|
||||
expect(screen.queryByText('billing.viewBillingDescription')).not.toBeInTheDocument()
|
||||
expect(
|
||||
screen.queryByRole('link', { name: /billing\.viewBillingTitle/ }),
|
||||
).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('keeps a working billing link when a background refresh fails', async () => {
|
||||
mocks.getInvoices.mockRejectedValueOnce(
|
||||
new ORPCError('billing_unavailable', { defined: true, status: 503 }),
|
||||
)
|
||||
|
||||
const { queryClient } = renderBilling()
|
||||
await act(() =>
|
||||
queryClient.refetchQueries({
|
||||
queryKey: consoleQuery.billing.invoices.get.queryOptions().queryKey,
|
||||
}),
|
||||
)
|
||||
|
||||
expect(
|
||||
queryClient.getQueryState(consoleQuery.billing.invoices.get.queryOptions().queryKey)?.status,
|
||||
).toBe('error')
|
||||
expect(screen.getByRole('link', { name: /billing\.viewBillingTitle/ })).toHaveAttribute(
|
||||
'href',
|
||||
'https://billing.example.com',
|
||||
)
|
||||
expect(screen.getByText('billing.viewBillingDescription')).toBeInTheDocument()
|
||||
expect(screen.queryByText('billing.errors.unavailable')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -9,6 +9,7 @@ import { LoadingPlaceholder } from '@/app/components/base/loading-placeholder'
|
||||
import { isCurrentWorkspaceManagerAtom } from '@/context/workspace-state'
|
||||
import { deploymentEditionAtom } from '@/features/system-features/state'
|
||||
import { consoleQuery } from '@/service/console'
|
||||
import { billingErrorMessageKey } from '../billing-error'
|
||||
import PlanComp from '../plan'
|
||||
|
||||
const Billing: FC = () => {
|
||||
@@ -16,12 +17,13 @@ const Billing: FC = () => {
|
||||
const isCurrentWorkspaceManager = useAtomValue(isCurrentWorkspaceManagerAtom)
|
||||
const deploymentEdition = useAtomValue(deploymentEditionAtom)
|
||||
usePrefetchQuery(consoleQuery.features.vectorSpace.get.queryOptions())
|
||||
const { data: billing } = useQuery(
|
||||
const billingQuery = useQuery(
|
||||
consoleQuery.billing.invoices.get.queryOptions({
|
||||
enabled: deploymentEdition === 'CLOUD' && isCurrentWorkspaceManager,
|
||||
context: { silent: true },
|
||||
}),
|
||||
)
|
||||
const billingUrl = billing?.url
|
||||
const billingUrl = billingQuery.data?.url
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -45,12 +47,14 @@ const Billing: FC = () => {
|
||||
target={billingUrl ? '_blank' : undefined}
|
||||
rel={billingUrl ? 'noopener noreferrer' : undefined}
|
||||
>
|
||||
<div className="flex flex-col gap-0.5 text-left">
|
||||
<div className="flex flex-col gap-0.5 text-start">
|
||||
<div className="system-md-semibold text-text-primary">
|
||||
{t(($) => $.viewBillingTitle, { ns: 'billing' })}
|
||||
</div>
|
||||
<div className="system-sm-regular text-text-secondary">
|
||||
{t(($) => $.viewBillingDescription, { ns: 'billing' })}
|
||||
{!billingUrl && billingQuery.isError
|
||||
? t(($) => $[billingErrorMessageKey(billingQuery.error)], { ns: 'billing' })
|
||||
: t(($) => $.viewBillingDescription, { ns: 'billing' })}
|
||||
</div>
|
||||
</div>
|
||||
<span className="inline-flex h-8 w-24 items-center justify-center gap-0.5 rounded-lg bg-components-button-secondary-bg px-3 py-2 text-saas-dify-blue-accessible shadow-[0_1px_2px_rgba(9,9,11,0.05)] inset-ring-[0.5px] inset-ring-components-button-secondary-border backdrop-blur-[5px]">
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { toast } from '@/app/notifications'
|
||||
import { isCurrentWorkspaceManagerAtom } from '@/context/workspace-state'
|
||||
import { consoleClient } from '@/service/console'
|
||||
import { billingErrorMessageKey } from '../billing-error'
|
||||
|
||||
export function useEducationDiscount() {
|
||||
const { t } = useTranslation(['billing'])
|
||||
@@ -21,10 +22,13 @@ export function useEducationDiscount() {
|
||||
|
||||
setIsEducationDiscountLoading(true)
|
||||
try {
|
||||
const { url } = await consoleClient.billing.subscription.get({
|
||||
query: { plan: 'professional', interval: 'year' },
|
||||
})
|
||||
const { url } = await consoleClient.billing.subscription.get(
|
||||
{ query: { plan: 'professional', interval: 'year' } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
window.location.href = url
|
||||
} catch (error) {
|
||||
toast.error(t(($) => $[billingErrorMessageKey(error)], { ns: 'billing' }))
|
||||
} finally {
|
||||
setIsEducationDiscountLoading(false)
|
||||
}
|
||||
|
||||
@@ -88,9 +88,10 @@ describe('PlanComp education actions', () => {
|
||||
const discountButton = screen.getByRole('button', { name: 'education.useEducationDiscount' })
|
||||
await user.click(discountButton)
|
||||
|
||||
expect(getSubscription).toHaveBeenCalledWith({
|
||||
query: { plan: 'professional', interval: 'year' },
|
||||
})
|
||||
expect(getSubscription).toHaveBeenCalledWith(
|
||||
{ query: { plan: 'professional', interval: 'year' } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
expect(discountButton).toBeDisabled()
|
||||
await user.click(discountButton)
|
||||
expect(getSubscription).toHaveBeenCalledTimes(1)
|
||||
|
||||
@@ -18,6 +18,7 @@ import { toast } from '@/app/notifications'
|
||||
import { isCurrentWorkspaceManagerAtom } from '@/context/workspace-state'
|
||||
import { useAsyncWindowOpen } from '@/hooks/use-async-window-open'
|
||||
import { consoleClient } from '@/service/console'
|
||||
import { billingErrorMessageKey } from '../../../billing-error'
|
||||
import { ALL_PLANS } from '../../../config'
|
||||
import { useEducationDiscount } from '../../../hooks/use-education-discount'
|
||||
import Professional from '../../assets/professional'
|
||||
@@ -111,8 +112,8 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
throw new Error('Failed to open billing page')
|
||||
},
|
||||
{
|
||||
onError: (err) => {
|
||||
toast.error(err.message || String(err))
|
||||
onError: (error) => {
|
||||
toast.error(t(($) => $[billingErrorMessageKey(error)], { ns: 'billing' }))
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -131,11 +132,14 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
return
|
||||
}
|
||||
|
||||
const { url } = await consoleClient.billing.subscription.get({
|
||||
query: { plan, interval: billingInterval },
|
||||
})
|
||||
const { url } = await consoleClient.billing.subscription.get(
|
||||
{ query: { plan, interval: billingInterval } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
// Adb Block additional tracking block the gtag, so we need to redirect directly
|
||||
window.location.href = url
|
||||
} catch (error) {
|
||||
toast.error(t(($) => $[billingErrorMessageKey(error)], { ns: 'billing' }))
|
||||
} finally {
|
||||
setIsPlanActionPending(false)
|
||||
}
|
||||
@@ -216,7 +220,7 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
variant="tertiary"
|
||||
size={null}
|
||||
disabled={isPlanDisabled}
|
||||
className="h-auto w-full justify-start gap-x-2 rounded-none bg-components-button-tertiary-bg py-3 pr-4 pl-5 system-xl-semibold whitespace-normal text-text-primary hover:bg-components-button-tertiary-bg-hover data-disabled:bg-components-button-tertiary-bg-disabled data-disabled:text-text-disabled data-disabled:hover:bg-components-button-tertiary-bg-disabled data-[plan=professional]:not-data-disabled:bg-saas-dify-blue-static data-[plan=professional]:not-data-disabled:text-text-primary-on-surface data-[plan=professional]:not-data-disabled:hover:bg-saas-dify-blue-static-hover data-[plan=team]:not-data-disabled:bg-saas-background-inverted data-[plan=team]:not-data-disabled:text-background-default data-[plan=team]:not-data-disabled:hover:bg-saas-background-inverted-hover xl:whitespace-nowrap"
|
||||
className="h-auto w-full justify-start gap-x-2 rounded-none bg-components-button-tertiary-bg py-3 ps-5 pe-4 system-xl-semibold whitespace-normal text-text-primary hover:bg-components-button-tertiary-bg-hover data-disabled:bg-components-button-tertiary-bg-disabled data-disabled:text-text-disabled data-disabled:hover:bg-components-button-tertiary-bg-disabled data-[plan=professional]:not-data-disabled:bg-saas-dify-blue-static data-[plan=professional]:not-data-disabled:text-text-primary-on-surface data-[plan=professional]:not-data-disabled:hover:bg-saas-dify-blue-static-hover data-[plan=team]:not-data-disabled:bg-saas-background-inverted data-[plan=team]:not-data-disabled:text-background-default data-[plan=team]:not-data-disabled:hover:bg-saas-background-inverted-hover xl:whitespace-nowrap"
|
||||
onClick={handlePlanButtonClick}
|
||||
>
|
||||
<span className="min-w-0 grow text-start">{buttonLabel}</span>
|
||||
@@ -225,7 +229,7 @@ export function CloudPlanItem({ plan, billingInterval, billing }: CloudPlanItemP
|
||||
)}
|
||||
</Button>
|
||||
{educationDiscountWarningText && (
|
||||
<div className="absolute inset-x-0 top-full mt-1.5 text-left system-2xs-medium text-text-tertiary">
|
||||
<div className="absolute inset-x-0 top-full mt-1.5 text-start system-2xs-medium text-text-tertiary">
|
||||
{educationDiscountWarningText}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Menu, MenuContent, MenuTrigger } from '@langgenius/dify-ui/menu'
|
||||
import { ORPCError } from '@orpc/client'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { fireEvent, render as renderWithoutPricing, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
@@ -14,12 +15,13 @@ const onPricingUrlUpdate = vi.hoisted(() => vi.fn())
|
||||
const mockDownloadCompliance = vi.hoisted(() => vi.fn())
|
||||
vi.mock('@/service/console', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/service/console')>()
|
||||
const { withConsoleClientResponses } = await import('@/test/console/service-responses')
|
||||
const { withConsoleClientResponses, withConsoleResponses } =
|
||||
await import('@/test/console/service-responses')
|
||||
const responses = { 'compliance.download.get': mockDownloadCompliance }
|
||||
return {
|
||||
...actual,
|
||||
consoleClient: withConsoleClientResponses(actual.consoleClient, {
|
||||
'compliance.download.get': mockDownloadCompliance,
|
||||
}),
|
||||
consoleClient: withConsoleClientResponses(actual.consoleClient, responses),
|
||||
consoleQuery: withConsoleResponses(actual.consoleQuery, responses),
|
||||
}
|
||||
})
|
||||
vi.mock('@/service/base', () => ({
|
||||
@@ -99,10 +101,9 @@ describe('Compliance', () => {
|
||||
expect(screen.queryByText('billing.upgradeBtn.encourageShort')).not.toBeInTheDocument()
|
||||
await user.click(screen.getByText('common.compliance.gdpr'))
|
||||
await waitFor(() =>
|
||||
expect(consoleClient.compliance.download.get).toHaveBeenCalledWith(
|
||||
{ query: { doc_name: 'GDPR' } },
|
||||
{ context: { silent: true } },
|
||||
),
|
||||
expect(consoleClient.compliance.download.get).toHaveBeenCalledWith({
|
||||
query: { doc_name: 'GDPR' },
|
||||
}),
|
||||
)
|
||||
expect(onPricingUrlUpdate).not.toHaveBeenCalled()
|
||||
})
|
||||
@@ -118,35 +119,47 @@ describe('Compliance', () => {
|
||||
await user.click(getComplianceMenuItem('common.compliance.soc2Type1'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(consoleClient.compliance.download.get).toHaveBeenCalledWith(
|
||||
{ query: { doc_name: 'SOC2_Type_I' } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
expect(consoleClient.compliance.download.get).toHaveBeenCalledWith({
|
||||
query: { doc_name: 'SOC2_Type_I' },
|
||||
})
|
||||
expect(downloadUrl).toHaveBeenCalledWith({ url: mockUrl })
|
||||
expect(toastSuccessSpy).toHaveBeenCalledWith('common.operation.downloadSuccess')
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle download mutation error', async () => {
|
||||
it.each([
|
||||
['compliance_download_forbidden', 403, 'common.compliance.downloadForbidden'],
|
||||
['compliance_document_not_found', 404, 'common.compliance.documentNotFound'],
|
||||
['compliance_rate_limit', 429, 'common.compliance.rateLimit'],
|
||||
['billing_request_in_progress', 429, 'billing.errors.requestInProgress'],
|
||||
['billing_unavailable', 503, 'billing.errors.unavailable'],
|
||||
['billing_operation_failed', 502, 'billing.errors.operationFailed'],
|
||||
])('shows the message for %s', async (code, status, message) => {
|
||||
const user = userEvent.setup()
|
||||
vi.mocked(consoleClient.compliance.download.get).mockRejectedValue(
|
||||
new ORPCError(code, { defined: true, status, message: 'Backend text' }),
|
||||
)
|
||||
seedFeatures(queryClient, { billing: { subscription: { plan: 'team' } } })
|
||||
|
||||
await openMenuAndRender()
|
||||
await user.click(getComplianceMenuItem('common.compliance.soc2Type1'))
|
||||
|
||||
await waitFor(() => expect(toastErrorSpy).toHaveBeenCalledWith(message))
|
||||
})
|
||||
|
||||
it('falls back to the generic billing message for undeclared errors', async () => {
|
||||
const user = userEvent.setup()
|
||||
vi.mocked(consoleClient.compliance.download.get).mockRejectedValue(
|
||||
new Error('Download failed'),
|
||||
)
|
||||
seedFeatures(queryClient, { billing: { subscription: { plan: 'team' } } })
|
||||
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
|
||||
await openMenuAndRender()
|
||||
await user.click(getComplianceMenuItem('common.compliance.soc2Type1'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(consoleClient.compliance.download.get).toHaveBeenCalledWith(
|
||||
{ query: { doc_name: 'SOC2_Type_I' } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
expect(toastErrorSpy).toHaveBeenCalledWith('common.operation.downloadFailed')
|
||||
})
|
||||
expect(consoleSpy).toHaveBeenCalled()
|
||||
consoleSpy.mockRestore()
|
||||
await waitFor(() =>
|
||||
expect(toastErrorSpy).toHaveBeenCalledWith('billing.errors.operationFailed'),
|
||||
)
|
||||
})
|
||||
|
||||
it('should handle upgrade click on badge for sandbox plan', async () => {
|
||||
|
||||
@@ -9,10 +9,12 @@ import {
|
||||
MenuSubmenuTrigger,
|
||||
} from '@langgenius/dify-ui/menu'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
|
||||
import { isDefinedError } from '@orpc/client'
|
||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||
import { useQueryState } from 'nuqs'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { billingErrorMessageKey } from '@/app/components/billing/billing-error'
|
||||
import {
|
||||
pricingQueryParamName,
|
||||
pricingQueryParser,
|
||||
@@ -22,7 +24,7 @@ import {
|
||||
settingsQueryParser,
|
||||
} from '@/app/components/header/account-setting/query-params'
|
||||
import { toast } from '@/app/notifications'
|
||||
import { consoleClient, consoleQuery } from '@/service/console'
|
||||
import { consoleQuery } from '@/service/console'
|
||||
import { downloadUrl } from '@/utils/download'
|
||||
import PremiumBadge from '../../base/premium-badge'
|
||||
import { MenuItemContent } from './menu-item-content'
|
||||
@@ -83,7 +85,7 @@ function ComplianceDocActionVisual({
|
||||
<PremiumBadge color="blue" allowHover={true}>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="i-custom-public-common-sparkles-soft flex h-3.5 w-3.5 items-center [background-clip:content-box] [background-origin:content-box] [mask-clip:content-box] [mask-origin:content-box] py-px pl-0.75 text-components-premium-badge-indigo-text-stop-0"
|
||||
className="i-custom-public-common-sparkles-soft flex h-3.5 w-3.5 items-center [background-clip:content-box] [background-origin:content-box] [mask-clip:content-box] [mask-origin:content-box] py-px ps-0.75 text-components-premium-badge-indigo-text-stop-0"
|
||||
/>
|
||||
<div className="px-1 system-xs-medium">{upgradeText}</div>
|
||||
</PremiumBadge>
|
||||
@@ -112,22 +114,25 @@ function ComplianceDocRowItem({ icon, label, docName }: ComplianceDocRowItemProp
|
||||
const [, setSettingsDestination] = useQueryState(settingsQueryParamName, settingsQueryParser)
|
||||
const isFreePlan = plan === 'sandbox'
|
||||
|
||||
const { isPending, mutate: downloadCompliance } = useMutation({
|
||||
mutationKey: ['downloadCompliance', docName],
|
||||
mutationFn: async () => {
|
||||
try {
|
||||
const ret = await consoleClient.compliance.download.get(
|
||||
{ query: { doc_name: docName } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
const { isPending, mutate: downloadCompliance } = useMutation(
|
||||
consoleQuery.compliance.download.get.mutationOptions({
|
||||
context: { silent: true },
|
||||
onSuccess: (ret) => {
|
||||
downloadUrl({ url: ret.url })
|
||||
toast.success(t(($) => $['operation.downloadSuccess'], { ns: 'common' }))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
toast.error(t(($) => $['operation.downloadFailed'], { ns: 'common' }))
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
onError: (error) => {
|
||||
const code = isDefinedError(error) ? error.code : undefined
|
||||
if (code === 'compliance_download_forbidden')
|
||||
toast.error(t(($) => $['compliance.downloadForbidden'], { ns: 'common' }))
|
||||
else if (code === 'compliance_document_not_found')
|
||||
toast.error(t(($) => $['compliance.documentNotFound'], { ns: 'common' }))
|
||||
else if (code === 'compliance_rate_limit')
|
||||
toast.error(t(($) => $['compliance.rateLimit'], { ns: 'common' }))
|
||||
else toast.error(t(($) => $[billingErrorMessageKey(error)], { ns: 'billing' }))
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const whichPlanCanDownloadCompliance: Record<DocName, CloudPlan[]> = {
|
||||
[DocName.SOC2_Type_I]: ['professional', 'team'],
|
||||
@@ -142,13 +147,14 @@ function ComplianceDocRowItem({ icon, label, docName }: ComplianceDocRowItemProp
|
||||
|
||||
const handleSelect = useCallback(() => {
|
||||
if (isCurrentPlanCanDownload) {
|
||||
if (!isPending) downloadCompliance()
|
||||
if (!isPending) downloadCompliance({ query: { doc_name: docName } })
|
||||
return
|
||||
}
|
||||
|
||||
if (isFreePlan) setPricing('open')
|
||||
else setSettingsDestination('billing')
|
||||
}, [
|
||||
docName,
|
||||
downloadCompliance,
|
||||
isCurrentPlanCanDownload,
|
||||
isFreePlan,
|
||||
@@ -168,7 +174,7 @@ function ComplianceDocRowItem({ icon, label, docName }: ComplianceDocRowItemProp
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
className="h-10 justify-between py-1 pr-2 pl-1"
|
||||
className="h-10 justify-between py-1 ps-1 pe-2"
|
||||
closeOnClick={!isCurrentPlanCanDownload}
|
||||
disabled={isPending}
|
||||
onClick={handleSelect}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { QueryClient } from '@tanstack/react-query'
|
||||
import type { ReactElement } from 'react'
|
||||
import { ORPCError } from '@orpc/client'
|
||||
import { act, render as RTLRender, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { useState } from 'react'
|
||||
@@ -241,4 +242,21 @@ describe('InstitutionField', () => {
|
||||
.some((element) => element.closest('[role="status"]') !== null),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('asks to try again later while the search service is unavailable', async () => {
|
||||
const user = userEvent.setup()
|
||||
mockAutocomplete.mockRejectedValue(
|
||||
new ORPCError('billing_unavailable', { defined: true, status: 503, message: 'Backend text' }),
|
||||
)
|
||||
|
||||
render(<ControlledInstitutionField />)
|
||||
|
||||
await user.type(
|
||||
screen.getByPlaceholderText(/(?:^|\.)form\.schoolName\.placeholder(?=$|:)/),
|
||||
'A',
|
||||
)
|
||||
|
||||
expect((await screen.findAllByText('billing.errors.unavailable')).length).toBeGreaterThan(0)
|
||||
expect(screen.queryByText('common.dynamicSelect.error')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { GetAccountProfileResponse } from '@dify/contracts/api/console/account/types.gen'
|
||||
import { ORPCError } from '@orpc/client'
|
||||
import { screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import EducationApplyPage from '@/app/education/apply/application-form'
|
||||
@@ -114,12 +115,28 @@ describe('EducationApplyPage billing boundary', () => {
|
||||
await user.click(screen.getByRole('button', { name: 'education.useEducationDiscount' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockGetSubscription).toHaveBeenCalledWith({
|
||||
query: { plan: 'professional', interval: 'year' },
|
||||
})
|
||||
expect(mockGetSubscription).toHaveBeenCalledWith(
|
||||
{ query: { plan: 'professional', interval: 'year' } },
|
||||
{ context: { silent: true } },
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('explains a checkout failure by its error code', async () => {
|
||||
setupContext(true)
|
||||
mockGetSubscription.mockRejectedValue(
|
||||
new ORPCError('billing_unavailable', { defined: true, status: 503, message: 'Backend text' }),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
renderPage()
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'education.useEducationDiscount' }))
|
||||
|
||||
await waitFor(() =>
|
||||
expect(vi.mocked(toast.error)).toHaveBeenCalledWith('billing.errors.unavailable'),
|
||||
)
|
||||
})
|
||||
|
||||
it('shows non-manager members that they cannot apply the coupon to payment', () => {
|
||||
setupContext(false)
|
||||
renderPage()
|
||||
@@ -221,4 +238,41 @@ describe('EducationApplyPage billing boundary', () => {
|
||||
await screen.findByRole('button', { name: 'education.useEducationDiscount' }),
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it.each([
|
||||
['education_activate_failed', 400, 'education.activateFailed'],
|
||||
['education_activate_limit', 429, 'education.tooManyAttempts'],
|
||||
['billing_request_in_progress', 429, 'billing.errors.requestInProgress'],
|
||||
['billing_unavailable', 503, 'billing.errors.unavailable'],
|
||||
['billing_operation_failed', 502, 'billing.errors.operationFailed'],
|
||||
])(
|
||||
'explains a %s application failure next to the submit button',
|
||||
async (code, status, message) => {
|
||||
setupContext(true)
|
||||
mockEducationAdd.mockRejectedValue(
|
||||
new ORPCError(code, { defined: true, status, message: 'Backend text' }),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
renderPage(false)
|
||||
|
||||
await user.type(
|
||||
screen.getByRole('combobox', { name: 'education.form.schoolName.title' }),
|
||||
'DifyUniversity',
|
||||
)
|
||||
await user.keyboard('{Escape}')
|
||||
await user.click(screen.getByRole('checkbox', { name: 'education.form.terms.option.age' }))
|
||||
await user.click(
|
||||
screen.getByRole('checkbox', { name: 'education.form.terms.option.inSchool' }),
|
||||
)
|
||||
await user.click(
|
||||
screen.getByRole('checkbox', { name: 'education.form.terms.option.personalUse' }),
|
||||
)
|
||||
await user.click(screen.getByRole('button', { name: 'education.submit' }))
|
||||
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent(message)
|
||||
expect(screen.queryByText('Backend text')).not.toBeInTheDocument()
|
||||
expect(vi.mocked(toast.error)).not.toHaveBeenCalled()
|
||||
expect(screen.getByRole('button', { name: 'education.submit' })).toBeInTheDocument()
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -1,7 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import type { contract } from '@dify/contracts/api/console/account/orpc.gen'
|
||||
import type { SubscriptionModel } from '@dify/contracts/api/console/features/types.gen'
|
||||
import type { GetWorkspacesCurrentSummaryResponse } from '@dify/contracts/api/console/workspaces/types.gen'
|
||||
import type { ErrorFromErrorMap, InferContractRouterErrorMap } from '@orpc/contract'
|
||||
import type { TFunction } from 'i18next'
|
||||
import type { ReactNode } from 'react'
|
||||
import type { EducationRole } from './types'
|
||||
import { Button, buttonVariants } from '@langgenius/dify-ui/button'
|
||||
@@ -10,10 +13,12 @@ import { CheckboxGroup } from '@langgenius/dify-ui/checkbox-group'
|
||||
import { Field, FieldDescription, FieldItem, FieldLabel } from '@langgenius/dify-ui/field'
|
||||
import { Fieldset, FieldsetLegend } from '@langgenius/dify-ui/fieldset'
|
||||
import { Form } from '@langgenius/dify-ui/form'
|
||||
import { isDefinedError } from '@orpc/client'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useState } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { billingErrorMessageKey } from '@/app/components/billing/billing-error'
|
||||
import { useEducationDiscount } from '@/app/components/billing/hooks/use-education-discount'
|
||||
import { toast } from '@/app/notifications'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
@@ -35,21 +40,44 @@ const AppliedEducationCase = {
|
||||
noPaymentPermission: 'noPaymentPermission',
|
||||
} as const
|
||||
|
||||
type EducationApplyError = ErrorFromErrorMap<
|
||||
InferContractRouterErrorMap<typeof contract.account.education.post>
|
||||
>
|
||||
|
||||
function educationApplyErrorMessage(
|
||||
error: EducationApplyError,
|
||||
t: TFunction<['billing', 'common', 'education']>,
|
||||
) {
|
||||
const code = isDefinedError(error) ? error.code : undefined
|
||||
switch (code) {
|
||||
case 'education_activate_failed':
|
||||
return t(($) => $.activateFailed, { ns: 'education' })
|
||||
case 'education_activate_limit':
|
||||
return t(($) => $.tooManyAttempts, { ns: 'education' })
|
||||
default:
|
||||
return t(($) => $[billingErrorMessageKey(error)], { ns: 'billing' })
|
||||
}
|
||||
}
|
||||
|
||||
type EducationApplyPageProps = {
|
||||
plan: SubscriptionModel['plan']
|
||||
token: string
|
||||
}
|
||||
|
||||
const EducationApplyPage = ({ plan, token }: EducationApplyPageProps) => {
|
||||
const { t } = useTranslation(['common', 'education'])
|
||||
const { t } = useTranslation(['billing', 'common', 'education'])
|
||||
const queryClient = useQueryClient()
|
||||
const [schoolName, setSchoolName] = useState('')
|
||||
const [role, setRole] = useState<EducationRole>('Student')
|
||||
const [agreements, setAgreements] = useState<string[]>([])
|
||||
const [hasSubmittedEducation, setHasSubmittedEducation] = useState(false)
|
||||
const [isOpeningBillingPortal, setIsOpeningBillingPortal] = useState(false)
|
||||
const { isPending, mutate: educationAdd } = useMutation(
|
||||
consoleQuery.account.education.post.mutationOptions(),
|
||||
const {
|
||||
error: submitError,
|
||||
isPending,
|
||||
mutate: educationAdd,
|
||||
} = useMutation(
|
||||
consoleQuery.account.education.post.mutationOptions({ context: { silent: true } }),
|
||||
)
|
||||
const { data: isEducationAccount = false } = useQuery(
|
||||
consoleQuery.account.education.get.queryOptions({
|
||||
@@ -108,8 +136,8 @@ const EducationApplyPage = ({ plan, token }: EducationApplyPageProps) => {
|
||||
throw new Error('Failed to open billing page')
|
||||
},
|
||||
{
|
||||
onError: (err) => {
|
||||
toast.error(err.message || String(err))
|
||||
onError: (error) => {
|
||||
toast.error(t(($) => $[billingErrorMessageKey(error)], { ns: 'billing' }))
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -150,7 +178,7 @@ const EducationApplyPage = ({ plan, token }: EducationApplyPageProps) => {
|
||||
<div className="flex w-full flex-col items-start gap-3">
|
||||
<div className="flex w-full items-start rounded-lg border-[0.5px] border-components-badge-status-light-warning-halo bg-state-warning-hover px-3 py-2.5">
|
||||
<span
|
||||
className="mt-0.5 mr-2 i-ri-alert-fill size-4 shrink-0 text-text-warning-secondary"
|
||||
className="me-2 mt-0.5 i-ri-alert-fill size-4 shrink-0 text-text-warning-secondary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div className="system-md-regular text-text-warning">
|
||||
@@ -179,7 +207,7 @@ const EducationApplyPage = ({ plan, token }: EducationApplyPageProps) => {
|
||||
<div className="flex w-full flex-col items-start gap-3">
|
||||
<div className="flex w-full items-start rounded-lg border-[0.5px] border-components-badge-status-light-warning-halo bg-state-warning-hover px-3 py-2.5">
|
||||
<span
|
||||
className="mt-0.5 mr-2 i-ri-alert-fill size-4 shrink-0 text-text-warning-secondary"
|
||||
className="me-2 mt-0.5 i-ri-alert-fill size-4 shrink-0 text-text-warning-secondary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div className="system-md-regular text-text-warning">
|
||||
@@ -279,6 +307,11 @@ const EducationApplyPage = ({ plan, token }: EducationApplyPageProps) => {
|
||||
>
|
||||
{t(($) => $.submit, { ns: 'education' })}
|
||||
</Button>
|
||||
{submitError && (
|
||||
<p role="alert" className="mt-2 system-sm-regular text-text-destructive">
|
||||
{educationApplyErrorMessage(submitError, t)}
|
||||
</p>
|
||||
)}
|
||||
<div className="mt-5 mb-4 h-px bg-linear-to-r from-[rgba(16,24,40,0.08)]" />
|
||||
<a
|
||||
className="flex items-center system-xs-regular text-text-accent focus-visible:ring-2 focus-visible:ring-state-accent-solid focus-visible:outline-hidden"
|
||||
@@ -287,7 +320,7 @@ const EducationApplyPage = ({ plan, token }: EducationApplyPageProps) => {
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t(($) => $.learn, { ns: 'education' })}
|
||||
<span className="ml-1 i-ri-external-link-line size-3" aria-hidden="true" />
|
||||
<span className="ms-1 i-ri-external-link-line size-3" aria-hidden="true" />
|
||||
</a>
|
||||
</Form>
|
||||
)}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from '@langgenius/dify-ui/autocomplete'
|
||||
import { Field, FieldLabel } from '@langgenius/dify-ui/field'
|
||||
import { SpinnerIcon } from '@langgenius/dify-ui/spinner'
|
||||
import { isDefinedError } from '@orpc/client'
|
||||
import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query'
|
||||
import { useDebouncedValue } from 'foxact/use-debounced-value'
|
||||
import { useId, useRef, useState } from 'react'
|
||||
@@ -30,7 +31,7 @@ type InstitutionFieldProps = {
|
||||
}
|
||||
|
||||
const InstitutionField = ({ value, onValueChange }: InstitutionFieldProps) => {
|
||||
const { t } = useTranslation(['common', 'education'])
|
||||
const { t } = useTranslation(['billing', 'common', 'education'])
|
||||
const inputId = useId()
|
||||
const listRef = useRef<HTMLDivElement>(null)
|
||||
const [isPopupOpen, setIsPopupOpen] = useState(false)
|
||||
@@ -38,7 +39,7 @@ const InstitutionField = ({ value, onValueChange }: InstitutionFieldProps) => {
|
||||
const debouncedSearchQuery = useDebouncedValue(searchQuery, 300)
|
||||
const hasSearchQuery = !!searchQuery
|
||||
const isDebouncing = hasSearchQuery && searchQuery !== debouncedSearchQuery
|
||||
const { data, fetchNextPage, hasNextPage, isError, isFetching } = useInfiniteQuery({
|
||||
const { data, error, fetchNextPage, hasNextPage, isError, isFetching } = useInfiniteQuery({
|
||||
...consoleQuery.account.education.autocomplete.get.infiniteOptions({
|
||||
input: (pageParam) => ({
|
||||
query: {
|
||||
@@ -49,6 +50,7 @@ const InstitutionField = ({ value, onValueChange }: InstitutionFieldProps) => {
|
||||
}),
|
||||
initialPageParam: 0,
|
||||
getNextPageParam: (lastPage) => (lastPage.has_next ? lastPage.curr_page + 1 : undefined),
|
||||
context: { silent: true },
|
||||
}),
|
||||
enabled: hasSearchQuery && !!debouncedSearchQuery,
|
||||
placeholderData: keepPreviousData,
|
||||
@@ -62,6 +64,10 @@ const InstitutionField = ({ value, onValueChange }: InstitutionFieldProps) => {
|
||||
else if (isError) footerState = 'error'
|
||||
else if (hasNextPage) footerState = 'loading'
|
||||
}
|
||||
const errorMessage =
|
||||
isDefinedError(error) && error.code === 'billing_unavailable'
|
||||
? t(($) => $['errors.unavailable'], { ns: 'billing' })
|
||||
: t(($) => $['dynamicSelect.error'], { ns: 'common' })
|
||||
const shouldShowEmpty = shouldOpenPopup && footerState === null && suggestions.length === 0
|
||||
const canLoadMore = shouldOpenPopup && hasNextPage && !isLoading && !isError
|
||||
|
||||
@@ -134,7 +140,7 @@ const InstitutionField = ({ value, onValueChange }: InstitutionFieldProps) => {
|
||||
) : null}
|
||||
{footerState === 'error' ? (
|
||||
<span className="system-sm-regular text-text-destructive">
|
||||
{t(($) => $['dynamicSelect.error'], { ns: 'common' })}
|
||||
{errorMessage}
|
||||
</span>
|
||||
) : (
|
||||
<SpinnerIcon />
|
||||
@@ -152,7 +158,7 @@ const InstitutionField = ({ value, onValueChange }: InstitutionFieldProps) => {
|
||||
{shouldOpenPopup && isLoading
|
||||
? t(($) => $.loading, { ns: 'common' })
|
||||
: footerState === 'error'
|
||||
? t(($) => $['dynamicSelect.error'], { ns: 'common' })
|
||||
? errorMessage
|
||||
: null}
|
||||
</span>
|
||||
</AutocompleteStatus>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ORPCError } from '@orpc/client'
|
||||
import { screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { StrictMode } from 'react'
|
||||
@@ -19,6 +20,17 @@ vi.mock('@/next/navigation', () => ({
|
||||
useRouter: () => ({ replace: mockReplace }),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/console', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/service/console')>()
|
||||
const { withConsoleResponses } = await import('@/test/console/service-responses')
|
||||
return {
|
||||
...actual,
|
||||
consoleQuery: withConsoleResponses(actual.consoleQuery, {
|
||||
'account.education.verify.get': mockRequestVerification,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/app/education/user-info', () => ({
|
||||
default: () => <div>Student account</div>,
|
||||
}))
|
||||
@@ -39,7 +51,7 @@ function renderFlow({
|
||||
})
|
||||
seedFeatures(queryClient, { education: { enabled: true } })
|
||||
|
||||
return render(<EducationVerifyFlow requestVerification={mockRequestVerification} />, { wrapper })
|
||||
return render(<EducationVerifyFlow />, { wrapper })
|
||||
}
|
||||
|
||||
describe('EducationVerifyFlow', () => {
|
||||
@@ -70,7 +82,7 @@ describe('EducationVerifyFlow', () => {
|
||||
|
||||
render(
|
||||
<StrictMode>
|
||||
<EducationVerifyFlow requestVerification={mockRequestVerification} />
|
||||
<EducationVerifyFlow />
|
||||
</StrictMode>,
|
||||
{ wrapper },
|
||||
)
|
||||
@@ -102,6 +114,7 @@ describe('EducationVerifyFlow', () => {
|
||||
expect(
|
||||
await screen.findByRole('heading', { name: 'common.errorBoundary.title' }),
|
||||
).toBeInTheDocument()
|
||||
expect(screen.getByText('billing.errors.operationFailed')).toBeInTheDocument()
|
||||
mockRequestVerification.mockResolvedValue({ status: 'eligible', token: 'retry-token' })
|
||||
await user.click(screen.getByRole('button', { name: 'common.errorBoundary.tryAgain' }))
|
||||
await waitFor(() =>
|
||||
@@ -109,4 +122,23 @@ describe('EducationVerifyFlow', () => {
|
||||
)
|
||||
expect(mockRequestVerification).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['education_verify_failed', 400, 'education.verifyFailed'],
|
||||
['education_verify_limit', 429, 'education.tooManyAttempts'],
|
||||
['billing_request_in_progress', 429, 'billing.errors.requestInProgress'],
|
||||
['billing_unavailable', 503, 'billing.errors.unavailable'],
|
||||
])('offers a retry for %s', async (code, status, message) => {
|
||||
mockRequestVerification.mockRejectedValue(
|
||||
new ORPCError(code, { defined: true, status, message: 'Backend text' }),
|
||||
)
|
||||
|
||||
renderFlow({})
|
||||
|
||||
expect(await screen.findByText(message)).toBeInTheDocument()
|
||||
expect(screen.queryByText('Backend text')).not.toBeInTheDocument()
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'common.errorBoundary.tryAgain' }),
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -1,46 +1,58 @@
|
||||
'use client'
|
||||
|
||||
import type {
|
||||
EducationStatusResponse,
|
||||
EducationVerifyResponse,
|
||||
} from '@dify/contracts/api/console/account/types.gen'
|
||||
import type { contract } from '@dify/contracts/api/console/account/orpc.gen'
|
||||
import type { EducationStatusResponse } from '@dify/contracts/api/console/account/types.gen'
|
||||
import type { GetFeaturesResponse } from '@dify/contracts/api/console/features/types.gen'
|
||||
import type { ErrorFromErrorMap, InferContractRouterErrorMap } from '@orpc/contract'
|
||||
import type { TFunction } from 'i18next'
|
||||
import type { ReactNode } from 'react'
|
||||
import { Button, buttonVariants } from '@langgenius/dify-ui/button'
|
||||
import { isDefinedError } from '@orpc/client'
|
||||
import { useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { LoadingPlaceholder } from '@/app/components/base/loading-placeholder'
|
||||
import { billingErrorMessageKey } from '@/app/components/billing/billing-error'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import Link from '@/next/link'
|
||||
import { redirect, useRouter } from '@/next/navigation'
|
||||
import { consoleClient, consoleQuery } from '@/service/console'
|
||||
import { consoleQuery } from '@/service/console'
|
||||
import { EducationStatusCard } from '../status-card'
|
||||
import UserInfo from '../user-info'
|
||||
|
||||
type EducationVerificationRequest = () => Promise<EducationVerifyResponse>
|
||||
|
||||
const selectEducationStatus = ({ allow_refresh, is_student }: EducationStatusResponse) => ({
|
||||
allowRefresh: allow_refresh,
|
||||
isEducationAccount: is_student,
|
||||
})
|
||||
|
||||
const selectEducationPlanEnabled = ({ education }: GetFeaturesResponse) => education.enabled
|
||||
type EducationVerificationError = ErrorFromErrorMap<
|
||||
InferContractRouterErrorMap<typeof contract.account.education.verify.get>
|
||||
>
|
||||
|
||||
const requestEducationVerification: EducationVerificationRequest = () =>
|
||||
consoleClient.account.education.verify.get({}, { context: { silent: true } })
|
||||
function educationVerifyErrorMessage(
|
||||
error: EducationVerificationError,
|
||||
t: TFunction<['billing', 'education']>,
|
||||
) {
|
||||
const code = isDefinedError(error) ? error.code : undefined
|
||||
switch (code) {
|
||||
case 'education_verify_failed':
|
||||
return t(($) => $.verifyFailed, { ns: 'education' })
|
||||
case 'education_verify_limit':
|
||||
return t(($) => $.tooManyAttempts, { ns: 'education' })
|
||||
default:
|
||||
return t(($) => $[billingErrorMessageKey(error)], { ns: 'billing' })
|
||||
}
|
||||
}
|
||||
|
||||
const selectEducationPlanEnabled = ({ education }: GetFeaturesResponse) => education.enabled
|
||||
|
||||
export default function EducationVerifyPage() {
|
||||
return <EducationVerifyFlow />
|
||||
}
|
||||
|
||||
export function EducationVerifyFlow({
|
||||
requestVerification = requestEducationVerification,
|
||||
}: {
|
||||
requestVerification?: EducationVerificationRequest
|
||||
}) {
|
||||
const { t } = useTranslation(['education'])
|
||||
export function EducationVerifyFlow() {
|
||||
const { t } = useTranslation(['billing', 'education'])
|
||||
const router = useRouter()
|
||||
const { data: userEmail } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
@@ -60,13 +72,13 @@ export function EducationVerifyFlow({
|
||||
)
|
||||
const {
|
||||
data: verification,
|
||||
error: verificationError,
|
||||
isError: isVerificationError,
|
||||
mutate: verifyEducation,
|
||||
reset: resetVerification,
|
||||
} = useMutation({
|
||||
mutationKey: ['education', 'verification'],
|
||||
mutationFn: () => requestVerification(),
|
||||
})
|
||||
} = useMutation(
|
||||
consoleQuery.account.education.verify.get.mutationOptions({ context: { silent: true } }),
|
||||
)
|
||||
|
||||
const startVerification = useCallback(() => {
|
||||
if (verificationStartedRef.current) return
|
||||
@@ -101,6 +113,9 @@ export function EducationVerifyFlow({
|
||||
if (educationStatusQuery.isError)
|
||||
return (
|
||||
<EducationVerifyError
|
||||
message={t(($) => $[billingErrorMessageKey(educationStatusQuery.error)], {
|
||||
ns: 'billing',
|
||||
})}
|
||||
onRetry={() => {
|
||||
void educationStatusQuery.refetch()
|
||||
}}
|
||||
@@ -155,6 +170,7 @@ export function EducationVerifyFlow({
|
||||
if (isVerificationError)
|
||||
return (
|
||||
<EducationVerifyError
|
||||
message={educationVerifyErrorMessage(verificationError, t)}
|
||||
onRetry={() => {
|
||||
verificationStartedRef.current = false
|
||||
resetVerification()
|
||||
@@ -214,7 +230,7 @@ function EducationVerifiedContent() {
|
||||
)
|
||||
}
|
||||
|
||||
function EducationVerifyError({ onRetry }: { onRetry: () => void }) {
|
||||
function EducationVerifyError({ message, onRetry }: { message: string; onRetry: () => void }) {
|
||||
const { t } = useTranslation(['common', 'education'])
|
||||
|
||||
return (
|
||||
@@ -239,7 +255,7 @@ function EducationVerifyError({ onRetry }: { onRetry: () => void }) {
|
||||
</>
|
||||
}
|
||||
>
|
||||
{t(($) => $['errorBoundary.message'], { ns: 'common' })}
|
||||
{message}
|
||||
</EducationStatusCard>
|
||||
</EducationVerifyContent>
|
||||
)
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "تم الوصول إلى حد الخطة",
|
||||
"apps.fullTip2des": "يوصى بتنظيف التطبيقات غير النشطة لتحرير الاستخدام، أو الاتصال بنا.",
|
||||
"buyPermissionDeniedTip": "يرجى الاتصال بمسؤول المؤسسة للاشتراك",
|
||||
"errors.operationFailed": "تعذر إكمال هذا الطلب. يرجى المحاولة مرة أخرى لاحقًا. إذا استمرت المشكلة، فاتصل بالدعم.",
|
||||
"errors.requestInProgress": "لا يزال طلبك السابق قيد المعالجة. يرجى المحاولة مرة أخرى بعد قليل.",
|
||||
"errors.unavailable": "هذه الخدمة غير متاحة مؤقتًا. يرجى المحاولة مرة أخرى لاحقًا.",
|
||||
"plans.community.btnText": "ابدأ الآن",
|
||||
"plans.community.description": "للمتحمسين للمصادر المفتوحة، والمطورين الأفراد، والمشاريع غير التجارية",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "إعادة تسمية المحادثة",
|
||||
"chat.thinking": "يفكر...",
|
||||
"chat.thought": "فكر",
|
||||
"compliance.documentNotFound": "هذا المستند غير متاح حاليًا. يرجى المحاولة مرة أخرى لاحقًا أو الاتصال بالدعم.",
|
||||
"compliance.downloadForbidden": "يمكن لمالك مساحة العمل فقط تنزيل هذا المستند، وفقط على خطة تتضمنه. اطلب من مالك مساحة العمل تنزيله.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "شهادة ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "متاح فقط مع خطة الفريق أو أعلى.",
|
||||
"compliance.rateLimit": "عدد كبير جدًا من التنزيلات. يرجى المحاولة مرة أخرى لاحقًا.",
|
||||
"compliance.sandboxUpgradeTooltip": "متاح فقط مع خطة المحترفين أو الفريق.",
|
||||
"compliance.soc2Type1": "تقرير SOC 2 النوع الأول",
|
||||
"compliance.soc2Type2": "تقرير SOC 2 النوع الثاني",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "تعذر تفعيل الخصم التعليمي. قد تكون حالة التحقق التعليمي الحالية لا تزال سارية، أو لم يعد هذا البريد الإلكتروني مؤهلًا.",
|
||||
"applied.activeSubscription.description": "لديك اشتراك نشط. يمكنك استخدام الخصم التعليمي بعد انتهاء صلاحية اشتراكك. تأكيد اشتراكك في <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "ليس لديك صلاحية الدفع في هذه مساحة العمل. يرجى التبديل إلى مساحة عمل حيث يمكنك إدارة الفوترة لاستخدام الخصم التعليمي.",
|
||||
"applied.noPaymentPermission.returnHome": "العودة إلى Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "كوبون حصري 100٪",
|
||||
"toVerifiedTip.end": "لخطة Dify الاحترافية.",
|
||||
"toVerifiedTip.front": "أنت الآن مؤهل للحصول على حالة التحقق التعليمي. يرجى إدخال معلومات التعليم الخاصة بك أدناه لإكمال العملية والحصول على",
|
||||
"useEducationDiscount": "استخدام الخصم التعليمي"
|
||||
"tooManyAttempts": "محاولات كثيرة جدًا. يرجى المحاولة مرة أخرى لاحقًا.",
|
||||
"useEducationDiscount": "استخدام الخصم التعليمي",
|
||||
"verifyFailed": "تعذر التحقق من حالتك التعليمية. إذا أكملت التحقق مؤخرًا، فقد تكون حالة التحقق التعليمي الحالية لا تزال سارية. وإلا، يرجى المحاولة مرة أخرى لاحقًا."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Plan limitinə çatılıb",
|
||||
"apps.fullTip2des": "İstifadə limitini boşaltmaq üçün qeyri-aktiv tətbiqləri silmək və ya bizimlə əlaqə saxlamaq tövsiyə olunur.",
|
||||
"buyPermissionDeniedTip": "Abunə olmaq üçün müəssisənizin inzibatçısı ilə əlaqə saxlayın",
|
||||
"errors.operationFailed": "Bu sorğunu tamamlaya bilmədik. Zəhmət olmasa, sonra yenidən cəhd edin. Problem davam edərsə, dəstək xidməti ilə əlaqə saxlayın.",
|
||||
"errors.requestInProgress": "Əvvəlki sorğunuz hələ də emal olunur. Zəhmət olmasa, bir azdan yenidən cəhd edin.",
|
||||
"errors.unavailable": "Bu xidmət müvəqqəti olaraq əlçatan deyil. Zəhmət olmasa, sonra yenidən cəhd edin.",
|
||||
"plans.community.btnText": "Başla",
|
||||
"plans.community.description": "Açıq mənbə həvəskarları, fərdi proqramçılar və qeyri-kommersiya layihələri üçün",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Söhbətin adının dəyişdirilməsi",
|
||||
"chat.thinking": "Düşünür...",
|
||||
"chat.thought": "Düşüncə",
|
||||
"compliance.documentNotFound": "Bu sənəd hazırda əlçatan deyil. Zəhmət olmasa, sonra yenidən cəhd edin və ya dəstək xidməti ilə əlaqə saxlayın.",
|
||||
"compliance.downloadForbidden": "Bu sənədi yalnız iş sahəsinin sahibi və yalnız onu əhatə edən planda yükləyə bilər. İş sahəsinin sahibindən onu yükləməsini xahiş edin.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 sertifikatı",
|
||||
"compliance.professionalUpgradeTooltip": "Yalnız Team və ya daha yüksək planda mövcuddur.",
|
||||
"compliance.rateLimit": "Həddindən çox yükləmə. Zəhmət olmasa, sonra yenidən cəhd edin.",
|
||||
"compliance.sandboxUpgradeTooltip": "Yalnız Professional və ya Team planında mövcuddur.",
|
||||
"compliance.soc2Type1": "SOC 2 tip I hesabatı",
|
||||
"compliance.soc2Type2": "SOC 2 tip II hesabatı",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Təhsil endirimini aktivləşdirə bilmədik. Cari təhsil statusu təsdiqiniz hələ də aktiv ola bilər və ya bu e-poçt artıq uyğun deyil.",
|
||||
"applied.activeSubscription.description": "Aktiv abunəliyiniz var. Abunəliyinizin vaxtı bitdikdən sonra təhsil endirimindən istifadə edə bilərsiniz. Abunəliyinizi <stripeLink>Stripe</stripeLink> üzərindən təsdiqləyin.",
|
||||
"applied.noPaymentPermission.description": "Bu iş sahəsində ödəniş icazəniz yoxdur. Təhsil endirimindən istifadə etmək üçün ödənişləri idarə edə bildiyiniz iş sahəsinə keçin.",
|
||||
"applied.noPaymentPermission.returnHome": "Dify-a qayıt",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "xüsusi 100% endirim kuponu",
|
||||
"toVerifiedTip.end": "(Dify peşəkar planı üçün).",
|
||||
"toVerifiedTip.front": "Artıq təsdiqlənmiş təhsil statusu almaq hüququnuz var. Prosesi tamamlamaq üçün təhsil məlumatlarınızı aşağıya daxil edin. Əldə edəcəyiniz üstünlük:",
|
||||
"useEducationDiscount": "Təhsil endirimindən istifadə et"
|
||||
"tooManyAttempts": "Həddindən çox cəhd. Zəhmət olmasa, sonra yenidən cəhd edin.",
|
||||
"useEducationDiscount": "Təhsil endirimindən istifadə et",
|
||||
"verifyFailed": "Təhsil statusunuzu təsdiqləyə bilmədik. Bu yaxınlarda təsdiqləmisinizsə, cari təhsil statusu təsdiqiniz hələ də aktiv ola bilər. Əks halda, zəhmət olmasa, sonra yenidən cəhd edin."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Limit erreicht",
|
||||
"apps.fullTip2des": "Es wird empfohlen, inaktive Anwendungen zu bereinigen, um Speicherplatz freizugeben, oder uns zu kontaktieren.",
|
||||
"buyPermissionDeniedTip": "Bitte kontaktieren Sie Ihren Unternehmensadministrator, um zu abonnieren",
|
||||
"errors.operationFailed": "Diese Anfrage konnte nicht abgeschlossen werden. Bitte versuchen Sie es später erneut. Wenn das Problem weiterhin besteht, wenden Sie sich an den Support.",
|
||||
"errors.requestInProgress": "Ihre vorherige Anfrage wird noch bearbeitet. Bitte versuchen Sie es gleich noch einmal.",
|
||||
"errors.unavailable": "Dieser Dienst ist vorübergehend nicht verfügbar. Bitte versuchen Sie es später erneut.",
|
||||
"plans.community.btnText": "Beginnen Sie mit der Gemeinschaft",
|
||||
"plans.community.description": "Für Einzelbenutzer, kleine Teams oder nicht-kommerzielle Projekte",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Konversation umbenennen",
|
||||
"chat.thinking": "Denken...",
|
||||
"chat.thought": "Gedanke",
|
||||
"compliance.documentNotFound": "Dieses Dokument ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut oder wenden Sie sich an den Support.",
|
||||
"compliance.downloadForbidden": "Nur der Inhaber des Arbeitsbereichs kann dieses Dokument herunterladen, und nur mit einem Tarif, der es enthält. Bitten Sie den Inhaber des Arbeitsbereichs, es herunterzuladen.",
|
||||
"compliance.gdpr": "DSGVO DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 Zertifizierung",
|
||||
"compliance.professionalUpgradeTooltip": "Nur verfügbar mit einem Teamplan oder höher.",
|
||||
"compliance.rateLimit": "Zu viele Downloads. Bitte versuchen Sie es später erneut.",
|
||||
"compliance.sandboxUpgradeTooltip": "Nur verfügbar mit einem Professional- oder Teamplan.",
|
||||
"compliance.soc2Type1": "SOC 2 Typ I Bericht",
|
||||
"compliance.soc2Type2": "SOC 2 Typ II Bericht",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Ihr Bildungsrabatt konnte nicht aktiviert werden. Ihre aktuelle Bildungsverifizierung ist möglicherweise noch aktiv, oder diese E-Mail-Adresse ist nicht mehr berechtigt.",
|
||||
"applied.activeSubscription.description": "Sie haben ein aktives Abonnement. Sie können den Bildungsrabatt verwenden, nachdem Ihr Abonnement abläuft. Bestätigen Sie Ihr Abonnement in <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Sie haben keine Zahlungsberechtigung in diesem Arbeitsbereich. Bitte wechseln Sie zu einem Arbeitsbereich, in dem Sie die Abrechnung verwalten können, um den Bildungsrabatt zu nutzen.",
|
||||
"applied.noPaymentPermission.returnHome": "Zurück zu Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "exklusiver 100% Gutschein",
|
||||
"toVerifiedTip.end": "für den Dify Professional Plan.",
|
||||
"toVerifiedTip.front": "Sie sind jetzt berechtigt, den Status Bildung verifiziert zu erhalten. Bitte geben Sie unten Ihre Bildungsinformationen ein, um den Prozess abzuschließen und eine zu erhalten.",
|
||||
"useEducationDiscount": "Bildungsrabatt verwenden"
|
||||
"tooManyAttempts": "Zu viele Versuche. Bitte versuchen Sie es später erneut.",
|
||||
"useEducationDiscount": "Bildungsrabatt verwenden",
|
||||
"verifyFailed": "Ihr Bildungsstatus konnte nicht verifiziert werden. Wenn Sie sich kürzlich verifiziert haben, ist Ihre aktuelle Bildungsverifizierung möglicherweise noch aktiv. Andernfalls versuchen Sie es bitte später erneut."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Plan limit reached",
|
||||
"apps.fullTip2des": "It is recommended to clean up inactive applications to free up usage, or contact us.",
|
||||
"buyPermissionDeniedTip": "Please contact your enterprise administrator to subscribe",
|
||||
"errors.operationFailed": "We couldn't complete this request. Please try again later. If the problem persists, contact support.",
|
||||
"errors.requestInProgress": "Your previous request is still being processed. Please try again in a moment.",
|
||||
"errors.unavailable": "This service is temporarily unavailable. Please try again later.",
|
||||
"plans.community.btnText": "Get Started",
|
||||
"plans.community.description": "For open-source enthusiasts, individual developers, and non-commercial projects",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Rename Conversation",
|
||||
"chat.thinking": "Thinking...",
|
||||
"chat.thought": "Thought",
|
||||
"compliance.documentNotFound": "This document is not available right now. Please try again later or contact support.",
|
||||
"compliance.downloadForbidden": "Only the workspace owner can download this document, and only on a plan that includes it. Ask your workspace owner to download it.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 Certification",
|
||||
"compliance.professionalUpgradeTooltip": "Only available with a Team plan or above.",
|
||||
"compliance.rateLimit": "Too many downloads. Please try again later.",
|
||||
"compliance.sandboxUpgradeTooltip": "Only available with a Professional or Team plan.",
|
||||
"compliance.soc2Type1": "SOC 2 Type I Report",
|
||||
"compliance.soc2Type2": "SOC 2 Type II Report",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "We couldn't activate your education discount. Your current Education Verified status may still be active, or this email is no longer eligible.",
|
||||
"applied.activeSubscription.description": "You have an active subscription. You can use the education discount after your subscription expires. Confirm your subscription in <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "You don't have payment permission in this workspace. Please switch to a workspace where you can manage billing to use the education discount.",
|
||||
"applied.noPaymentPermission.returnHome": "Back to Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "exclusive 100% coupon",
|
||||
"toVerifiedTip.end": "for the Dify Professional Plan.",
|
||||
"toVerifiedTip.front": "You are now eligible for Education Verified status. Please enter your education information below to complete the process and receive an",
|
||||
"useEducationDiscount": "Use education discount"
|
||||
"tooManyAttempts": "Too many attempts. Please try again later.",
|
||||
"useEducationDiscount": "Use education discount",
|
||||
"verifyFailed": "We couldn't verify your education status. If you verified recently, your current Education Verified status may still be active. Otherwise, please try again later."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Límite de plan alcanzado",
|
||||
"apps.fullTip2des": "Se recomienda limpiar las aplicaciones inactivas para liberar espacio de uso, o contactarnos.",
|
||||
"buyPermissionDeniedTip": "Por favor, contacta al administrador de tu empresa para suscribirte",
|
||||
"errors.operationFailed": "No pudimos completar esta solicitud. Inténtalo de nuevo más tarde. Si el problema persiste, contacta con el soporte.",
|
||||
"errors.requestInProgress": "Tu solicitud anterior aún se está procesando. Inténtalo de nuevo en un momento.",
|
||||
"errors.unavailable": "Este servicio no está disponible temporalmente. Inténtalo de nuevo más tarde.",
|
||||
"plans.community.btnText": "Comienza con la Comunidad",
|
||||
"plans.community.description": "Para usuarios individuales, pequeños equipos o proyectos no comerciales",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Renombrar Conversación",
|
||||
"chat.thinking": "Pensamiento...",
|
||||
"chat.thought": "Pensamiento",
|
||||
"compliance.documentNotFound": "Este documento no está disponible en este momento. Inténtalo de nuevo más tarde o contacta con el soporte.",
|
||||
"compliance.downloadForbidden": "Solo el propietario del espacio de trabajo puede descargar este documento, y solo con un plan que lo incluya. Pide al propietario del espacio de trabajo que lo descargue.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Certificación ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Solo disponible con un plan de equipo o superior.",
|
||||
"compliance.rateLimit": "Demasiadas descargas. Inténtalo de nuevo más tarde.",
|
||||
"compliance.sandboxUpgradeTooltip": "Solo disponible con un plan Profesional o de Equipo.",
|
||||
"compliance.soc2Type1": "Informe SOC 2 Tipo I",
|
||||
"compliance.soc2Type2": "Informe SOC 2 Tipo II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "No pudimos activar tu descuento educativo. Es posible que tu verificación educativa actual siga activa o que este correo electrónico ya no cumpla los requisitos.",
|
||||
"applied.activeSubscription.description": "Tienes una suscripción activa. Puedes usar el descuento educativo después de que expire tu suscripción. Confirma tu suscripción en <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "No tienes permiso de pago en este workspace. Por favor, cambia a un workspace donde puedas gestionar la facturación para usar el descuento educativo.",
|
||||
"applied.noPaymentPermission.returnHome": "Volver a Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "cupón exclusivo del 100%",
|
||||
"toVerifiedTip.end": "para el Plan Profesional de Dify.",
|
||||
"toVerifiedTip.front": "Ahora eres elegible para el estado de Educación Verificada. Por favor, introduce tu información educativa a continuación para completar el proceso y recibir un",
|
||||
"useEducationDiscount": "Usar descuento educativo"
|
||||
"tooManyAttempts": "Demasiados intentos. Inténtalo de nuevo más tarde.",
|
||||
"useEducationDiscount": "Usar descuento educativo",
|
||||
"verifyFailed": "No pudimos verificar tu estado educativo. Si te verificaste recientemente, es posible que tu verificación educativa actual siga activa. De lo contrario, inténtalo de nuevo más tarde."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "محدودیت طرح به پایان رسید",
|
||||
"apps.fullTip2des": "توصیه میشود برنامههای غیرفعال را پاک کنید تا فضای استفاده را آزاد کنید، یا با ما تماس بگیرید.",
|
||||
"buyPermissionDeniedTip": "لطفاً با مدیر سازمان خود تماس بگیرید تا اشتراک تهیه کنید",
|
||||
"errors.operationFailed": "نتوانستیم این درخواست را تکمیل کنیم. لطفاً بعداً دوباره تلاش کنید. اگر مشکل ادامه داشت، با پشتیبانی تماس بگیرید.",
|
||||
"errors.requestInProgress": "درخواست قبلی شما هنوز در حال پردازش است. لطفاً کمی بعد دوباره تلاش کنید.",
|
||||
"errors.unavailable": "این سرویس موقتاً در دسترس نیست. لطفاً بعداً دوباره تلاش کنید.",
|
||||
"plans.community.btnText": "شروع کنید با جامعه",
|
||||
"plans.community.description": "برای کاربران فردی، تیمهای کوچک یا پروژههای غیر تجاری",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "تغییر نام مکالمه",
|
||||
"chat.thinking": "تفکر...",
|
||||
"chat.thought": "فکر",
|
||||
"compliance.documentNotFound": "این سند در حال حاضر در دسترس نیست. لطفاً بعداً دوباره تلاش کنید یا با پشتیبانی تماس بگیرید.",
|
||||
"compliance.downloadForbidden": "فقط مالک فضای کاری میتواند این سند را دانلود کند، و فقط در طرحی که شامل آن باشد. از مالک فضای کاری بخواهید آن را دانلود کند.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "گواهینامه ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "تنها با برنامه تیم یا بالاتر در دسترس است.",
|
||||
"compliance.rateLimit": "تعداد دانلودها بیش از حد است. لطفاً بعداً دوباره تلاش کنید.",
|
||||
"compliance.sandboxUpgradeTooltip": "تنها با برنامه حرفهای یا تیمی در دسترس است.",
|
||||
"compliance.soc2Type1": "گزارش نوع I SOC 2",
|
||||
"compliance.soc2Type2": "گزارش نوع II SOC 2",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "نتوانستیم تخفیف آموزشی شما را فعال کنیم. ممکن است تأییدیه آموزشی فعلی شما هنوز فعال باشد یا این ایمیل دیگر واجد شرایط نباشد.",
|
||||
"applied.activeSubscription.description": "شما یک اشتراک فعال دارید. پس از انقضای اشتراک میتوانید از تخفیف آموزشی استفاده کنید. اشتراک خود را در <stripeLink>Stripe</stripeLink> تأیید کنید.",
|
||||
"applied.noPaymentPermission.description": "شما در این workspace مجوز پرداخت ندارید. لطفاً به workspaceای بروید که بتوانید صورتحساب را مدیریت کنید تا از تخفیف آموزشی استفاده کنید.",
|
||||
"applied.noPaymentPermission.returnHome": "بازگشت به Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "کوپن انحصاری ۱۰۰٪",
|
||||
"toVerifiedTip.end": "برای طرح حرفهای دیفی.",
|
||||
"toVerifiedTip.front": "شما اکنون برای وضعیت تأیید شده آموزشی واجد شرایط هستید. لطفاً اطلاعات تحصیلی خود را در زیر وارد کنید تا فرآیند را کامل کرده و یک دریافت کنید.",
|
||||
"useEducationDiscount": "استفاده از تخفیف آموزشی"
|
||||
"tooManyAttempts": "تلاشهای بیش از حد. لطفاً بعداً دوباره تلاش کنید.",
|
||||
"useEducationDiscount": "استفاده از تخفیف آموزشی",
|
||||
"verifyFailed": "نتوانستیم وضعیت آموزشی شما را تأیید کنیم. اگر اخیراً تأیید شدهاید، ممکن است تأییدیه آموزشی فعلی شما هنوز فعال باشد. در غیر این صورت، لطفاً بعداً دوباره تلاش کنید."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Limite de plan atteinte",
|
||||
"apps.fullTip2des": "Il est recommandé de nettoyer les applications inactives pour libérer de l'espace d'utilisation, ou de nous contacter.",
|
||||
"buyPermissionDeniedTip": "Veuillez contacter votre administrateur d'entreprise pour vous abonner",
|
||||
"errors.operationFailed": "Impossible de traiter cette demande. Veuillez réessayer plus tard. Si le problème persiste, contactez le support.",
|
||||
"errors.requestInProgress": "Votre demande précédente est toujours en cours de traitement. Veuillez réessayer dans un instant.",
|
||||
"errors.unavailable": "Ce service est temporairement indisponible. Veuillez réessayer plus tard.",
|
||||
"plans.community.btnText": "Commencez avec la communauté",
|
||||
"plans.community.description": "Pour les utilisateurs individuels, les petites équipes ou les projets non commerciaux",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Renommer la conversation",
|
||||
"chat.thinking": "Pensée...",
|
||||
"chat.thought": "Pensée",
|
||||
"compliance.documentNotFound": "Ce document n'est pas disponible pour le moment. Veuillez réessayer plus tard ou contacter le support.",
|
||||
"compliance.downloadForbidden": "Seul le propriétaire de l'espace de travail peut télécharger ce document, et uniquement avec un forfait qui l'inclut. Demandez au propriétaire de l'espace de travail de le télécharger.",
|
||||
"compliance.gdpr": "RGPD DPA",
|
||||
"compliance.iso27001": "Certification ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Disponible uniquement avec un plan Équipe ou supérieur.",
|
||||
"compliance.rateLimit": "Trop de téléchargements. Veuillez réessayer plus tard.",
|
||||
"compliance.sandboxUpgradeTooltip": "Disponible uniquement avec un plan Professionnel ou Équipe.",
|
||||
"compliance.soc2Type1": "Rapport SOC 2 Type I",
|
||||
"compliance.soc2Type2": "Rapport SOC 2 Type II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Impossible d'activer votre réduction éducation. Votre vérification éducative actuelle est peut-être encore active, ou cette adresse e-mail n'est plus éligible.",
|
||||
"applied.activeSubscription.description": "Vous avez un abonnement actif. Vous pouvez utiliser la remise éducative après l'expiration de votre abonnement. Confirmez votre abonnement dans <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Vous n'avez pas la permission de payer dans cet espace de travail. Veuillez passer à un espace de travail où vous pouvez gérer la facturation pour utiliser la remise éducative.",
|
||||
"applied.noPaymentPermission.returnHome": "Retour à Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "coupon exclusif 100%",
|
||||
"toVerifiedTip.end": "pour le Plan Professionnel Dify.",
|
||||
"toVerifiedTip.front": "Vous êtes maintenant éligible pour le statut Vérifié en Éducation. Veuillez entrer vos informations éducatives ci-dessous pour compléter le processus et recevoir un",
|
||||
"useEducationDiscount": "Utiliser la remise éducative"
|
||||
"tooManyAttempts": "Trop de tentatives. Veuillez réessayer plus tard.",
|
||||
"useEducationDiscount": "Utiliser la remise éducative",
|
||||
"verifyFailed": "Impossible de vérifier votre statut éducatif. Si vous vous êtes vérifié récemment, votre vérification éducative actuelle est peut-être encore active. Sinon, veuillez réessayer plus tard."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "योजना की सीमा पहुँच गई",
|
||||
"apps.fullTip2des": "अचल अनुप्रयोगों को साफ करने की सिफारिश की जाती है ताकि उपयोग को मुक्त किया जा सके, या हमसे संपर्क करें।",
|
||||
"buyPermissionDeniedTip": "सब्सक्राइब करने के लिए कृपया अपने एंटरप्राइज़ व्यवस्थापक से संपर्क करें",
|
||||
"errors.operationFailed": "हम यह अनुरोध पूरा नहीं कर सके। कृपया बाद में पुनः प्रयास करें। यदि समस्या बनी रहती है, तो सहायता से संपर्क करें।",
|
||||
"errors.requestInProgress": "आपका पिछला अनुरोध अभी भी संसाधित हो रहा है। कृपया थोड़ी देर में पुनः प्रयास करें।",
|
||||
"errors.unavailable": "यह सेवा अस्थायी रूप से अनुपलब्ध है। कृपया बाद में पुनः प्रयास करें।",
|
||||
"plans.community.btnText": "समुदाय के साथ आरंभ करें",
|
||||
"plans.community.description": "व्यक्तिगत उपयोगकर्ताओं, छोटे टीमों, या गैर-व्यावसायिक परियोजनाओं के लिए",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "संवाद का नाम बदलें",
|
||||
"chat.thinking": "सोचते हुए...",
|
||||
"chat.thought": "विचार",
|
||||
"compliance.documentNotFound": "यह दस्तावेज़ अभी उपलब्ध नहीं है। कृपया बाद में पुनः प्रयास करें या सहायता से संपर्क करें।",
|
||||
"compliance.downloadForbidden": "केवल कार्यक्षेत्र स्वामी ही इस दस्तावेज़ को डाउनलोड कर सकते हैं, और केवल उसी योजना पर जिसमें यह शामिल हो। कार्यक्षेत्र स्वामी से इसे डाउनलोड करने के लिए कहें।",
|
||||
"compliance.gdpr": "जीडीपीआर डीपीए",
|
||||
"compliance.iso27001": "आईएसओ 27001:2022 प्रमाणन",
|
||||
"compliance.professionalUpgradeTooltip": "केवल टीम योजना या उससे ऊपर के साथ उपलब्ध है।",
|
||||
"compliance.rateLimit": "बहुत अधिक डाउनलोड। कृपया बाद में पुनः प्रयास करें।",
|
||||
"compliance.sandboxUpgradeTooltip": "केवल पेशेवर या टीम योजना के साथ उपलब्ध है।",
|
||||
"compliance.soc2Type1": "SOC 2 प्रकार I रिपोर्ट",
|
||||
"compliance.soc2Type2": "SOC 2 प्रकार II रिपोर्ट",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "हम आपकी शैक्षणिक छूट सक्रिय नहीं कर सके। आपका वर्तमान शैक्षणिक सत्यापन अभी भी सक्रिय हो सकता है, या यह ईमेल अब पात्र नहीं है।",
|
||||
"applied.activeSubscription.description": "आपके पास एक सक्रिय सदस्यता है। आपकी सदस्यता समाप्त होने के बाद आप शिक्षा छूट का उपयोग कर सकते हैं। <stripeLink>Stripe</stripeLink> में अपनी सदस्यता की पुष्टि करें।",
|
||||
"applied.noPaymentPermission.description": "इस workspace में आपके पास भुगतान की अनुमति नहीं है। शिक्षा छूट का उपयोग करने के लिए कृपया ऐसे workspace पर स्विच करें जहाँ आप बिलिंग प्रबंधित कर सकते हैं।",
|
||||
"applied.noPaymentPermission.returnHome": "Dify पर वापस जाएं",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "विशेष 100% कूपन",
|
||||
"toVerifiedTip.end": "Dify प्रोफेशनल योजना के लिए।",
|
||||
"toVerifiedTip.front": "आप अब शिक्षा सत्यापित स्थिति के लिए योग्य हैं। कृपया नीचे अपनी शिक्षा की जानकारी प्रदान करें ताकि प्रक्रिया को पूरा किया जा सके और एक प्राप्त हो सके",
|
||||
"useEducationDiscount": "शिक्षा छूट का उपयोग करें"
|
||||
"tooManyAttempts": "बहुत अधिक प्रयास। कृपया बाद में पुनः प्रयास करें।",
|
||||
"useEducationDiscount": "शिक्षा छूट का उपयोग करें",
|
||||
"verifyFailed": "हम आपकी शैक्षणिक स्थिति सत्यापित नहीं कर सके। यदि आपने हाल ही में सत्यापन किया है, तो आपका वर्तमान शैक्षणिक सत्यापन अभी भी सक्रिय हो सकता है। अन्यथा, कृपया बाद में पुनः प्रयास करें।"
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Batas paket tercapai",
|
||||
"apps.fullTip2des": "Disarankan untuk membersihkan aplikasi yang tidak aktif untuk mengosongkan penggunaan, atau hubungi kami.",
|
||||
"buyPermissionDeniedTip": "Hubungi administrator perusahaan Anda untuk berlangganan",
|
||||
"errors.operationFailed": "Kami tidak dapat menyelesaikan permintaan ini. Silakan coba lagi nanti. Jika masalah berlanjut, hubungi dukungan.",
|
||||
"errors.requestInProgress": "Permintaan Anda sebelumnya masih diproses. Silakan coba lagi sebentar lagi.",
|
||||
"errors.unavailable": "Layanan ini sementara tidak tersedia. Silakan coba lagi nanti.",
|
||||
"plans.community.btnText": "Mulai dengan Komunitas",
|
||||
"plans.community.description": "Untuk Pengguna Individu, Tim Kecil, atau Proyek Non-Komersial",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Ganti Nama Percakapan",
|
||||
"chat.thinking": "Sedang berpikir...",
|
||||
"chat.thought": "Pikiran",
|
||||
"compliance.documentNotFound": "Dokumen ini sedang tidak tersedia. Silakan coba lagi nanti atau hubungi dukungan.",
|
||||
"compliance.downloadForbidden": "Hanya pemilik ruang kerja yang dapat mengunduh dokumen ini, dan hanya pada paket yang menyertakannya. Minta pemilik ruang kerja untuk mengunduhnya.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Sertifikasi ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Hanya tersedia dengan paket Tim atau lebih tinggi.",
|
||||
"compliance.rateLimit": "Terlalu banyak unduhan. Silakan coba lagi nanti.",
|
||||
"compliance.sandboxUpgradeTooltip": "Hanya tersedia dengan paket Profesional atau Tim.",
|
||||
"compliance.soc2Type1": "Laporan SOC 2 Tipe I",
|
||||
"compliance.soc2Type2": "Laporan SOC 2 Tipe II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Kami tidak dapat mengaktifkan diskon pendidikan Anda. Verifikasi pendidikan Anda saat ini mungkin masih aktif, atau email ini sudah tidak memenuhi syarat.",
|
||||
"applied.activeSubscription.description": "Anda memiliki langganan aktif. Anda dapat menggunakan diskon pendidikan setelah langganan Anda berakhir. Konfirmasi langganan Anda di <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Anda tidak memiliki izin pembayaran di workspace ini. Silakan beralih ke workspace di mana Anda dapat mengelola penagihan untuk menggunakan diskon pendidikan.",
|
||||
"applied.noPaymentPermission.returnHome": "Kembali ke Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "kupon eksklusif 100%",
|
||||
"toVerifiedTip.end": "untuk Paket Profesional Dify.",
|
||||
"toVerifiedTip.front": "Anda sekarang memenuhi syarat untuk status Terverifikasi Pendidikan. Silakan masukkan informasi pendidikan Anda di bawah ini untuk menyelesaikan proses dan menerima",
|
||||
"useEducationDiscount": "Gunakan diskon pendidikan"
|
||||
"tooManyAttempts": "Terlalu banyak percobaan. Silakan coba lagi nanti.",
|
||||
"useEducationDiscount": "Gunakan diskon pendidikan",
|
||||
"verifyFailed": "Kami tidak dapat memverifikasi status pendidikan Anda. Jika Anda baru saja memverifikasi, verifikasi pendidikan Anda saat ini mungkin masih aktif. Jika tidak, silakan coba lagi nanti."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Limite del piano raggiunto",
|
||||
"apps.fullTip2des": "Si consiglia di disinstallare le applicazioni inattive per liberare spazio, o contattarci.",
|
||||
"buyPermissionDeniedTip": "Contatta l'amministratore della tua azienda per abbonarti",
|
||||
"errors.operationFailed": "Non è stato possibile completare questa richiesta. Riprova più tardi. Se il problema persiste, contatta l'assistenza.",
|
||||
"errors.requestInProgress": "La tua richiesta precedente è ancora in elaborazione. Riprova tra un momento.",
|
||||
"errors.unavailable": "Questo servizio è temporaneamente non disponibile. Riprova più tardi.",
|
||||
"plans.community.btnText": "Inizia con la comunità",
|
||||
"plans.community.description": "Per utenti individuali, piccole squadre o progetti non commerciali",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Rinomina Conversazione",
|
||||
"chat.thinking": "Pensante...",
|
||||
"chat.thought": "Pensiero",
|
||||
"compliance.documentNotFound": "Questo documento non è al momento disponibile. Riprova più tardi o contatta l'assistenza.",
|
||||
"compliance.downloadForbidden": "Solo il proprietario dell'area di lavoro può scaricare questo documento, e solo con un piano che lo include. Chiedi al proprietario dell'area di lavoro di scaricarlo.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Certificazione ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Disponibile solo con un piano Team o superiore.",
|
||||
"compliance.rateLimit": "Troppi download. Riprova più tardi.",
|
||||
"compliance.sandboxUpgradeTooltip": "Disponibile solo con un piano Professionale o Team.",
|
||||
"compliance.soc2Type1": "Rapporto SOC 2 Tipo I",
|
||||
"compliance.soc2Type2": "Rapporto SOC 2 di Tipo II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Non è stato possibile attivare lo sconto educativo. La tua verifica educativa attuale potrebbe essere ancora attiva, oppure questa email non è più idonea.",
|
||||
"applied.activeSubscription.description": "Hai un abbonamento attivo. Puoi utilizzare lo sconto educativo dopo la scadenza dell'abbonamento. Conferma il tuo abbonamento su <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Non hai il permesso di pagamento in questo workspace. Passa a un workspace in cui puoi gestire la fatturazione per utilizzare lo sconto educativo.",
|
||||
"applied.noPaymentPermission.returnHome": "Torna a Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "coupon esclusivo al 100%",
|
||||
"toVerifiedTip.end": "per il Piano Professionale Dify.",
|
||||
"toVerifiedTip.front": "Ora sei idoneo per lo stato di Educazione Verificata. Per favore, inserisci le tue informazioni educative qui sotto per completare il processo e ricevere un",
|
||||
"useEducationDiscount": "Utilizza lo sconto educativo"
|
||||
"tooManyAttempts": "Troppi tentativi. Riprova più tardi.",
|
||||
"useEducationDiscount": "Utilizza lo sconto educativo",
|
||||
"verifyFailed": "Non è stato possibile verificare il tuo stato educativo. Se ti sei verificato di recente, la tua verifica educativa attuale potrebbe essere ancora attiva. Altrimenti, riprova più tardi."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "プラン制限に達しました。",
|
||||
"apps.fullTip2des": "非アクティブなアプリを削除するか、アップグレードプランをご検討ください。",
|
||||
"buyPermissionDeniedTip": "サブスクリプションするには、エンタープライズ管理者に連絡してください",
|
||||
"errors.operationFailed": "このリクエストを完了できませんでした。しばらくしてからもう一度お試しください。問題が解決しない場合は、サポートにお問い合わせください。",
|
||||
"errors.requestInProgress": "前回のリクエストはまだ処理中です。少し待ってからもう一度お試しください。",
|
||||
"errors.unavailable": "このサービスは一時的に利用できません。しばらくしてからもう一度お試しください。",
|
||||
"plans.community.btnText": "コミュニティ版を始めましょう",
|
||||
"plans.community.description": "オープンソース版の無料プラン",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "会話名を変更",
|
||||
"chat.thinking": "考え中...",
|
||||
"chat.thought": "思考",
|
||||
"compliance.documentNotFound": "このドキュメントは現在利用できません。しばらくしてからもう一度お試しいただくか、サポートにお問い合わせください。",
|
||||
"compliance.downloadForbidden": "このドキュメントをダウンロードできるのはワークスペースのオーナーのみで、対象のドキュメントを含むプランが必要です。ワークスペースのオーナーにダウンロードを依頼してください。",
|
||||
"compliance.gdpr": "GDPR データ処理契約(DPA)",
|
||||
"compliance.iso27001": "ISO 27001:2022 認証",
|
||||
"compliance.professionalUpgradeTooltip": "チームプラン以上の契約が必要です",
|
||||
"compliance.rateLimit": "ダウンロード回数が多すぎます。しばらくしてからもう一度お試しください。",
|
||||
"compliance.sandboxUpgradeTooltip": "プロフェッショナルプランまたはチームプランでのみ利用可能",
|
||||
"compliance.soc2Type1": "SOC 2 Type I 報告書",
|
||||
"compliance.soc2Type2": "SOC 2 Type II 報告書",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "教育割引を有効にできませんでした。現在の教育認証がまだ有効であるか、このメールアドレスが対象外になっている可能性があります。",
|
||||
"applied.activeSubscription.description": "現在有効なサブスクリプションがあります。サブスクリプションの有効期限が切れた後、教育割引を使用できます。<stripeLink>Stripe</stripeLink> でサブスクリプションを確認してください。",
|
||||
"applied.noPaymentPermission.description": "このワークスペースでは支払い権限がありません。教育割引を使用するには、請求を管理できるワークスペースに切り替えてください。",
|
||||
"applied.noPaymentPermission.returnHome": "Dify に戻る",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "100%割引クーポン",
|
||||
"toVerifiedTip.end": "を受け取ることができます。",
|
||||
"toVerifiedTip.front": "現在、教育認証ステータスを取得する資格があります。以下に教育情報を入力し、認証プロセスを完了すると、Dify プロフェッショナルプランの",
|
||||
"useEducationDiscount": "教育割引を使用"
|
||||
"tooManyAttempts": "試行回数が多すぎます。しばらくしてからもう一度お試しください。",
|
||||
"useEducationDiscount": "教育割引を使用",
|
||||
"verifyFailed": "教育認証を確認できませんでした。最近認証した場合は、現在の教育認証がまだ有効である可能性があります。それ以外の場合は、しばらくしてからもう一度お試しください。"
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "계획 한도에 도달했습니다.",
|
||||
"apps.fullTip2des": "비활성 애플리케이션을 정리하여 사용량을 줄이거나 저희에게 문의하는 것이 좋습니다.",
|
||||
"buyPermissionDeniedTip": "구독하려면 엔터프라이즈 관리자에게 문의하세요",
|
||||
"errors.operationFailed": "이 요청을 완료할 수 없습니다. 나중에 다시 시도해 주세요. 문제가 계속되면 지원팀에 문의하세요.",
|
||||
"errors.requestInProgress": "이전 요청이 아직 처리 중입니다. 잠시 후 다시 시도해 주세요.",
|
||||
"errors.unavailable": "이 서비스는 일시적으로 사용할 수 없습니다. 나중에 다시 시도해 주세요.",
|
||||
"plans.community.btnText": "커뮤니티 시작하기",
|
||||
"plans.community.description": "개인 사용자, 소규모 팀 또는 비상업적 프로젝트를 위한",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "대화 이름 바꾸기",
|
||||
"chat.thinking": "생각...",
|
||||
"chat.thought": "생각",
|
||||
"compliance.documentNotFound": "현재 이 문서를 사용할 수 없습니다. 나중에 다시 시도하거나 지원팀에 문의하세요.",
|
||||
"compliance.downloadForbidden": "이 문서는 워크스페이스 소유자만, 해당 문서가 포함된 플랜에서만 다운로드할 수 있습니다. 워크스페이스 소유자에게 다운로드를 요청하세요.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 인증",
|
||||
"compliance.professionalUpgradeTooltip": "팀 플랜 이상에서만 사용할 수 있습니다.",
|
||||
"compliance.rateLimit": "다운로드 횟수가 너무 많습니다. 나중에 다시 시도해 주세요.",
|
||||
"compliance.sandboxUpgradeTooltip": "전문가 또는 팀 플랜에서만 사용할 수 있습니다.",
|
||||
"compliance.soc2Type1": "SOC 2 유형 I 보고서",
|
||||
"compliance.soc2Type2": "SOC 2 유형 II 보고서",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "교육 할인을 활성화할 수 없습니다. 현재 교육 인증이 아직 유효하거나 이 이메일이 더 이상 자격 요건을 충족하지 않을 수 있습니다.",
|
||||
"applied.activeSubscription.description": "현재 활성 구독이 있습니다. 구독이 만료된 후 교육 할인을 사용할 수 있습니다. <stripeLink>Stripe</stripeLink>에서 구독을 확인하세요.",
|
||||
"applied.noPaymentPermission.description": "이 워크스페이스에서 결제 권한이 없습니다. 교육 할인을 사용하려면 청구를 관리할 수 있는 워크스페이스로 전환하세요.",
|
||||
"applied.noPaymentPermission.returnHome": "Dify로 돌아가기",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "독점 100% 쿠폰",
|
||||
"toVerifiedTip.end": "Dify 프로페셔널 플랜을 위해.",
|
||||
"toVerifiedTip.front": "당신은 이제 교육 인증 상태를 받을 자격이 있습니다. 아래에 귀하의 교육 정보를 입력하여 과정을 완료하고 인증을 받으십시오.",
|
||||
"useEducationDiscount": "교육 할인 사용"
|
||||
"tooManyAttempts": "시도 횟수가 너무 많습니다. 나중에 다시 시도해 주세요.",
|
||||
"useEducationDiscount": "교육 할인 사용",
|
||||
"verifyFailed": "교육 인증을 확인할 수 없습니다. 최근에 인증했다면 현재 교육 인증이 아직 유효할 수 있습니다. 그렇지 않다면 나중에 다시 시도해 주세요."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "ຮອດຂີດຈຳກັດຂອງແພັກເກດແລ້ວ",
|
||||
"apps.fullTip2des": "ແນະນຳໃຫ້ລຶບແອັບຯທີ່ບໍ່ໄດ້ໃຊ້ງານອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ ຫຼື ຕິດຕໍ່ພວກເຮົາ.",
|
||||
"buyPermissionDeniedTip": "ກະລຸນາຕິດຕໍ່ຜູ້ດູແລລະບົບຂອງອົງກອນຂອງທ່ານເພື່ອສະໝັກໃຊ້ບໍລິການ",
|
||||
"errors.operationFailed": "ພວກເຮົາບໍ່ສາມາດດຳເນີນຄຳຮ້ອງນີ້ໃຫ້ສຳເລັດໄດ້. ກະລຸນາລອງໃໝ່ພາຍຫຼັງ. ຖ້າບັນຫາຍັງຄົງຢູ່, ກະລຸນາຕິດຕໍ່ຝ່າຍຊ່ວຍເຫຼືອ.",
|
||||
"errors.requestInProgress": "ຄຳຮ້ອງກ່ອນໜ້າຂອງທ່ານຍັງຢູ່ໃນລະຫວ່າງການດຳເນີນການ. ກະລຸນາລອງໃໝ່ໃນອີກຈັກໜ່ອຍ.",
|
||||
"errors.unavailable": "ບໍລິການນີ້ບໍ່ສາມາດໃຊ້ງານໄດ້ຊົ່ວຄາວ. ກະລຸນາລອງໃໝ່ພາຍຫຼັງ.",
|
||||
"plans.community.btnText": "ເລີ່ມຕົ້ນໃຊ້ງານ",
|
||||
"plans.community.description": "ສຳລັບຜູ້ທີ່ມັກຮັກໃນ Open-source, ນັກພັດທະນາທົ່ວໄປ ແລະ ໂຄງການທີ່ບໍ່ແມ່ນເພື່ອການຄ້າ",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "ປ່ຽນຊື່ການສົນທະນາ",
|
||||
"chat.thinking": "ກຳລັງຄິດ...",
|
||||
"chat.thought": "ຄວາມຄິດ",
|
||||
"compliance.documentNotFound": "ເອກະສານນີ້ບໍ່ສາມາດໃຊ້ງານໄດ້ໃນຂະນະນີ້. ກະລຸນາລອງໃໝ່ພາຍຫຼັງ ຫຼື ຕິດຕໍ່ຝ່າຍຊ່ວຍເຫຼືອ.",
|
||||
"compliance.downloadForbidden": "ມີແຕ່ເຈົ້າຂອງພື້ນທີ່ເຮັດວຽກເທົ່ານັ້ນທີ່ສາມາດດາວໂຫຼດເອກະສານນີ້ໄດ້, ແລະ ສະເພາະໃນແຜນທີ່ລວມເອກະສານນີ້. ຂໍໃຫ້ເຈົ້າຂອງພື້ນທີ່ເຮັດວຽກດາວໂຫຼດມັນ.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ໃບຢັ້ງຢືນ ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "ໃຊ້ໄດ້ສະເພາະກັບແຜນ Team ຂຶ້ນໄປ.",
|
||||
"compliance.rateLimit": "ດາວໂຫຼດຫຼາຍເກີນໄປ. ກະລຸນາລອງໃໝ່ພາຍຫຼັງ.",
|
||||
"compliance.sandboxUpgradeTooltip": "ໃຊ້ໄດ້ສະເພາະກັບແຜນ Professional ຫຼື Team.",
|
||||
"compliance.soc2Type1": "ລາຍງານ SOC 2 Type I",
|
||||
"compliance.soc2Type2": "ລາຍງານ SOC 2 Type II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "ພວກເຮົາບໍ່ສາມາດເປີດໃຊ້ສ່ວນຫຼຸດເພື່ອການສຶກສາຂອງທ່ານໄດ້. ການຢືນຢັນເພື່ອການສຶກສາປັດຈຸບັນຂອງທ່ານອາດຍັງມີຜົນຢູ່, ຫຼື ອີເມວນີ້ບໍ່ມີສິດອີກຕໍ່ໄປ.",
|
||||
"applied.activeSubscription.description": "ທ່ານມີການສະໝັກໃຊ້ງານທີ່ຍັງມີຜົນຢູ່. ທ່ານສາມາດໃຊ້ສ່ວນຫຼຸດເພື່ອການສຶກສາໄດ້ຫຼັງຈາກການສະໝັກໃຊ້ງານຂອງທ່ານໝົດອາຍຸ. ຢືນຢັນການສະໝັກໃຊ້ງານຂອງທ່ານໃນ <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "ທ່ານບໍ່ມີສິດໃນການຊຳລະເງິນໃນພື້ນທີ່ເຮັດວຽກນີ້. ກະລຸນາປ່ຽນໄປໃຊ້ພື້ນທີ່ເຮັດວຽກທີ່ທ່ານສາມາດຈັດການການຮຽກເກັບເງິນເພື່ອໃຊ້ສ່ວນຫຼຸດເພື່ອການສຶກສາ.",
|
||||
"applied.noPaymentPermission.returnHome": "ກັບຄືນສູ່ Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "ຄູປອງສ່ວນຫຼຸດ 100% ພິເສດ",
|
||||
"toVerifiedTip.end": "ສຳລັບແພັກເກດ Dify Professional.",
|
||||
"toVerifiedTip.front": "ຕອນນີ້ທ່ານມີຄຸນສົມບັດສຳລັບສະຖານະການຢືນຢັນເພື່ອການສຶກສາແລ້ວ. ກະລຸນາປ້ອນຂໍ້ມູນການສຶກສາຂອງທ່ານຂ້າງລຸ່ມນີ້ເພື່ອສຳເລັດຂັ້ນຕອນ ແລະ ຮັບ",
|
||||
"useEducationDiscount": "ໃຊ້ສ່ວນຫຼຸດເພື່ອການສຶກສາ"
|
||||
"tooManyAttempts": "ພະຍາຍາມຫຼາຍເກີນໄປ. ກະລຸນາລອງໃໝ່ພາຍຫຼັງ.",
|
||||
"useEducationDiscount": "ໃຊ້ສ່ວນຫຼຸດເພື່ອການສຶກສາ",
|
||||
"verifyFailed": "ພວກເຮົາບໍ່ສາມາດຢືນຢັນສະຖານະການສຶກສາຂອງທ່ານໄດ້. ຖ້າທ່ານຫາກໍຢືນຢັນມາບໍ່ດົນ, ການຢືນຢັນເພື່ອການສຶກສາປັດຈຸບັນຂອງທ່ານອາດຍັງມີຜົນຢູ່. ຖ້າບໍ່ແມ່ນ, ກະລຸນາລອງໃໝ່ພາຍຫຼັງ."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Plan limit reached",
|
||||
"apps.fullTip2des": "It is recommended to clean up inactive applications to free up usage, or contact us.",
|
||||
"buyPermissionDeniedTip": "Please contact your enterprise administrator to subscribe",
|
||||
"errors.operationFailed": "We konden dit verzoek niet voltooien. Probeer het later opnieuw. Neem contact op met support als het probleem aanhoudt.",
|
||||
"errors.requestInProgress": "Je vorige verzoek wordt nog verwerkt. Probeer het zo meteen opnieuw.",
|
||||
"errors.unavailable": "Deze dienst is tijdelijk niet beschikbaar. Probeer het later opnieuw.",
|
||||
"plans.community.btnText": "Get Started",
|
||||
"plans.community.description": "For open-source enthusiasts, individual developers, and non-commercial projects",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Rename Conversation",
|
||||
"chat.thinking": "Thinking...",
|
||||
"chat.thought": "Thought",
|
||||
"compliance.documentNotFound": "Dit document is momenteel niet beschikbaar. Probeer het later opnieuw of neem contact op met support.",
|
||||
"compliance.downloadForbidden": "Alleen de eigenaar van de werkruimte kan dit document downloaden, en alleen met een abonnement dat het bevat. Vraag de eigenaar van de werkruimte om het te downloaden.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 Certification",
|
||||
"compliance.professionalUpgradeTooltip": "Only available with a Team plan or above.",
|
||||
"compliance.rateLimit": "Te veel downloads. Probeer het later opnieuw.",
|
||||
"compliance.sandboxUpgradeTooltip": "Only available with a Professional or Team plan.",
|
||||
"compliance.soc2Type1": "SOC 2 Type I Report",
|
||||
"compliance.soc2Type2": "SOC 2 Type II Report",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "We konden je onderwijskorting niet activeren. Je huidige onderwijsverificatie is mogelijk nog actief, of dit e-mailadres komt niet meer in aanmerking.",
|
||||
"applied.activeSubscription.description": "U heeft een actief abonnement. U kunt de onderwijskorting gebruiken nadat uw abonnement is verlopen. Bevestig uw abonnement in <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "U heeft geen betalingsrechten in deze werkruimte. Schakel over naar een werkruimte waar u facturering kunt beheren om de onderwijskorting te gebruiken.",
|
||||
"applied.noPaymentPermission.returnHome": "Terug naar Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "exclusive 100% coupon",
|
||||
"toVerifiedTip.end": "for the Dify Professional Plan.",
|
||||
"toVerifiedTip.front": "You are now eligible for Education Verified status. Please enter your education information below to complete the process and receive an",
|
||||
"useEducationDiscount": "Gebruik onderwijskorting"
|
||||
"tooManyAttempts": "Te veel pogingen. Probeer het later opnieuw.",
|
||||
"useEducationDiscount": "Gebruik onderwijskorting",
|
||||
"verifyFailed": "We konden je onderwijsstatus niet verifiëren. Als je onlangs bent geverifieerd, is je huidige onderwijsverificatie mogelijk nog actief. Probeer het anders later opnieuw."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Osiągnięto limit planu",
|
||||
"apps.fullTip2des": "Zaleca się usunięcie nieaktywnych aplikacji, aby zwolnić miejsce, lub skontaktowanie się z nami.",
|
||||
"buyPermissionDeniedTip": "Skontaktuj się z administratorem swojej firmy, aby zasubskrybować",
|
||||
"errors.operationFailed": "Nie udało się zrealizować tego żądania. Spróbuj ponownie później. Jeśli problem będzie się powtarzał, skontaktuj się z pomocą techniczną.",
|
||||
"errors.requestInProgress": "Twoje poprzednie żądanie jest nadal przetwarzane. Spróbuj ponownie za chwilę.",
|
||||
"errors.unavailable": "Ta usługa jest tymczasowo niedostępna. Spróbuj ponownie później.",
|
||||
"plans.community.btnText": "Rozpocznij pracę z społecznością",
|
||||
"plans.community.description": "Dla użytkowników indywidualnych, małych zespołów lub projektów niekomercyjnych",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Zmień nazwę rozmowy",
|
||||
"chat.thinking": "Myślenie...",
|
||||
"chat.thought": "Myśl",
|
||||
"compliance.documentNotFound": "Ten dokument jest obecnie niedostępny. Spróbuj ponownie później lub skontaktuj się z pomocą techniczną.",
|
||||
"compliance.downloadForbidden": "Tylko właściciel przestrzeni roboczej może pobrać ten dokument i tylko w planie, który go obejmuje. Poproś właściciela przestrzeni roboczej o jego pobranie.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Certyfikacja ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Dostępne tylko w planie zespołowym lub wyższym.",
|
||||
"compliance.rateLimit": "Zbyt wiele pobrań. Spróbuj ponownie później.",
|
||||
"compliance.sandboxUpgradeTooltip": "Dostępne tylko w planie Professional lub Team.",
|
||||
"compliance.soc2Type1": "Raport SOC 2 Typ I",
|
||||
"compliance.soc2Type2": "Raport SOC 2 Typ II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Nie udało się aktywować zniżki edukacyjnej. Twoja obecna weryfikacja edukacyjna może być nadal aktywna albo ten adres e-mail nie spełnia już wymagań.",
|
||||
"applied.activeSubscription.description": "Masz aktywną subskrypcję. Możesz skorzystać z rabatu edukacyjnego po wygaśnięciu subskrypcji. Potwierdź subskrypcję w <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Nie masz uprawnień do płatności w tym obszarze roboczym. Przejdź do obszaru roboczego, w którym możesz zarządzać rozliczeniami, aby skorzystać z rabatu edukacyjnego.",
|
||||
"applied.noPaymentPermission.returnHome": "Powrót do Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "ekskluzywny kupon 100%",
|
||||
"toVerifiedTip.end": "dla Profesjonalnego Planu Dify.",
|
||||
"toVerifiedTip.front": "Teraz jesteś uprawniony do statusu zweryfikowanej edukacji. Proszę wprowadzić swoje informacje edukacyjne poniżej, aby zakończyć proces i otrzymać",
|
||||
"useEducationDiscount": "Użyj rabatu edukacyjnego"
|
||||
"tooManyAttempts": "Zbyt wiele prób. Spróbuj ponownie później.",
|
||||
"useEducationDiscount": "Użyj rabatu edukacyjnego",
|
||||
"verifyFailed": "Nie udało się zweryfikować Twojego statusu edukacyjnego. Jeśli niedawno przeszedłeś weryfikację, Twoja obecna weryfikacja edukacyjna może być nadal aktywna. W przeciwnym razie spróbuj ponownie później."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Limite do plano alcançado",
|
||||
"apps.fullTip2des": "É recomendado limpar aplicações inativas para liberar uso ou entrar em contato conosco.",
|
||||
"buyPermissionDeniedTip": "Por favor, entre em contato com o administrador da sua empresa para assinar",
|
||||
"errors.operationFailed": "Não foi possível concluir esta solicitação. Tente novamente mais tarde. Se o problema persistir, entre em contato com o suporte.",
|
||||
"errors.requestInProgress": "Sua solicitação anterior ainda está sendo processada. Tente novamente em instantes.",
|
||||
"errors.unavailable": "Este serviço está temporariamente indisponível. Tente novamente mais tarde.",
|
||||
"plans.community.btnText": "Comece com a Comunidade",
|
||||
"plans.community.description": "Para Usuários Individuais, Pequenas Equipes ou Projetos Não Comerciais",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Renomear Conversa",
|
||||
"chat.thinking": "Pensante...",
|
||||
"chat.thought": "Pensamento",
|
||||
"compliance.documentNotFound": "Este documento não está disponível no momento. Tente novamente mais tarde ou entre em contato com o suporte.",
|
||||
"compliance.downloadForbidden": "Somente o proprietário do espaço de trabalho pode baixar este documento, e somente em um plano que o inclua. Peça ao proprietário do espaço de trabalho para baixá-lo.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Certificação ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Apenas disponível com um plano Team ou superior.",
|
||||
"compliance.rateLimit": "Muitos downloads. Tente novamente mais tarde.",
|
||||
"compliance.sandboxUpgradeTooltip": "Apenas disponível com um plano Profissional ou de Equipe.",
|
||||
"compliance.soc2Type1": "Relatório SOC 2 Tipo I",
|
||||
"compliance.soc2Type2": "Relatório SOC 2 Tipo II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Não foi possível ativar seu desconto educacional. Sua verificação educacional atual pode ainda estar ativa, ou este e-mail não é mais elegível.",
|
||||
"applied.activeSubscription.description": "Você tem uma assinatura ativa. Você pode usar o desconto educacional após o vencimento da assinatura. Confirme sua assinatura no <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Você não tem permissão de pagamento neste workspace. Por favor, mude para um workspace onde você possa gerenciar o faturamento para usar o desconto educacional.",
|
||||
"applied.noPaymentPermission.returnHome": "Voltar para o Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "cupom exclusivo de 100%",
|
||||
"toVerifiedTip.end": "para o Plano Profissional Dify.",
|
||||
"toVerifiedTip.front": "Você agora está elegível para o status de Educação Verificada. Por favor, insira suas informações educacionais abaixo para concluir o processo e receber um",
|
||||
"useEducationDiscount": "Usar desconto educacional"
|
||||
"tooManyAttempts": "Muitas tentativas. Tente novamente mais tarde.",
|
||||
"useEducationDiscount": "Usar desconto educacional",
|
||||
"verifyFailed": "Não foi possível verificar seu status educacional. Se você se verificou recentemente, sua verificação educacional atual pode ainda estar ativa. Caso contrário, tente novamente mais tarde."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Limita planului a fost atinsă",
|
||||
"apps.fullTip2des": "Se recomandă curățarea aplicațiilor inactive pentru a elibera resurse, sau contactați-ne.",
|
||||
"buyPermissionDeniedTip": "Vă rugăm să contactați administratorul dvs. de întreprindere pentru a vă abona",
|
||||
"errors.operationFailed": "Nu am putut finaliza această solicitare. Încercați din nou mai târziu. Dacă problema persistă, contactați asistența.",
|
||||
"errors.requestInProgress": "Solicitarea anterioară este încă în curs de procesare. Încercați din nou în câteva momente.",
|
||||
"errors.unavailable": "Acest serviciu este temporar indisponibil. Încercați din nou mai târziu.",
|
||||
"plans.community.btnText": "Începe cu Comunitatea",
|
||||
"plans.community.description": "Pentru utilizatori individuali, echipe mici sau proiecte necomerciale",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Redenumește conversația",
|
||||
"chat.thinking": "Gândire...",
|
||||
"chat.thought": "Gând",
|
||||
"compliance.documentNotFound": "Acest document nu este disponibil momentan. Încercați din nou mai târziu sau contactați asistența.",
|
||||
"compliance.downloadForbidden": "Doar proprietarul spațiului de lucru poate descărca acest document și doar cu un plan care îl include. Cereți proprietarului spațiului de lucru să îl descarce.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Certificare ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Disponibilă doar cu un plan de echipă sau superior.",
|
||||
"compliance.rateLimit": "Prea multe descărcări. Încercați din nou mai târziu.",
|
||||
"compliance.sandboxUpgradeTooltip": "Disponibilă doar cu un plan Profesional sau de Echipă.",
|
||||
"compliance.soc2Type1": "Raport SOC 2 Tip I",
|
||||
"compliance.soc2Type2": "Raport SOC 2 Tip II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Nu am putut activa reducerea educațională. Verificarea educațională actuală poate fi încă activă sau acest e-mail nu mai este eligibil.",
|
||||
"applied.activeSubscription.description": "Ai un abonament activ. Poți folosi reducerea educațională după expirarea abonamentului. Confirmați abonamentul în <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Nu ai permisiunea de plată în acest workspace. Te rugăm să treci la un workspace unde poți gestiona facturarea pentru a folosi reducerea educațională.",
|
||||
"applied.noPaymentPermission.returnHome": "Înapoi la Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "cupom exclusiv 100%",
|
||||
"toVerifiedTip.end": "pentru Planul Profesional Dify.",
|
||||
"toVerifiedTip.front": "Sunteți acum eligibil pentru statutul de Educație Verificată. Vă rugăm să introduceți informațiile despre educația dumneavoastră mai jos pentru a finaliza procesul și a primi un",
|
||||
"useEducationDiscount": "Folosește reducerea educațională"
|
||||
"tooManyAttempts": "Prea multe încercări. Încercați din nou mai târziu.",
|
||||
"useEducationDiscount": "Folosește reducerea educațională",
|
||||
"verifyFailed": "Nu am putut verifica statutul dvs. educațional. Dacă v-ați verificat recent, verificarea educațională actuală poate fi încă activă. În caz contrar, încercați din nou mai târziu."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Достигнут лимит плана",
|
||||
"apps.fullTip2des": "Рекомендуется удалить неактивные приложения, чтобы освободить место, или свяжитесь с нами.",
|
||||
"buyPermissionDeniedTip": "Пожалуйста, свяжитесь с администратором вашей организации, чтобы подписаться",
|
||||
"errors.operationFailed": "Не удалось выполнить этот запрос. Повторите попытку позже. Если проблема не исчезнет, обратитесь в службу поддержки.",
|
||||
"errors.requestInProgress": "Ваш предыдущий запрос ещё обрабатывается. Повторите попытку чуть позже.",
|
||||
"errors.unavailable": "Этот сервис временно недоступен. Повторите попытку позже.",
|
||||
"plans.community.btnText": "Начните с сообщества",
|
||||
"plans.community.description": "Для отдельных пользователей, малых команд или некоммерческих проектов",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Переименовать разговор",
|
||||
"chat.thinking": "Мыслящий...",
|
||||
"chat.thought": "Мысль",
|
||||
"compliance.documentNotFound": "Этот документ сейчас недоступен. Повторите попытку позже или обратитесь в службу поддержки.",
|
||||
"compliance.downloadForbidden": "Скачать этот документ может только владелец рабочего пространства и только на тарифе, который его включает. Попросите владельца рабочего пространства скачать его.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Сертификация ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Доступно только с командным планом или выше.",
|
||||
"compliance.rateLimit": "Слишком много загрузок. Повторите попытку позже.",
|
||||
"compliance.sandboxUpgradeTooltip": "Доступно только с профессиональным или командным планом.",
|
||||
"compliance.soc2Type1": "Отчет SOC 2 Тип I",
|
||||
"compliance.soc2Type2": "Отчет SOC 2 Тип II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Не удалось активировать образовательную скидку. Возможно, ваша текущая образовательная проверка ещё действует или этот адрес электронной почты больше не подходит.",
|
||||
"applied.activeSubscription.description": "У вас есть активная подписка. Вы можете использовать образовательную скидку после истечения срока действия подписки. Подтвердите подписку в <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "У вас нет прав на оплату в этом рабочем пространстве. Пожалуйста, переключитесь в рабочее пространство, где вы можете управлять выставлением счетов, чтобы использовать образовательную скидку.",
|
||||
"applied.noPaymentPermission.returnHome": "Вернуться в Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "эксклюзивный 100% купон",
|
||||
"toVerifiedTip.end": "для профессионального плана Dify.",
|
||||
"toVerifiedTip.front": "Теперь вы имеете право на статус \"Проверенное образование\". Пожалуйста, введите свои образовательные данные ниже, чтобы завершить процесс и получить",
|
||||
"useEducationDiscount": "Использовать образовательную скидку"
|
||||
"tooManyAttempts": "Слишком много попыток. Повторите попытку позже.",
|
||||
"useEducationDiscount": "Использовать образовательную скидку",
|
||||
"verifyFailed": "Не удалось подтвердить ваш образовательный статус. Если вы недавно проходили проверку, ваша текущая образовательная проверка может ещё действовать. В противном случае повторите попытку позже."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Dosežena meja načrta",
|
||||
"apps.fullTip2des": "Priporočljivo je, da očistite neaktivne aplikacije, da sprostite prostor, ali nas kontaktirate.",
|
||||
"buyPermissionDeniedTip": "Za naročnino kontaktirajte svojega skrbnika podjetja",
|
||||
"errors.operationFailed": "Te zahteve ni bilo mogoče dokončati. Poskusite znova pozneje. Če težava ne izgine, se obrnite na podporo.",
|
||||
"errors.requestInProgress": "Vaša prejšnja zahteva se še obdeluje. Poskusite znova čez trenutek.",
|
||||
"errors.unavailable": "Ta storitev je začasno nedosegljiva. Poskusite znova pozneje.",
|
||||
"plans.community.btnText": "Začnite s skupnostjo",
|
||||
"plans.community.description": "Za posamezne uporabnike, majhne skupine ali nekomercialne projekte",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Preimenovanje pogovora",
|
||||
"chat.thinking": "Razmišljanje...",
|
||||
"chat.thought": "Misel",
|
||||
"compliance.documentNotFound": "Ta dokument trenutno ni na voljo. Poskusite znova pozneje ali se obrnite na podporo.",
|
||||
"compliance.downloadForbidden": "Ta dokument lahko prenese samo lastnik delovnega prostora in samo s paketom, ki ga vključuje. Prosite lastnika delovnega prostora, da ga prenese.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Certifikacija ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Na voljo je le s Team načrtom ali višjim.",
|
||||
"compliance.rateLimit": "Preveč prenosov. Poskusite znova pozneje.",
|
||||
"compliance.sandboxUpgradeTooltip": "Na voljo je le z načrtom Professional ali Team.",
|
||||
"compliance.soc2Type1": "Poročilo SOC 2 Tip I",
|
||||
"compliance.soc2Type2": "Poročilo SOC 2 Tip II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Izobraževalnega popusta ni bilo mogoče aktivirati. Vaša trenutna izobraževalna verifikacija je morda še aktivna ali ta e-poštni naslov ni več upravičen.",
|
||||
"applied.activeSubscription.description": "Imate aktivno naročnino. Izobraževalni popust lahko uporabite po poteku naročnine. Potrdite naročnino v <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "V tem delovnem prostoru nimate dovoljenja za plačilo. Preklopite na delovni prostor, kjer lahko upravljate obračunavanje, da uporabite izobraževalni popust.",
|
||||
"applied.noPaymentPermission.returnHome": "Nazaj na Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "izključno 100% kupon",
|
||||
"toVerifiedTip.end": "za profesionalni načrt Dify.",
|
||||
"toVerifiedTip.front": "Zdaj ste upravičeni do statusa Preverjeno izobraževanje. Prosimo, vnesite svoje izobraževalne podatke spodaj, da zaključite postopek in prejmete",
|
||||
"useEducationDiscount": "Uporabi izobraževalni popust"
|
||||
"tooManyAttempts": "Preveč poskusov. Poskusite znova pozneje.",
|
||||
"useEducationDiscount": "Uporabi izobraževalni popust",
|
||||
"verifyFailed": "Vašega izobraževalnega statusa ni bilo mogoče preveriti. Če ste se nedavno verificirali, je vaša trenutna izobraževalna verifikacija morda še aktivna. V nasprotnem primeru poskusite znova pozneje."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "ถึงขีดจำกัดของแผนแล้ว",
|
||||
"apps.fullTip2des": "แนะนำให้ทำความสะอาดแอปพลิเคชันที่ไม่ใช้งานเพื่อเพิ่มการใช้งาน หรือติดต่อเรา",
|
||||
"buyPermissionDeniedTip": "โปรดติดต่อผู้ดูแลระบบองค์กรของคุณเพื่อสมัครสมาชิก",
|
||||
"errors.operationFailed": "ไม่สามารถดำเนินการคำขอนี้ให้เสร็จสมบูรณ์ได้ โปรดลองอีกครั้งในภายหลัง หากปัญหายังคงอยู่ โปรดติดต่อฝ่ายสนับสนุน",
|
||||
"errors.requestInProgress": "คำขอก่อนหน้าของคุณยังอยู่ระหว่างดำเนินการ โปรดลองอีกครั้งในอีกสักครู่",
|
||||
"errors.unavailable": "บริการนี้ไม่พร้อมใช้งานชั่วคราว โปรดลองอีกครั้งในภายหลัง",
|
||||
"plans.community.btnText": "เริ่มต้นกับชุมชน",
|
||||
"plans.community.description": "สำหรับผู้ใช้ส่วนบุคคล ทีมขนาดเล็ก หรือโครงการที่ไม่ใช่เชิงพาณิชย์",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "เปลี่ยนชื่อการสนทนา",
|
||||
"chat.thinking": "ความคิด ",
|
||||
"chat.thought": "ความคิด",
|
||||
"compliance.documentNotFound": "เอกสารนี้ไม่พร้อมใช้งานในขณะนี้ โปรดลองอีกครั้งในภายหลังหรือติดต่อฝ่ายสนับสนุน",
|
||||
"compliance.downloadForbidden": "เฉพาะเจ้าของพื้นที่ทำงานเท่านั้นที่ดาวน์โหลดเอกสารนี้ได้ และต้องใช้แผนที่รวมเอกสารนี้ โปรดขอให้เจ้าของพื้นที่ทำงานดาวน์โหลดแทน",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "การรับรอง ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "ใช้ได้เฉพาะแผนทีมหรือสูงกว่าเท่านั้น.",
|
||||
"compliance.rateLimit": "ดาวน์โหลดบ่อยเกินไป โปรดลองอีกครั้งในภายหลัง",
|
||||
"compliance.sandboxUpgradeTooltip": "มีให้บริการเฉพาะกับแผนการใช้งานแบบมืออาชีพหรือทีมเท่านั้น.",
|
||||
"compliance.soc2Type1": "รายงาน SOC 2 ประเภท I",
|
||||
"compliance.soc2Type2": "รายงาน SOC 2 Type II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "ไม่สามารถเปิดใช้ส่วนลดการศึกษาของคุณได้ การยืนยันการศึกษาปัจจุบันของคุณอาจยังมีผลอยู่ หรืออีเมลนี้ไม่มีสิทธิ์แล้ว",
|
||||
"applied.activeSubscription.description": "คุณมีการสมัครสมาชิกที่ยังใช้งานอยู่ คุณสามารถใช้ส่วนลดการศึกษาได้หลังจากการสมัครสมาชิกของคุณหมดอายุ ยืนยันการสมัครสมาชิกของคุณใน <stripeLink>Stripe</stripeLink>",
|
||||
"applied.noPaymentPermission.description": "คุณไม่มีสิทธิ์การชำระเงินในพื้นที่ทำงานนี้ โปรดเปลี่ยนไปยังพื้นที่ทำงานที่คุณสามารถจัดการการเรียกเก็บเงินเพื่อใช้ส่วนลดการศึกษา",
|
||||
"applied.noPaymentPermission.returnHome": "กลับไปที่ Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "คูปองพิเศษ 100%",
|
||||
"toVerifiedTip.end": "สำหรับแผนมืออาชีพของ Dify.",
|
||||
"toVerifiedTip.front": "คุณมีสิทธิ์ได้รับสถานะการตรวจสอบการศึกษาแล้ว กรุณากรอกข้อมูลการศึกษาของคุณด้านล่างเพื่อดำเนินการให้เสร็จสิ้นและรับสิทธิ์",
|
||||
"useEducationDiscount": "ใช้ส่วนลดการศึกษา"
|
||||
"tooManyAttempts": "พยายามบ่อยเกินไป โปรดลองอีกครั้งในภายหลัง",
|
||||
"useEducationDiscount": "ใช้ส่วนลดการศึกษา",
|
||||
"verifyFailed": "ไม่สามารถยืนยันสถานะการศึกษาของคุณได้ หากคุณเพิ่งยืนยันไปเมื่อเร็วๆ นี้ การยืนยันการศึกษาปัจจุบันของคุณอาจยังมีผลอยู่ หากไม่ใช่ โปรดลองอีกครั้งในภายหลัง"
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Plan limiti aşıldı",
|
||||
"apps.fullTip2des": "Kullanımı serbest bırakmak için etkisiz uygulamaların temizlenmesi önerilir veya bizimle iletişime geçin.",
|
||||
"buyPermissionDeniedTip": "Abone olmak için lütfen işletme yöneticinize başvurun",
|
||||
"errors.operationFailed": "Bu istek tamamlanamadı. Lütfen daha sonra tekrar deneyin. Sorun devam ederse destekle iletişime geçin.",
|
||||
"errors.requestInProgress": "Önceki isteğiniz hâlâ işleniyor. Lütfen birazdan tekrar deneyin.",
|
||||
"errors.unavailable": "Bu hizmet geçici olarak kullanılamıyor. Lütfen daha sonra tekrar deneyin.",
|
||||
"plans.community.btnText": "Topluluğa Başlayın",
|
||||
"plans.community.description": "Bireysel Kullanıcılar, Küçük Ekipler veya Ticari Olmayan Projeler İçin",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Konuşmayı Yeniden Adlandır",
|
||||
"chat.thinking": "Düşünüyor...",
|
||||
"chat.thought": "Düşünce",
|
||||
"compliance.documentNotFound": "Bu belge şu anda kullanılamıyor. Lütfen daha sonra tekrar deneyin veya destekle iletişime geçin.",
|
||||
"compliance.downloadForbidden": "Bu belgeyi yalnızca çalışma alanı sahibi ve yalnızca belgeyi içeren bir planda indirebilir. Çalışma alanı sahibinden belgeyi indirmesini isteyin.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 Sertifikası",
|
||||
"compliance.professionalUpgradeTooltip": "Yalnızca Takım planı veya üstü ile mevcuttur.",
|
||||
"compliance.rateLimit": "Çok fazla indirme. Lütfen daha sonra tekrar deneyin.",
|
||||
"compliance.sandboxUpgradeTooltip": "Yalnızca Profesyonel veya Takım planı ile kullanılabilir.",
|
||||
"compliance.soc2Type1": "SOC 2 Tip I Raporu",
|
||||
"compliance.soc2Type2": "SOC 2 Tip II Raporu",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Eğitim indiriminiz etkinleştirilemedi. Mevcut eğitim doğrulamanız hâlâ etkin olabilir veya bu e-posta artık uygun değil.",
|
||||
"applied.activeSubscription.description": "Aktif bir aboneliğiniz var. Aboneliğinizin süresi dolduktan sonra eğitim indirimini kullanabilirsiniz. Aboneliğinizi <stripeLink>Stripe</stripeLink>'da onaylayın.",
|
||||
"applied.noPaymentPermission.description": "Bu çalışma alanında ödeme izniniz yok. Eğitim indirimini kullanmak için lütfen faturalamayı yönetebileceğiniz bir çalışma alanına geçin.",
|
||||
"applied.noPaymentPermission.returnHome": "Dify'e geri dön",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "özel %100 kupon",
|
||||
"toVerifiedTip.end": "Dify Profesyonel Planı için.",
|
||||
"toVerifiedTip.front": "Artık Eğitim Doğrulandı statüsüne uygun oldunuz. Lütfen süreci tamamlamak ve bir almak için eğitim bilgilerinizi aşağıya girin.",
|
||||
"useEducationDiscount": "Eğitim indirimini kullan"
|
||||
"tooManyAttempts": "Çok fazla deneme. Lütfen daha sonra tekrar deneyin.",
|
||||
"useEducationDiscount": "Eğitim indirimini kullan",
|
||||
"verifyFailed": "Eğitim durumunuz doğrulanamadı. Yakın zamanda doğrulama yaptıysanız mevcut eğitim doğrulamanız hâlâ etkin olabilir. Aksi takdirde lütfen daha sonra tekrar deneyin."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Досягнуто ліміту плану",
|
||||
"apps.fullTip2des": "Рекомендується очистити неактивні програми, щоб звільнити місце, або зв'язатися з нами.",
|
||||
"buyPermissionDeniedTip": "Зв'яжіться з адміністратором вашого підприємства, щоб оформити підписку",
|
||||
"errors.operationFailed": "Не вдалося виконати цей запит. Спробуйте пізніше. Якщо проблема не зникне, зверніться до служби підтримки.",
|
||||
"errors.requestInProgress": "Ваш попередній запит ще обробляється. Спробуйте трохи пізніше.",
|
||||
"errors.unavailable": "Цей сервіс тимчасово недоступний. Спробуйте пізніше.",
|
||||
"plans.community.btnText": "Розпочніть з громади",
|
||||
"plans.community.description": "Для індивідуальних користувачів, малих команд або некомерційних проектів",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Перейменувати розмову",
|
||||
"chat.thinking": "Мислення...",
|
||||
"chat.thought": "Думка",
|
||||
"compliance.documentNotFound": "Цей документ зараз недоступний. Спробуйте пізніше або зверніться до служби підтримки.",
|
||||
"compliance.downloadForbidden": "Завантажити цей документ може лише власник робочого простору і лише на тарифному плані, який його включає. Попросіть власника робочого простору завантажити його.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Сертифікація ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Доступно лише з командним планом або вище.",
|
||||
"compliance.rateLimit": "Забагато завантажень. Спробуйте пізніше.",
|
||||
"compliance.sandboxUpgradeTooltip": "Доступно лише з професійним або командним планом.",
|
||||
"compliance.soc2Type1": "Звіт SOC 2 Тип I",
|
||||
"compliance.soc2Type2": "Звіт SOC 2 Тип II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Не вдалося активувати освітню знижку. Можливо, ваша поточна перевірка освіти ще діє або ця електронна адреса більше не відповідає вимогам.",
|
||||
"applied.activeSubscription.description": "У вас є активна підписка. Ви можете скористатися освітньою знижкою після закінчення терміну дії підписки. Підтвердіть підписку в <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "У вас немає прав на оплату в цьому робочому просторі. Будь ласка, перейдіть до робочого простору, де ви можете керувати платіжними даними, щоб скористатися освітньою знижкою.",
|
||||
"applied.noPaymentPermission.returnHome": "Повернутися до Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "ексклюзивний купон 100%",
|
||||
"toVerifiedTip.end": "для професійного плану Dify.",
|
||||
"toVerifiedTip.front": "Ви тепер маєте право на статус перевіреної освіти. Будь ласка, введіть свою інформацію про освіту нижче, щоб завершити процес і отримати",
|
||||
"useEducationDiscount": "Використати освітню знижку"
|
||||
"tooManyAttempts": "Забагато спроб. Спробуйте пізніше.",
|
||||
"useEducationDiscount": "Використати освітню знижку",
|
||||
"verifyFailed": "Не вдалося підтвердити ваш освітній статус. Якщо ви нещодавно проходили перевірку, ваша поточна перевірка освіти може ще діяти. Інакше спробуйте пізніше."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "Đã đạt giới hạn kế hoạch",
|
||||
"apps.fullTip2des": "Chúng tôi khuyên bạn nên xóa các ứng dụng không hoạt động để giải phóng dung lượng, hoặc liên hệ với chúng tôi.",
|
||||
"buyPermissionDeniedTip": "Vui lòng liên hệ với quản trị viên doanh nghiệp của bạn để đăng ký",
|
||||
"errors.operationFailed": "Không thể hoàn tất yêu cầu này. Vui lòng thử lại sau. Nếu sự cố vẫn tiếp diễn, hãy liên hệ bộ phận hỗ trợ.",
|
||||
"errors.requestInProgress": "Yêu cầu trước đó của bạn vẫn đang được xử lý. Vui lòng thử lại sau giây lát.",
|
||||
"errors.unavailable": "Dịch vụ này tạm thời không khả dụng. Vui lòng thử lại sau.",
|
||||
"plans.community.btnText": "Bắt đầu với Cộng đồng",
|
||||
"plans.community.description": "Dành cho người dùng cá nhân, nhóm nhỏ hoặc các dự án phi thương mại",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "Đổi tên Cuộc trò chuyện",
|
||||
"chat.thinking": "Suy nghĩ...",
|
||||
"chat.thought": "Tư duy",
|
||||
"compliance.documentNotFound": "Tài liệu này hiện không khả dụng. Vui lòng thử lại sau hoặc liên hệ bộ phận hỗ trợ.",
|
||||
"compliance.downloadForbidden": "Chỉ chủ sở hữu không gian làm việc mới có thể tải xuống tài liệu này, và chỉ với gói có bao gồm tài liệu đó. Hãy nhờ chủ sở hữu không gian làm việc tải xuống.",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "Chứng nhận ISO 27001:2022",
|
||||
"compliance.professionalUpgradeTooltip": "Chỉ có sẵn với gói Team hoặc cao hơn.",
|
||||
"compliance.rateLimit": "Tải xuống quá nhiều lần. Vui lòng thử lại sau.",
|
||||
"compliance.sandboxUpgradeTooltip": "Chỉ có sẵn với gói Chuyên nghiệp hoặc Nhóm.",
|
||||
"compliance.soc2Type1": "Báo cáo loại SOC 2 Type I",
|
||||
"compliance.soc2Type2": "Báo cáo SOC 2 Type II",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "Không thể kích hoạt ưu đãi giáo dục của bạn. Xác minh giáo dục hiện tại của bạn có thể vẫn còn hiệu lực, hoặc email này không còn đủ điều kiện.",
|
||||
"applied.activeSubscription.description": "Bạn có một gói đăng ký đang hoạt động. Bạn có thể sử dụng giảm giá giáo dục sau khi gói đăng ký hết hạn. Xác nhận gói đăng ký của bạn trên <stripeLink>Stripe</stripeLink>.",
|
||||
"applied.noPaymentPermission.description": "Bạn không có quyền thanh toán trong workspace này. Vui lòng chuyển sang workspace mà bạn có thể quản lý thanh toán để sử dụng giảm giá giáo dục.",
|
||||
"applied.noPaymentPermission.returnHome": "Quay lại Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "mã giảm giá độc quyền 100%",
|
||||
"toVerifiedTip.end": "cho Kế hoạch Chuyên nghiệp Dify.",
|
||||
"toVerifiedTip.front": "Bạn hiện đủ điều kiện để có trạng thái Xác minh Giáo dục. Vui lòng nhập thông tin giáo dục của bạn bên dưới để hoàn tất quá trình và nhận một",
|
||||
"useEducationDiscount": "Sử dụng giảm giá giáo dục"
|
||||
"tooManyAttempts": "Thử quá nhiều lần. Vui lòng thử lại sau.",
|
||||
"useEducationDiscount": "Sử dụng giảm giá giáo dục",
|
||||
"verifyFailed": "Không thể xác minh tình trạng giáo dục của bạn. Nếu bạn vừa xác minh gần đây, xác minh giáo dục hiện tại của bạn có thể vẫn còn hiệu lực. Nếu không, vui lòng thử lại sau."
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "计划限制已达到",
|
||||
"apps.fullTip2des": "推荐您清理不活跃的应用或者联系我们",
|
||||
"buyPermissionDeniedTip": "请联系企业管理员订阅",
|
||||
"errors.operationFailed": "无法完成此请求,请稍后重试。如果问题持续存在,请联系支持团队。",
|
||||
"errors.requestInProgress": "上一个请求仍在处理中,请稍后再试。",
|
||||
"errors.unavailable": "服务暂时不可用,请稍后再试。",
|
||||
"plans.community.btnText": "开始使用",
|
||||
"plans.community.description": "适用于开源爱好者、个人开发者以及非商业项目",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "重命名会话",
|
||||
"chat.thinking": "深度思考中...",
|
||||
"chat.thought": "已深度思考",
|
||||
"compliance.documentNotFound": "该文档暂不可用,请稍后再试或联系支持团队。",
|
||||
"compliance.downloadForbidden": "只有工作空间所有者可以下载此文档,且当前套餐需包含该文档。请联系工作空间所有者下载。",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 Certification",
|
||||
"compliance.professionalUpgradeTooltip": "仅适用于 Team 版计划或以上。",
|
||||
"compliance.rateLimit": "下载次数过多,请稍后再试。",
|
||||
"compliance.sandboxUpgradeTooltip": "仅适用于 Professional 或 Team 版计划。",
|
||||
"compliance.soc2Type1": "SOC 2 Type I Report",
|
||||
"compliance.soc2Type2": "SOC 2 Type II Report",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "无法激活教育优惠。您当前的教育认证可能仍在有效期内,或者此邮箱已不符合认证条件。",
|
||||
"applied.activeSubscription.description": "你当前有生效中的订阅。订阅到期后即可使用教育优惠。请前往 <stripeLink>Stripe</stripeLink> 确认你的订阅。",
|
||||
"applied.noPaymentPermission.description": "你没有此工作空间的付款权限。请切换到你可以管理账单的工作空间,以使用教育优惠。",
|
||||
"applied.noPaymentPermission.returnHome": "返回 Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "100% 独家优惠券",
|
||||
"toVerifiedTip.end": "。",
|
||||
"toVerifiedTip.front": "您现在符合教育版认证的资格。请在下方输入您的教育信息,以完成认证流程,并领取 Dify Professional 版的",
|
||||
"useEducationDiscount": "使用教育优惠"
|
||||
"tooManyAttempts": "尝试次数过多,请稍后再试。",
|
||||
"useEducationDiscount": "使用教育优惠",
|
||||
"verifyFailed": "无法验证您的教育身份。如果您最近完成过认证,当前的教育认证可能仍在有效期内;否则请稍后重试。"
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"apps.fullTip2": "計劃限制已達",
|
||||
"apps.fullTip2des": "建議清除不活躍的應用程式以釋放使用空間,或聯繫我們。",
|
||||
"buyPermissionDeniedTip": "請聯絡企業管理員訂閱",
|
||||
"errors.operationFailed": "無法完成此請求,請稍後重試。如果問題持續發生,請聯絡支援團隊。",
|
||||
"errors.requestInProgress": "上一個請求仍在處理中,請稍後再試。",
|
||||
"errors.unavailable": "服務暫時無法使用,請稍後再試。",
|
||||
"plans.community.btnText": "開始使用社區",
|
||||
"plans.community.description": "適用於個別用戶、小型團隊或非商業項目",
|
||||
"plans.community.features": [
|
||||
|
||||
@@ -60,9 +60,12 @@
|
||||
"chat.renameConversation": "重新命名會話",
|
||||
"chat.thinking": "思維。。。",
|
||||
"chat.thought": "思想",
|
||||
"compliance.documentNotFound": "該文件暫時無法使用,請稍後再試或聯絡支援團隊。",
|
||||
"compliance.downloadForbidden": "只有工作空間擁有者可以下載此文件,且目前方案需包含該文件。請聯絡工作空間擁有者下載。",
|
||||
"compliance.gdpr": "GDPR DPA",
|
||||
"compliance.iso27001": "ISO 27001:2022 認證",
|
||||
"compliance.professionalUpgradeTooltip": "僅可用於團隊計劃或更高版本。",
|
||||
"compliance.rateLimit": "下載次數過多,請稍後再試。",
|
||||
"compliance.sandboxUpgradeTooltip": "僅可用於專業或團隊計劃。",
|
||||
"compliance.soc2Type1": "SOC 2 類型 I 報告",
|
||||
"compliance.soc2Type2": "SOC 2 類型 II 報告",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"activateFailed": "無法啟用教育優惠。您目前的教育驗證可能仍在有效期內,或此電子郵件已不符合驗證資格。",
|
||||
"applied.activeSubscription.description": "你目前有生效中的訂閱。訂閱到期後即可使用教育優惠。請前往 <stripeLink>Stripe</stripeLink> 確認你的訂閱。",
|
||||
"applied.noPaymentPermission.description": "你沒有此工作空間的付款權限。請切換到你可以管理帳單的工作空間,以使用教育優惠。",
|
||||
"applied.noPaymentPermission.returnHome": "返回 Dify",
|
||||
@@ -51,5 +52,7 @@
|
||||
"toVerifiedTip.coupon": "獨家 100% 優惠券",
|
||||
"toVerifiedTip.end": "用於 Dify 專業計劃。",
|
||||
"toVerifiedTip.front": "您現在符合教育驗證狀態的資格。請在下面輸入您的教育資訊以完成此流程並獲得一個",
|
||||
"useEducationDiscount": "使用教育優惠"
|
||||
"tooManyAttempts": "嘗試次數過多,請稍後再試。",
|
||||
"useEducationDiscount": "使用教育優惠",
|
||||
"verifyFailed": "無法驗證您的教育身分。如果您最近完成過驗證,目前的教育驗證可能仍在有效期內;否則請稍後重試。"
|
||||
}
|
||||
Vendored
+9
@@ -1504,6 +1504,9 @@ export default interface Resources {
|
||||
'apps.fullTip2': 'Plan limit reached'
|
||||
'apps.fullTip2des': 'It is recommended to clean up inactive applications to free up usage, or contact us.'
|
||||
buyPermissionDeniedTip: 'Please contact your enterprise administrator to subscribe'
|
||||
'errors.operationFailed': "We couldn't complete this request. Please try again later. If the problem persists, contact support."
|
||||
'errors.requestInProgress': 'Your previous request is still being processed. Please try again in a moment.'
|
||||
'errors.unavailable': 'This service is temporarily unavailable. Please try again later.'
|
||||
'plans.community.btnText': 'Get Started'
|
||||
'plans.community.description': 'For open-source enthusiasts, individual developers, and non-commercial projects'
|
||||
'plans.community.features': [
|
||||
@@ -1710,9 +1713,12 @@ export default interface Resources {
|
||||
'chat.renameConversation': 'Rename Conversation'
|
||||
'chat.thinking': 'Thinking...'
|
||||
'chat.thought': 'Thought'
|
||||
'compliance.documentNotFound': 'This document is not available right now. Please try again later or contact support.'
|
||||
'compliance.downloadForbidden': 'Only the workspace owner can download this document, and only on a plan that includes it. Ask your workspace owner to download it.'
|
||||
'compliance.gdpr': 'GDPR DPA'
|
||||
'compliance.iso27001': 'ISO 27001:2022 Certification'
|
||||
'compliance.professionalUpgradeTooltip': 'Only available with a Team plan or above.'
|
||||
'compliance.rateLimit': 'Too many downloads. Please try again later.'
|
||||
'compliance.sandboxUpgradeTooltip': 'Only available with a Professional or Team plan.'
|
||||
'compliance.soc2Type1': 'SOC 2 Type I Report'
|
||||
'compliance.soc2Type2': 'SOC 2 Type II Report'
|
||||
@@ -3318,6 +3324,7 @@ export default interface Resources {
|
||||
tryAgain: '← Try again'
|
||||
}
|
||||
education: {
|
||||
activateFailed: "We couldn't activate your education discount. Your current Education Verified status may still be active, or this email is no longer eligible."
|
||||
'applied.activeSubscription.description': 'You have an active subscription. You can use the education discount after your subscription expires. Confirm your subscription in <stripeLink>Stripe</stripeLink>.'
|
||||
'applied.noPaymentPermission.description': "You don't have payment permission in this workspace. Please switch to a workspace where you can manage billing to use the education discount."
|
||||
'applied.noPaymentPermission.returnHome': 'Back to Dify'
|
||||
@@ -3370,7 +3377,9 @@ export default interface Resources {
|
||||
'toVerifiedTip.coupon': 'exclusive 100% coupon'
|
||||
'toVerifiedTip.end': 'for the Dify Professional Plan.'
|
||||
'toVerifiedTip.front': 'You are now eligible for Education Verified status. Please enter your education information below to complete the process and receive an'
|
||||
tooManyAttempts: 'Too many attempts. Please try again later.'
|
||||
useEducationDiscount: 'Use education discount'
|
||||
verifyFailed: "We couldn't verify your education status. If you verified recently, your current Education Verified status may still be active. Otherwise, please try again later."
|
||||
}
|
||||
explore: {
|
||||
'appCard.try': 'Details'
|
||||
|
||||
Reference in new issue
Block a user