fix: merge conflicts

This commit is contained in:
Ephraim Atta-Duncan
2024-09-21 09:07:16 +00:00
449 changed files with 28724 additions and 4841 deletions

View File

@ -0,0 +1,60 @@
import { useCallback, useRef, useState } from 'react';
type ThrottleOptions = {
leading?: boolean;
trailing?: boolean;
};
export function useThrottleFn<T extends (...args: unknown[]) => unknown>(
fn: T,
ms = 500,
options: ThrottleOptions = {},
): [(...args: Parameters<T>) => void, boolean, () => void] {
const [isThrottling, setIsThrottling] = useState(false);
const $isThrottling = useRef(false);
const $timeout = useRef<NodeJS.Timeout | null>(null);
const $lastArgs = useRef<Parameters<T> | null>(null);
const { leading = true, trailing = true } = options;
const $setIsThrottling = useCallback((value: boolean) => {
$isThrottling.current = value;
setIsThrottling(value);
}, []);
const throttledFn = useCallback(
(...args: Parameters<T>) => {
if (!$isThrottling.current) {
$setIsThrottling(true);
if (leading) {
fn(...args);
} else {
$lastArgs.current = args;
}
$timeout.current = setTimeout(() => {
if (trailing && $lastArgs.current) {
fn(...$lastArgs.current);
$lastArgs.current = null;
}
$setIsThrottling(false);
}, ms);
} else {
$lastArgs.current = args;
}
},
[fn, ms, leading, trailing, $setIsThrottling],
);
const cancel = useCallback(() => {
if ($timeout.current) {
clearTimeout($timeout.current);
$timeout.current = null;
$setIsThrottling(false);
$lastArgs.current = null;
}
}, [$setIsThrottling]);
return [throttledFn, isThrottling, cancel];
}

View File

