fix: email translations (#1454)

This commit is contained in:
David Nguyen
2024-11-08 00:33:48 +09:00
committed by GitHub
parent 61ea4971ad
commit 9b769e7e33
11 changed files with 51 additions and 75 deletions

View File

@ -7,7 +7,7 @@ import { useRouter, useSearchParams } from 'next/navigation';
import { msg } from '@lingui/macro'; import { msg } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import type { Field } from '@documenso/prisma/client'; import type { Field } from '@documenso/prisma/client';
import { type Recipient } from '@documenso/prisma/client'; import { type Recipient } from '@documenso/prisma/client';
import type { TemplateWithDetails } from '@documenso/prisma/types/template'; import type { TemplateWithDetails } from '@documenso/prisma/types/template';
@ -53,7 +53,9 @@ export const DirectTemplatePageView = ({
const [step, setStep] = useState<DirectTemplateStep>('configure'); const [step, setStep] = useState<DirectTemplateStep>('configure');
const [isDocumentPdfLoaded, setIsDocumentPdfLoaded] = useState(false); const [isDocumentPdfLoaded, setIsDocumentPdfLoaded] = useState(false);
const recipientRoleDescription = RECIPIENT_ROLES_DESCRIPTION_ENG[directTemplateRecipient.role]; const recipientActionVerb = _(
RECIPIENT_ROLES_DESCRIPTION[directTemplateRecipient.role].actionVerb,
);
const directTemplateFlow: Record<DirectTemplateStep, DocumentFlowStep> = { const directTemplateFlow: Record<DirectTemplateStep, DocumentFlowStep> = {
configure: { configure: {
@ -62,9 +64,8 @@ export const DirectTemplatePageView = ({
stepIndex: 1, stepIndex: 1,
}, },
sign: { sign: {
// Todo: Translations title: msg`${recipientActionVerb} document`,
title: msg`${recipientRoleDescription.actionVerb} document`, description: msg`${recipientActionVerb} the document to complete the process.`,
description: msg`${recipientRoleDescription.actionVerb} the document to complete the process.`,
stepIndex: 2, stepIndex: 2,
}, },
}; };

View File

@ -1,5 +1,4 @@
import { Trans } from '@lingui/macro'; import { Trans } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { Button, Section, Text } from '../components'; import { Button, Section, Text } from '../components';
import { TemplateDocumentImage } from './template-document-image'; import { TemplateDocumentImage } from './template-document-image';
@ -13,8 +12,6 @@ export const TemplateConfirmationEmail = ({
confirmationLink, confirmationLink,
assetBaseUrl, assetBaseUrl,
}: TemplateConfirmationEmailProps) => { }: TemplateConfirmationEmailProps) => {
const { _ } = useLingui();
return ( return (
<> <>
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} /> <TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />

View File

@ -38,7 +38,7 @@ export const TemplateDocumentCompleted = ({
</Section> </Section>
<Text className="text-primary mb-0 text-center text-lg font-semibold"> <Text className="text-primary mb-0 text-center text-lg font-semibold">
<Trans>{customBody ?? `${documentName}” was signed by all signers`}</Trans> {customBody || <Trans>{documentName} was signed by all signers</Trans>}
</Text> </Text>
<Text className="my-1 text-center text-base text-slate-400"> <Text className="my-1 text-center text-base text-slate-400">

View File

@ -1,8 +1,9 @@
import { Trans } from '@lingui/macro'; import { Trans } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { match } from 'ts-pattern';
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import type { RecipientRole } from '@documenso/prisma/client'; import { RecipientRole } from '@documenso/prisma/client';
import { Button, Section, Text } from '../components'; import { Button, Section, Text } from '../components';
import { TemplateDocumentImage } from './template-document-image'; import { TemplateDocumentImage } from './template-document-image';
@ -31,7 +32,7 @@ export const TemplateDocumentInvite = ({
}: TemplateDocumentInviteProps) => { }: TemplateDocumentInviteProps) => {
const { _ } = useLingui(); const { _ } = useLingui();
const { actionVerb, progressiveVerb } = RECIPIENT_ROLES_DESCRIPTION_ENG[role]; const { actionVerb } = RECIPIENT_ROLES_DESCRIPTION[role];
return ( return (
<> <>
@ -41,29 +42,29 @@ export const TemplateDocumentInvite = ({
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold"> <Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
{selfSigner ? ( {selfSigner ? (
<Trans> <Trans>
{`Please ${_(actionVerb).toLowerCase()} your document`} Please {_(actionVerb).toLowerCase()} your document
<br /> <br />"{documentName}"
{`"${documentName}"`}
</Trans> </Trans>
) : isTeamInvite ? ( ) : isTeamInvite ? (
<Trans> <Trans>
{`${inviterName} on behalf of ${teamName} has invited you to ${_( {inviterName} on behalf of {teamName} has invited you to {_(actionVerb).toLowerCase()}
actionVerb, <br />"{documentName}"
).toLowerCase()}`}
<br />
{`"${documentName}"`}
</Trans> </Trans>
) : ( ) : (
<Trans> <Trans>
{`${inviterName} has invited you to ${_(actionVerb).toLowerCase()}`} {inviterName} has invited you to {_(actionVerb).toLowerCase()}
<br /> <br />"{documentName}"
{`"${documentName}"`}
</Trans> </Trans>
)} )}
</Text> </Text>
<Text className="my-1 text-center text-base text-slate-400"> <Text className="my-1 text-center text-base text-slate-400">
<Trans>Continue by {_(progressiveVerb).toLowerCase()} the document.</Trans> {match(role)
.with(RecipientRole.SIGNER, () => <Trans>Continue by signing the document.</Trans>)
.with(RecipientRole.VIEWER, () => <Trans>Continue by viewing the document.</Trans>)
.with(RecipientRole.APPROVER, () => <Trans>Continue by approving the document.</Trans>)
.with(RecipientRole.CC, () => '')
.exhaustive()}
</Text> </Text>
<Section className="mb-6 mt-8 text-center"> <Section className="mb-6 mt-8 text-center">
@ -71,7 +72,12 @@ export const TemplateDocumentInvite = ({
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline" className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
href={signDocumentLink} href={signDocumentLink}
> >
<Trans>{_(actionVerb)} Document</Trans> {match(role)
.with(RecipientRole.SIGNER, () => <Trans>Sign Document</Trans>)
.with(RecipientRole.VIEWER, () => <Trans>View Document</Trans>)
.with(RecipientRole.APPROVER, () => <Trans>Approve Document</Trans>)
.with(RecipientRole.CC, () => '')
.exhaustive()}
</Button> </Button>
</Section> </Section>
</Section> </Section>

View File

@ -1,7 +1,7 @@
import { Trans, msg } from '@lingui/macro'; import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import { Body, Button, Container, Head, Html, Img, Preview, Section, Text } from '../components'; import { Body, Button, Container, Head, Html, Img, Preview, Section, Text } from '../components';
import TemplateDocumentImage from '../template-components/template-document-image'; import TemplateDocumentImage from '../template-components/template-document-image';
@ -25,7 +25,7 @@ export const DocumentCreatedFromDirectTemplateEmailTemplate = ({
}: DocumentCompletedEmailTemplateProps) => { }: DocumentCompletedEmailTemplateProps) => {
const { _ } = useLingui(); const { _ } = useLingui();
const action = _(RECIPIENT_ROLES_DESCRIPTION_ENG[recipientRole].actioned).toLowerCase(); const action = _(RECIPIENT_ROLES_DESCRIPTION[recipientRole].actioned).toLowerCase();
const previewText = msg`Document created from direct template`; const previewText = msg`Document created from direct template`;

View File

@ -1,7 +1,7 @@
import { Trans, msg } from '@lingui/macro'; import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import type { RecipientRole } from '@documenso/prisma/client'; import type { RecipientRole } from '@documenso/prisma/client';
import { Body, Container, Head, Hr, Html, Img, Link, Preview, Section, Text } from '../components'; import { Body, Container, Head, Hr, Html, Img, Link, Preview, Section, Text } from '../components';
@ -32,7 +32,7 @@ export const DocumentInviteEmailTemplate = ({
}: DocumentInviteEmailTemplateProps) => { }: DocumentInviteEmailTemplateProps) => {
const { _ } = useLingui(); const { _ } = useLingui();
const action = _(RECIPIENT_ROLES_DESCRIPTION_ENG[role].actionVerb).toLowerCase(); const action = _(RECIPIENT_ROLES_DESCRIPTION[role].actionVerb).toLowerCase();
const previewText = selfSigner const previewText = selfSigner
? msg`Please ${action} your document ${documentName}` ? msg`Please ${action} your document ${documentName}`
@ -89,7 +89,7 @@ export const DocumentInviteEmailTemplate = ({
<pre className="font-sans text-base text-slate-400">{customBody}</pre> <pre className="font-sans text-base text-slate-400">{customBody}</pre>
) : ( ) : (
<Trans> <Trans>
`${inviterName} has invited you to ${action} the document "${documentName}".` {inviterName} has invited you to {action} the document {documentName}.
</Trans> </Trans>
)} )}
</Text> </Text>

View File

@ -1,4 +1,4 @@
import { msg } from '@lingui/macro'; import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { Body, Container, Head, Hr, Html, Img, Preview, Section, Text } from '../components'; import { Body, Container, Head, Hr, Html, Img, Preview, Section, Text } from '../components';
@ -40,8 +40,10 @@ export const RecipientRemovedFromDocumentTemplate = ({
<Section> <Section>
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold"> <Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
<Trans>
{inviterName} has removed you from the document {inviterName} has removed you from the document
<br />"{documentName}" <br />"{documentName}"
</Trans>
</Text> </Text>
</Section> </Section>
</Section> </Section>

View File

@ -9,59 +9,27 @@ export const RECIPIENT_ROLES_DESCRIPTION = {
actioned: msg`Approved`, actioned: msg`Approved`,
progressiveVerb: msg`Approving`, progressiveVerb: msg`Approving`,
roleName: msg`Approver`, roleName: msg`Approver`,
roleNamePlural: msg`Approvers`,
}, },
[RecipientRole.CC]: { [RecipientRole.CC]: {
actionVerb: msg`CC`, actionVerb: msg`CC`,
actioned: msg`CC'd`, actioned: msg`CC'd`,
progressiveVerb: msg`CC`, progressiveVerb: msg`CC`,
roleName: msg`Cc`, roleName: msg`Cc`,
roleNamePlural: msg`Ccers`,
}, },
[RecipientRole.SIGNER]: { [RecipientRole.SIGNER]: {
actionVerb: msg`Sign`, actionVerb: msg`Sign`,
actioned: msg`Signed`, actioned: msg`Signed`,
progressiveVerb: msg`Signing`, progressiveVerb: msg`Signing`,
roleName: msg`Signer`, roleName: msg`Signer`,
roleNamePlural: msg`Signers`,
}, },
[RecipientRole.VIEWER]: { [RecipientRole.VIEWER]: {
actionVerb: msg`View`, actionVerb: msg`View`,
actioned: msg`Viewed`, actioned: msg`Viewed`,
progressiveVerb: msg`Viewing`, progressiveVerb: msg`Viewing`,
roleName: msg`Viewer`, 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`,
roleNamePlural: msg`Approvers`,
},
[RecipientRole.CC]: {
actionVerb: `CC`,
actioned: `CC'd`,
progressiveVerb: `CC`,
roleName: `Cc`,
roleNamePlural: msg`Ccers`,
},
[RecipientRole.SIGNER]: {
actionVerb: `Sign`,
actioned: `Signed`,
progressiveVerb: `Signing`,
roleName: `Signer`,
roleNamePlural: msg`Signers`,
},
[RecipientRole.VIEWER]: {
actionVerb: `View`,
actioned: `Viewed`,
progressiveVerb: `Viewing`,
roleName: `Viewer`,
roleNamePlural: msg`Viewers`, roleNamePlural: msg`Viewers`,
}, },
} satisfies Record<keyof typeof RecipientRole, unknown>; } satisfies Record<keyof typeof RecipientRole, unknown>;

View File

@ -17,7 +17,7 @@ import { getI18nInstance } from '../../../client-only/providers/i18n.server';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../../constants/app'; import { NEXT_PUBLIC_WEBAPP_URL } from '../../../constants/app';
import { FROM_ADDRESS, FROM_NAME } from '../../../constants/email'; import { FROM_ADDRESS, FROM_NAME } from '../../../constants/email';
import { import {
RECIPIENT_ROLES_DESCRIPTION_ENG, RECIPIENT_ROLES_DESCRIPTION,
RECIPIENT_ROLE_TO_EMAIL_TYPE, RECIPIENT_ROLE_TO_EMAIL_TYPE,
} from '../../../constants/recipient-roles'; } from '../../../constants/recipient-roles';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs'; import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs';
@ -89,11 +89,13 @@ export const SEND_SIGNING_EMAIL_JOB_DEFINITION = {
const { email, name } = recipient; const { email, name } = recipient;
const selfSigner = email === user.email; const selfSigner = email === user.email;
const recipientActionVerb =
RECIPIENT_ROLES_DESCRIPTION_ENG[recipient.role].actionVerb.toLowerCase();
const i18n = await getI18nInstance(documentMeta?.language); const i18n = await getI18nInstance(documentMeta?.language);
const recipientActionVerb = i18n
._(RECIPIENT_ROLES_DESCRIPTION[recipient.role].actionVerb)
.toLowerCase();
let emailMessage = customEmail?.message || ''; let emailMessage = customEmail?.message || '';
let emailSubject = i18n._(msg`Please ${recipientActionVerb} this document`); let emailSubject = i18n._(msg`Please ${recipientActionVerb} this document`);

View File

@ -28,7 +28,7 @@ import { prop, sortBy } from 'remeda';
import { getBoundingClientRect } from '@documenso/lib/client-only/get-bounding-client-rect'; import { getBoundingClientRect } from '@documenso/lib/client-only/get-bounding-client-rect';
import { useDocumentElement } from '@documenso/lib/client-only/hooks/use-document-element'; import { useDocumentElement } from '@documenso/lib/client-only/hooks/use-document-element';
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer'; import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import { import {
type TFieldMetaSchema as FieldMeta, type TFieldMetaSchema as FieldMeta,
ZFieldMetaSchema, ZFieldMetaSchema,
@ -690,7 +690,7 @@ export const AddFieldsFormPartial = ({
{recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => ( {recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => (
<CommandGroup key={roleIndex}> <CommandGroup key={roleIndex}>
<div className="text-muted-foreground mb-1 ml-2 mt-2 text-xs font-medium"> <div className="text-muted-foreground mb-1 ml-2 mt-2 text-xs font-medium">
{_(RECIPIENT_ROLES_DESCRIPTION_ENG[role].roleNamePlural)} {_(RECIPIENT_ROLES_DESCRIPTION[role].roleNamePlural)}
</div> </div>
{roleRecipients.length === 0 && ( {roleRecipients.length === 0 && (

View File

@ -23,7 +23,7 @@ import { useFieldArray, useForm } from 'react-hook-form';
import { getBoundingClientRect } from '@documenso/lib/client-only/get-bounding-client-rect'; import { getBoundingClientRect } from '@documenso/lib/client-only/get-bounding-client-rect';
import { useDocumentElement } from '@documenso/lib/client-only/hooks/use-document-element'; import { useDocumentElement } from '@documenso/lib/client-only/hooks/use-document-element';
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer'; import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import { import {
type TFieldMetaSchema as FieldMeta, type TFieldMetaSchema as FieldMeta,
ZFieldMetaSchema, ZFieldMetaSchema,
@ -508,7 +508,7 @@ export const AddTemplateFieldsFormPartial = ({
{recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => ( {recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => (
<CommandGroup key={roleIndex}> <CommandGroup key={roleIndex}>
<div className="text-muted-foreground mb-1 ml-2 mt-2 text-xs font-medium"> <div className="text-muted-foreground mb-1 ml-2 mt-2 text-xs font-medium">
{_(RECIPIENT_ROLES_DESCRIPTION_ENG[role].roleNamePlural)} {_(RECIPIENT_ROLES_DESCRIPTION[role].roleNamePlural)}
</div> </div>
{roleRecipients.length === 0 && ( {roleRecipients.length === 0 && (