@ -5,19 +5,24 @@ import { useState } from 'react';
import { type Messages, setupI18n } from '@lingui/core';
import { I18nProvider } from '@lingui/react';
import type { I18nLocaleData } from '../../constants/i18n';
export function I18nClientProvider({
children,
initialLocale,
initialLocaleData,
initialMessages,
}: {
children: React.ReactNode;
initialLocale: string;
initialLocaleData: I18nLocaleData;
initialMessages: Messages;
}) {
const { lang, locales } = initialLocaleData;
const [i18n] = useState(() => {
return setupI18n({
locale: initialLocale,
messages: { [initialLocale]: initialMessages },
locale: lang,
locales: locales,
messages: { [lang]: initialMessages },
});
});

View File

@ -1,6 +1,6 @@
import 'server-only';
import { cookies } from 'next/headers';
import { cookies, headers } from 'next/headers';
import type { I18n, Messages } from '@lingui/core';
import { setupI18n } from '@lingui/core';
@ -8,19 +8,19 @@ import { setI18n } from '@lingui/react/server';
import { IS_APP_WEB } from '../../constants/app';
import { SUPPORTED_LANGUAGE_CODES } from '../../constants/i18n';
import { extractSupportedLanguage } from '../../utils/i18n';
import { extractLocaleData } from '../../utils/i18n';
type SupportedLocales = (typeof SUPPORTED_LANGUAGE_CODES)[number];
type SupportedLanguages = (typeof SUPPORTED_LANGUAGE_CODES)[number];
async function loadCatalog(locale: SupportedLocales): Promise<{
async function loadCatalog(lang: SupportedLanguages): Promise<{
[k: string]: Messages;
}> {
const { messages } = await import(
`../../translations/${locale}/${IS_APP_WEB ? 'web' : 'marketing'}.js`
`../../translations/${lang}/${IS_APP_WEB ? 'web' : 'marketing'}.js`
);
return {
[locale]: messages,
[lang]: messages,
};
}
@ -31,18 +31,18 @@ export const allMessages = catalogs.reduce((acc, oneCatalog) => {
return { ...acc, ...oneCatalog };
}, {});
type AllI18nInstances = { [K in SupportedLocales]: I18n };
type AllI18nInstances = { [K in SupportedLanguages]: I18n };
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
export const allI18nInstances = SUPPORTED_LANGUAGE_CODES.reduce((acc, locale) => {
const messages = allMessages[locale] ?? {};
export const allI18nInstances = SUPPORTED_LANGUAGE_CODES.reduce((acc, lang) => {
const messages = allMessages[lang] ?? {};
const i18n = setupI18n({
locale,
messages: { [locale]: messages },
locale: lang,
messages: { [lang]: messages },
});
return { ...acc, [locale]: i18n };
return { ...acc, [lang]: i18n };
}, {}) as AllI18nInstances;
/**
@ -50,19 +50,23 @@ export const allI18nInstances = SUPPORTED_LANGUAGE_CODES.reduce((acc, locale) =>
*
* https://lingui.dev/tutorials/react-rsc#pages-layouts-and-lingui
*/
export const setupI18nSSR = (overrideLang?: SupportedLocales) => {
const lang =
overrideLang ||
extractSupportedLanguage({
cookies: cookies(),
});
export const setupI18nSSR = () => {
const { lang, locales } = extractLocaleData({
cookies: cookies(),
headers: headers(),
});
// Get and set a ready-made i18n instance for the given language.
const i18n = allI18nInstances[lang];
// Reactivate the i18n instance with the locale for date and number formatting.
i18n.activate(lang, locales);
setI18n(i18n);
return {
lang,
locales,
i18n,
};
};

View File

@ -1,37 +0,0 @@
'use client';
import { createContext, useContext } from 'react';
export type LocaleContextValue = {
locale: string;
};
export const LocaleContext = createContext<LocaleContextValue | null>(null);
export const useLocale = () => {
const context = useContext(LocaleContext);
if (!context) {
throw new Error('useLocale must be used within a LocaleProvider');
}
return context;
};
export function LocaleProvider({
children,
locale,
}: {
children: React.ReactNode;
locale: string;
}) {
return (
<LocaleContext.Provider
value={{
locale: locale,
}}
>
{children}
</LocaleContext.Provider>
);
}

View File

@ -5,10 +5,13 @@ export const APP_DOCUMENT_UPLOAD_SIZE_LIMIT =
export const NEXT_PUBLIC_WEBAPP_URL = () => env('NEXT_PUBLIC_WEBAPP_URL');
export const NEXT_PUBLIC_MARKETING_URL = () => env('NEXT_PUBLIC_MARKETING_URL');
export const NEXT_PRIVATE_INTERNAL_WEBAPP_URL =
process.env.NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? NEXT_PUBLIC_WEBAPP_URL();
export const IS_APP_MARKETING = process.env.NEXT_PUBLIC_PROJECT === 'marketing';
export const IS_APP_WEB = process.env.NEXT_PUBLIC_PROJECT === 'web';
export const IS_BILLING_ENABLED = () => env('NEXT_PUBLIC_FEATURE_BILLING_ENABLED') === 'true';
export const IS_APP_WEB_I18N_ENABLED = true;
export const APP_FOLDER = () => (IS_APP_MARKETING ? 'marketing' : 'web');

View File

@ -0,0 +1,3 @@
// Put into a separate file due to Playwright not compiling due to the macro in the templates.ts file.
export const DIRECT_TEMPLATE_RECIPIENT_EMAIL = 'direct.link@documenso.com';
export const DIRECT_TEMPLATE_RECIPIENT_NAME = 'Direct link recipient';

View File

@ -0,0 +1,23 @@
import { DocumentVisibility } from '@documenso/lib/types/document-visibility';
import type { TDocumentVisibility } from '../types/document-visibility';
type DocumentVisibilityTypeData = {
key: TDocumentVisibility;
value: string;
};
export const DOCUMENT_VISIBILITY: Record<string, DocumentVisibilityTypeData> = {
[DocumentVisibility.ADMIN]: {
key: DocumentVisibility.ADMIN,
value: 'Admins only',
},
[DocumentVisibility.EVERYONE]: {
key: DocumentVisibility.EVERYONE,
value: 'Everyone',
},
[DocumentVisibility.MANAGER_AND_ABOVE]: {
key: DocumentVisibility.MANAGER_AND_ABOVE,
value: 'Managers and above',
},
} satisfies Record<TDocumentVisibility, DocumentVisibilityTypeData>;

View File

@ -1,14 +1,27 @@
import { z } from 'zod';
export const SUPPORTED_LANGUAGE_CODES = ['de', 'en'] as const;
export const SUPPORTED_LANGUAGE_CODES = ['de', 'en', 'fr'] as const;
export const ZSupportedLanguageCodeSchema = z.enum(SUPPORTED_LANGUAGE_CODES).catch('en');
export type SupportedLanguageCodes = (typeof SUPPORTED_LANGUAGE_CODES)[number];
export type I18nLocaleData = {
/**
* The supported language extracted from the locale.
*/
lang: SupportedLanguageCodes;
/**
* The preferred locales.
*/
locales: string[];
};
export const APP_I18N_OPTIONS = {
supportedLangs: SUPPORTED_LANGUAGE_CODES,
sourceLang: 'en',
defaultLocale: 'en-US',
} as const;
type SupportedLanguage = {
@ -25,4 +38,8 @@ export const SUPPORTED_LANGUAGES: Record<string, SupportedLanguage> = {
full: 'English',
short: 'en',
},
fr: {
full: 'French',
short: 'fr',
},
} satisfies Record<SupportedLanguageCodes, SupportedLanguage>;

View File

@ -1,29 +1,64 @@
import type { MessageDescriptor } from '@lingui/core';
import { msg } from '@lingui/macro';
import { RecipientRole } from '@documenso/prisma/client';
export const RECIPIENT_ROLES_DESCRIPTION = {
[RecipientRole.APPROVER]: {
actionVerb: 'Approve',
actioned: 'Approved',
progressiveVerb: 'Approving',
roleName: 'Approver',
actionVerb: msg`Approve`,
actioned: msg`Approved`,
progressiveVerb: msg`Approving`,
roleName: msg`Approver`,
},
[RecipientRole.CC]: {
actionVerb: 'CC',
actioned: `CC'd`,
progressiveVerb: 'CC',
roleName: 'Cc',
actionVerb: msg`CC`,
actioned: msg`CC'd`,
progressiveVerb: msg`CC`,
roleName: msg`Cc`,
},
[RecipientRole.SIGNER]: {
actionVerb: 'Sign',
actioned: 'Signed',
progressiveVerb: 'Signing',
roleName: 'Signer',
actionVerb: msg`Sign`,
actioned: msg`Signed`,
progressiveVerb: msg`Signing`,
roleName: msg`Signer`,
},
[RecipientRole.VIEWER]: {
actionVerb: 'View',
actioned: 'Viewed',
progressiveVerb: 'Viewing',
roleName: 'Viewer',
actionVerb: msg`View`,
actioned: msg`Viewed`,
progressiveVerb: msg`Viewing`,
roleName: msg`Viewer`,
},
} satisfies Record<keyof typeof RecipientRole, unknown>;
/**
* Raw english descriptions for emails.
*
* Todo: Handle i18n for emails.
*/
export const RECIPIENT_ROLES_DESCRIPTION_ENG = {
[RecipientRole.APPROVER]: {
actionVerb: `Approve`,
actioned: `Approved`,
progressiveVerb: `Approving`,
roleName: `Approver`,
},
[RecipientRole.CC]: {
actionVerb: `CC`,
actioned: `CC'd`,
progressiveVerb: `CC`,
roleName: `Cc`,
},
[RecipientRole.SIGNER]: {
actionVerb: `Sign`,
actioned: `Signed`,
progressiveVerb: `Signing`,
roleName: `Signer`,
},
[RecipientRole.VIEWER]: {
actionVerb: `View`,
actioned: `Viewed`,
progressiveVerb: `Viewing`,
roleName: `Viewer`,
},
} satisfies Record<keyof typeof RecipientRole, unknown>;
@ -34,8 +69,18 @@ export const RECIPIENT_ROLE_TO_EMAIL_TYPE = {
} as const;
export const RECIPIENT_ROLE_SIGNING_REASONS = {
[RecipientRole.SIGNER]: 'I am a signer of this document',
[RecipientRole.APPROVER]: 'I am an approver of this document',
[RecipientRole.CC]: 'I am required to recieve a copy of this document',
[RecipientRole.VIEWER]: 'I am a viewer of this document',
[RecipientRole.SIGNER]: msg`I am a signer of this document`,
[RecipientRole.APPROVER]: msg`I am an approver of this document`,
[RecipientRole.CC]: msg`I am required to receive a copy of this document`,
[RecipientRole.VIEWER]: msg`I am a viewer of this document`,
} satisfies Record<keyof typeof RecipientRole, MessageDescriptor>;
/**
* Raw english descriptions for certificates.
*/
export const RECIPIENT_ROLE_SIGNING_REASONS_ENG = {
[RecipientRole.SIGNER]: `I am a signer of this document`,
[RecipientRole.APPROVER]: `I am an approver of this document`,
[RecipientRole.CC]: `I am required to receive a copy of this document`,
[RecipientRole.VIEWER]: `I am a viewer of this document`,
} satisfies Record<keyof typeof RecipientRole, string>;

View File

@ -1,12 +1,15 @@
import type { MessageDescriptor } from '@lingui/core';
import { msg } from '@lingui/macro';
import { TeamMemberRole } from '@documenso/prisma/client';
export const TEAM_URL_ROOT_REGEX = new RegExp('^/t/[^/]+$');
export const TEAM_URL_REGEX = new RegExp('^/t/[^/]+');
export const TEAM_MEMBER_ROLE_MAP: Record<keyof typeof TeamMemberRole, string> = {
ADMIN: 'Admin',
MANAGER: 'Manager',
MEMBER: 'Member',
export const TEAM_MEMBER_ROLE_MAP: Record<keyof typeof TeamMemberRole, MessageDescriptor> = {
ADMIN: msg`Admin`,
MANAGER: msg`Manager`,
MEMBER: msg`Member`,
};
export const TEAM_MEMBER_ROLE_PERMISSIONS_MAP = {

View File

@ -1,28 +1,23 @@
import { msg } from '@lingui/macro';
export const TEMPLATE_RECIPIENT_EMAIL_PLACEHOLDER_REGEX = /recipient\.\d+@documenso\.com/i;
export const TEMPLATE_RECIPIENT_NAME_PLACEHOLDER_REGEX = /Recipient \d+/i;
export const DIRECT_TEMPLATE_DOCUMENTATION = [
{
title: 'Enable Direct Link Signing',
description:
'Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted.',
title: msg`Enable Direct Link Signing`,
description: msg`Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted.`,
},
{
title: 'Configure Direct Recipient',
description:
'Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient.',
title: msg`Configure Direct Recipient`,
description: msg`Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient.`,
},
{
title: 'Share the Link',
description:
'Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them.',
title: msg`Share the Link`,
description: msg`Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them.`,
},
{
title: 'Document Creation',
description:
'After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email.',
title: msg`Document Creation`,
description: msg`After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email.`,
},
];
export const DIRECT_TEMPLATE_RECIPIENT_EMAIL = 'direct.link@documenso.com';
export const DIRECT_TEMPLATE_RECIPIENT_NAME = 'Direct link recipient';

View File

@ -1,13 +0,0 @@
import { Toast } from '@documenso/ui/primitives/use-toast';
export const TOAST_DOCUMENT_SHARE_SUCCESS: Toast = {
title: 'Copied to clipboard',
description: 'The sharing link has been copied to your clipboard.',
} as const;
export const TOAST_DOCUMENT_SHARE_ERROR: Toast = {
variant: 'destructive',
title: 'Something went wrong',
description: 'The sharing link could not be created at this time. Please try again.',
duration: 5000,
};

View File

@ -6,7 +6,7 @@ import { json } from 'micro';
import { prisma } from '@documenso/prisma';
import { BackgroundJobStatus, Prisma } from '@documenso/prisma/client';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
import { NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app';
import { sign } from '../../server-only/crypto/sign';
import { verify } from '../../server-only/crypto/verify';
import {
@ -229,7 +229,7 @@ export class LocalJobProvider extends BaseJobProvider {
}) {
const { jobId, jobDefinitionId, data, isRetry } = options;
const endpoint = `${NEXT_PUBLIC_WEBAPP_URL()}/api/jobs/${jobDefinitionId}/${jobId}`;
const endpoint = `${NEXT_PRIVATE_INTERNAL_WEBAPP_URL}/api/jobs/${jobDefinitionId}/${jobId}`;
const signature = sign(data);
const headers: Record<string, string> = {

View File

@ -16,7 +16,7 @@ import {
import { NEXT_PUBLIC_WEBAPP_URL } from '../../../constants/app';
import { FROM_ADDRESS, FROM_NAME } from '../../../constants/email';
import {
RECIPIENT_ROLES_DESCRIPTION,
RECIPIENT_ROLES_DESCRIPTION_ENG,
RECIPIENT_ROLE_TO_EMAIL_TYPE,
} from '../../../constants/recipient-roles';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs';
@ -87,8 +87,8 @@ export const SEND_SIGNING_EMAIL_JOB_DEFINITION = {
const { email, name } = recipient;
const selfSigner = email === user.email;
const { actionVerb } = RECIPIENT_ROLES_DESCRIPTION[recipient.role];
const recipientActionVerb = actionVerb.toLowerCase();
const recipientActionVerb =
RECIPIENT_ROLES_DESCRIPTION_ENG[recipient.role].actionVerb.toLowerCase();
let emailMessage = customEmail?.message || '';
let emailSubject = `Please ${recipientActionVerb} this document`;

View File

@ -17,6 +17,7 @@ import { AppError, AppErrorCode } from '../errors/app-error';
import { jobsClient } from '../jobs/client';
import { isTwoFactorAuthenticationEnabled } from '../server-only/2fa/is-2fa-availble';
import { validateTwoFactorAuthentication } from '../server-only/2fa/validate-2fa';
import { decryptSecondaryData } from '../server-only/crypto/decrypt';
import { getMostRecentVerificationTokenByUserId } from '../server-only/user/get-most-recent-verification-token-by-user-id';
import { getUserByEmail } from '../server-only/user/get-user-by-email';
import type { TAuthenticationResponseJSONSchema } from '../types/webauthn';
@ -267,6 +268,55 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = {
},
});
return {
id: Number(user.id),
email: user.email,
name: user.name,
emailVerified: user.emailVerified?.toISOString() ?? null,
} satisfies User;
},
}),
CredentialsProvider({
id: 'manual',
name: 'Manual',
credentials: {
credential: { label: 'Credential', type: 'credential' },
},
async authorize(credentials, req) {
const credential = credentials?.credential;
if (typeof credential !== 'string' || credential.length === 0) {
throw new AppError(AppErrorCode.INVALID_REQUEST);
}
const decryptedCredential = decryptSecondaryData(credential);
if (!decryptedCredential) {
throw new AppError(AppErrorCode.INVALID_REQUEST);
}
const parsedCredential = JSON.parse(decryptedCredential);
if (typeof parsedCredential !== 'object' || parsedCredential === null) {
throw new AppError(AppErrorCode.INVALID_REQUEST);
}
const { userId, email } = parsedCredential;
if (typeof userId !== 'number' || typeof email !== 'string') {
throw new AppError(AppErrorCode.INVALID_REQUEST);
}
const user = await prisma.user.findFirst({
where: {
id: userId,
},
});
if (!user) {
throw new AppError(AppErrorCode.INVALID_REQUEST);
}
return {
id: Number(user.id),
email: user.email,

View File

@ -41,14 +41,14 @@
"luxon": "^3.4.0",
"micro": "^10.0.1",
"nanoid": "^4.0.2",
"next": "14.0.3",
"next": "14.2.6",
"next-auth": "4.24.5",
"oslo": "^0.17.0",
"pdf-lib": "^1.17.1",
"pg": "^8.11.3",
"playwright": "1.43.0",
"react": "18.2.0",
"remeda": "^1.27.1",
"react": "^18",
"remeda": "^2.12.1",
"sharp": "0.32.6",
"stripe": "^12.7.0",
"ts-pattern": "^5.0.5",

View File

@ -2,25 +2,33 @@ import { prisma } from '@documenso/prisma';
import type { User } from '@documenso/prisma/client';
import { UserSecurityAuditLogType } from '@documenso/prisma/client';
import { AppError } from '../../errors/app-error';
import { AppError, AppErrorCode } from '../../errors/app-error';
import type { RequestMetadata } from '../../universal/extract-request-metadata';
import { validateTwoFactorAuthentication } from './validate-2fa';
type DisableTwoFactorAuthenticationOptions = {
user: User;
token: string;
totpCode?: string;
backupCode?: string;
requestMetadata?: RequestMetadata;
};
export const disableTwoFactorAuthentication = async ({
token,
totpCode,
backupCode,
user,
requestMetadata,
}: DisableTwoFactorAuthenticationOptions) => {
let isValid = await validateTwoFactorAuthentication({ totpCode: token, user });
let isValid = false;
if (!isValid) {
isValid = await validateTwoFactorAuthentication({ backupCode: token, user });
if (!totpCode && !backupCode) {
throw new AppError(AppErrorCode.INVALID_REQUEST);
}
if (totpCode) {
isValid = await validateTwoFactorAuthentication({ totpCode, user });
} else if (backupCode) {
isValid = await validateTwoFactorAuthentication({ backupCode, user });
}
if (!isValid) {

View File

@ -7,6 +7,7 @@ import {
diffDocumentMetaChanges,
} from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import type { DocumentSigningOrder } from '@documenso/prisma/client';
export type CreateDocumentMetaOptions = {
documentId: number;
@ -16,6 +17,7 @@ export type CreateDocumentMetaOptions = {
password?: string;
dateFormat?: string;
redirectUrl?: string;
signingOrder?: DocumentSigningOrder;
userId: number;
requestMetadata: RequestMetadata;
};
@ -29,6 +31,7 @@ export const upsertDocumentMeta = async ({
password,
userId,
redirectUrl,
signingOrder,
requestMetadata,
}: CreateDocumentMetaOptions) => {
const user = await prisma.user.findFirstOrThrow({
@ -78,6 +81,7 @@ export const upsertDocumentMeta = async ({
timezone,
documentId,
redirectUrl,
signingOrder,
},
update: {
subject,
@ -86,6 +90,7 @@ export const upsertDocumentMeta = async ({
dateFormat,
timezone,
redirectUrl,
signingOrder,
},
});

View File

@ -2,11 +2,18 @@ import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-log
import type { RequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import { DocumentStatus, SigningStatus } from '@documenso/prisma/client';
import {
DocumentSigningOrder,
DocumentStatus,
RecipientRole,
SendStatus,
SigningStatus,
} from '@documenso/prisma/client';
import { WebhookTriggerEvents } from '@documenso/prisma/client';
import { jobs } from '../../jobs/client';
import type { TRecipientActionAuth } from '../../types/document-auth';
import { getIsRecipientsTurnToSign } from '../recipient/get-is-recipient-turn';
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
import { sendPendingEmail } from './send-pending-email';
@ -29,6 +36,7 @@ const getDocument = async ({ token, documentId }: CompleteDocumentWithTokenOptio
},
},
include: {
documentMeta: true,
Recipient: {
where: {
token,
@ -59,6 +67,16 @@ export const completeDocumentWithToken = async ({
throw new Error(`Recipient ${recipient.id} has already signed`);
}
if (document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL) {
const isRecipientsTurn = await getIsRecipientsTurnToSign({ token: recipient.token });
if (!isRecipientsTurn) {
throw new Error(
`Recipient ${recipient.id} attempted to complete the document before it was their turn`,
);
}
}
const fields = await prisma.field.findMany({
where: {
documentId: document.id,
@ -120,17 +138,48 @@ export const completeDocumentWithToken = async ({
});
});
const pendingRecipients = await prisma.recipient.count({
const pendingRecipients = await prisma.recipient.findMany({
select: {
id: true,
signingOrder: true,
},
where: {
documentId: document.id,
signingStatus: {
not: SigningStatus.SIGNED,
},
role: {
not: RecipientRole.CC,
},
},
// Composite sort so our next recipient is always the one with the lowest signing order or id
// if there is a tie.
orderBy: [{ signingOrder: { sort: 'asc', nulls: 'last' } }, { id: 'asc' }],
});
if (pendingRecipients > 0) {
if (pendingRecipients.length > 0) {
await sendPendingEmail({ documentId, recipientId: recipient.id });
if (document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL) {
const [nextRecipient] = pendingRecipients;
await prisma.$transaction(async (tx) => {
await tx.recipient.update({
where: { id: nextRecipient.id },
data: { sendStatus: SendStatus.SENT },
});
await jobs.triggerJob({
name: 'send.signing.requested.email',
payload: {
userId: document.userId,
documentId: document.id,
recipientId: nextRecipient.id,
requestMetadata,
},
});
});
}
}
const haveAllRecipientsSigned = await prisma.document.findFirst({
@ -138,7 +187,7 @@ export const completeDocumentWithToken = async ({
id: document.id,
Recipient: {
every: {
signingStatus: SigningStatus.SIGNED,
OR: [{ signingStatus: SigningStatus.SIGNED }, { role: RecipientRole.CC }],
},
},
},

View File

@ -2,10 +2,11 @@ import { DateTime } from 'luxon';
import { P, match } from 'ts-pattern';
import { prisma } from '@documenso/prisma';
import { Prisma, RecipientRole, SigningStatus } from '@documenso/prisma/client';
import { Prisma, RecipientRole, SigningStatus, TeamMemberRole } from '@documenso/prisma/client';
import type { Document, Team, TeamEmail, User } from '@documenso/prisma/client';
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
import { DocumentVisibility } from '../../types/document-visibility';
import type { FindResultSet } from '../../types/find-result-set';
import { maskRecipientTokensForDocument } from '../../utils/mask-recipient-tokens-for-document';
@ -48,9 +49,23 @@ export const findDocuments = async ({
team = await tx.team.findFirstOrThrow({
where: {
id: teamId,
members: { some: { userId } },
members: {
some: {
userId,
},
},
},
include: {
teamEmail: true,
members: {
where: {
userId,
},
select: {
role: true,
},
},
},
include: { teamEmail: true },
});
}
@ -59,6 +74,7 @@ export const findDocuments = async ({
const orderByColumn = orderBy?.column ?? 'createdAt';
const orderByDirection = orderBy?.direction ?? 'desc';
const teamMemberRole = team?.members[0].role ?? null;
const termFilters = match(term)
.with(P.string.minLength(1), () => ({
@ -69,7 +85,37 @@ export const findDocuments = async ({
}))
.otherwise(() => undefined);
const filters = team ? findTeamDocumentsFilter(status, team) : findDocumentsFilter(status, user);
const visibilityFilters = [
match(teamMemberRole)
.with(TeamMemberRole.ADMIN, () => ({
visibility: {
in: [
DocumentVisibility.EVERYONE,
DocumentVisibility.MANAGER_AND_ABOVE,
DocumentVisibility.ADMIN,
],
},
}))
.with(TeamMemberRole.MANAGER, () => ({
visibility: {
in: [DocumentVisibility.EVERYONE, DocumentVisibility.MANAGER_AND_ABOVE],
},
}))
.otherwise(() => ({ visibility: DocumentVisibility.EVERYONE })),
{
Recipient: {
some: {
email: user.email,
},
},
},
];
let filters: Prisma.DocumentWhereInput | null = findDocumentsFilter(status, user);
if (team) {
filters = findTeamDocumentsFilter(status, team, visibilityFilters);
}
if (filters === null) {
return {
@ -309,6 +355,7 @@ const findDocumentsFilter = (status: ExtendedDocumentStatus, user: User) => {
const findTeamDocumentsFilter = (
status: ExtendedDocumentStatus,
team: Team & { teamEmail: TeamEmail | null },
visibilityFilters: Prisma.DocumentWhereInput[],
) => {
const teamEmail = team.teamEmail?.email ?? null;
@ -319,6 +366,7 @@ const findTeamDocumentsFilter = (
{
teamId: team.id,
deletedAt: null,
OR: visibilityFilters,
},
],
};
@ -334,6 +382,7 @@ const findTeamDocumentsFilter = (
},
},
deletedAt: null,
OR: visibilityFilters,
});
filter.OR.push({
@ -341,6 +390,7 @@ const findTeamDocumentsFilter = (
email: teamEmail,
},
deletedAt: null,
OR: visibilityFilters,
});
}
@ -365,6 +415,7 @@ const findTeamDocumentsFilter = (
},
},
deletedAt: null,
OR: visibilityFilters,
};
})
.with(ExtendedDocumentStatus.DRAFT, () => {
@ -374,6 +425,7 @@ const findTeamDocumentsFilter = (
teamId: team.id,
status: ExtendedDocumentStatus.DRAFT,
deletedAt: null,
OR: visibilityFilters,
},
],
};
@ -385,6 +437,7 @@ const findTeamDocumentsFilter = (
email: teamEmail,
},
deletedAt: null,
OR: visibilityFilters,
});
}
@ -397,6 +450,7 @@ const findTeamDocumentsFilter = (
teamId: team.id,
status: ExtendedDocumentStatus.PENDING,
deletedAt: null,
OR: visibilityFilters,
},
],
};
@ -415,11 +469,13 @@ const findTeamDocumentsFilter = (
},
},
},
OR: visibilityFilters,
},
{
User: {
email: teamEmail,
},
OR: visibilityFilters,
},
],
deletedAt: null,
@ -435,6 +491,7 @@ const findTeamDocumentsFilter = (
OR: [
{
teamId: team.id,
OR: visibilityFilters,
},
],
};
@ -447,11 +504,13 @@ const findTeamDocumentsFilter = (
email: teamEmail,
},
},
OR: visibilityFilters,
},
{
User: {
email: teamEmail,
},
OR: visibilityFilters,
},
);
}

View File

@ -1,6 +1,10 @@
import { match } from 'ts-pattern';
import { prisma } from '@documenso/prisma';
import type { Prisma } from '@documenso/prisma/client';
import { TeamMemberRole } from '@documenso/prisma/client';
import { DocumentVisibility } from '../../types/document-visibility';
import { getTeamById } from '../team/get-team';
export type GetDocumentByIdOptions = {
@ -28,6 +32,11 @@ export const getDocumentById = async ({ id, userId, teamId }: GetDocumentByIdOpt
email: true,
},
},
Recipient: {
select: {
email: true,
},
},
team: {
select: {
id: true,
@ -115,5 +124,35 @@ export const getDocumentWhereInput = async ({
);
}
return documentWhereInput;
const user = await prisma.user.findFirstOrThrow({
where: {
id: userId,
},
});
const visibilityFilters = [
...match(team.currentTeamMember?.role)
.with(TeamMemberRole.ADMIN, () => [
{ visibility: DocumentVisibility.EVERYONE },
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
{ visibility: DocumentVisibility.ADMIN },
])
.with(TeamMemberRole.MANAGER, () => [
{ visibility: DocumentVisibility.EVERYONE },
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
])
.otherwise(() => [{ visibility: DocumentVisibility.EVERYONE }]),
{
Recipient: {
some: {
email: user.email,
},
},
},
];
return {
...documentWhereInput,
OR: [...visibilityFilters],
};
};

View File

@ -147,7 +147,7 @@ export const getDocumentAndRecipientByToken = async ({
},
});
const recipient = result.Recipient[0];
const [recipient] = result.Recipient;
// Sanity check, should not be possible.
if (!recipient) {

View File

@ -1,12 +1,16 @@
import { DateTime } from 'luxon';
import { match } from 'ts-pattern';
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
import { prisma } from '@documenso/prisma';
import { TeamMemberRole } from '@documenso/prisma/client';
import type { Prisma, User } from '@documenso/prisma/client';
import { SigningStatus } from '@documenso/prisma/client';
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
import { DocumentVisibility } from '../../types/document-visibility';
export type GetStatsInput = {
user: User;
team?: Omit<GetTeamCountsOption, 'createdAt'>;
@ -27,7 +31,7 @@ export const getStats = async ({ user, period, ...options }: GetStatsInput) => {
}
const [ownerCounts, notSignedCounts, hasSignedCounts, deletedCounts] = await (options.team
? getTeamCounts({ ...options.team, createdAt })
? getTeamCounts({ ...options.team, createdAt, currentUserEmail: user.email, userId: user.id })
: getCounts({ user, createdAt }));
const stats: Record<ExtendedDocumentStatus, number> = {
@ -194,11 +198,21 @@ type GetTeamCountsOption = {
teamId: number;
teamEmail?: string;
senderIds?: number[];
currentUserEmail: string;
userId: number;
createdAt: Prisma.DocumentWhereInput['createdAt'];
currentTeamMemberRole?: TeamMemberRole;
};
const getTeamCounts = async (options: GetTeamCountsOption) => {
const { createdAt, teamId, teamEmail, senderIds = [] } = options;
const {
createdAt,
teamId,
teamEmail,
senderIds = [],
currentUserEmail,
currentTeamMemberRole,
} = options;
const userIdWhereClause: Prisma.DocumentWhereInput['userId'] =
senderIds.length > 0
@ -207,10 +221,50 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
}
: undefined;
const visibilityFilters = [
...match(currentTeamMemberRole)
.with(TeamMemberRole.ADMIN, () => [
{ visibility: DocumentVisibility.EVERYONE },
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
{ visibility: DocumentVisibility.ADMIN },
])
.with(TeamMemberRole.MANAGER, () => [
{ visibility: DocumentVisibility.EVERYONE },
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
])
.otherwise(() => [{ visibility: DocumentVisibility.EVERYONE }]),
];
const ownerCountsWhereInput: Prisma.DocumentWhereInput = {
userId: userIdWhereClause,
createdAt,
OR: [{ teamId }, ...(teamEmail ? [{ User: { email: teamEmail } }] : [])],
OR: [
{ teamId },
...(teamEmail ? [{ User: { email: teamEmail } }] : []),
{
AND: [
{
visibility: {
in: visibilityFilters.map((filter) => filter.visibility),
},
},
{
Recipient: {
none: {
email: currentUserEmail,
},
},
},
],
},
{
Recipient: {
some: {
email: currentUserEmail,
},
},
},
],
deletedAt: null,
};
@ -246,9 +300,6 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
status: {
in: [ExtendedDocumentStatus.PENDING, ExtendedDocumentStatus.COMPLETED],
},
deletedAt: {
gte: DateTime.now().minus({ days: 30 }).startOf('day').toJSDate(),
},
},
...(teamEmail
? [
@ -257,17 +308,12 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
some: {
email: teamEmail,
signingStatus: SigningStatus.SIGNED,
documentDeletedAt: {
gte: DateTime.now().minus({ days: 30 }).startOf('day').toJSDate(),
},
documentDeletedAt: null,
},
},
status: {
in: [ExtendedDocumentStatus.PENDING, ExtendedDocumentStatus.COMPLETED],
},
deletedAt: {
gte: DateTime.now().minus({ days: 30 }).startOf('day').toJSDate(),
},
},
]
: []),

View File

@ -5,7 +5,7 @@ import { render } from '@documenso/email/render';
import { DocumentInviteEmailTemplate } from '@documenso/email/templates/document-invite';
import { FROM_ADDRESS, FROM_NAME } from '@documenso/lib/constants/email';
import {
RECIPIENT_ROLES_DESCRIPTION,
RECIPIENT_ROLES_DESCRIPTION_ENG,
RECIPIENT_ROLE_TO_EMAIL_TYPE,
} from '@documenso/lib/constants/recipient-roles';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
@ -97,8 +97,8 @@ export const resendDocument = async ({
const { email, name } = recipient;
const selfSigner = email === user.email;
const { actionVerb } = RECIPIENT_ROLES_DESCRIPTION[recipient.role];
const recipientActionVerb = actionVerb.toLowerCase();
const recipientActionVerb =
RECIPIENT_ROLES_DESCRIPTION_ENG[recipient.role].actionVerb.toLowerCase();
let emailMessage = customEmail?.message || '';
let emailSubject = `Reminder: Please ${recipientActionVerb} this document`;

View File

@ -3,7 +3,13 @@ import type { RequestMetadata } from '@documenso/lib/universal/extract-request-m
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import { DocumentStatus, RecipientRole, SendStatus, SigningStatus } from '@documenso/prisma/client';
import {
DocumentSigningOrder,
DocumentStatus,
RecipientRole,
SendStatus,
SigningStatus,
} from '@documenso/prisma/client';
import { WebhookTriggerEvents } from '@documenso/prisma/client';
import { jobs } from '../../jobs/client';
@ -57,7 +63,9 @@ export const sendDocument = async ({
}),
},
include: {
Recipient: true,
Recipient: {
orderBy: [{ signingOrder: { sort: 'asc', nulls: 'last' } }, { id: 'asc' }],
},
documentMeta: true,
documentData: true,
},
@ -75,6 +83,21 @@ export const sendDocument = async ({
throw new Error('Can not send completed document');
}
const signingOrder = document.documentMeta?.signingOrder || DocumentSigningOrder.PARALLEL;
let recipientsToNotify = document.Recipient;
if (signingOrder === DocumentSigningOrder.SEQUENTIAL) {
// Get the currently active recipient.
recipientsToNotify = document.Recipient.filter(
(r) => r.signingStatus === SigningStatus.NOT_SIGNED && r.role !== RecipientRole.CC,
).slice(0, 1);
// Secondary filter so we aren't resending if the current active recipient has already
// received the document.
recipientsToNotify.filter((r) => r.sendStatus !== SendStatus.SENT);
}
const { documentData } = document;
if (!documentData.data) {
@ -135,7 +158,7 @@ export const sendDocument = async ({
if (sendEmail) {
await Promise.all(
document.Recipient.map(async (recipient) => {
recipientsToNotify.map(async (recipient) => {
if (recipient.sendStatus === SendStatus.SENT || recipient.role === RecipientRole.CC) {
return;
}

View File

@ -6,6 +6,7 @@ import type { RequestMetadata } from '@documenso/lib/universal/extract-request-m
import type { CreateDocumentAuditLogDataResponse } from '@documenso/lib/utils/document-audit-logs';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import type { DocumentVisibility } from '@documenso/prisma/client';
import { DocumentStatus } from '@documenso/prisma/client';
import { AppError, AppErrorCode } from '../../errors/app-error';
@ -19,6 +20,7 @@ export type UpdateDocumentSettingsOptions = {
data: {
title?: string;
externalId?: string | null;
visibility?: string | null;
globalAccessAuth?: TDocumentAccessAuthTypes | null;
globalActionAuth?: TDocumentActionAuthTypes | null;
};
@ -91,10 +93,14 @@ export const updateDocumentSettings = async ({
}
}
const isTitleSame = data.title === document.title;
const isExternalIdSame = data.externalId === document.externalId;
const isGlobalAccessSame = documentGlobalAccessAuth === newGlobalAccessAuth;
const isGlobalActionSame = documentGlobalActionAuth === newGlobalActionAuth;
const isTitleSame = data.title === undefined || data.title === document.title;
const isExternalIdSame = data.externalId === undefined || data.externalId === document.externalId;
const isGlobalAccessSame =
documentGlobalAccessAuth === undefined || documentGlobalAccessAuth === newGlobalAccessAuth;
const isGlobalActionSame =
documentGlobalActionAuth === undefined || documentGlobalActionAuth === newGlobalActionAuth;
const isDocumentVisibilitySame =
data.visibility === undefined || data.visibility === document.visibility;
const auditLogs: CreateDocumentAuditLogDataResponse[] = [];
@ -165,6 +171,21 @@ export const updateDocumentSettings = async ({
);
}
if (!isDocumentVisibilitySame) {
auditLogs.push(
createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED,
documentId,
user,
requestMetadata,
data: {
from: document.visibility,
to: data.visibility || '',
},
}),
);
}
// Early return if nothing is required.
if (auditLogs.length === 0) {
return document;
@ -182,7 +203,8 @@ export const updateDocumentSettings = async ({
},
data: {
title: data.title,
externalId: data.externalId || null,
externalId: data.externalId,
visibility: data.visibility as DocumentVisibility,
authOptions,
},
});

View File

@ -5,7 +5,11 @@ import { getToken } from 'next-auth/jwt';
import { LOCAL_FEATURE_FLAGS } from '@documenso/lib/constants/feature-flags';
import PostHogServerClient from '@documenso/lib/server-only/feature-flags/get-post-hog-server-client';
import { NEXT_PUBLIC_MARKETING_URL, NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
import {
NEXT_PRIVATE_INTERNAL_WEBAPP_URL,
NEXT_PUBLIC_MARKETING_URL,
NEXT_PUBLIC_WEBAPP_URL,
} from '../../constants/app';
import { extractDistinctUserId, mapJwtToFlagProperties } from './get';
/**
@ -46,6 +50,10 @@ export default async function handlerFeatureFlagAll(req: Request) {
if (origin.startsWith(NEXT_PUBLIC_MARKETING_URL() ?? 'http://localhost:3001')) {
res.headers.set('Access-Control-Allow-Origin', origin);
}
if (origin.startsWith(NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? 'http://localhost:3000')) {
res.headers.set('Access-Control-Allow-Origin', origin);
}
}
return res;

View File

@ -7,7 +7,11 @@ import { getToken } from 'next-auth/jwt';
import { LOCAL_FEATURE_FLAGS, extractPostHogConfig } from '@documenso/lib/constants/feature-flags';
import PostHogServerClient from '@documenso/lib/server-only/feature-flags/get-post-hog-server-client';
import { NEXT_PUBLIC_MARKETING_URL, NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
import {
NEXT_PRIVATE_INTERNAL_WEBAPP_URL,
NEXT_PUBLIC_MARKETING_URL,
NEXT_PUBLIC_WEBAPP_URL,
} from '../../constants/app';
/**
* Evaluate a single feature flag based on the current user if possible.
@ -67,6 +71,10 @@ export default async function handleFeatureFlagGet(req: Request) {
if (origin.startsWith(NEXT_PUBLIC_MARKETING_URL() ?? 'http://localhost:3001')) {
res.headers.set('Access-Control-Allow-Origin', origin);
}
if (origin.startsWith(NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? 'http://localhost:3000')) {
res.headers.set('Access-Control-Allow-Origin', origin);
}
}
return res;

View File

@ -1,6 +1,16 @@
import { match } from 'ts-pattern';
import { prisma } from '@documenso/prisma';
import type { FieldType, Team } from '@documenso/prisma/client';
import {
ZCheckboxFieldMeta,
ZDropdownFieldMeta,
ZNumberFieldMeta,
ZRadioFieldMeta,
ZTextFieldMeta,
} from '../../types/field-meta';
import type { TFieldMetaSchema as FieldMeta } from '../../types/field-meta';
import type { RequestMetadata } from '../../universal/extract-request-metadata';
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
@ -15,6 +25,7 @@ export type CreateFieldOptions = {
pageY: number;
pageWidth: number;
pageHeight: number;
fieldMeta?: FieldMeta;
requestMetadata?: RequestMetadata;
};
@ -29,6 +40,7 @@ export const createField = async ({
pageY,
pageWidth,
pageHeight,
fieldMeta,
requestMetadata,
}: CreateFieldOptions) => {
const document = await prisma.document.findFirst({
@ -85,6 +97,39 @@ export const createField = async ({
});
}
const advancedField = ['NUMBER', 'RADIO', 'CHECKBOX', 'DROPDOWN', 'TEXT'].includes(type);
if (advancedField && !fieldMeta) {
throw new Error(
'Field meta is required for this type of field. Please provide the appropriate field meta object.',
);
}
if (fieldMeta && fieldMeta.type.toLowerCase() !== String(type).toLowerCase()) {
throw new Error('Field meta type does not match the field type');
}
const result = match(type)
.with('RADIO', () => ZRadioFieldMeta.safeParse(fieldMeta))
.with('CHECKBOX', () => ZCheckboxFieldMeta.safeParse(fieldMeta))
.with('DROPDOWN', () => ZDropdownFieldMeta.safeParse(fieldMeta))
.with('NUMBER', () => ZNumberFieldMeta.safeParse(fieldMeta))
.with('TEXT', () => ZTextFieldMeta.safeParse(fieldMeta))
.with('SIGNATURE', 'INITIALS', 'DATE', 'EMAIL', 'NAME', () => ({
success: true,
data: {},
}))
.with('FREE_SIGNATURE', () => ({
success: false,
error: 'FREE_SIGNATURE is not supported',
data: {},
}))
.exhaustive();
if (!result.success) {
throw new Error('Field meta parsing failed');
}
const field = await prisma.field.create({
data: {
documentId,
@ -97,6 +142,7 @@ export const createField = async ({
height: pageHeight,
customText: '',
inserted: false,
fieldMeta: result.data,
},
include: {
Recipient: true,

View File

@ -1,3 +1,5 @@
import { isDeepEqual } from 'remeda';
import { validateCheckboxField } from '@documenso/lib/advanced-fields-validation/validate-checkbox';
import { validateDropdownField } from '@documenso/lib/advanced-fields-validation/validate-dropdown';
import { validateNumberField } from '@documenso/lib/advanced-fields-validation/validate-number';
@ -20,22 +22,15 @@ import {
} from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import type { Field } from '@documenso/prisma/client';
import { FieldType, SendStatus, SigningStatus } from '@documenso/prisma/client';
import { FieldType } from '@documenso/prisma/client';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientFieldsBeModified } from '../../utils/recipients';
export interface SetFieldsForDocumentOptions {
userId: number;
documentId: number;
fields: {
id?: number | null;
type: FieldType;
signerEmail: string;
pageNumber: number;
pageX: number;
pageY: number;
pageWidth: number;
pageHeight: number;
fieldMeta?: FieldMeta;
}[];
fields: FieldData[];
requestMetadata?: RequestMetadata;
}
@ -63,6 +58,9 @@ export const setFieldsForDocument = async ({
},
],
},
include: {
Recipient: true,
},
});
const user = await prisma.user.findFirstOrThrow({
@ -97,21 +95,36 @@ export const setFieldsForDocument = async ({
(existingField) => !fields.find((field) => field.id === existingField.id),
);
const linkedFields = fields
.map((field) => {
const existing = existingFields.find((existingField) => existingField.id === field.id);
const linkedFields = fields.map((field) => {
const existing = existingFields.find((existingField) => existingField.id === field.id);
return {
...field,
_persisted: existing,
};
})
.filter((field) => {
return (
field._persisted?.Recipient?.sendStatus !== SendStatus.SENT &&
field._persisted?.Recipient?.signingStatus !== SigningStatus.SIGNED
const recipient = document.Recipient.find(
(recipient) => recipient.email.toLowerCase() === field.signerEmail.toLowerCase(),
);
// Each field MUST have a recipient associated with it.
if (!recipient) {
throw new AppError(AppErrorCode.INVALID_REQUEST, `Recipient not found for field ${field.id}`);
}
// Check whether the existing field can be modified.
if (
existing &&
hasFieldBeenChanged(existing, field) &&
!canRecipientFieldsBeModified(recipient, existingFields)
) {
throw new AppError(
AppErrorCode.INVALID_REQUEST,
'Cannot modify a field where the recipient has already interacted with the document',
);
});
}
return {
...field,
_persisted: existing,
_recipient: recipient,
};
});
const persistedFields = await prisma.$transaction(async (tx) => {
return await Promise.all(
@ -322,3 +335,33 @@ export const setFieldsForDocument = async ({
return [...filteredFields, ...persistedFields];
};
/**
* If you change this you MUST update the `hasFieldBeenChanged` function.
*/
type FieldData = {
id?: number | null;
type: FieldType;
signerEmail: string;
pageNumber: number;
pageX: number;
pageY: number;
pageWidth: number;
pageHeight: number;
fieldMeta?: FieldMeta;
};
const hasFieldBeenChanged = (field: Field, newFieldData: FieldData) => {
const currentFieldMeta = field.fieldMeta || null;
const newFieldMeta = newFieldData.fieldMeta || null;
return (
field.type !== newFieldData.type ||
field.page !== newFieldData.pageNumber ||
field.positionX.toNumber() !== newFieldData.pageX ||
field.positionY.toNumber() !== newFieldData.pageY ||
field.width.toNumber() !== newFieldData.pageWidth ||
field.height.toNumber() !== newFieldData.pageHeight ||
!isDeepEqual(currentFieldMeta, newFieldMeta)
);
};

View File

@ -107,7 +107,10 @@ export const setFieldsForTemplate = async ({
}
}
if (field.type === FieldType.CHECKBOX && field.fieldMeta) {
if (field.type === FieldType.CHECKBOX) {
if (!field.fieldMeta) {
throw new Error('Checkbox field is missing required metadata');
}
const checkboxFieldParsedMeta = ZCheckboxFieldMeta.parse(field.fieldMeta);
const errors = validateCheckboxField(
checkboxFieldParsedMeta?.values?.map((item) => item.value) ?? [],
@ -118,7 +121,10 @@ export const setFieldsForTemplate = async ({
}
}
if (field.type === FieldType.RADIO && field.fieldMeta) {
if (field.type === FieldType.RADIO) {
if (!field.fieldMeta) {
throw new Error('Radio field is missing required metadata');
}
const radioFieldParsedMeta = ZRadioFieldMeta.parse(field.fieldMeta);
const checkedRadioFieldValue = radioFieldParsedMeta.values?.find(
(option) => option.checked,
@ -129,7 +135,10 @@ export const setFieldsForTemplate = async ({
}
}
if (field.type === FieldType.DROPDOWN && field.fieldMeta) {
if (field.type === FieldType.DROPDOWN) {
if (!field.fieldMeta) {
throw new Error('Dropdown field is missing required metadata');
}
const dropdownFieldParsedMeta = ZDropdownFieldMeta.parse(field.fieldMeta);
const errors = validateDropdownField(undefined, dropdownFieldParsedMeta);
if (errors.length > 0) {

View File

@ -37,6 +37,10 @@ export const updateField = async ({
requestMetadata,
fieldMeta,
}: UpdateFieldOptions) => {
if (type === 'FREE_SIGNATURE') {
throw new Error('Cannot update a FREE_SIGNATURE field');
}
const oldField = await prisma.field.findFirstOrThrow({
where: {
id: fieldId,
@ -61,6 +65,11 @@ export const updateField = async ({
},
});
const newFieldMeta = {
...(oldField.fieldMeta as FieldMeta),
...fieldMeta,
};
const field = prisma.$transaction(async (tx) => {
const updatedField = await tx.field.update({
where: {
@ -74,13 +83,39 @@ export const updateField = async ({
positionY: pageY,
width: pageWidth,
height: pageHeight,
fieldMeta,
fieldMeta: newFieldMeta,
},
include: {
Recipient: true,
},
});
const user = await prisma.user.findFirstOrThrow({
where: {
id: userId,
},
select: {
id: true,
name: true,
email: true,
},
});
let team: Team | null = null;
if (teamId) {
team = await prisma.team.findFirst({
where: {
id: teamId,
members: {
some: {
userId,
},
},
},
});
}
await tx.documentAuditLog.create({
data: createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.FIELD_UPDATED,
@ -104,31 +139,5 @@ export const updateField = async ({
return updatedField;
});
const user = await prisma.user.findFirstOrThrow({
where: {
id: userId,
},
select: {
id: true,
name: true,
email: true,
},
});
let team: Team | null = null;
if (teamId) {
team = await prisma.team.findFirst({
where: {
id: teamId,
members: {
some: {
userId,
},
},
},
});
}
return field;
};

View File

@ -1,11 +0,0 @@
import { headers } from 'next/headers';
export const getLocale = () => {
const headerItems = headers();
const locales = headerItems.get('accept-language') ?? 'en-US';
const [locale] = locales.split(',');
return locale;
};

View File

@ -4,5 +4,5 @@ import { cookies } from 'next/headers';
// eslint-disable-next-line @typescript-eslint/require-await
export const switchI18NLanguage = async (lang: string) => {
cookies().set('i18n', lang);
cookies().set('language', lang);
};

View File

@ -0,0 +1,46 @@
import { prisma } from '@documenso/prisma';
import { DocumentSigningOrder, SigningStatus } from '@documenso/prisma/client';
export type GetIsRecipientTurnOptions = {
token: string;
};
export async function getIsRecipientsTurnToSign({ token }: GetIsRecipientTurnOptions) {
const document = await prisma.document.findFirstOrThrow({
where: {
Recipient: {
some: {
token,
},
},
},
include: {
documentMeta: true,
Recipient: {
orderBy: {
signingOrder: 'asc',
},
},
},
});
if (document.documentMeta?.signingOrder !== DocumentSigningOrder.SEQUENTIAL) {
return true;
}
const recipients = document.Recipient;
const currentRecipientIndex = recipients.findIndex((r) => r.token === token);
if (currentRecipientIndex === -1) {
return false;
}
for (let i = 0; i < currentRecipientIndex; i++) {
if (recipients[i].signingStatus !== SigningStatus.SIGNED) {
return false;
}
}
return true;
}

View File

@ -1,4 +1,9 @@
import { createElement } from 'react';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { mailer } from '@documenso/email/mailer';
import { render } from '@documenso/email/render';
import RecipientRemovedFromDocumentTemplate from '@documenso/email/templates/recipient-removed-from-document';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import {
type TRecipientActionAuthTypes,
@ -16,19 +21,16 @@ import type { Recipient } from '@documenso/prisma/client';
import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
import { FROM_ADDRESS, FROM_NAME } from '../../constants/email';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientBeModified } from '../../utils/recipients';
export interface SetRecipientsForDocumentOptions {
userId: number;
teamId?: number;
documentId: number;
recipients: {
id?: number | null;
email: string;
name: string;
role: RecipientRole;
actionAuth?: TRecipientActionAuthTypes | null;
}[];
recipients: RecipientData[];
requestMetadata?: RequestMetadata;
}
@ -58,6 +60,9 @@ export const setRecipientsForDocument = async ({
teamId: null,
}),
},
include: {
Field: true,
},
});
const user = await prisma.user.findFirstOrThrow({
@ -115,25 +120,28 @@ export const setRecipientsForDocument = async ({
),
);
const linkedRecipients = normalizedRecipients
.map((recipient) => {
const existing = existingRecipients.find(
(existingRecipient) =>
existingRecipient.id === recipient.id || existingRecipient.email === recipient.email,
);
const linkedRecipients = normalizedRecipients.map((recipient) => {
const existing = existingRecipients.find(
(existingRecipient) =>
existingRecipient.id === recipient.id || existingRecipient.email === recipient.email,
);
return {
...recipient,
_persisted: existing,
};
})
.filter((recipient) => {
return (
recipient._persisted?.role === RecipientRole.CC ||
(recipient._persisted?.sendStatus !== SendStatus.SENT &&
recipient._persisted?.signingStatus !== SigningStatus.SIGNED)
if (
existing &&
hasRecipientBeenChanged(existing, recipient) &&
!canRecipientBeModified(existing, document.Field)
) {
throw new AppError(
AppErrorCode.INVALID_REQUEST,
'Cannot modify a recipient who has already interacted with the document',
);
});
}
return {
...recipient,
_persisted: existing,
};
});
const persistedRecipients = await prisma.$transaction(async (tx) => {
return await Promise.all(
@ -156,6 +164,7 @@ export const setRecipientsForDocument = async ({
name: recipient.name,
email: recipient.email,
role: recipient.role,
signingOrder: recipient.signingOrder,
documentId,
sendStatus: recipient.role === RecipientRole.CC ? SendStatus.SENT : SendStatus.NOT_SENT,
signingStatus:
@ -166,6 +175,7 @@ export const setRecipientsForDocument = async ({
name: recipient.name,
email: recipient.email,
role: recipient.role,
signingOrder: recipient.signingOrder,
token: nanoid(),
documentId,
sendStatus: recipient.role === RecipientRole.CC ? SendStatus.SENT : SendStatus.NOT_SENT,
@ -265,6 +275,37 @@ export const setRecipientsForDocument = async ({
),
});
});
// Send emails to deleted recipients.
await Promise.all(
removedRecipients.map(async (recipient) => {
if (recipient.sendStatus !== SendStatus.SENT) {
return;
}
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';
const template = createElement(RecipientRemovedFromDocumentTemplate, {
documentName: document.title,
inviterName: user.name || undefined,
assetBaseUrl,
});
await mailer.sendMail({
to: {
address: recipient.email,
name: recipient.name,
},
from: {
name: FROM_NAME,
address: FROM_ADDRESS,
},
subject: 'You have been removed from a document',
html: render(template),
text: render(template, { plainText: true }),
});
}),
);
}
// Filter out recipients that have been removed or have been updated.
@ -281,3 +322,27 @@ export const setRecipientsForDocument = async ({
return [...filteredRecipients, ...persistedRecipients];
};
/**
* If you change this you MUST update the `hasRecipientBeenChanged` function.
*/
type RecipientData = {
id?: number | null;
email: string;
name: string;
role: RecipientRole;
signingOrder?: number | null;
actionAuth?: TRecipientActionAuthTypes | null;
};
const hasRecipientBeenChanged = (recipient: Recipient, newRecipientData: RecipientData) => {
const authOptions = ZRecipientAuthOptionsSchema.parse(recipient.authOptions);
return (
recipient.email !== newRecipientData.email ||
recipient.name !== newRecipientData.name ||
recipient.role !== newRecipientData.role ||
recipient.signingOrder !== newRecipientData.signingOrder ||
authOptions.actionAuth !== newRecipientData.actionAuth
);
};

View File

@ -1,12 +1,12 @@
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import {
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
DIRECT_TEMPLATE_RECIPIENT_NAME,
} from '@documenso/lib/constants/direct-templates';
import { prisma } from '@documenso/prisma';
import type { Recipient } from '@documenso/prisma/client';
import { RecipientRole } from '@documenso/prisma/client';
import {
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
DIRECT_TEMPLATE_RECIPIENT_NAME,
} from '../../constants/template';
import { AppError, AppErrorCode } from '../../errors/app-error';
import {
type TRecipientActionAuthTypes,
@ -24,6 +24,7 @@ export type SetRecipientsForTemplateOptions = {
email: string;
name: string;
role: RecipientRole;
signingOrder?: number | null;
actionAuth?: TRecipientActionAuthTypes | null;
}[];
};
@ -162,6 +163,7 @@ export const setRecipientsForTemplate = async ({
name: recipient.name,
email: recipient.email,
role: recipient.role,
signingOrder: recipient.signingOrder,
templateId,
authOptions,
},
@ -169,6 +171,7 @@ export const setRecipientsForTemplate = async ({
name: recipient.name,
email: recipient.email,
role: recipient.role,
signingOrder: recipient.signingOrder,
token: nanoid(),
templateId,
authOptions,

View File

@ -1,9 +1,16 @@
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { prisma } from '@documenso/prisma';
import type { RecipientRole, Team } from '@documenso/prisma/client';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
import {
type TRecipientActionAuthTypes,
ZRecipientAuthOptionsSchema,
} from '../../types/document-auth';
import type { RequestMetadata } from '../../universal/extract-request-metadata';
import { createDocumentAuditLogData, diffRecipientChanges } from '../../utils/document-audit-logs';
import { createRecipientAuthOptions } from '../../utils/document-auth';
export type UpdateRecipientOptions = {
documentId: number;
@ -11,6 +18,8 @@ export type UpdateRecipientOptions = {
email?: string;
name?: string;
role?: RecipientRole;
signingOrder?: number | null;
actionAuth?: TRecipientActionAuthTypes | null;
userId: number;
teamId?: number;
requestMetadata?: RequestMetadata;
@ -22,6 +31,8 @@ export const updateRecipient = async ({
email,
name,
role,
signingOrder,
actionAuth,
userId,
teamId,
requestMetadata,
@ -48,6 +59,9 @@ export const updateRecipient = async ({
}),
},
},
include: {
Document: true,
},
});
let team: Team | null = null;
@ -75,6 +89,22 @@ export const updateRecipient = async ({
throw new Error('Recipient not found');
}
if (actionAuth) {
const isDocumentEnterprise = await isUserEnterprise({
userId,
teamId,
});
if (!isDocumentEnterprise) {
throw new AppError(
AppErrorCode.UNAUTHORIZED,
'You do not have permission to set the action auth',
);
}
}
const recipientAuthOptions = ZRecipientAuthOptionsSchema.parse(recipient.authOptions);
const updatedRecipient = await prisma.$transaction(async (tx) => {
const persisted = await prisma.recipient.update({
where: {
@ -84,6 +114,11 @@ export const updateRecipient = async ({
email: email?.toLowerCase() ?? recipient.email,
name: name ?? recipient.name,
role: role ?? recipient.role,
signingOrder,
authOptions: createRecipientAuthOptions({
accessAuth: recipientAuthOptions.accessAuth,
actionAuth: actionAuth ?? null,
}),
},
});

View File

@ -0,0 +1,21 @@
'use server';
import { prisma } from '@documenso/prisma';
import { SubscriptionStatus } from '@documenso/prisma/client';
export type GetActiveSubscriptionsByUserIdOptions = {
userId: number;
};
export const getActiveSubscriptionsByUserId = async ({
userId,
}: GetActiveSubscriptionsByUserIdOptions) => {
return await prisma.subscription.findMany({
where: {
userId,
status: {
not: SubscriptionStatus.INACTIVE,
},
},
});
};

View File

@ -1,6 +1,7 @@
import { updateSubscriptionItemQuantity } from '@documenso/ee/server-only/stripe/update-subscription-item-quantity';
import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
import { prisma } from '@documenso/prisma';
import { TeamMemberInviteStatus } from '@documenso/prisma/client';
import { jobs } from '../../jobs/client';
@ -22,6 +23,9 @@ export const acceptTeamInvitation = async ({ userId, teamId }: AcceptTeamInvitat
where: {
teamId,
email: user.email,
status: {
not: TeamMemberInviteStatus.DECLINED,
},
},
include: {
team: {
@ -37,6 +41,10 @@ export const acceptTeamInvitation = async ({ userId, teamId }: AcceptTeamInvitat
},
});
if (teamMemberInvite.status === TeamMemberInviteStatus.ACCEPTED) {
return;
}
const { team } = teamMemberInvite;
const teamMember = await tx.teamMember.create({
@ -47,10 +55,13 @@ export const acceptTeamInvitation = async ({ userId, teamId }: AcceptTeamInvitat
},
});
await tx.teamMemberInvite.delete({
await tx.teamMemberInvite.update({
where: {
id: teamMemberInvite.id,
},
data: {
status: TeamMemberInviteStatus.ACCEPTED,
},
});
if (IS_BILLING_ENABLED() && team.subscription) {

View File

@ -6,6 +6,8 @@ export type GetTeamByIdOptions = {
teamId: number;
};
export type GetTeamResponse = Awaited<ReturnType<typeof getTeamById>>;
/**
* Get a team given a teamId.
*

View File

@ -28,11 +28,24 @@ export const transferTeamOwnership = async ({ token }: TransferTeamOwnershipOpti
const { team, userId: newOwnerUserId } = teamTransferVerification;
await tx.teamTransferVerification.delete({
where: {
teamId: team.id,
},
});
await Promise.all([
tx.teamTransferVerification.updateMany({
where: {
teamId: team.id,
},
data: {
completed: true,
},
}),
tx.teamTransferVerification.deleteMany({
where: {
teamId: team.id,
expiresAt: {
lt: new Date(),
},
},
}),
]);
const newOwnerUser = await tx.user.findFirstOrThrow({
where: {

View File

@ -210,7 +210,7 @@ export const createDocumentFromDirectTemplate = async ({
const initialRequestTime = new Date();
const { documentId, directRecipientToken } = await prisma.$transaction(async (tx) => {
const { documentId, recipientId, token } = await prisma.$transaction(async (tx) => {
const documentData = await tx.documentData.create({
data: {
type: template.templateDocumentData.type,
@ -539,8 +539,9 @@ export const createDocumentFromDirectTemplate = async ({
});
return {
token: createdDirectRecipient.token,
documentId: document.id,
directRecipientToken: createdDirectRecipient.token,
recipientId: createdDirectRecipient.id,
};
});
@ -559,5 +560,9 @@ export const createDocumentFromDirectTemplate = async ({
// Log and reseal as required until we configure middleware.
}
return directRecipientToken;
return {
token,
documentId,
recipientId,
};
};

View File

@ -10,6 +10,7 @@ export type CreateDocumentFromTemplateLegacyOptions = {
name?: string;
email: string;
role?: RecipientRole;
signingOrder?: number | null;
}[];
};
@ -73,6 +74,7 @@ export const createDocumentFromTemplateLegacy = async ({
email: recipient.email,
name: recipient.name,
role: recipient.role,
signingOrder: recipient.signingOrder,
token: nanoid(),
})),
},
@ -129,12 +131,14 @@ export const createDocumentFromTemplateLegacy = async ({
name: recipient.name,
email: recipient.email,
role: recipient.role,
signingOrder: recipient.signingOrder,
},
create: {
documentId: document.id,
email: recipient.email,
name: recipient.name,
role: recipient.role,
signingOrder: recipient.signingOrder,
token: nanoid(),
},
});

View File

@ -1,6 +1,6 @@
import { nanoid } from '@documenso/lib/universal/id';
import { prisma } from '@documenso/prisma';
import type { Field } from '@documenso/prisma/client';
import type { DocumentSigningOrder, Field } from '@documenso/prisma/client';
import {
DocumentSource,
type Recipient,
@ -41,6 +41,7 @@ export type CreateDocumentFromTemplateOptions = {
id: number;
name?: string;
email: string;
signingOrder?: number | null;
}[];
/**
@ -54,6 +55,7 @@ export type CreateDocumentFromTemplateOptions = {
password?: string;
dateFormat?: string;
redirectUrl?: string;
signingOrder?: DocumentSigningOrder;
};
requestMetadata?: RequestMetadata;
};
@ -134,6 +136,7 @@ export const createDocumentFromTemplate = async ({
name: foundRecipient ? foundRecipient.name ?? '' : templateRecipient.name,
email: foundRecipient ? foundRecipient.email : templateRecipient.email,
role: templateRecipient.role,
signingOrder: foundRecipient?.signingOrder ?? templateRecipient.signingOrder,
authOptions: templateRecipient.authOptions,
};
});
@ -168,6 +171,8 @@ export const createDocumentFromTemplate = async ({
password: override?.password || template.templateMeta?.password,
dateFormat: override?.dateFormat || template.templateMeta?.dateFormat,
redirectUrl: override?.redirectUrl || template.templateMeta?.redirectUrl,
signingOrder:
override?.signingOrder || template.templateMeta?.signingOrder || undefined,
},
},
Recipient: {

View File

@ -2,13 +2,13 @@
import { nanoid } from 'nanoid';
import { prisma } from '@documenso/prisma';
import type { Recipient, TemplateDirectLink } from '@documenso/prisma/client';
import {
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
DIRECT_TEMPLATE_RECIPIENT_NAME,
} from '../../constants/template';
} from '@documenso/lib/constants/direct-templates';
import { prisma } from '@documenso/prisma';
import type { Recipient, TemplateDirectLink } from '@documenso/prisma/client';
import { AppError, AppErrorCode } from '../../errors/app-error';
export type CreateTemplateDirectLinkOptions = {

View File

@ -33,7 +33,7 @@ export const updateTemplateSettings = async ({
meta,
data,
}: UpdateTemplateSettingsOptions) => {
if (Object.values(data).length === 0) {
if (Object.values(data).length === 0 && Object.keys(meta ?? {}).length === 0) {
throw new AppError(AppErrorCode.INVALID_BODY, 'Missing data to update');
}

View File

@ -4,6 +4,13 @@ import { prisma } from '@documenso/prisma';
import { jobsClient } from '../../jobs/client';
export const EMAIL_VERIFICATION_STATE = {
NOT_FOUND: 'NOT_FOUND',
VERIFIED: 'VERIFIED',
EXPIRED: 'EXPIRED',
ALREADY_VERIFIED: 'ALREADY_VERIFIED',
} as const;
export type VerifyEmailProps = {
token: string;
};
@ -19,7 +26,7 @@ export const verifyEmail = async ({ token }: VerifyEmailProps) => {
});
if (!verificationToken) {
return null;
return EMAIL_VERIFICATION_STATE.NOT_FOUND;
}
// check if the token is valid or expired
@ -48,10 +55,14 @@ export const verifyEmail = async ({ token }: VerifyEmailProps) => {
});
}
return valid;
return EMAIL_VERIFICATION_STATE.EXPIRED;
}
const [updatedUser, deletedToken] = await prisma.$transaction([
if (verificationToken.completed) {
return EMAIL_VERIFICATION_STATE.ALREADY_VERIFIED;
}
const [updatedUser] = await prisma.$transaction([
prisma.user.update({
where: {
id: verificationToken.userId,
@ -60,16 +71,28 @@ export const verifyEmail = async ({ token }: VerifyEmailProps) => {
emailVerified: new Date(),
},
}),
prisma.verificationToken.updateMany({
where: {
userId: verificationToken.userId,
},
data: {
completed: true,
},
}),
// Tidy up old expired tokens
prisma.verificationToken.deleteMany({
where: {
userId: verificationToken.userId,
expires: {
lt: new Date(),
},
},
}),
]);
if (!updatedUser || !deletedToken) {
if (!updatedUser) {
throw new Error('Something went wrong while verifying your email. Please try again.');
}
return !!updatedUser && !!deletedToken;
return EMAIL_VERIFICATION_STATE.VERIFIED;
};

View File

@ -1,6 +1,6 @@
import type { WebhookTriggerEvents } from '@documenso/prisma/client';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../../constants/app';
import { NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../../constants/app';
import { sign } from '../../crypto/sign';
import { getAllWebhooksByEventTrigger } from '../get-all-webhooks-by-event-trigger';
@ -29,7 +29,7 @@ export const triggerWebhook = async ({ event, data, userId, teamId }: TriggerWeb
const signature = sign(body);
await Promise.race([
fetch(`${NEXT_PUBLIC_WEBAPP_URL()}/api/webhook/trigger`, {
fetch(`${NEXT_PRIVATE_INTERNAL_WEBAPP_URL}/api/webhook/trigger`, {
method: 'POST',
headers: {
'content-type': 'application/json',

View File

@ -8,7 +8,7 @@ msgstr ""
"Language: de\n"
"Project-Id-Version: documenso-app\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-08-20 14:03\n"
"PO-Revision-Date: 2024-09-16 16:03\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@ -17,3 +17,776 @@ msgstr ""
"X-Crowdin-Language: de\n"
"X-Crowdin-File: common.po\n"
"X-Crowdin-File-ID: 4\n"
#: packages/ui/primitives/data-table-pagination.tsx:30
msgid "{0} of {1} row(s) selected."
msgstr "{0} von {1} Zeile(n) ausgewählt."
#: packages/ui/primitives/data-table-pagination.tsx:41
msgid "{visibleRows, plural, one {Showing # result.} other {Showing # results.}}"
msgstr "{visibleRows, plural, one {Eine # Ergebnis wird angezeigt.} other {# Ergebnisse werden angezeigt.}}"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:53
msgid "<0>Inherit authentication method</0> - Use the global action signing authentication method configured in the \"General Settings\" step"
msgstr "<0>Authentifizierungsmethode erben</0> - Verwenden Sie die in den \"Allgemeinen Einstellungen\" konfigurierte globale Aktionssignatur-Authentifizierungsmethode"
#: packages/ui/components/document/document-global-auth-action-select.tsx:95
msgid "<0>No restrictions</0> - No authentication required"
msgstr "<0>Keine Einschränkungen</0> - Keine Authentifizierung erforderlich"
#: packages/ui/components/document/document-global-auth-access-select.tsx:77
msgid "<0>No restrictions</0> - The document can be accessed directly by the URL sent to the recipient"
msgstr "<0>Keine Einschränkungen</0> - Das Dokument kann direkt über die dem Empfänger gesendete URL abgerufen werden"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:75
msgid "<0>None</0> - No authentication required"
msgstr "<0>Keine</0> - Keine Authentifizierung erforderlich"
#: packages/ui/components/document/document-global-auth-action-select.tsx:89
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:69
msgid "<0>Require 2FA</0> - The recipient must have an account and 2FA enabled via their settings"
msgstr "<0>2FA erforderlich</0> - Der Empfänger muss ein Konto haben und die 2FA über seine Einstellungen aktiviert haben"
#: packages/ui/components/document/document-global-auth-access-select.tsx:72
msgid "<0>Require account</0> - The recipient must be signed in to view the document"
msgstr "<0>Konto erforderlich</0> - Der Empfänger muss angemeldet sein, um das Dokument anzeigen zu können"
#: packages/ui/components/document/document-global-auth-action-select.tsx:83
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:63
msgid "<0>Require passkey</0> - The recipient must have an account and passkey configured via their settings"
msgstr "<0>Passkey erforderlich</0> - Der Empfänger muss ein Konto haben und den Passkey über seine Einstellungen konfiguriert haben"
#: packages/ui/primitives/document-dropzone.tsx:69
msgid "Add a document"
msgstr "Dokument hinzufügen"
#: packages/ui/primitives/document-flow/add-settings.tsx:336
#: packages/ui/primitives/template-flow/add-template-settings.tsx:339
msgid "Add a URL to redirect the user to once the document is signed"
msgstr "Fügen Sie eine URL hinzu, um den Benutzer nach der Unterzeichnung des Dokuments weiterzuleiten"
#: packages/ui/primitives/document-flow/add-settings.tsx:248
msgid "Add an external ID to the document. This can be used to identify the document in external systems."
msgstr "Fügen Sie dem Dokument eine externe ID hinzu. Diese kann verwendet werden, um das Dokument in externen Systemen zu identifizieren."
#: packages/ui/primitives/template-flow/add-template-settings.tsx:256
msgid "Add an external ID to the template. This can be used to identify in external systems."
msgstr "Fügen Sie der Vorlage eine externe ID hinzu. Diese kann zur Identifizierung in externen Systemen verwendet werden."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:177
msgid "Add another option"
msgstr "Weitere Option hinzufügen"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:230
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:167
msgid "Add another value"
msgstr "Weiteren Wert hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:662
msgid "Add myself"
msgstr "Mich selbst hinzufügen"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:637
msgid "Add Myself"
msgstr "Mich hinzufügen"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:623
msgid "Add Placeholder Recipient"
msgstr "Platzhalterempfänger hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:651
msgid "Add Signer"
msgstr "Unterzeichner hinzufügen"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:70
msgid "Add text"
msgstr "Text hinzufügen"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:75
msgid "Add text to the field"
msgstr "Text zum Feld hinzufügen"
#: packages/lib/constants/teams.ts:10
msgid "Admin"
msgstr "Admin"
#: packages/ui/primitives/document-flow/add-settings.tsx:230
#: packages/ui/primitives/template-flow/add-template-settings.tsx:238
msgid "Advanced Options"
msgstr "Erweiterte Optionen"
#: packages/ui/primitives/document-flow/add-fields.tsx:527
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402
msgid "Advanced settings"
msgstr "Erweiterte Einstellungen"
#: packages/lib/constants/template.ts:21
msgid "After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email."
msgstr "Nach der Übermittlung wird ein Dokument automatisch generiert und zu Ihrer Dokumentenseite hinzugefügt. Sie erhalten außerdem eine Benachrichtigung per E-Mail."
#: packages/lib/constants/recipient-roles.ts:8
msgid "Approve"
msgstr "Genehmigen"
#: packages/lib/constants/recipient-roles.ts:9
msgid "Approved"
msgstr "Genehmigt"
#: packages/lib/constants/recipient-roles.ts:11
msgid "Approver"
msgstr "Genehmiger"
#: packages/lib/constants/recipient-roles.ts:10
msgid "Approving"
msgstr "Genehmigung"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:276
msgid "Black"
msgstr "Schwarz"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:290
msgid "Blue"
msgstr "Blau"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:287
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:58
msgid "Cancel"
msgstr "Abbrechen"
#: packages/ui/primitives/document-flow/add-signers.tsx:193
msgid "Cannot remove signer"
msgstr "Unterzeichner kann nicht entfernt werden"
#: packages/ui/primitives/document-flow/add-signers.tsx:221
#~ msgid "Cannot update signer because they have already signed a field"
#~ msgstr ""
#: packages/lib/constants/recipient-roles.ts:17
msgid "Cc"
msgstr "Cc"
#: packages/lib/constants/recipient-roles.ts:14
#: packages/lib/constants/recipient-roles.ts:16
msgid "CC"
msgstr "CC"
#: packages/lib/constants/recipient-roles.ts:15
msgid "CC'd"
msgstr "CC'd"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:83
msgid "Character Limit"
msgstr "Zeichenbeschränkung"
#: packages/ui/primitives/document-flow/add-fields.tsx:950
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788
msgid "Checkbox"
msgstr "Checkbox"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:195
msgid "Checkbox values"
msgstr "Checkbox-Werte"
#: packages/ui/primitives/data-table.tsx:156
msgid "Clear filters"
msgstr "Filter löschen"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:310
msgid "Clear Signature"
msgstr "Unterschrift löschen"
#: packages/ui/primitives/document-flow/add-signature.tsx:394
msgid "Click to insert field"
msgstr "Klicken, um das Feld einzufügen"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:44
msgid "Close"
msgstr "Schließen"
#: packages/lib/constants/template.ts:12
msgid "Configure Direct Recipient"
msgstr "Direkten Empfänger konfigurieren"
#: packages/ui/primitives/document-flow/add-fields.tsx:528
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403
msgid "Configure the {0} field"
msgstr "Konfigurieren Sie das Feld {0}"
#: packages/ui/primitives/document-flow/document-flow-root.tsx:141
msgid "Continue"
msgstr "Fortsetzen"
#: packages/ui/components/document/document-share-button.tsx:46
msgid "Copied to clipboard"
msgstr "In die Zwischenablage kopiert"
#: packages/ui/primitives/document-flow/add-signature.tsx:360
msgid "Custom Text"
msgstr "Benutzerdefinierter Text"
#: packages/ui/primitives/document-flow/add-fields.tsx:846
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684
msgid "Date"
msgstr "Datum"
#: packages/ui/primitives/document-flow/add-settings.tsx:271
#: packages/ui/primitives/template-flow/add-template-settings.tsx:279
msgid "Date Format"
msgstr "Datumsformat"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:570
msgid "Direct link receiver"
msgstr "Empfänger des direkten Links"
#: packages/ui/components/document/document-global-auth-access-select.tsx:62
#: packages/ui/primitives/document-flow/add-settings.tsx:174
#: packages/ui/primitives/template-flow/add-template-settings.tsx:151
msgid "Document access"
msgstr "Dokumentenzugriff"
#: packages/lib/constants/template.ts:20
msgid "Document Creation"
msgstr "Dokumenterstellung"
#: packages/ui/components/document/document-download-button.tsx:68
msgid "Download"
msgstr "Herunterladen"
#: packages/ui/primitives/document-dropzone.tsx:162
msgid "Drag & drop your PDF here."
msgstr "Ziehen Sie Ihr PDF hierher."
#: packages/ui/primitives/document-flow/add-fields.tsx:976
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814
msgid "Dropdown"
msgstr "Dropdown"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:148
msgid "Dropdown options"
msgstr "Dropdown-Optionen"
#: packages/ui/primitives/document-flow/add-fields.tsx:794
#: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:500
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
msgid "Email"
msgstr "E-Mail"
#: packages/ui/primitives/template-flow/add-template-settings.tsx:184
msgid "Email Options"
msgstr "E-Mail-Optionen"
#: packages/lib/constants/template.ts:8
msgid "Enable Direct Link Signing"
msgstr "Direktlink-Signierung aktivieren"
#: packages/ui/primitives/document-flow/add-signers.tsx:401
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
msgid "Enable signing order"
msgstr "Aktiviere die Signaturreihenfolge"
#: packages/ui/primitives/document-password-dialog.tsx:84
msgid "Enter password"
msgstr "Passwort eingeben"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:216
msgid "Error"
msgstr "Fehler"
#: packages/ui/primitives/document-flow/add-settings.tsx:241
#: packages/ui/primitives/template-flow/add-template-settings.tsx:249
msgid "External ID"
msgstr "Externe ID"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:217
msgid "Failed to save settings."
msgstr "Einstellungen konnten nicht gespeichert werden."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:90
msgid "Field character limit"
msgstr "Zeichenbeschränkung des Feldes"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:107
msgid "Field format"
msgstr "Feldformat"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:50
msgid "Field label"
msgstr "Feldbeschriftung"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:62
msgid "Field placeholder"
msgstr "Feldplatzhalter"
#: packages/ui/components/document/document-global-auth-action-select.tsx:64
msgid "Global recipient action authentication"
msgstr "Globale Empfängerauthentifizierung"
#: packages/ui/primitives/document-flow/document-flow-root.tsx:142
msgid "Go Back"
msgstr "Zurück"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:297
msgid "Green"
msgstr "Grün"
#: packages/lib/constants/recipient-roles.ts:72
msgid "I am a signer of this document"
msgstr "Ich bin ein Unterzeichner dieses Dokuments"
#: packages/lib/constants/recipient-roles.ts:75
msgid "I am a viewer of this document"
msgstr "Ich bin ein Betrachter dieses Dokuments"
#: packages/lib/constants/recipient-roles.ts:73
msgid "I am an approver of this document"
msgstr "Ich bin ein Genehmiger dieses Dokuments"
#: packages/lib/constants/recipient-roles.ts:74
msgid "I am required to receive a copy of this document"
msgstr "Ich bin verpflichtet, eine Kopie dieses Dokuments zu erhalten"
#: packages/lib/constants/recipient-roles.ts:74
#~ msgid "I am required to recieve a copy of this document"
#~ msgstr "I am required to recieve a copy of this document"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:29
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:87
msgid "Inherit authentication method"
msgstr "Authentifizierungsmethode erben"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:64
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:69
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:45
msgid "Label"
msgstr "Beschriftung"
#: packages/lib/constants/teams.ts:11
msgid "Manager"
msgstr "Manager"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:168
msgid "Max"
msgstr "Max"
#: packages/lib/constants/teams.ts:12
msgid "Member"
msgstr "Mitglied"
#: packages/ui/primitives/document-flow/add-subject.tsx:95
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
msgid "Message <0>(Optional)</0>"
msgstr "Nachricht <0>(Optional)</0>"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:156
msgid "Min"
msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:820
#: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:535
#: packages/ui/primitives/document-flow/add-signers.tsx:541
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
msgid "Name"
msgstr "Name"
#: packages/ui/components/recipient/recipient-role-select.tsx:52
msgid "Needs to approve"
msgstr "Muss genehmigen"
#: packages/ui/components/recipient/recipient-role-select.tsx:31
msgid "Needs to sign"
msgstr "Muss unterzeichnen"
#: packages/ui/components/recipient/recipient-role-select.tsx:73
msgid "Needs to view"
msgstr "Muss sehen"
#: packages/ui/primitives/document-flow/add-fields.tsx:631
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497
msgid "No recipient matching this description was found."
msgstr "Kein passender Empfänger mit dieser Beschreibung gefunden."
#: packages/ui/primitives/document-flow/add-fields.tsx:647
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513
msgid "No recipients with this role"
msgstr "Keine Empfänger mit dieser Rolle"
#: packages/ui/components/document/document-global-auth-access-select.tsx:30
#: packages/ui/components/document/document-global-auth-access-select.tsx:43
#: packages/ui/components/document/document-global-auth-action-select.tsx:31
#: packages/ui/components/document/document-global-auth-action-select.tsx:46
msgid "No restrictions"
msgstr "Keine Einschränkungen"
#: packages/ui/primitives/data-table.tsx:148
msgid "No results found"
msgstr "Keine Ergebnisse gefunden"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:30
msgid "No signature field found"
msgstr "Kein Unterschriftsfeld gefunden"
#: packages/ui/primitives/combobox.tsx:60
#: packages/ui/primitives/multi-select-combobox.tsx:153
msgid "No value found."
msgstr "Kein Wert gefunden."
#: packages/ui/primitives/document-flow/add-fields.tsx:898
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736
msgid "Number"
msgstr "Nummer"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:100
msgid "Number format"
msgstr "Zahlenformat"
#: packages/lib/constants/template.ts:9
msgid "Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted."
msgstr "Sobald aktiviert, können Sie einen aktiven Empfänger für die Direktlink-Signierung auswählen oder einen neuen erstellen. Dieser Empfängertyp kann nicht bearbeitet oder gelöscht werden."
#: packages/lib/constants/template.ts:17
msgid "Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them."
msgstr "Sobald Ihre Vorlage eingerichtet ist, teilen Sie den Link überall, wo Sie möchten. Die Person, die den Link öffnet, kann ihre Informationen im Feld für direkte Empfänger eingeben und alle anderen ihr zugewiesenen Felder ausfüllen."
#: packages/ui/primitives/data-table-pagination.tsx:77
msgid "Page {0} of {1}"
msgstr "Seite {0} von {1}"
#: packages/ui/primitives/document-password-dialog.tsx:62
msgid "Password Required"
msgstr "Passwort erforderlich"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:154
msgid "Pick a number"
msgstr "Wählen Sie eine Zahl"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:76
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:81
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:57
msgid "Placeholder"
msgstr "Platzhalter"
#: packages/ui/primitives/document-flow/add-fields.tsx:924
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762
msgid "Radio"
msgstr "Radio"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:133
msgid "Radio values"
msgstr "Radio-Werte"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:184
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:137
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:136
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:122
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:114
msgid "Read only"
msgstr "Nur lesen"
#: packages/ui/components/recipient/recipient-role-select.tsx:95
msgid "Receives copy"
msgstr "Erhält Kopie"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:39
#: packages/ui/primitives/document-flow/add-settings.tsx:215
#: packages/ui/primitives/template-flow/add-template-settings.tsx:169
msgid "Recipient action authentication"
msgstr "Empfängeraktion Authentifizierung"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:283
msgid "Red"
msgstr "Rot"
#: packages/ui/primitives/document-flow/add-settings.tsx:329
#: packages/ui/primitives/template-flow/add-template-settings.tsx:332
msgid "Redirect URL"
msgstr "Weiterleitungs-URL"
#: packages/ui/primitives/document-flow/add-fields.tsx:1027
msgid "Remove"
msgstr "Entfernen"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:174
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:127
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:126
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:112
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:104
msgid "Required field"
msgstr "Pflichtfeld"
#: packages/ui/primitives/data-table-pagination.tsx:55
msgid "Rows per page"
msgstr "Zeilen pro Seite"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:286
msgid "Save"
msgstr "Speichern"
#: packages/ui/primitives/template-flow/add-template-fields.tsx:848
msgid "Save Template"
msgstr "Vorlage speichern"
#: packages/ui/components/common/language-switcher-dialog.tsx:34
msgid "Search languages..."
msgstr "Sprachen suchen..."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:105
msgid "Select"
msgstr "Auswählen"
#: packages/ui/primitives/combobox.tsx:38
msgid "Select an option"
msgstr "Option auswählen"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:137
msgid "Select at least"
msgstr "Wählen Sie mindestens"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:95
msgid "Select default option"
msgstr "Standardoption auswählen"
#: packages/ui/primitives/document-flow/add-subject.tsx:124
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
msgid "Send"
msgstr "Senden"
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:41
msgid "Send Document"
msgstr "Dokument senden"
#: packages/ui/components/document/document-share-button.tsx:135
msgid "Share Signature Card"
msgstr "Unterschriftenkarte teilen"
#: packages/lib/constants/template.ts:16
msgid "Share the Link"
msgstr "Link teilen"
#: packages/ui/primitives/document-flow/add-signers.tsx:680
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
msgid "Show advanced settings"
msgstr "Erweiterte Einstellungen anzeigen"
#: packages/lib/constants/recipient-roles.ts:20
msgid "Sign"
msgstr "Unterschreiben"
#: packages/ui/primitives/document-flow/add-fields.tsx:742
#: packages/ui/primitives/document-flow/add-signature.tsx:323
#: packages/ui/primitives/document-flow/field-icon.tsx:52
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580
msgid "Signature"
msgstr "Unterschrift"
#: packages/lib/constants/recipient-roles.ts:21
msgid "Signed"
msgstr "Unterzeichnet"
#: packages/lib/constants/recipient-roles.ts:23
msgid "Signer"
msgstr "Unterzeichner"
#: packages/lib/constants/recipient-roles.ts:22
msgid "Signing"
msgstr "Unterzeichnung"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:34
msgid "Some signers have not been assigned a signature field. Please assign at least 1 signature field to each signer before proceeding."
msgstr "Einige Unterzeichner haben noch kein Unterschriftsfeld zugewiesen bekommen. Bitte weisen Sie jedem Unterzeichner mindestens ein Unterschriftsfeld zu, bevor Sie fortfahren."
#: packages/ui/components/document/document-share-button.tsx:51
msgid "Something went wrong"
msgstr "Etwas ist schief gelaufen"
#: packages/ui/primitives/data-table.tsx:136
msgid "Something went wrong."
msgstr "Etwas ist schief gelaufen."
#: packages/ui/primitives/document-flow/document-flow-root.tsx:107
msgid "Step <0>{step} of {maxStep}</0>"
msgstr "Schritt <0>{step} von {maxStep}</0>"
#: packages/ui/primitives/document-flow/add-subject.tsx:78
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
msgid "Subject <0>(Optional)</0>"
msgstr "Betreff <0>(Optional)</0>"
#: packages/ui/primitives/document-password-dialog.tsx:97
msgid "Submit"
msgstr "Einreichen"
#: packages/ui/primitives/template-flow/add-template-settings.tsx:134
msgid "Template title"
msgstr "Vorlagentitel"
#: packages/ui/primitives/document-flow/add-fields.tsx:872
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710
msgid "Text"
msgstr "Text"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:44
msgid "The authentication required for recipients to sign fields"
msgstr "Die Authentifizierung, die erforderlich ist, damit Empfänger Felder signieren"
#: packages/ui/components/document/document-global-auth-action-select.tsx:68
msgid "The authentication required for recipients to sign the signature field."
msgstr "Die Authentifizierung, die erforderlich ist, damit Empfänger das Signaturfeld signieren können."
#: packages/ui/components/document/document-global-auth-access-select.tsx:67
msgid "The authentication required for recipients to view the document."
msgstr "Die Authentifizierung, die erforderlich ist, damit Empfänger das Dokument anzeigen können."
#: packages/ui/components/document/document-send-email-message-helper.tsx:31
msgid "The document's name"
msgstr "Der Name des Dokuments"
#: packages/ui/primitives/document-password-dialog.tsx:52
msgid "The password you have entered is incorrect. Please try again."
msgstr "Das eingegebene Passwort ist falsch. Bitte versuchen Sie es erneut."
#: packages/ui/components/recipient/recipient-role-select.tsx:103
msgid "The recipient is not required to take any action and receives a copy of the document after it is completed."
msgstr "Der Empfänger muss keine Aktion ausführen und erhält nach Abschluss eine Kopie des Dokuments."
#: packages/ui/components/recipient/recipient-role-select.tsx:60
msgid "The recipient is required to approve the document for it to be completed."
msgstr "Der Empfänger muss das Dokument genehmigen, damit es abgeschlossen werden kann."
#: packages/ui/components/recipient/recipient-role-select.tsx:39
msgid "The recipient is required to sign the document for it to be completed."
msgstr "Der Empfänger muss das Dokument unterschreiben, damit es abgeschlossen werden kann."
#: packages/ui/components/recipient/recipient-role-select.tsx:81
msgid "The recipient is required to view the document for it to be completed."
msgstr "Der Empfänger muss das Dokument anzeigen, damit es abgeschlossen werden kann."
#: packages/ui/components/document/document-share-button.tsx:52
msgid "The sharing link could not be created at this time. Please try again."
msgstr "Der Freigabelink konnte in diesem Moment nicht erstellt werden. Bitte versuchen Sie es erneut."
#: packages/ui/components/document/document-share-button.tsx:47
msgid "The sharing link has been copied to your clipboard."
msgstr "Der Freigabelink wurde in Ihre Zwischenablage kopiert."
#: packages/ui/components/document/document-send-email-message-helper.tsx:25
msgid "The signer's email"
msgstr "Die E-Mail des Unterzeichners"
#: packages/ui/components/document/document-send-email-message-helper.tsx:19
msgid "The signer's name"
msgstr "Der Name des Unterzeichners"
#: packages/ui/components/document/document-global-auth-action-select.tsx:72
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
msgstr "Dies kann überschrieben werden, indem die Authentifizierungsanforderungen im nächsten Schritt direkt für jeden Empfänger festgelegt werden."
#: packages/ui/primitives/document-flow/add-fields.tsx:703
msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
msgstr "Dieses Dokument wurde bereits an diesen Empfänger gesendet. Sie können diesen Empfänger nicht mehr bearbeiten."
#: packages/ui/primitives/document-password-dialog.tsx:66
msgid "This document is password protected. Please enter the password to view the document."
msgstr "Dieses Dokument ist durch ein Passwort geschützt. Bitte geben Sie das Passwort ein, um das Dokument anzusehen."
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:573
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "Dieses Feld kann nicht geändert oder gelöscht werden. Wenn Sie den direkten Link dieser Vorlage teilen oder zu Ihrem öffentlichen Profil hinzufügen, kann jeder, der darauf zugreift, seinen Namen und seine E-Mail-Adresse eingeben und die ihm zugewiesenen Felder ausfüllen."
#: packages/ui/primitives/document-flow/add-fields.tsx:1007
msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
msgstr ""
#: packages/ui/primitives/document-flow/add-signers.tsx:195
#~ msgid "This signer has already received the document."
#~ msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
#: packages/ui/primitives/document-flow/add-signers.tsx:194
msgid "This signer has already signed the document."
msgstr ""
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings."
msgstr "Dies überschreibt alle globalen Einstellungen."
#: packages/ui/primitives/document-flow/add-settings.tsx:305
#: packages/ui/primitives/template-flow/add-template-settings.tsx:309
msgid "Time Zone"
msgstr "Zeitzone"
#: packages/ui/primitives/document-flow/add-settings.tsx:153
msgid "Title"
msgstr "Titel"
#: packages/ui/primitives/document-flow/add-fields.tsx:990
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828
msgid "To proceed further, please set at least one value for the {0} field."
msgstr "Um fortzufahren, legen Sie bitte mindestens einen Wert für das Feld {0} fest."
#: packages/ui/primitives/document-flow/add-subject.tsx:124
msgid "Update"
msgstr "Aktualisieren"
#: packages/lib/constants/template.ts:13
msgid "Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient."
msgstr "Aktualisieren Sie die Rolle und fügen Sie Felder nach Bedarf für den direkten Empfänger hinzu. Die Person, die den direkten Link verwendet, wird das Dokument als direkter Empfänger unterzeichnen."
#: packages/ui/primitives/document-dropzone.tsx:168
msgid "Upgrade"
msgstr "Upgrade"
#: packages/ui/primitives/document-dropzone.tsx:70
msgid "Upload Template Document"
msgstr "Vorlagendokument hochladen"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:130
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:147
msgid "Validation"
msgstr "Validierung"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:88
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:93
msgid "Value"
msgstr "Wert"
#: packages/lib/constants/recipient-roles.ts:26
msgid "View"
msgstr "View"
#: packages/lib/constants/recipient-roles.ts:27
msgid "Viewed"
msgstr "Viewed"
#: packages/lib/constants/recipient-roles.ts:29
msgid "Viewer"
msgstr "Viewer"
#: packages/lib/constants/recipient-roles.ts:28
msgid "Viewing"
msgstr "Viewing"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:280
#~ msgid "White"
#~ msgstr "White"
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:44
msgid "You are about to send this document to the recipients. Are you sure you want to continue?"
msgstr "Sie sind dabei, dieses Dokument an die Empfänger zu senden. Sind Sie sicher, dass Sie fortfahren möchten?"
#: packages/ui/components/document/document-send-email-message-helper.tsx:11
msgid "You can use the following variables in your message:"
msgstr "Sie können die folgenden Variablen in Ihrer Nachricht verwenden:"
#: packages/ui/primitives/document-dropzone.tsx:43
msgid "You cannot upload documents at this time."
msgstr "Sie können derzeit keine Dokumente hochladen."
#: packages/ui/primitives/document-dropzone.tsx:69
msgid "You have reached your document limit."
msgstr "Sie haben Ihr Dokumentenlimit erreicht."

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@ msgstr ""
"Language: de\n"
"Project-Id-Version: documenso-app\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-08-20 14:03\n"
"PO-Revision-Date: 2024-09-16 14:04\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@ -34,6 +34,10 @@ msgstr "5 Benutzer inbegriffen"
msgid "A 10x better signing experience."
msgstr "Eine 10x bessere Signaturerfahrung."
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:51
msgid "Add document"
msgstr "Dokument hinzufügen"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:201
msgid "Add More Users for {0}"
msgstr "Mehr Benutzer hinzufügen für {0}"
@ -173,6 +177,10 @@ msgstr "E-Mail- und Discord-Support"
msgid "Engagement"
msgstr "Beteiligung"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:64
msgid "Enter your details."
msgstr "Geben Sie Ihre Details ein."
#: apps/marketing/src/components/(marketing)/enterprise.tsx:16
msgid "Enterprise Compliance, License or Technical Needs?"
msgstr "Enterprise-Konformität, Lizenz- oder technische Bedürfnisse?"
@ -422,8 +430,8 @@ msgid "Save $60 or $120"
msgstr "Sparen Sie $60 oder $120"
#: apps/marketing/src/components/(marketing)/i18n-switcher.tsx:47
msgid "Search languages..."
msgstr "Sprachen suchen..."
#~ msgid "Search languages..."
#~ msgstr "Search languages..."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109
msgid "Securely. Our data centers are located in Frankfurt (Germany), giving us the best local privacy laws. We are very aware of the sensitive nature of our data and follow best practices to ensure the security and integrity of the data entrusted to us."
@ -441,6 +449,10 @@ msgstr "Dienstalter"
msgid "Shop"
msgstr "Shop"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:63
msgid "Sign"
msgstr "Signieren"
#: apps/marketing/src/components/(marketing)/header.tsx:72
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:61
msgid "Sign in"
@ -554,6 +566,10 @@ msgstr "Unbegrenzte Dokumente pro Monat"
msgid "Up to 10 recipients per document"
msgstr "Bis zu 10 Empfänger pro Dokument"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:52
msgid "Upload a document and add fields."
msgstr "Laden Sie ein Dokument hoch und fügen Sie Felder hinzu."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:123
msgid "Using our hosted version is the easiest way to get started, you can simply subscribe and start signing your documents. We take care of the infrastructure, so you can focus on your business. Additionally, when using our hosted version you benefit from our trusted signing certificates which helps you to build trust with your customers."
msgstr "Die Nutzung unserer gehosteten Version ist der einfachste Weg, um zu starten. Sie können einfach abonnieren und mit der Unterzeichnung Ihrer Dokumente beginnen. Wir kümmern uns um die Infrastruktur, damit Sie sich auf Ihr Geschäft konzentrieren können. Zudem profitieren Sie bei der Nutzung unserer gehosteten Version von unseren vertrauenswürdigen Signaturzertifikaten, die Ihnen helfen, Vertrauen bei Ihren Kunden aufzubauen."

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -12,3 +12,776 @@ msgstr ""
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
#: packages/ui/primitives/data-table-pagination.tsx:30
msgid "{0} of {1} row(s) selected."
msgstr "{0} of {1} row(s) selected."
#: packages/ui/primitives/data-table-pagination.tsx:41
msgid "{visibleRows, plural, one {Showing # result.} other {Showing # results.}}"
msgstr "{visibleRows, plural, one {Showing # result.} other {Showing # results.}}"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:53
msgid "<0>Inherit authentication method</0> - Use the global action signing authentication method configured in the \"General Settings\" step"
msgstr "<0>Inherit authentication method</0> - Use the global action signing authentication method configured in the \"General Settings\" step"
#: packages/ui/components/document/document-global-auth-action-select.tsx:95
msgid "<0>No restrictions</0> - No authentication required"
msgstr "<0>No restrictions</0> - No authentication required"
#: packages/ui/components/document/document-global-auth-access-select.tsx:77
msgid "<0>No restrictions</0> - The document can be accessed directly by the URL sent to the recipient"
msgstr "<0>No restrictions</0> - The document can be accessed directly by the URL sent to the recipient"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:75
msgid "<0>None</0> - No authentication required"
msgstr "<0>None</0> - No authentication required"
#: packages/ui/components/document/document-global-auth-action-select.tsx:89
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:69
msgid "<0>Require 2FA</0> - The recipient must have an account and 2FA enabled via their settings"
msgstr "<0>Require 2FA</0> - The recipient must have an account and 2FA enabled via their settings"
#: packages/ui/components/document/document-global-auth-access-select.tsx:72
msgid "<0>Require account</0> - The recipient must be signed in to view the document"
msgstr "<0>Require account</0> - The recipient must be signed in to view the document"
#: packages/ui/components/document/document-global-auth-action-select.tsx:83
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:63
msgid "<0>Require passkey</0> - The recipient must have an account and passkey configured via their settings"
msgstr "<0>Require passkey</0> - The recipient must have an account and passkey configured via their settings"
#: packages/ui/primitives/document-dropzone.tsx:69
msgid "Add a document"
msgstr "Add a document"
#: packages/ui/primitives/document-flow/add-settings.tsx:336
#: packages/ui/primitives/template-flow/add-template-settings.tsx:339
msgid "Add a URL to redirect the user to once the document is signed"
msgstr "Add a URL to redirect the user to once the document is signed"
#: packages/ui/primitives/document-flow/add-settings.tsx:248
msgid "Add an external ID to the document. This can be used to identify the document in external systems."
msgstr "Add an external ID to the document. This can be used to identify the document in external systems."
#: packages/ui/primitives/template-flow/add-template-settings.tsx:256
msgid "Add an external ID to the template. This can be used to identify in external systems."
msgstr "Add an external ID to the template. This can be used to identify in external systems."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:177
msgid "Add another option"
msgstr "Add another option"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:230
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:167
msgid "Add another value"
msgstr "Add another value"
#: packages/ui/primitives/document-flow/add-signers.tsx:662
msgid "Add myself"
msgstr "Add myself"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:637
msgid "Add Myself"
msgstr "Add Myself"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:623
msgid "Add Placeholder Recipient"
msgstr "Add Placeholder Recipient"
#: packages/ui/primitives/document-flow/add-signers.tsx:651
msgid "Add Signer"
msgstr "Add Signer"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:70
msgid "Add text"
msgstr "Add text"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:75
msgid "Add text to the field"
msgstr "Add text to the field"
#: packages/lib/constants/teams.ts:10
msgid "Admin"
msgstr "Admin"
#: packages/ui/primitives/document-flow/add-settings.tsx:230
#: packages/ui/primitives/template-flow/add-template-settings.tsx:238
msgid "Advanced Options"
msgstr "Advanced Options"
#: packages/ui/primitives/document-flow/add-fields.tsx:527
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402
msgid "Advanced settings"
msgstr "Advanced settings"
#: packages/lib/constants/template.ts:21
msgid "After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email."
msgstr "After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email."
#: packages/lib/constants/recipient-roles.ts:8
msgid "Approve"
msgstr "Approve"
#: packages/lib/constants/recipient-roles.ts:9
msgid "Approved"
msgstr "Approved"
#: packages/lib/constants/recipient-roles.ts:11
msgid "Approver"
msgstr "Approver"
#: packages/lib/constants/recipient-roles.ts:10
msgid "Approving"
msgstr "Approving"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:276
msgid "Black"
msgstr "Black"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:290
msgid "Blue"
msgstr "Blue"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:287
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:58
msgid "Cancel"
msgstr "Cancel"
#: packages/ui/primitives/document-flow/add-signers.tsx:193
msgid "Cannot remove signer"
msgstr "Cannot remove signer"
#: packages/ui/primitives/document-flow/add-signers.tsx:221
#~ msgid "Cannot update signer because they have already signed a field"
#~ msgstr "Cannot update signer because they have already signed a field"
#: packages/lib/constants/recipient-roles.ts:17
msgid "Cc"
msgstr "Cc"
#: packages/lib/constants/recipient-roles.ts:14
#: packages/lib/constants/recipient-roles.ts:16
msgid "CC"
msgstr "CC"
#: packages/lib/constants/recipient-roles.ts:15
msgid "CC'd"
msgstr "CC'd"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:83
msgid "Character Limit"
msgstr "Character Limit"
#: packages/ui/primitives/document-flow/add-fields.tsx:950
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788
msgid "Checkbox"
msgstr "Checkbox"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:195
msgid "Checkbox values"
msgstr "Checkbox values"
#: packages/ui/primitives/data-table.tsx:156
msgid "Clear filters"
msgstr "Clear filters"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:310
msgid "Clear Signature"
msgstr "Clear Signature"
#: packages/ui/primitives/document-flow/add-signature.tsx:394
msgid "Click to insert field"
msgstr "Click to insert field"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:44
msgid "Close"
msgstr "Close"
#: packages/lib/constants/template.ts:12
msgid "Configure Direct Recipient"
msgstr "Configure Direct Recipient"
#: packages/ui/primitives/document-flow/add-fields.tsx:528
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403
msgid "Configure the {0} field"
msgstr "Configure the {0} field"
#: packages/ui/primitives/document-flow/document-flow-root.tsx:141
msgid "Continue"
msgstr "Continue"
#: packages/ui/components/document/document-share-button.tsx:46
msgid "Copied to clipboard"
msgstr "Copied to clipboard"
#: packages/ui/primitives/document-flow/add-signature.tsx:360
msgid "Custom Text"
msgstr "Custom Text"
#: packages/ui/primitives/document-flow/add-fields.tsx:846
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684
msgid "Date"
msgstr "Date"
#: packages/ui/primitives/document-flow/add-settings.tsx:271
#: packages/ui/primitives/template-flow/add-template-settings.tsx:279
msgid "Date Format"
msgstr "Date Format"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:570
msgid "Direct link receiver"
msgstr "Direct link receiver"
#: packages/ui/components/document/document-global-auth-access-select.tsx:62
#: packages/ui/primitives/document-flow/add-settings.tsx:174
#: packages/ui/primitives/template-flow/add-template-settings.tsx:151
msgid "Document access"
msgstr "Document access"
#: packages/lib/constants/template.ts:20
msgid "Document Creation"
msgstr "Document Creation"
#: packages/ui/components/document/document-download-button.tsx:68
msgid "Download"
msgstr "Download"
#: packages/ui/primitives/document-dropzone.tsx:162
msgid "Drag & drop your PDF here."
msgstr "Drag & drop your PDF here."
#: packages/ui/primitives/document-flow/add-fields.tsx:976
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814
msgid "Dropdown"
msgstr "Dropdown"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:148
msgid "Dropdown options"
msgstr "Dropdown options"
#: packages/ui/primitives/document-flow/add-fields.tsx:794
#: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:500
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
msgid "Email"
msgstr "Email"
#: packages/ui/primitives/template-flow/add-template-settings.tsx:184
msgid "Email Options"
msgstr "Email Options"
#: packages/lib/constants/template.ts:8
msgid "Enable Direct Link Signing"
msgstr "Enable Direct Link Signing"
#: packages/ui/primitives/document-flow/add-signers.tsx:401
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
msgid "Enable signing order"
msgstr "Enable signing order"
#: packages/ui/primitives/document-password-dialog.tsx:84
msgid "Enter password"
msgstr "Enter password"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:216
msgid "Error"
msgstr "Error"
#: packages/ui/primitives/document-flow/add-settings.tsx:241
#: packages/ui/primitives/template-flow/add-template-settings.tsx:249
msgid "External ID"
msgstr "External ID"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:217
msgid "Failed to save settings."
msgstr "Failed to save settings."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:90
msgid "Field character limit"
msgstr "Field character limit"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:107
msgid "Field format"
msgstr "Field format"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:50
msgid "Field label"
msgstr "Field label"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:62
msgid "Field placeholder"
msgstr "Field placeholder"
#: packages/ui/components/document/document-global-auth-action-select.tsx:64
msgid "Global recipient action authentication"
msgstr "Global recipient action authentication"
#: packages/ui/primitives/document-flow/document-flow-root.tsx:142
msgid "Go Back"
msgstr "Go Back"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:297
msgid "Green"
msgstr "Green"
#: packages/lib/constants/recipient-roles.ts:72
msgid "I am a signer of this document"
msgstr "I am a signer of this document"
#: packages/lib/constants/recipient-roles.ts:75
msgid "I am a viewer of this document"
msgstr "I am a viewer of this document"
#: packages/lib/constants/recipient-roles.ts:73
msgid "I am an approver of this document"
msgstr "I am an approver of this document"
#: packages/lib/constants/recipient-roles.ts:74
msgid "I am required to receive a copy of this document"
msgstr "I am required to receive a copy of this document"
#: packages/lib/constants/recipient-roles.ts:74
#~ msgid "I am required to recieve a copy of this document"
#~ msgstr "I am required to recieve a copy of this document"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:29
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:87
msgid "Inherit authentication method"
msgstr "Inherit authentication method"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:64
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:69
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:45
msgid "Label"
msgstr "Label"
#: packages/lib/constants/teams.ts:11
msgid "Manager"
msgstr "Manager"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:168
msgid "Max"
msgstr "Max"
#: packages/lib/constants/teams.ts:12
msgid "Member"
msgstr "Member"
#: packages/ui/primitives/document-flow/add-subject.tsx:95
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
msgid "Message <0>(Optional)</0>"
msgstr "Message <0>(Optional)</0>"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:156
msgid "Min"
msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:820
#: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:535
#: packages/ui/primitives/document-flow/add-signers.tsx:541
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
msgid "Name"
msgstr "Name"
#: packages/ui/components/recipient/recipient-role-select.tsx:52
msgid "Needs to approve"
msgstr "Needs to approve"
#: packages/ui/components/recipient/recipient-role-select.tsx:31
msgid "Needs to sign"
msgstr "Needs to sign"
#: packages/ui/components/recipient/recipient-role-select.tsx:73
msgid "Needs to view"
msgstr "Needs to view"
#: packages/ui/primitives/document-flow/add-fields.tsx:631
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497
msgid "No recipient matching this description was found."
msgstr "No recipient matching this description was found."
#: packages/ui/primitives/document-flow/add-fields.tsx:647
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513
msgid "No recipients with this role"
msgstr "No recipients with this role"
#: packages/ui/components/document/document-global-auth-access-select.tsx:30
#: packages/ui/components/document/document-global-auth-access-select.tsx:43
#: packages/ui/components/document/document-global-auth-action-select.tsx:31
#: packages/ui/components/document/document-global-auth-action-select.tsx:46
msgid "No restrictions"
msgstr "No restrictions"
#: packages/ui/primitives/data-table.tsx:148
msgid "No results found"
msgstr "No results found"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:30
msgid "No signature field found"
msgstr "No signature field found"
#: packages/ui/primitives/combobox.tsx:60
#: packages/ui/primitives/multi-select-combobox.tsx:153
msgid "No value found."
msgstr "No value found."
#: packages/ui/primitives/document-flow/add-fields.tsx:898
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736
msgid "Number"
msgstr "Number"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:100
msgid "Number format"
msgstr "Number format"
#: packages/lib/constants/template.ts:9
msgid "Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted."
msgstr "Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted."
#: packages/lib/constants/template.ts:17
msgid "Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them."
msgstr "Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them."
#: packages/ui/primitives/data-table-pagination.tsx:77
msgid "Page {0} of {1}"
msgstr "Page {0} of {1}"
#: packages/ui/primitives/document-password-dialog.tsx:62
msgid "Password Required"
msgstr "Password Required"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:154
msgid "Pick a number"
msgstr "Pick a number"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:76
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:81
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:57
msgid "Placeholder"
msgstr "Placeholder"
#: packages/ui/primitives/document-flow/add-fields.tsx:924
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762
msgid "Radio"
msgstr "Radio"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:133
msgid "Radio values"
msgstr "Radio values"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:184
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:137
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:136
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:122
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:114
msgid "Read only"
msgstr "Read only"
#: packages/ui/components/recipient/recipient-role-select.tsx:95
msgid "Receives copy"
msgstr "Receives copy"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:39
#: packages/ui/primitives/document-flow/add-settings.tsx:215
#: packages/ui/primitives/template-flow/add-template-settings.tsx:169
msgid "Recipient action authentication"
msgstr "Recipient action authentication"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:283
msgid "Red"
msgstr "Red"
#: packages/ui/primitives/document-flow/add-settings.tsx:329
#: packages/ui/primitives/template-flow/add-template-settings.tsx:332
msgid "Redirect URL"
msgstr "Redirect URL"
#: packages/ui/primitives/document-flow/add-fields.tsx:1027
msgid "Remove"
msgstr "Remove"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:174
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:127
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:126
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:112
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:104
msgid "Required field"
msgstr "Required field"
#: packages/ui/primitives/data-table-pagination.tsx:55
msgid "Rows per page"
msgstr "Rows per page"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:286
msgid "Save"
msgstr "Save"
#: packages/ui/primitives/template-flow/add-template-fields.tsx:848
msgid "Save Template"
msgstr "Save Template"
#: packages/ui/components/common/language-switcher-dialog.tsx:34
msgid "Search languages..."
msgstr "Search languages..."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:105
msgid "Select"
msgstr "Select"
#: packages/ui/primitives/combobox.tsx:38
msgid "Select an option"
msgstr "Select an option"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:137
msgid "Select at least"
msgstr "Select at least"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:95
msgid "Select default option"
msgstr "Select default option"
#: packages/ui/primitives/document-flow/add-subject.tsx:124
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
msgid "Send"
msgstr "Send"
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:41
msgid "Send Document"
msgstr "Send Document"
#: packages/ui/components/document/document-share-button.tsx:135
msgid "Share Signature Card"
msgstr "Share Signature Card"
#: packages/lib/constants/template.ts:16
msgid "Share the Link"
msgstr "Share the Link"
#: packages/ui/primitives/document-flow/add-signers.tsx:680
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
msgid "Show advanced settings"
msgstr "Show advanced settings"
#: packages/lib/constants/recipient-roles.ts:20
msgid "Sign"
msgstr "Sign"
#: packages/ui/primitives/document-flow/add-fields.tsx:742
#: packages/ui/primitives/document-flow/add-signature.tsx:323
#: packages/ui/primitives/document-flow/field-icon.tsx:52
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580
msgid "Signature"
msgstr "Signature"
#: packages/lib/constants/recipient-roles.ts:21
msgid "Signed"
msgstr "Signed"
#: packages/lib/constants/recipient-roles.ts:23
msgid "Signer"
msgstr "Signer"
#: packages/lib/constants/recipient-roles.ts:22
msgid "Signing"
msgstr "Signing"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:34
msgid "Some signers have not been assigned a signature field. Please assign at least 1 signature field to each signer before proceeding."
msgstr "Some signers have not been assigned a signature field. Please assign at least 1 signature field to each signer before proceeding."
#: packages/ui/components/document/document-share-button.tsx:51
msgid "Something went wrong"
msgstr "Something went wrong"
#: packages/ui/primitives/data-table.tsx:136
msgid "Something went wrong."
msgstr "Something went wrong."
#: packages/ui/primitives/document-flow/document-flow-root.tsx:107
msgid "Step <0>{step} of {maxStep}</0>"
msgstr "Step <0>{step} of {maxStep}</0>"
#: packages/ui/primitives/document-flow/add-subject.tsx:78
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
msgid "Subject <0>(Optional)</0>"
msgstr "Subject <0>(Optional)</0>"
#: packages/ui/primitives/document-password-dialog.tsx:97
msgid "Submit"
msgstr "Submit"
#: packages/ui/primitives/template-flow/add-template-settings.tsx:134
msgid "Template title"
msgstr "Template title"
#: packages/ui/primitives/document-flow/add-fields.tsx:872
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710
msgid "Text"
msgstr "Text"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:44
msgid "The authentication required for recipients to sign fields"
msgstr "The authentication required for recipients to sign fields"
#: packages/ui/components/document/document-global-auth-action-select.tsx:68
msgid "The authentication required for recipients to sign the signature field."
msgstr "The authentication required for recipients to sign the signature field."
#: packages/ui/components/document/document-global-auth-access-select.tsx:67
msgid "The authentication required for recipients to view the document."
msgstr "The authentication required for recipients to view the document."
#: packages/ui/components/document/document-send-email-message-helper.tsx:31
msgid "The document's name"
msgstr "The document's name"
#: packages/ui/primitives/document-password-dialog.tsx:52
msgid "The password you have entered is incorrect. Please try again."
msgstr "The password you have entered is incorrect. Please try again."
#: packages/ui/components/recipient/recipient-role-select.tsx:103
msgid "The recipient is not required to take any action and receives a copy of the document after it is completed."
msgstr "The recipient is not required to take any action and receives a copy of the document after it is completed."
#: packages/ui/components/recipient/recipient-role-select.tsx:60
msgid "The recipient is required to approve the document for it to be completed."
msgstr "The recipient is required to approve the document for it to be completed."
#: packages/ui/components/recipient/recipient-role-select.tsx:39
msgid "The recipient is required to sign the document for it to be completed."
msgstr "The recipient is required to sign the document for it to be completed."
#: packages/ui/components/recipient/recipient-role-select.tsx:81
msgid "The recipient is required to view the document for it to be completed."
msgstr "The recipient is required to view the document for it to be completed."
#: packages/ui/components/document/document-share-button.tsx:52
msgid "The sharing link could not be created at this time. Please try again."
msgstr "The sharing link could not be created at this time. Please try again."
#: packages/ui/components/document/document-share-button.tsx:47
msgid "The sharing link has been copied to your clipboard."
msgstr "The sharing link has been copied to your clipboard."
#: packages/ui/components/document/document-send-email-message-helper.tsx:25
msgid "The signer's email"
msgstr "The signer's email"
#: packages/ui/components/document/document-send-email-message-helper.tsx:19
msgid "The signer's name"
msgstr "The signer's name"
#: packages/ui/components/document/document-global-auth-action-select.tsx:72
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
msgstr "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
#: packages/ui/primitives/document-flow/add-fields.tsx:703
msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
msgstr "This document has already been sent to this recipient. You can no longer edit this recipient."
#: packages/ui/primitives/document-password-dialog.tsx:66
msgid "This document is password protected. Please enter the password to view the document."
msgstr "This document is password protected. Please enter the password to view the document."
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:573
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
#: packages/ui/primitives/document-flow/add-fields.tsx:1007
msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
msgstr "This recipient can no longer be modified as they have signed a field, or completed the document."
#: packages/ui/primitives/document-flow/add-signers.tsx:165
#~ msgid "This signer has already received the document."
#~ msgstr "This signer has already received the document."
#: packages/ui/primitives/document-flow/add-signers.tsx:194
msgid "This signer has already signed the document."
msgstr "This signer has already signed the document."
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings."
msgstr "This will override any global settings."
#: packages/ui/primitives/document-flow/add-settings.tsx:305
#: packages/ui/primitives/template-flow/add-template-settings.tsx:309
msgid "Time Zone"
msgstr "Time Zone"
#: packages/ui/primitives/document-flow/add-settings.tsx:153
msgid "Title"
msgstr "Title"
#: packages/ui/primitives/document-flow/add-fields.tsx:990
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828
msgid "To proceed further, please set at least one value for the {0} field."
msgstr "To proceed further, please set at least one value for the {0} field."
#: packages/ui/primitives/document-flow/add-subject.tsx:124
msgid "Update"
msgstr "Update"
#: packages/lib/constants/template.ts:13
msgid "Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient."
msgstr "Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient."
#: packages/ui/primitives/document-dropzone.tsx:168
msgid "Upgrade"
msgstr "Upgrade"
#: packages/ui/primitives/document-dropzone.tsx:70
msgid "Upload Template Document"
msgstr "Upload Template Document"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:130
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:147
msgid "Validation"
msgstr "Validation"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:88
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:93
msgid "Value"
msgstr "Value"
#: packages/lib/constants/recipient-roles.ts:26
msgid "View"
msgstr "View"
#: packages/lib/constants/recipient-roles.ts:27
msgid "Viewed"
msgstr "Viewed"
#: packages/lib/constants/recipient-roles.ts:29
msgid "Viewer"
msgstr "Viewer"
#: packages/lib/constants/recipient-roles.ts:28
msgid "Viewing"
msgstr "Viewing"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:280
#~ msgid "White"
#~ msgstr "White"
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:44
msgid "You are about to send this document to the recipients. Are you sure you want to continue?"
msgstr "You are about to send this document to the recipients. Are you sure you want to continue?"
#: packages/ui/components/document/document-send-email-message-helper.tsx:11
msgid "You can use the following variables in your message:"
msgstr "You can use the following variables in your message:"
#: packages/ui/primitives/document-dropzone.tsx:43
msgid "You cannot upload documents at this time."
msgstr "You cannot upload documents at this time."
#: packages/ui/primitives/document-dropzone.tsx:69
msgid "You have reached your document limit."
msgstr "You have reached your document limit."

File diff suppressed because one or more lines are too long

View File

@ -29,6 +29,10 @@ msgstr "5 Users Included"
msgid "A 10x better signing experience."
msgstr "A 10x better signing experience."
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:51
msgid "Add document"
msgstr "Add document"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:201
msgid "Add More Users for {0}"
msgstr "Add More Users for {0}"
@ -168,6 +172,10 @@ msgstr "Email and Discord Support"
msgid "Engagement"
msgstr "Engagement"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:64
msgid "Enter your details."
msgstr "Enter your details."
#: apps/marketing/src/components/(marketing)/enterprise.tsx:16
msgid "Enterprise Compliance, License or Technical Needs?"
msgstr "Enterprise Compliance, License or Technical Needs?"
@ -417,8 +425,8 @@ msgid "Save $60 or $120"
msgstr "Save $60 or $120"
#: apps/marketing/src/components/(marketing)/i18n-switcher.tsx:47
msgid "Search languages..."
msgstr "Search languages..."
#~ msgid "Search languages..."
#~ msgstr "Search languages..."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109
msgid "Securely. Our data centers are located in Frankfurt (Germany), giving us the best local privacy laws. We are very aware of the sensitive nature of our data and follow best practices to ensure the security and integrity of the data entrusted to us."
@ -436,6 +444,10 @@ msgstr "Seniority"
msgid "Shop"
msgstr "Shop"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:63
msgid "Sign"
msgstr "Sign"
#: apps/marketing/src/components/(marketing)/header.tsx:72
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:61
msgid "Sign in"
@ -549,6 +561,10 @@ msgstr "Unlimited Documents per Month"
msgid "Up to 10 recipients per document"
msgstr "Up to 10 recipients per document"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:52
msgid "Upload a document and add fields."
msgstr "Upload a document and add fields."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:123
msgid "Using our hosted version is the easiest way to get started, you can simply subscribe and start signing your documents. We take care of the infrastructure, so you can focus on your business. Additionally, when using our hosted version you benefit from our trusted signing certificates which helps you to build trust with your customers."
msgstr "Using our hosted version is the easiest way to get started, you can simply subscribe and start signing your documents. We take care of the infrastructure, so you can focus on your business. Additionally, when using our hosted version you benefit from our trusted signing certificates which helps you to build trust with your customers."

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,788 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2024-07-24 13:01+1000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: fr\n"
"Project-Id-Version: documenso-app\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-19 09:18\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Crowdin-Project: documenso-app\n"
"X-Crowdin-Project-ID: 694691\n"
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: common.po\n"
"X-Crowdin-File-ID: 4\n"
#: packages/ui/primitives/data-table-pagination.tsx:30
msgid "{0} of {1} row(s) selected."
msgstr "{0} sur {1} ligne(s) sélectionnée(s)."
#: packages/ui/primitives/data-table-pagination.tsx:41
msgid "{visibleRows, plural, one {Showing # result.} other {Showing # results.}}"
msgstr "{visibleRows, plural, one {Affichage de # résultat.} other {Affichage de # résultats.}}"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:53
msgid "<0>Inherit authentication method</0> - Use the global action signing authentication method configured in the \"General Settings\" step"
msgstr "<0>Hériter du méthode d'authentification</0> - Utiliser la méthode d'authentification de signature d'action globale configurée dans l'étape \"Paramètres Générales\""
#: packages/ui/components/document/document-global-auth-action-select.tsx:95
msgid "<0>No restrictions</0> - No authentication required"
msgstr "<0>Aucune restriction</0> - Aucune authentification requise"
#: packages/ui/components/document/document-global-auth-access-select.tsx:77
msgid "<0>No restrictions</0> - The document can be accessed directly by the URL sent to the recipient"
msgstr "<0>Aucune restriction</0> - Le document peut être accédé directement par l'URL envoyée au destinataire"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:75
msgid "<0>None</0> - No authentication required"
msgstr "<0>Aucun</0> - Aucune authentification requise"
#: packages/ui/components/document/document-global-auth-action-select.tsx:89
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:69
msgid "<0>Require 2FA</0> - The recipient must have an account and 2FA enabled via their settings"
msgstr "<0>Exiger 2FA</0> - Le destinataire doit avoir un compte et 2FA activé via ses paramètres"
#: packages/ui/components/document/document-global-auth-access-select.tsx:72
msgid "<0>Require account</0> - The recipient must be signed in to view the document"
msgstr "<0>Exiger un compte</0> - Le destinataire doit être connecté pour voir le document"
#: packages/ui/components/document/document-global-auth-action-select.tsx:83
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:63
msgid "<0>Require passkey</0> - The recipient must have an account and passkey configured via their settings"
msgstr "<0>Exiger une clé d'accès</0> - Le destinataire doit avoir un compte et une clé d'accès configurée via ses paramètres"
#: packages/ui/primitives/document-dropzone.tsx:69
msgid "Add a document"
msgstr "Ajouter un document"
#: packages/ui/primitives/document-flow/add-settings.tsx:336
#: packages/ui/primitives/template-flow/add-template-settings.tsx:339
msgid "Add a URL to redirect the user to once the document is signed"
msgstr "Ajouter une URL pour rediriger l'utilisateur une fois le document signé"
#: packages/ui/primitives/document-flow/add-settings.tsx:248
msgid "Add an external ID to the document. This can be used to identify the document in external systems."
msgstr "Ajouter un ID externe au document. Cela peut être utilisé pour identifier le document dans des systèmes externes."
#: packages/ui/primitives/template-flow/add-template-settings.tsx:256
msgid "Add an external ID to the template. This can be used to identify in external systems."
msgstr "Ajouter un ID externe au modèle. Cela peut être utilisé pour identifier dans des systèmes externes."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:177
msgid "Add another option"
msgstr "Ajouter une autre option"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:230
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:167
msgid "Add another value"
msgstr "Ajouter une autre valeur"
#: packages/ui/primitives/document-flow/add-signers.tsx:662
msgid "Add myself"
msgstr "Ajoutez-moi"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:637
msgid "Add Myself"
msgstr "Ajoutez-moi"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:623
msgid "Add Placeholder Recipient"
msgstr "Ajouter un destinataire de substitution"
#: packages/ui/primitives/document-flow/add-signers.tsx:651
msgid "Add Signer"
msgstr "Ajouter un signataire"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:70
msgid "Add text"
msgstr "Ajouter du texte"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:75
msgid "Add text to the field"
msgstr "Ajouter du texte au champ"
#: packages/lib/constants/teams.ts:10
msgid "Admin"
msgstr "Administrateur"
#: packages/ui/primitives/document-flow/add-settings.tsx:230
#: packages/ui/primitives/template-flow/add-template-settings.tsx:238
msgid "Advanced Options"
msgstr "Options avancées"
#: packages/ui/primitives/document-flow/add-fields.tsx:527
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402
msgid "Advanced settings"
msgstr "Paramètres avancés"
#: packages/lib/constants/template.ts:21
msgid "After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email."
msgstr "Après soumission, un document sera automatiquement généré et ajouté à votre page de documents. Vous recevrez également une notification par email."
#: packages/lib/constants/recipient-roles.ts:8
msgid "Approve"
msgstr "Approuver"
#: packages/lib/constants/recipient-roles.ts:9
msgid "Approved"
msgstr "Approuvé"
#: packages/lib/constants/recipient-roles.ts:11
msgid "Approver"
msgstr "Approuveur"
#: packages/lib/constants/recipient-roles.ts:10
msgid "Approving"
msgstr "En attente d'approbation"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:276
msgid "Black"
msgstr "Noir"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:290
msgid "Blue"
msgstr "Bleu"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:287
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:58
msgid "Cancel"
msgstr "Annuler"
#: packages/ui/primitives/document-flow/add-signers.tsx:193
msgid "Cannot remove signer"
msgstr "Impossible de retirer le signataire"
#: packages/lib/constants/recipient-roles.ts:17
msgid "Cc"
msgstr "Cc"
#: packages/lib/constants/recipient-roles.ts:14
#: packages/lib/constants/recipient-roles.ts:16
msgid "CC"
msgstr "CC"
#: packages/lib/constants/recipient-roles.ts:15
msgid "CC'd"
msgstr "CC'd"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:83
msgid "Character Limit"
msgstr "Limite de caractères"
#: packages/ui/primitives/document-flow/add-fields.tsx:950
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788
msgid "Checkbox"
msgstr "Case à cocher"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:195
msgid "Checkbox values"
msgstr "Valeurs de case à cocher"
#: packages/ui/primitives/data-table.tsx:156
msgid "Clear filters"
msgstr "Effacer les filtres"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:310
msgid "Clear Signature"
msgstr "Effacer la signature"
#: packages/ui/primitives/document-flow/add-signature.tsx:394
msgid "Click to insert field"
msgstr "Cliquez pour insérer un champ"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:44
msgid "Close"
msgstr "Fermer"
#: packages/lib/constants/template.ts:12
msgid "Configure Direct Recipient"
msgstr "Configurer le destinataire direct"
#: packages/ui/primitives/document-flow/add-fields.tsx:528
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403
msgid "Configure the {0} field"
msgstr "Configurer le champ {0}"
#: packages/ui/primitives/document-flow/document-flow-root.tsx:141
msgid "Continue"
msgstr "Continuer"
#: packages/ui/components/document/document-share-button.tsx:46
msgid "Copied to clipboard"
msgstr "Copié dans le presse-papiers"
#: packages/ui/primitives/document-flow/add-signature.tsx:360
msgid "Custom Text"
msgstr "Texte personnalisé"
#: packages/ui/primitives/document-flow/add-fields.tsx:846
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684
msgid "Date"
msgstr "Date"
#: packages/ui/primitives/document-flow/add-settings.tsx:271
#: packages/ui/primitives/template-flow/add-template-settings.tsx:279
msgid "Date Format"
msgstr "Format de date"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:570
msgid "Direct link receiver"
msgstr "Receveur de lien direct"
#: packages/ui/components/document/document-global-auth-access-select.tsx:62
#: packages/ui/primitives/document-flow/add-settings.tsx:174
#: packages/ui/primitives/template-flow/add-template-settings.tsx:151
msgid "Document access"
msgstr "Accès au document"
#: packages/lib/constants/template.ts:20
msgid "Document Creation"
msgstr "Création de document"
#: packages/ui/components/document/document-download-button.tsx:68
msgid "Download"
msgstr "Télécharger"
#: packages/ui/primitives/document-dropzone.tsx:162
msgid "Drag & drop your PDF here."
msgstr "Faites glisser et déposez votre PDF ici."
#: packages/ui/primitives/document-flow/add-fields.tsx:976
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814
msgid "Dropdown"
msgstr "Liste déroulante"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:148
msgid "Dropdown options"
msgstr "Options de liste déroulante"
#: packages/ui/primitives/document-flow/add-fields.tsx:794
#: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:500
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
msgid "Email"
msgstr "Email"
#: packages/ui/primitives/template-flow/add-template-settings.tsx:184
msgid "Email Options"
msgstr "Options d'email"
#: packages/lib/constants/template.ts:8
msgid "Enable Direct Link Signing"
msgstr "Activer la signature de lien direct"
#: packages/ui/primitives/document-flow/add-signers.tsx:401
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
msgid "Enable signing order"
msgstr "Activer l'ordre de signature"
#: packages/ui/primitives/document-password-dialog.tsx:84
msgid "Enter password"
msgstr "Entrez le mot de passe"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:216
msgid "Error"
msgstr "Erreur"
#: packages/ui/primitives/document-flow/add-settings.tsx:241
#: packages/ui/primitives/template-flow/add-template-settings.tsx:249
msgid "External ID"
msgstr "ID externe"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:217
msgid "Failed to save settings."
msgstr "Échec de l'enregistrement des paramètres."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:90
msgid "Field character limit"
msgstr "Limite de caractères du champ"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:107
msgid "Field format"
msgstr "Format du champ"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:50
msgid "Field label"
msgstr "Étiquette du champ"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:62
msgid "Field placeholder"
msgstr "Espace réservé du champ"
#: packages/ui/components/document/document-global-auth-action-select.tsx:64
msgid "Global recipient action authentication"
msgstr "Authentification d'action de destinataire globale"
#: packages/ui/primitives/document-flow/document-flow-root.tsx:142
msgid "Go Back"
msgstr "Retourner"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:297
msgid "Green"
msgstr "Vert"
#: packages/lib/constants/recipient-roles.ts:72
msgid "I am a signer of this document"
msgstr "Je suis un signataire de ce document"
#: packages/lib/constants/recipient-roles.ts:75
msgid "I am a viewer of this document"
msgstr "Je suis un visualiseur de ce document"
#: packages/lib/constants/recipient-roles.ts:73
msgid "I am an approver of this document"
msgstr "Je suis un approuveur de ce document"
#: packages/lib/constants/recipient-roles.ts:74
msgid "I am required to receive a copy of this document"
msgstr "Je dois recevoir une copie de ce document"
#: packages/lib/constants/recipient-roles.ts:74
#~ msgid "I am required to recieve a copy of this document"
#~ msgstr "I am required to recieve a copy of this document"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:29
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:87
msgid "Inherit authentication method"
msgstr "Hériter de la méthode d'authentification"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:64
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:69
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:45
msgid "Label"
msgstr "Étiquette"
#: packages/lib/constants/teams.ts:11
msgid "Manager"
msgstr "Gestionnaire"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:168
msgid "Max"
msgstr "Max"
#: packages/lib/constants/teams.ts:12
msgid "Member"
msgstr "Membre"
#: packages/ui/primitives/document-flow/add-subject.tsx:95
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
msgid "Message <0>(Optional)</0>"
msgstr "Message <0>(Optionnel)</0>"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:156
msgid "Min"
msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:820
#: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:535
#: packages/ui/primitives/document-flow/add-signers.tsx:541
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
msgid "Name"
msgstr "Nom"
#: packages/ui/components/recipient/recipient-role-select.tsx:52
msgid "Needs to approve"
msgstr "Nécessite une approbation"
#: packages/ui/components/recipient/recipient-role-select.tsx:31
msgid "Needs to sign"
msgstr "Nécessite une signature"
#: packages/ui/components/recipient/recipient-role-select.tsx:73
msgid "Needs to view"
msgstr "Nécessite une visualisation"
#: packages/ui/primitives/document-flow/add-fields.tsx:631
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497
msgid "No recipient matching this description was found."
msgstr "Aucun destinataire correspondant à cette description n'a été trouvé."
#: packages/ui/primitives/document-flow/add-fields.tsx:647
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513
msgid "No recipients with this role"
msgstr "Aucun destinataire avec ce rôle"
#: packages/ui/components/document/document-global-auth-access-select.tsx:30
#: packages/ui/components/document/document-global-auth-access-select.tsx:43
#: packages/ui/components/document/document-global-auth-action-select.tsx:31
#: packages/ui/components/document/document-global-auth-action-select.tsx:46
msgid "No restrictions"
msgstr "Aucune restriction"
#: packages/ui/primitives/data-table.tsx:148
msgid "No results found"
msgstr "Aucun résultat trouvé"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:30
msgid "No signature field found"
msgstr "Aucun champ de signature trouvé"
#: packages/ui/primitives/combobox.tsx:60
#: packages/ui/primitives/multi-select-combobox.tsx:153
msgid "No value found."
msgstr "Aucune valeur trouvée."
#: packages/ui/primitives/document-flow/add-fields.tsx:898
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736
msgid "Number"
msgstr "Numéro"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:100
msgid "Number format"
msgstr "Format de numéro"
#: packages/lib/constants/template.ts:9
msgid "Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted."
msgstr "Une fois activé, vous pouvez sélectionner n'importe quel destinataire actif pour être un destinataire de signature de lien direct ou en créer un nouveau. Ce type de destinataire ne peut pas être modifié ou supprimé."
#: packages/lib/constants/template.ts:17
msgid "Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them."
msgstr "Une fois votre modèle configuré, partagez le lien où vous le souhaitez. La personne qui ouvre le lien pourra saisir ses informations dans le champ de destinataire de lien direct et remplir tout autre champ qui lui est attribué."
#: packages/ui/primitives/data-table-pagination.tsx:77
msgid "Page {0} of {1}"
msgstr "Page {0} sur {1}"
#: packages/ui/primitives/document-password-dialog.tsx:62
msgid "Password Required"
msgstr "Mot de passe requis"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:154
msgid "Pick a number"
msgstr "Choisissez un numéro"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:76
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:81
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:57
msgid "Placeholder"
msgstr "Espace réservé"
#: packages/ui/primitives/document-flow/add-fields.tsx:924
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762
msgid "Radio"
msgstr "Radio"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:133
msgid "Radio values"
msgstr "Valeurs radio"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:184
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:137
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:136
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:122
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:114
msgid "Read only"
msgstr "Lecture seule"
#: packages/ui/components/recipient/recipient-role-select.tsx:95
msgid "Receives copy"
msgstr "Recevoir une copie"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:39
#: packages/ui/primitives/document-flow/add-settings.tsx:215
#: packages/ui/primitives/template-flow/add-template-settings.tsx:169
msgid "Recipient action authentication"
msgstr "Authentification d'action de destinataire"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:283
msgid "Red"
msgstr "Rouge"
#: packages/ui/primitives/document-flow/add-settings.tsx:329
#: packages/ui/primitives/template-flow/add-template-settings.tsx:332
msgid "Redirect URL"
msgstr "URL de redirection"
#: packages/ui/primitives/document-flow/add-fields.tsx:1027
msgid "Remove"
msgstr "Retirer"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:174
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:127
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:126
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:112
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:104
msgid "Required field"
msgstr "Champ requis"
#: packages/ui/primitives/data-table-pagination.tsx:55
msgid "Rows per page"
msgstr "Lignes par page"
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:286
msgid "Save"
msgstr "Sauvegarder"
#: packages/ui/primitives/template-flow/add-template-fields.tsx:848
msgid "Save Template"
msgstr "Sauvegarder le modèle"
#: packages/ui/components/common/language-switcher-dialog.tsx:34
msgid "Search languages..."
msgstr "Rechercher des langues..."
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:105
msgid "Select"
msgstr "Sélectionner"
#: packages/ui/primitives/combobox.tsx:38
msgid "Select an option"
msgstr "Sélectionner une option"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:137
msgid "Select at least"
msgstr "Sélectionnez au moins"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:95
msgid "Select default option"
msgstr "Sélectionner l'option par défaut"
#: packages/ui/primitives/document-flow/add-subject.tsx:124
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
msgid "Send"
msgstr "Envoyer"
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:41
msgid "Send Document"
msgstr "Envoyer le document"
#: packages/ui/components/document/document-share-button.tsx:135
msgid "Share Signature Card"
msgstr "Partager la carte de signature"
#: packages/lib/constants/template.ts:16
msgid "Share the Link"
msgstr "Partager le lien"
#: packages/ui/primitives/document-flow/add-signers.tsx:680
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
msgid "Show advanced settings"
msgstr "Afficher les paramètres avancés"
#: packages/lib/constants/recipient-roles.ts:20
msgid "Sign"
msgstr "Signer"
#: packages/ui/primitives/document-flow/add-fields.tsx:742
#: packages/ui/primitives/document-flow/add-signature.tsx:323
#: packages/ui/primitives/document-flow/field-icon.tsx:52
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580
msgid "Signature"
msgstr "Signature"
#: packages/lib/constants/recipient-roles.ts:21
msgid "Signed"
msgstr "Signé"
#: packages/lib/constants/recipient-roles.ts:23
msgid "Signer"
msgstr "Signataire"
#: packages/lib/constants/recipient-roles.ts:22
msgid "Signing"
msgstr "Signature en cours"
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:34
msgid "Some signers have not been assigned a signature field. Please assign at least 1 signature field to each signer before proceeding."
msgstr "Certains signataires n'ont pas été assignés à un champ de signature. Veuillez assigner au moins 1 champ de signature à chaque signataire avant de continuer."
#: packages/ui/components/document/document-share-button.tsx:51
msgid "Something went wrong"
msgstr "Quelque chose a mal tourné"
#: packages/ui/primitives/data-table.tsx:136
msgid "Something went wrong."
msgstr "Quelque chose a mal tourné."
#: packages/ui/primitives/document-flow/document-flow-root.tsx:107
msgid "Step <0>{step} of {maxStep}</0>"
msgstr "Étape <0>{step} sur {maxStep}</0>"
#: packages/ui/primitives/document-flow/add-subject.tsx:78
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
msgid "Subject <0>(Optional)</0>"
msgstr "Objet <0>(Optionnel)</0>"
#: packages/ui/primitives/document-password-dialog.tsx:97
msgid "Submit"
msgstr "Soumettre"
#: packages/ui/primitives/template-flow/add-template-settings.tsx:134
msgid "Template title"
msgstr "Titre du modèle"
#: packages/ui/primitives/document-flow/add-fields.tsx:872
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710
msgid "Text"
msgstr "Texte"
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:44
msgid "The authentication required for recipients to sign fields"
msgstr "L'authentification requise pour que les destinataires signent des champs"
#: packages/ui/components/document/document-global-auth-action-select.tsx:68
msgid "The authentication required for recipients to sign the signature field."
msgstr "L'authentification requise pour que les destinataires signent le champ de signature."
#: packages/ui/components/document/document-global-auth-access-select.tsx:67
msgid "The authentication required for recipients to view the document."
msgstr "L'authentification requise pour que les destinataires visualisent le document."
#: packages/ui/components/document/document-send-email-message-helper.tsx:31
msgid "The document's name"
msgstr "Le nom du document"
#: packages/ui/primitives/document-password-dialog.tsx:52
msgid "The password you have entered is incorrect. Please try again."
msgstr "Le mot de passe que vous avez entré est incorrect. Veuillez réessayer."
#: packages/ui/components/recipient/recipient-role-select.tsx:103
msgid "The recipient is not required to take any action and receives a copy of the document after it is completed."
msgstr "Le destinataire n'est pas tenu de prendre des mesures et reçoit une copie du document après son achèvement."
#: packages/ui/components/recipient/recipient-role-select.tsx:60
msgid "The recipient is required to approve the document for it to be completed."
msgstr "Le destinataire doit approuver le document pour qu'il soit complété."
#: packages/ui/components/recipient/recipient-role-select.tsx:39
msgid "The recipient is required to sign the document for it to be completed."
msgstr "Le destinataire doit signer le document pour qu'il soit complété."
#: packages/ui/components/recipient/recipient-role-select.tsx:81
msgid "The recipient is required to view the document for it to be completed."
msgstr "Le destinataire doit visualiser le document pour qu'il soit complété."
#: packages/ui/components/document/document-share-button.tsx:52
msgid "The sharing link could not be created at this time. Please try again."
msgstr "Le lien de partage n'a pas pu être créé pour le moment. Veuillez réessayer."
#: packages/ui/components/document/document-share-button.tsx:47
msgid "The sharing link has been copied to your clipboard."
msgstr "Le lien de partage a été copié dans votre presse-papiers."
#: packages/ui/components/document/document-send-email-message-helper.tsx:25
msgid "The signer's email"
msgstr "L'email du signataire"
#: packages/ui/components/document/document-send-email-message-helper.tsx:19
msgid "The signer's name"
msgstr "Le nom du signataire"
#: packages/ui/components/document/document-global-auth-action-select.tsx:72
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
msgstr "Cela peut être remplacé par le paramétrage direct des exigences d'authentification pour chaque destinataire à l'étape suivante."
#: packages/ui/primitives/document-flow/add-fields.tsx:703
msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
msgstr "Ce document a déjà été envoyé à ce destinataire. Vous ne pouvez plus modifier ce destinataire."
#: packages/ui/primitives/document-password-dialog.tsx:66
msgid "This document is password protected. Please enter the password to view the document."
msgstr "Ce document est protégé par mot de passe. Veuillez entrer le mot de passe pour visualiser le document."
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:573
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "Ce champ ne peut pas être modifié ou supprimé. Lorsque vous partagez le lien direct de ce modèle ou l'ajoutez à votre profil public, toute personne qui y accède peut saisir son nom et son email, et remplir les champs qui lui sont attribués."
#: packages/ui/primitives/document-flow/add-fields.tsx:1007
msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
msgstr ""
#: packages/ui/primitives/document-flow/add-signers.tsx:195
#~ msgid "This signer has already received the document."
#~ msgstr "Ce signataire a déjà reçu le document."
#: packages/ui/primitives/document-flow/add-signers.tsx:194
msgid "This signer has already signed the document."
msgstr ""
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings."
msgstr "Cela remplacera tous les paramètres globaux."
#: packages/ui/primitives/document-flow/add-settings.tsx:305
#: packages/ui/primitives/template-flow/add-template-settings.tsx:309
msgid "Time Zone"
msgstr "Fuseau horaire"
#: packages/ui/primitives/document-flow/add-settings.tsx:153
msgid "Title"
msgstr "Titre"
#: packages/ui/primitives/document-flow/add-fields.tsx:990
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828
msgid "To proceed further, please set at least one value for the {0} field."
msgstr "Pour continuer, veuillez définir au moins une valeur pour le champ {0}."
#: packages/ui/primitives/document-flow/add-subject.tsx:124
msgid "Update"
msgstr "Mettre à jour"
#: packages/lib/constants/template.ts:13
msgid "Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient."
msgstr "Mettez à jour le rôle et ajoutez des champs selon les besoins pour le destinataire direct. L'individu qui utilise le lien direct signera le document en tant que destinataire direct."
#: packages/ui/primitives/document-dropzone.tsx:168
msgid "Upgrade"
msgstr "Améliorer"
#: packages/ui/primitives/document-dropzone.tsx:70
msgid "Upload Template Document"
msgstr "Télécharger le document modèle"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:130
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:147
msgid "Validation"
msgstr "Validation"
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:88
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:93
msgid "Value"
msgstr "Valeur"
#: packages/lib/constants/recipient-roles.ts:26
msgid "View"
msgstr "Vue"
#: packages/lib/constants/recipient-roles.ts:27
msgid "Viewed"
msgstr "Vu"
#: packages/lib/constants/recipient-roles.ts:29
msgid "Viewer"
msgstr "Visiteur"
#: packages/lib/constants/recipient-roles.ts:28
msgid "Viewing"
msgstr "Visionnage"
#: packages/ui/primitives/signature-pad/signature-pad.tsx:280
#~ msgid "White"
#~ msgstr "White"
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:44
msgid "You are about to send this document to the recipients. Are you sure you want to continue?"
msgstr "Vous êtes sur le point d'envoyer ce document aux destinataires. Êtes-vous sûr de vouloir continuer ?"
#: packages/ui/components/document/document-send-email-message-helper.tsx:11
msgid "You can use the following variables in your message:"
msgstr "Vous pouvez utiliser les variables suivantes dans votre message :"
#: packages/ui/primitives/document-dropzone.tsx:43
msgid "You cannot upload documents at this time."
msgstr "Vous ne pouvez pas télécharger de documents pour le moment."
#: packages/ui/primitives/document-dropzone.tsx:69
msgid "You have reached your document limit."
msgstr "Vous avez atteint votre limite de documents."

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,619 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2024-07-24 13:01+1000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: fr\n"
"Project-Id-Version: documenso-app\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-19 09:18\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Crowdin-Project: documenso-app\n"
"X-Crowdin-Project-ID: 694691\n"
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: marketing.po\n"
"X-Crowdin-File-ID: 6\n"
#: apps/marketing/src/app/(marketing)/blog/page.tsx:45
msgid "{0}"
msgstr "{0}"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:100
msgid "5 standard documents per month"
msgstr "5 documents standard par mois"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:198
msgid "5 Users Included"
msgstr "5 utilisateurs inclus"
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:34
msgid "A 10x better signing experience."
msgstr "Une expérience de signature 10 fois meilleure."
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:51
msgid "Add document"
msgstr "Ajouter un document"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:201
msgid "Add More Users for {0}"
msgstr "Ajouter plus d'utilisateurs pour {0}"
#: apps/marketing/src/app/(marketing)/open/page.tsx:165
msgid "All our metrics, finances, and learnings are public. We believe in transparency and want to share our journey with you. You can read more about why here: <0>Announcing Open Metrics</0>"
msgstr "Tous nos indicateurs, finances et apprentissages sont publics. Nous croyons en la transparence et souhaitons partager notre parcours avec vous. Vous pouvez en lire plus sur pourquoi ici : <0>Annonce de Open Metrics</0>"
#: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:58
#: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:65
msgid "Amount Raised"
msgstr "Montant levé"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:145
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:189
msgid "API Access"
msgstr "Accès API"
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:67
msgid "Beautiful."
msgstr "Beau."
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:69
msgid "Because signing should be celebrated. Thats why we care about the smallest detail in our product."
msgstr "Parce que la signature doit être célébrée. C'est pourquoi nous nous soucions du moindre détail dans notre produit."
#: apps/marketing/src/components/(marketing)/footer.tsx:35
#: apps/marketing/src/components/(marketing)/header.tsx:57
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:36
msgid "Blog"
msgstr "Blog"
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:64
msgid "Build on top."
msgstr "Construire dessus."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:163
msgid "Can I use Documenso commercially?"
msgstr "Puis-je utiliser Documenso commercialement ?"
#: apps/marketing/src/components/(marketing)/footer.tsx:42
msgid "Careers"
msgstr "Carrières"
#: apps/marketing/src/components/(marketing)/footer.tsx:36
msgid "Changelog"
msgstr "Changelog"
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:85
msgid "Choose a template from the community app store. Or submit your own template for others to use."
msgstr "Choisissez un modèle dans la boutique d'applications communautaires. Ou soumettez votre propre modèle pour que d'autres puissent l'utiliser."
#: apps/marketing/src/app/(marketing)/open/page.tsx:219
msgid "Community"
msgstr "Communauté"
#: apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart.tsx:55
msgid "Completed Documents"
msgstr "Documents complets"
#: apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart.tsx:33
msgid "Completed Documents per Month"
msgstr "Documents complets par mois"
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:65
msgid "Connections"
msgstr "Connexions"
#: apps/marketing/src/components/(marketing)/enterprise.tsx:35
msgid "Contact Us"
msgstr "Contactez-nous"
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:67
msgid "Create connections and automations with Zapier and more to integrate with your favorite tools."
msgstr "Créez des connexions et des automatisations avec Zapier et plus encore pour intégrer vos outils préférés."
#: apps/marketing/src/components/(marketing)/call-to-action.tsx:23
msgid "Create your account and start using state-of-the-art document signing. Open and beautiful signing is within your grasp."
msgstr "Créez votre compte et commencez à utiliser la signature de documents à la pointe de la technologie. Une signature ouverte et belle est à votre portée."
#: apps/marketing/src/app/(marketing)/open/tooltip.tsx:35
msgid "Customers with an Active Subscriptions."
msgstr "Clients avec un abonnement actif."
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:33
msgid "Customise and expand."
msgstr "Personnaliser et étendre."
#: apps/marketing/src/components/(marketing)/footer.tsx:38
msgid "Design"
msgstr "Conception"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:44
msgid "Designed for every stage of your journey."
msgstr "Conçu pour chaque étape de votre parcours."
#: apps/marketing/src/components/(marketing)/carousel.tsx:40
msgid "Direct Link"
msgstr "Lien Direct"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:181
msgid "Documenso is a community effort to create an open and vibrant ecosystem around a tool, everybody is free to use and adapt. By being truly open we want to create trusted infrastructure for the future of the internet."
msgstr "Documenso est un effort collectif pour créer un écosystème ouvert et dynamique autour d'un outil, tout le monde est libre de l'utiliser et de l'adapter. En étant vraiment ouvert, nous voulons créer une infrastructure de confiance pour l'avenir d'Internet."
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:28
msgid "Documenso on X"
msgstr "Documenso sur X"
#: apps/marketing/src/components/(marketing)/hero.tsx:104
msgid "Document signing,<0/>finally open source."
msgstr "Signature de documents,<0/> enfin open source."
#: apps/marketing/src/components/(marketing)/footer.tsx:33
#: apps/marketing/src/components/(marketing)/header.tsx:50
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:28
msgid "Documentation"
msgstr "Documentation"
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:110
msgid "Easily embed Documenso into your product. Simply copy and paste our react widget into your application."
msgstr "Intégrez facilement Documenso dans votre produit. Il vous suffit de copier et coller notre widget React dans votre application."
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:42
#~ msgid "Easy Sharing (Soon)."
#~ msgstr "Easy Sharing (Soon)."
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:46
msgid "Easy Sharing."
msgstr "Partage facile."
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:148
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:192
msgid "Email and Discord Support"
msgstr "Support par e-mail et Discord"
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:43
msgid "Engagement"
msgstr "Engagement"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:64
msgid "Enter your details."
msgstr "Entrez vos détails."
#: apps/marketing/src/components/(marketing)/enterprise.tsx:16
msgid "Enterprise Compliance, License or Technical Needs?"
msgstr "Conformité des entreprises, besoins en licence ou techniques ?"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:128
msgid "Everything you need for a great signing experience."
msgstr "Tout ce dont vous avez besoin pour une excellente expérience de signature."
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:45
msgid "Fast."
msgstr "Rapide."
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:36
msgid "Faster, smarter and more beautiful."
msgstr "Plus rapide, plus intelligent et plus beau."
#: apps/marketing/src/app/(marketing)/open/page.tsx:210
msgid "Finances"
msgstr "Finances"
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:38
msgid "Follow us on X"
msgstr "Suivez-nous sur X"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:172
msgid "For companies looking to scale across multiple teams."
msgstr "Pour les entreprises cherchant à se développer au sein de plusieurs équipes."
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:85
msgid "For small teams and individuals with basic needs."
msgstr "Pour les petites équipes et les individus ayant des besoins de base."
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:80
msgid "Free"
msgstr "Gratuit"
#: apps/marketing/src/app/(marketing)/blog/page.tsx:26
msgid "From the blog"
msgstr "Du blog"
#: apps/marketing/src/app/(marketing)/open/data.ts:9
#: apps/marketing/src/app/(marketing)/open/data.ts:17
#: apps/marketing/src/app/(marketing)/open/data.ts:33
#: apps/marketing/src/app/(marketing)/open/data.ts:41
#: apps/marketing/src/app/(marketing)/open/data.ts:49
msgid "Full-Time"
msgstr "Temps plein"
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:87
msgid "Get paid (Soon)."
msgstr "Recevez une rémunération (Bientôt)."
#: apps/marketing/src/components/(marketing)/call-to-action.tsx:31
msgid "Get started"
msgstr "Commencez"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:75
msgid "Get Started"
msgstr "Commencez"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:47
msgid "Get started today."
msgstr "Commencez aujourd'hui."
#: apps/marketing/src/app/(marketing)/blog/page.tsx:30
msgid "Get the latest news from Documenso, including product updates, team announcements and more!"
msgstr "Obtenez les dernières nouvelles de Documenso, y compris les mises à jour de produits, les annonces d'équipe et plus encore !"
#: apps/marketing/src/app/(marketing)/open/page.tsx:233
msgid "GitHub: Total Merged PRs"
msgstr "GitHub : Total des PRs fusionnées"
#: apps/marketing/src/app/(marketing)/open/page.tsx:251
msgid "GitHub: Total Open Issues"
msgstr "GitHub : Total des problèmes ouverts"
#: apps/marketing/src/app/(marketing)/open/page.tsx:225
msgid "GitHub: Total Stars"
msgstr "GitHub : Nombre total d'étoiles"
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:23
msgid "Global Salary Bands"
msgstr "Bandes de salaire globales"
#: apps/marketing/src/app/(marketing)/open/page.tsx:261
msgid "Growth"
msgstr "Croissance"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:134
msgid "How can I contribute?"
msgstr "Comment puis-je contribuer ?"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:105
msgid "How do you handle my data?"
msgstr "Comment gérez-vous mes données ?"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:118
msgid "Individual"
msgstr "Individuel"
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:89
msgid "Integrated payments with Stripe so you dont have to worry about getting paid."
msgstr "Paiements intégrés avec Stripe afin que vous n'ayez pas à vous soucier d'être payé."
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:35
msgid "Integrates with all your favourite tools."
msgstr "S'intègre à tous vos outils préférés."
#: apps/marketing/src/app/(marketing)/open/page.tsx:289
msgid "Is there more?"
msgstr "Y a-t-il plus ?"
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:44
msgid "Its up to you. Either clone our repository or rely on our easy to use hosting solution."
msgstr "C'est à vous de décider. Soit vous clonez notre dépôt, soit vous vous fiez à notre solution d'hébergement simple à utiliser."
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:49
msgid "Join Date"
msgstr "Date d'adhésion"
#: apps/marketing/src/components/(marketing)/call-to-action.tsx:19
msgid "Join the Open Signing Movement"
msgstr "Rejoignez le mouvement de signature ouverte"
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:46
msgid "Location"
msgstr "Emplacement"
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:66
msgid "Make it your own through advanced customization and adjustability."
msgstr "Faites-en votre propre grâce à une personnalisation avancée et un ajustement."
#: apps/marketing/src/app/(marketing)/open/page.tsx:199
msgid "Merged PR's"
msgstr "PRs fusionnées"
#: apps/marketing/src/app/(marketing)/open/page.tsx:234
msgid "Merged PRs"
msgstr "PRs fusionnées"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:40
msgid "Monthly"
msgstr "Mensuel"
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:34
msgid "Name"
msgstr "Nom"
#: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:30
#: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:43
#: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:52
msgid "New Users"
msgstr "Nouveaux utilisateurs"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:106
msgid "No credit card required"
msgstr "Aucune carte de crédit requise"
#: apps/marketing/src/components/(marketing)/callout.tsx:29
#: apps/marketing/src/components/(marketing)/hero.tsx:125
msgid "No Credit Card required"
msgstr "Aucune carte de crédit requise"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:61
msgid "None of these work for you? Try self-hosting!"
msgstr "Aucune de ces options ne fonctionne pour vous ? Essayez l'hébergement autonome !"
#: apps/marketing/src/app/(marketing)/open/page.tsx:194
#: apps/marketing/src/app/(marketing)/open/page.tsx:252
msgid "Open Issues"
msgstr "Problèmes ouverts"
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:42
msgid "Open Source or Hosted."
msgstr "Open Source ou hébergé."
#: apps/marketing/src/app/(marketing)/open/page.tsx:161
#: apps/marketing/src/components/(marketing)/footer.tsx:37
#: apps/marketing/src/components/(marketing)/header.tsx:64
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:40
msgid "Open Startup"
msgstr "Startup ouverte"
#: apps/marketing/src/components/(marketing)/footer.tsx:41
msgid "OSS Friends"
msgstr "Amis OSS"
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:91
msgid "Our custom templates come with smart rules that can help you save time and energy."
msgstr "Nos modèles personnalisés sont dotés de règles intelligentes qui peuvent vous aider à gagner du temps et de l'énergie."
#: apps/marketing/src/components/(marketing)/enterprise.tsx:20
msgid "Our Enterprise License is great for large organizations looking to switch to Documenso for all their signing needs. It's available for our cloud offering as well as self-hosted setups and offers a wide range of compliance and Adminstration Features."
msgstr "Notre licence entreprise est idéale pour les grandes organisations cherchant à passer à Documenso pour tous leurs besoins de signature. Elle est disponible pour notre offre cloud ainsi que pour des configurations auto-hébergées et propose un large éventail de fonctionnalités de conformité et d'administration."
#: apps/marketing/src/components/(marketing)/enterprise.tsx:20
#~ msgid "Our Enterprise License is great large organizations looking to switch to Documenso for all their signing needs. It's availible for our cloud offering as well as self-hosted setups and offer a wide range of compliance and Adminstration Features."
#~ msgstr "Our Enterprise License is great large organizations looking to switch to Documenso for all their signing needs. It's availible for our cloud offering as well as self-hosted setups and offer a wide range of compliance and Adminstration Features."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:65
msgid "Our self-hosted option is great for small teams and individuals who need a simple solution. You can use our docker based setup to get started in minutes. Take control with full customizability and data ownership."
msgstr "Notre option auto-hébergée est idéale pour les petites équipes et les individus qui ont besoin d'une solution simple. Vous pouvez utiliser notre configuration basée sur Docker pour commencer en quelques minutes. Prenez le contrôle avec une personnalisation complète et une propriété des données."
#: apps/marketing/src/app/(marketing)/open/data.ts:25
msgid "Part-Time"
msgstr "Temps partiel"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:151
msgid "Premium Profile Name"
msgstr "Nom de profil premium"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:40
#: apps/marketing/src/components/(marketing)/footer.tsx:31
#: apps/marketing/src/components/(marketing)/header.tsx:42
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:24
msgid "Pricing"
msgstr "Prix"
#: apps/marketing/src/components/(marketing)/footer.tsx:43
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:53
msgid "Privacy"
msgstr "Confidentialité"
#: apps/marketing/src/components/(marketing)/carousel.tsx:58
msgid "Profile"
msgstr "Profil"
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:108
msgid "React Widget (Soon)."
msgstr "Widget React (Bientôt)."
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:48
msgid "Receive your personal link to share with everyone you care about."
msgstr "Recevez votre lien personnel à partager avec tous ceux qui vous tiennent à cœur."
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:37
msgid "Role"
msgstr "Rôle"
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:37
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:40
msgid "Salary"
msgstr "Salaire"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:62
msgid "Save $60 or $120"
msgstr "Économisez 60 $ ou 120 $"
#: apps/marketing/src/components/(marketing)/i18n-switcher.tsx:47
#~ msgid "Search languages..."
#~ msgstr "Search languages..."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109
msgid "Securely. Our data centers are located in Frankfurt (Germany), giving us the best local privacy laws. We are very aware of the sensitive nature of our data and follow best practices to ensure the security and integrity of the data entrusted to us."
msgstr "De manière sécurisée. Nos centres de données sont situés à Francfort (Allemagne), ce qui nous permet de bénéficier des meilleures lois locales sur la confidentialité. Nous sommes très conscients de la nature sensible de nos données et suivons les meilleures pratiques pour garantir la sécurité et l'intégrité des données qui nous sont confiées."
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:37
msgid "Send, connect, receive and embed everywhere."
msgstr "Envoyer, connecter, recevoir et intégrer partout."
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:34
msgid "Seniority"
msgstr "Ancienneté"
#: apps/marketing/src/components/(marketing)/footer.tsx:39
msgid "Shop"
msgstr "Boutique"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:63
msgid "Sign"
msgstr "Signer"
#: apps/marketing/src/components/(marketing)/header.tsx:72
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:61
msgid "Sign in"
msgstr "Se connecter"
#: apps/marketing/src/components/(marketing)/header.tsx:77
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:57
msgid "Sign up"
msgstr "S'inscrire"
#: apps/marketing/src/components/(marketing)/carousel.tsx:22
msgid "Signing Process"
msgstr "Processus de signature"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:94
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:136
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:180
msgid "Signup Now"
msgstr "Inscrivez-vous maintenant"
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:89
msgid "Smart."
msgstr "Intelligent."
#: apps/marketing/src/components/(marketing)/hero.tsx:132
msgid "Star on GitHub"
msgstr "Étoile sur GitHub"
#: apps/marketing/src/app/(marketing)/open/page.tsx:226
msgid "Stars"
msgstr "Étoiles"
#: apps/marketing/src/components/(marketing)/footer.tsx:40
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:44
msgid "Status"
msgstr "Statut"
#: apps/marketing/src/components/(marketing)/footer.tsx:34
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:48
msgid "Support"
msgstr "Soutien"
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:26
msgid "Team"
msgstr "Équipe"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:195
msgid "Team Inbox"
msgstr "Boîte de réception de l'équipe"
#: apps/marketing/src/components/(marketing)/carousel.tsx:28
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:162
msgid "Teams"
msgstr "Équipes"
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:83
msgid "Template Store (Soon)."
msgstr "Boutique de modèles (Bientôt)."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:138
msgid "That's awesome. You can take a look at the current <0>Issues</0> and join our <1>Discord Community</1> to keep up to date, on what the current priorities are. In any case, we are an open community and welcome all input, technical and non-technical ❤️"
msgstr "C'est génial. Vous pouvez consulter les <0>Problèmes</0> actuels et rejoindre notre <1>Communauté Discord</1> pour rester à jour sur ce qui est actuellement prioritaire. Dans tous les cas, nous sommes une communauté ouverte et accueillons toutes les contributions, techniques et non techniques ❤️"
#: apps/marketing/src/app/(marketing)/open/page.tsx:293
msgid "This page is evolving as we learn what makes a great signing company. We'll update it when we have more to share."
msgstr "Cette page évolue à mesure que nous apprenons ce qui fait une grande entreprise de signature. Nous la mettrons à jour lorsque nous aurons plus à partager."
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:31
msgid "Title"
msgstr "Titre"
#: apps/marketing/src/app/(marketing)/open/total-signed-documents-chart.tsx:30
#: apps/marketing/src/app/(marketing)/open/total-signed-documents-chart.tsx:55
msgid "Total Completed Documents"
msgstr "Documents totalisés complétés"
#: apps/marketing/src/app/(marketing)/open/page.tsx:267
#: apps/marketing/src/app/(marketing)/open/page.tsx:268
msgid "Total Customers"
msgstr "Total des clients"
#: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:29
msgid "Total Funding Raised"
msgstr "Total des fonds levés"
#: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:30
#: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:43
#: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:52
msgid "Total Users"
msgstr "Total des utilisateurs"
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:31
msgid "Truly your own."
msgstr "Vraiment le vôtre."
#: apps/marketing/src/components/(marketing)/callout.tsx:27
#: apps/marketing/src/components/(marketing)/hero.tsx:123
msgid "Try our Free Plan"
msgstr "Essayez notre plan gratuit"
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:20
msgid "Twitter Stats"
msgstr "Statistiques Twitter"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:142
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:186
msgid "Unlimited Documents per Month"
msgstr "Documents illimités par mois"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:103
msgid "Up to 10 recipients per document"
msgstr "Jusqu'à 10 destinataires par document"
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:52
msgid "Upload a document and add fields."
msgstr "Téléchargez un document et ajoutez des champs."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:123
msgid "Using our hosted version is the easiest way to get started, you can simply subscribe and start signing your documents. We take care of the infrastructure, so you can focus on your business. Additionally, when using our hosted version you benefit from our trusted signing certificates which helps you to build trust with your customers."
msgstr "Utiliser notre version hébergée est le moyen le plus simple de commencer, vous pouvez simplement vous abonner et commencer à signer vos documents. Nous nous occupons de l'infrastructure, vous pouvez vous concentrer sur votre entreprise. De plus, en utilisant notre version hébergée, vous bénéficiez de nos certificats de signature de confiance, ce qui vous aide à instaurer une relation de confiance avec vos clients."
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:33
msgid "View all stats"
msgstr "Voir toutes les statistiques"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:195
msgid "We are happy to assist you at <0>support@documenso.com</0> or <1>in our Discord-Support-Channel</1> please message either Lucas or Timur to get added to the channel if you are not already a member."
msgstr "Nous sommes heureux de vous aider à <0>support@documenso.com</0> ou <1>dans notre canal de support Discord</1>, veuillez envoyer un message à Lucas ou Timur pour être ajouté au canal si vous n'êtes pas déjà membre."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:89
msgid "What is the difference between the plans?"
msgstr "Quelle est la différence entre les plans ?"
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:47
msgid "When it comes to sending or receiving a contract, you can count on lightning-fast speeds."
msgstr "En ce qui concerne l'envoi ou la réception d'un contrat, vous pouvez compter sur des vitesses ultrarapides."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:191
msgid "Where can I get support?"
msgstr "Où puis-je obtenir du support ?"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:177
msgid "Why should I prefer Documenso over DocuSign or some other signing tool?"
msgstr "Pourquoi devrais-je préférer Documenso à DocuSign ou à un autre outil de signature ?"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:119
msgid "Why should I use your hosting service?"
msgstr "Pourquoi devrais-je utiliser votre service d'hébergement ?"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:60
msgid "Yearly"
msgstr "Annuel"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:167
msgid "Yes! Documenso is offered under the GNU AGPL V3 open source license. This means you can use it for free and even modify it to fit your needs, as long as you publish your changes under the same license."
msgstr "Oui ! Documenso est proposé sous la licence open source GNU AGPL V3. Cela signifie que vous pouvez l'utiliser gratuitement et même le modifier pour répondre à vos besoins, tant que vous publiez vos modifications sous la même licence."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:93
msgid "You can self-host Documenso for free or use our ready-to-use hosted version. The hosted version comes with additional support, painless scalability and more. Early adopters will get access to all features we build this year, for no additional cost! Forever! Yes, that includes multiple users per account later. If you want Documenso for your enterprise, we are happy to talk about your needs."
msgstr "Vous pouvez auto-héberger Documenso gratuitement ou utiliser notre version hébergée prête à l'emploi. La version hébergée est accompagnée d'une assistance supplémentaire, d'une montée en charge sans effort et d'autres avantages. Les premiers adoptants auront accès à toutes les fonctionnalités que nous construirons cette année, sans coût supplémentaire ! Pour toujours ! Oui, cela inclut plusieurs utilisateurs par compte à l'avenir. Si vous souhaitez Documenso pour votre entreprise, nous serons heureux de discuter de vos besoins."
#: apps/marketing/src/components/(marketing)/carousel.tsx:265
msgid "Your browser does not support the video tag."
msgstr "Votre navigateur ne prend pas en charge la balise vidéo."

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@ export const ZDocumentAuditLogTypeSchema = z.enum([
'DOCUMENT_RESTORED', // When the document is restored.
'DOCUMENT_FIELD_INSERTED', // When a field is inserted (signed/approved/etc) by a recipient.
'DOCUMENT_FIELD_UNINSERTED', // When a field is uninserted by a recipient.
'DOCUMENT_VISIBILITY_UPDATED', // When the document visibility scope is updated
'DOCUMENT_GLOBAL_AUTH_ACCESS_UPDATED', // When the global access authentication is updated.
'DOCUMENT_GLOBAL_AUTH_ACTION_UPDATED', // When the global action authentication is updated.
'DOCUMENT_META_UPDATED', // When the document meta data is updated.
@ -322,6 +323,11 @@ export const ZDocumentAuditLogEventDocumentFieldUninsertedSchema = z.object({
}),
});
export const ZDocumentAuditLogEventDocumentVisibilitySchema = z.object({
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED),
data: ZGenericFromToSchema,
});
/**
* Event: Document global authentication access updated.
*/
@ -487,6 +493,7 @@ export const ZDocumentAuditLogSchema = ZDocumentAuditLogBaseSchema.and(
ZDocumentAuditLogEventDocumentRestoredSchema,
ZDocumentAuditLogEventDocumentFieldInsertedSchema,
ZDocumentAuditLogEventDocumentFieldUninsertedSchema,
ZDocumentAuditLogEventDocumentVisibilitySchema,
ZDocumentAuditLogEventDocumentGlobalAuthAccessUpdatedSchema,
ZDocumentAuditLogEventDocumentGlobalAuthActionUpdatedSchema,
ZDocumentAuditLogEventDocumentMetaUpdatedSchema,

View File

@ -0,0 +1,7 @@
import { z } from 'zod';
import { DocumentVisibility as DocumentVisibilityEnum } from '@documenso/prisma/client';
export const ZDocumentVisibilitySchema = z.nativeEnum(DocumentVisibilityEnum);
export const DocumentVisibility = ZDocumentVisibilitySchema.enum;
export type TDocumentVisibility = z.infer<typeof ZDocumentVisibilitySchema>;

View File

@ -8,7 +8,7 @@ import type {
RecipientRole,
} from '@documenso/prisma/client';
import { RECIPIENT_ROLES_DESCRIPTION } from '../constants/recipient-roles';
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '../constants/recipient-roles';
import type {
TDocumentAuditLog,
TDocumentAuditLogDocumentMetaDiffSchema,
@ -268,6 +268,7 @@ export const formatDocumentAuditLogActionString = (
*
* Provide a userId to prefix the action with the user, example 'X did Y'.
*/
// Todo: Translations.
export const formatDocumentAuditLogAction = (auditLog: TDocumentAuditLog, userId?: number) => {
let prefix = userId === auditLog.userId ? 'You' : auditLog.name || auditLog.email || '';
@ -316,6 +317,10 @@ export const formatDocumentAuditLogAction = (auditLog: TDocumentAuditLog, userId
anonymous: 'Field unsigned',
identified: 'unsigned a field',
}))
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED }, () => ({
anonymous: 'Document visibility updated',
identified: 'updated the document visibility',
}))
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_GLOBAL_AUTH_ACCESS_UPDATED }, () => ({
anonymous: 'Document access auth updated',
identified: 'updated the document access auth requirements',
@ -350,7 +355,7 @@ export const formatDocumentAuditLogAction = (auditLog: TDocumentAuditLog, userId
}))
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_RECIPIENT_COMPLETED }, ({ data }) => {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const action = RECIPIENT_ROLES_DESCRIPTION[data.recipientRole as RecipientRole]?.actioned;
const action = RECIPIENT_ROLES_DESCRIPTION_ENG[data.recipientRole as RecipientRole]?.actioned;
const value = action ? `${action.toLowerCase()} the document` : 'completed their task';

View File

@ -2,8 +2,8 @@ import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension
import type { I18n } from '@lingui/core';
import { IS_APP_WEB } from '../constants/app';
import type { SupportedLanguageCodes } from '../constants/i18n';
import { IS_APP_WEB, IS_APP_WEB_I18N_ENABLED } from '../constants/app';
import type { I18nLocaleData, SupportedLanguageCodes } from '../constants/i18n';
import { APP_I18N_OPTIONS } from '../constants/i18n';
export async function dynamicActivate(i18nInstance: I18n, locale: string) {
@ -14,48 +14,58 @@ export async function dynamicActivate(i18nInstance: I18n, locale: string) {
i18nInstance.loadAndActivate({ locale, messages });
}
/**
* Extract the language if supported from the cookies header.
*
* Returns `null` if not supported or not found.
*/
export const extractSupportedLanguageFromCookies = (
cookies: ReadonlyRequestCookies,
): SupportedLanguageCodes | null => {
const preferredLanguage = cookies.get('i18n');
const foundSupportedLanguage = APP_I18N_OPTIONS.supportedLangs.find(
(lang): lang is SupportedLanguageCodes => lang === preferredLanguage?.value,
);
return foundSupportedLanguage || null;
};
/**
* Extracts the language from the `accept-language` header.
*
* Returns `null` if not supported or not found.
*/
export const extractSupportedLanguageFromHeaders = (
headers: Headers,
): SupportedLanguageCodes | null => {
const locales = headers.get('accept-language') ?? '';
const [locale] = locales.split(',');
// Convert locale to language.
const [language] = locale.split('-');
const parseLanguageFromLocale = (locale: string): SupportedLanguageCodes | null => {
const [language, _country] = locale.split('-');
const foundSupportedLanguage = APP_I18N_OPTIONS.supportedLangs.find(
(lang): lang is SupportedLanguageCodes => lang === language,
);
return foundSupportedLanguage || null;
if (!foundSupportedLanguage) {
return null;
}
return foundSupportedLanguage;
};
type ExtractSupportedLanguageOptions = {
headers?: Headers;
cookies?: ReadonlyRequestCookies;
/**
* Extract the language if supported from the cookies header.
*
* Returns `null` if not supported or not found.
*/
export const extractLocaleDataFromCookies = (
cookies: ReadonlyRequestCookies,
): SupportedLanguageCodes | null => {
const preferredLocale = cookies.get('language')?.value || '';
const language = parseLanguageFromLocale(preferredLocale || '');
if (!language) {
return null;
}
return language;
};
/**
* Extracts the language from the `accept-language` header.
*/
export const extractLocaleDataFromHeaders = (
headers: Headers,
): { lang: SupportedLanguageCodes | null; locales: string[] } => {
const headerLocales = (headers.get('accept-language') ?? '').split(',');
const language = parseLanguageFromLocale(headerLocales[0]);
return {
lang: language,
locales: [headerLocales[0]],
};
};
type ExtractLocaleDataOptions = {
headers: Headers;
cookies: ReadonlyRequestCookies;
};
/**
@ -63,25 +73,35 @@ type ExtractSupportedLanguageOptions = {
*
* Will return the default fallback language if not found.
*/
export const extractSupportedLanguage = ({
export const extractLocaleData = ({
headers,
cookies,
}: ExtractSupportedLanguageOptions): SupportedLanguageCodes => {
if (cookies) {
const langCookie = extractSupportedLanguageFromCookies(cookies);
}: ExtractLocaleDataOptions): I18nLocaleData => {
let lang: SupportedLanguageCodes | null = extractLocaleDataFromCookies(cookies);
if (langCookie) {
return langCookie;
}
const langHeader = extractLocaleDataFromHeaders(headers);
if (!lang && langHeader?.lang) {
lang = langHeader.lang;
}
if (headers) {
const langHeader = extractSupportedLanguageFromHeaders(headers);
if (langHeader) {
return langHeader;
}
// Override web app to be English.
if (!IS_APP_WEB_I18N_ENABLED && IS_APP_WEB) {
lang = 'en';
}
return APP_I18N_OPTIONS.sourceLang;
// Filter out locales that are not valid.
const locales = (langHeader?.locales ?? []).filter((locale) => {
try {
new Intl.Locale(locale);
return true;
} catch {
return false;
}
});
return {
lang: lang || APP_I18N_OPTIONS.sourceLang,
locales,
};
};

View File

@ -0,0 +1,33 @@
import { type Field, type Recipient, RecipientRole, SigningStatus } from '@documenso/prisma/client';
/**
* Whether a recipient can be modified by the document owner.
*/
export const canRecipientBeModified = (recipient: Recipient, fields: Field[]) => {
// Deny if the recipient has already signed the document.
if (!recipient || recipient.signingStatus === SigningStatus.SIGNED) {
return false;
}
// Deny if the recipient has inserted any fields.
if (fields.some((field) => field.recipientId === recipient.id && field.inserted)) {
return false;
}
return true;
};
/**
* Whether a recipient can have their fields modified by the document owner.
*
* A recipient can their fields modified if all the conditions are met:
* - They are not a Viewer or CCer
* - They can be modified (canRecipientBeModified)
*/
export const canRecipientFieldsBeModified = (recipient: Recipient, fields: Field[]) => {
if (!canRecipientBeModified(recipient, fields)) {
return false;
}
return recipient.role !== RecipientRole.VIEWER && recipient.role !== RecipientRole.CC;
};