Do not define translatable messages inline

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2022-11-12 00:07:02 +01:00
parent 84ff4d928d
commit f2c5e138f3
5 changed files with 108 additions and 94 deletions

View file

@ -1,6 +1,6 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { HotKeys } from 'react-hotkeys'; import { HotKeys } from 'react-hotkeys';
import { defineMessages, useIntl, FormattedMessage, IntlShape, MessageDescriptor } from 'react-intl'; import { defineMessages, useIntl, FormattedMessage, IntlShape, MessageDescriptor, defineMessage } from 'react-intl';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { mentionCompose } from 'soapbox/actions/compose'; import { mentionCompose } from 'soapbox/actions/compose';
@ -55,6 +55,11 @@ const icons: Record<NotificationType, string> = {
update: require('@tabler/icons/pencil.svg'), update: require('@tabler/icons/pencil.svg'),
}; };
const nameMessage = defineMessage({
id: 'notification.name',
defaultMessage: '{link}{others}',
});
const messages: Record<NotificationType, MessageDescriptor> = defineMessages({ const messages: Record<NotificationType, MessageDescriptor> = defineMessages({
follow: { follow: {
id: 'notification.follow', id: 'notification.follow',
@ -115,10 +120,7 @@ const buildMessage = (
instanceTitle: string, instanceTitle: string,
): React.ReactNode => { ): React.ReactNode => {
const link = buildLink(account); const link = buildLink(account);
const name = intl.formatMessage({ const name = intl.formatMessage(nameMessage, {
id: 'notification.name',
defaultMessage: '{link}{others}',
}, {
link, link,
others: totalCount && totalCount > 0 ? ( others: totalCount && totalCount > 0 ? (
<FormattedMessage <FormattedMessage

View file

@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import OtpInput from 'react-otp-input'; import OtpInput from 'react-otp-input';
import { verifyCredentials } from 'soapbox/actions/auth'; import { verifyCredentials } from 'soapbox/actions/auth';
@ -10,6 +10,37 @@ import { FormGroup, PhoneInput, Modal, Stack, Text } from 'soapbox/components/ui
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { getAccessToken } from 'soapbox/utils/auth'; import { getAccessToken } from 'soapbox/utils/auth';
const messages = defineMessages({
verificationInvalid: {
id: 'sms_verification.invalid',
defaultMessage: 'Please enter a valid phone number.',
},
verificationSuccess: {
id: 'sms_verification.success',
defaultMessage: 'A verification code has been sent to your phone number.',
},
verificationFail: {
id: 'sms_verification.fail',
defaultMessage: 'Failed to send SMS message to your phone number.',
},
verificationExpired: {
id: 'sms_verification.expired',
defaultMessage: 'Your SMS token has expired.',
},
verifySms: {
id: 'sms_verification.modal.verify_sms',
defaultMessage: 'Verify SMS',
},
verifyNumber: {
id: 'sms_verification.modal.verify_number',
defaultMessage: 'Verify phone number',
},
verifyCode: {
id: 'sms_verification.modal.verify_code',
defaultMessage: 'Verify code',
},
});
interface IVerifySmsModal { interface IVerifySmsModal {
onClose: (type: string) => void, onClose: (type: string) => void,
} }
@ -47,10 +78,7 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
setStatus(Statuses.IDLE); setStatus(Statuses.IDLE);
dispatch( dispatch(
snackbar.error( snackbar.error(
intl.formatMessage({ intl.formatMessage(messages.verificationInvalid),
id: 'sms_verification.invalid',
defaultMessage: 'Please enter a valid phone number.',
}),
), ),
); );
return; return;
@ -59,10 +87,7 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
dispatch(reRequestPhoneVerification(phone!)).then(() => { dispatch(reRequestPhoneVerification(phone!)).then(() => {
dispatch( dispatch(
snackbar.success( snackbar.success(
intl.formatMessage({ intl.formatMessage(messages.verificationSuccess),
id: 'sms_verification.success',
defaultMessage: 'A verification code has been sent to your phone number.',
}),
), ),
); );
}) })
@ -70,10 +95,7 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
.catch(() => { .catch(() => {
dispatch( dispatch(
snackbar.error( snackbar.error(
intl.formatMessage({ intl.formatMessage(messages.verificationFail),
id: 'sms_verification.fail',
defaultMessage: 'Failed to send SMS message to your phone number.',
}),
), ),
); );
}); });
@ -102,20 +124,11 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
const confirmationText = useMemo(() => { const confirmationText = useMemo(() => {
switch (status) { switch (status) {
case Statuses.IDLE: case Statuses.IDLE:
return intl.formatMessage({ return intl.formatMessage(messages.verifySms);
id: 'sms_verification.modal.verify_sms',
defaultMessage: 'Verify SMS',
});
case Statuses.READY: case Statuses.READY:
return intl.formatMessage({ return intl.formatMessage(messages.verifyNumber);
id: 'sms_verification.modal.verify_number',
defaultMessage: 'Verify phone number',
});
case Statuses.REQUESTED: case Statuses.REQUESTED:
return intl.formatMessage({ return intl.formatMessage(messages.verifyCode);
id: 'sms_verification.modal.verify_code',
defaultMessage: 'Verify code',
});
default: default:
return null; return null;
} }
@ -126,12 +139,13 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
case Statuses.IDLE: case Statuses.IDLE:
return ( return (
<Text theme='muted'> <Text theme='muted'>
{intl.formatMessage({ <FormattedMessage
id: 'sms_verification.modal.verify_help_text', id='sms_verification.modal.verify_help_text'
defaultMessage: 'Verify your phone number to start using {instance}.', defaultMessage='Verify your phone number to start using {instance}.'
}, { values={{
instance: title, instance: title,
})} }}
/>
</Text> </Text>
); );
case Statuses.READY: case Statuses.READY:
@ -149,10 +163,10 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
return ( return (
<> <>
<Text theme='muted' size='sm' align='center'> <Text theme='muted' size='sm' align='center'>
{intl.formatMessage({ <FormattedMessage
id: 'sms_verification.modal.enter_code', id='sms_verification.modal.enter_code'
defaultMessage: 'We sent you a 6-digit code via SMS. Enter it below.', defaultMessage='We sent you a 6-digit code via SMS. Enter it below.'
})} />
</Text> </Text>
<OtpInput <OtpInput
@ -184,10 +198,7 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
}) })
.catch(() => dispatch( .catch(() => dispatch(
snackbar.error( snackbar.error(
intl.formatMessage({ intl.formatMessage(messages.verificationExpired),
id: 'sms_verification.invalid',
defaultMessage: 'Your SMS token has expired.',
}),
), ),
)); ));
}; };
@ -201,10 +212,10 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
return ( return (
<Modal <Modal
title={ title={
intl.formatMessage({ <FormattedMessage
id: 'sms_verification.modal.verify_title', id='sms_verification.modal.verify_title'
defaultMessage: 'Verify your phone number', defaultMessage='Verify your phone number'
}) />
} }
onClose={() => onClose('VERIFY_SMS')} onClose={() => onClose('VERIFY_SMS')}
cancelAction={status === Statuses.IDLE ? () => onClose('VERIFY_SMS') : undefined} cancelAction={status === Statuses.IDLE ? () => onClose('VERIFY_SMS') : undefined}
@ -212,10 +223,12 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
confirmationAction={onConfirmationClick} confirmationAction={onConfirmationClick}
confirmationText={confirmationText} confirmationText={confirmationText}
secondaryAction={status === Statuses.REQUESTED ? resendVerificationCode : undefined} secondaryAction={status === Statuses.REQUESTED ? resendVerificationCode : undefined}
secondaryText={status === Statuses.REQUESTED ? intl.formatMessage({ secondaryText={status === Statuses.REQUESTED ? (
id: 'sms_verification.modal.resend_code', <FormattedMessage
defaultMessage: 'Resend verification code?', id='sms_verification.modal.resend_code'
}) : undefined} defaultMessage='Resend verification code?'
/>
) : undefined}
secondaryDisabled={requestedAnother} secondaryDisabled={requestedAnother}
> >
<Stack space={4}> <Stack space={4}>

View file

@ -28,6 +28,11 @@ const messages = defineMessages({
tokenNotFoundBody: { id: 'email_passthru.token_not_found.body', defaultMessage: 'Your email token was not found. Please request a new email confirmation from the {bold} from which you sent this email confirmation.' }, tokenNotFoundBody: { id: 'email_passthru.token_not_found.body', defaultMessage: 'Your email token was not found. Please request a new email confirmation from the {bold} from which you sent this email confirmation.' },
tokenExpiredHeading: { id: 'email_passthru.token_expired.heading', defaultMessage: 'Token Expired' }, tokenExpiredHeading: { id: 'email_passthru.token_expired.heading', defaultMessage: 'Token Expired' },
tokenExpiredBody: { id: 'email_passthru.token_expired.body', defaultMessage: 'Your email token has expired. Please request a new email confirmation from the {bold} from which you sent this email confirmation.' }, tokenExpiredBody: { id: 'email_passthru.token_expired.body', defaultMessage: 'Your email token has expired. Please request a new email confirmation from the {bold} from which you sent this email confirmation.' },
emailConfirmed: { id: 'email_passthru.success', defaultMessage: 'Your email has been verified!' },
genericFail: { id: 'email_passthru.fail.generic', defaultMessage: 'Unable to confirm your email' },
tokenExpired: { id: 'email_passthru.fail.expired', defaultMessage: 'Your email token has expired' },
tokenNotFound: { id: 'email_passthru.fail.not_found', defaultMessage: 'Your email token is invalid.' },
invalidToken: { id: 'email_passthru.fail.invalid_token', defaultMessage: 'Your token is invalid' },
}); });
const Success = () => { const Success = () => {
@ -116,30 +121,21 @@ const EmailPassThru = () => {
dispatch(confirmEmailVerification(token)) dispatch(confirmEmailVerification(token))
.then(() => { .then(() => {
setStatus(Statuses.SUCCESS); setStatus(Statuses.SUCCESS);
dispatch(snackbar.success(intl.formatMessage({ id: 'email_passthru.success', defaultMessage: 'Your email has been verified!' }))); dispatch(snackbar.success(intl.formatMessage(messages.emailConfirmed)));
}) })
.catch((error: AxiosError<any>) => { .catch((error: AxiosError<any>) => {
const errorKey = error?.response?.data?.error; const errorKey = error?.response?.data?.error;
let message = intl.formatMessage({ let message = intl.formatMessage(messages.genericFail);
id: 'email_passthru.fail.generic',
defaultMessage: 'Unable to confirm your email',
});
if (errorKey) { if (errorKey) {
switch (errorKey) { switch (errorKey) {
case 'token_expired': case 'token_expired':
message = intl.formatMessage({ message = intl.formatMessage(messages.tokenExpired);
id: 'email_passthru.fail.expired',
defaultMessage: 'Your email token has expired.',
});
setStatus(Statuses.TOKEN_EXPIRED); setStatus(Statuses.TOKEN_EXPIRED);
break; break;
case 'token_not_found': case 'token_not_found':
message = intl.formatMessage({ message = intl.formatMessage(messages.tokenNotFound);
id: 'email_passthru.fail.not_found', message = intl.formatMessage(messages.invalidToken);
defaultMessage: 'Your email token is invalid.',
});
message = 'Your token is invalid';
setStatus(Statuses.TOKEN_NOT_FOUND); setStatus(Statuses.TOKEN_NOT_FOUND);
break; break;
default: default:

View file

@ -1,6 +1,6 @@
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import React from 'react'; import React from 'react';
import { useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import snackbar from 'soapbox/actions/snackbar'; import snackbar from 'soapbox/actions/snackbar';
import { checkEmailVerification, postEmailVerification, requestEmailVerification } from 'soapbox/actions/verification'; import { checkEmailVerification, postEmailVerification, requestEmailVerification } from 'soapbox/actions/verification';
@ -8,6 +8,13 @@ import Icon from 'soapbox/components/icon';
import { Button, Form, FormGroup, Input, Text } from 'soapbox/components/ui'; import { Button, Form, FormGroup, Input, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
const messages = defineMessages({
verificationSuccess: { id: 'email_verification.success', defaultMessage: 'Verification email sent successfully.' },
verificationFail: { id: 'email_verification.fail', defaultMessage: 'Failed to request email verification.' },
verificationFailTakenAlert: { id: 'emai_verifilcation.exists', defaultMessage: 'This email has already been taken.' },
verificationFailTaken: { id: 'email_verification.taken', defaultMessage: 'is taken' },
});
const Statuses = { const Statuses = {
IDLE: 'IDLE', IDLE: 'IDLE',
REQUESTED: 'REQUESTED', REQUESTED: 'REQUESTED',
@ -77,26 +84,23 @@ const EmailVerification = () => {
dispatch( dispatch(
snackbar.success( snackbar.success(
intl.formatMessage({ intl.formatMessage(messages.verificationSuccess),
id: 'email_verification.exists',
defaultMessage: 'Verification email sent successfully.',
}),
), ),
); );
}) })
.catch((error: AxiosError) => { .catch((error: AxiosError) => {
const errorMessage = (error.response?.data as any)?.error; const errorMessage = (error.response?.data as any)?.error;
const isEmailTaken = errorMessage === 'email_taken'; const isEmailTaken = errorMessage === 'email_taken';
let message = intl.formatMessage({ id: 'email_verification.fail', defaultMessage: 'Failed to request email verification.' }); let message = intl.formatMessage(messages.verificationFail);
if (isEmailTaken) { if (isEmailTaken) {
message = intl.formatMessage({ id: 'email_verification.exists', defaultMessage: 'This email has already been taken.' }); message = intl.formatMessage(messages.verificationFailTakenAlert);
} else if (errorMessage) { } else if (errorMessage) {
message = errorMessage; message = errorMessage;
} }
if (isEmailTaken) { if (isEmailTaken) {
setErrors([intl.formatMessage({ id: 'email_verification.taken', defaultMessage: 'is taken' })]); setErrors([intl.formatMessage(messages.verificationFailTaken)]);
} }
dispatch(snackbar.error(message)); dispatch(snackbar.error(message));
@ -111,7 +115,9 @@ const EmailVerification = () => {
return ( return (
<div> <div>
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-800 border-solid -mx-4 sm:-mx-10'> <div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-800 border-solid -mx-4 sm:-mx-10'>
<h1 className='text-center font-bold text-2xl'>{intl.formatMessage({ id: 'email_verification.header', defaultMessage: 'Enter your email address' })}</h1> <h1 className='text-center font-bold text-2xl'>
<FormattedMessage id='email_verification.header' defaultMessage='Enter your email address' />
</h1>
</div> </div>
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'> <div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>

View file

@ -1,6 +1,6 @@
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import React from 'react'; import React from 'react';
import { useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import OtpInput from 'react-otp-input'; import OtpInput from 'react-otp-input';
import snackbar from 'soapbox/actions/snackbar'; import snackbar from 'soapbox/actions/snackbar';
@ -8,6 +8,13 @@ import { confirmPhoneVerification, requestPhoneVerification } from 'soapbox/acti
import { Button, Form, FormGroup, PhoneInput, Text } from 'soapbox/components/ui'; import { Button, Form, FormGroup, PhoneInput, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
const messages = defineMessages({
verificationInvalid: { id: 'sms_verification.invalid', defaultMessage: 'Please enter a valid phone number.' },
verificationSuccess: { id: 'sms_verification.success', defaultMessage: 'A verification code has been sent to your phone number.' },
verificationFail: { id: 'sms_verification.fail', defaultMessage: 'Failed to send SMS message to your phone number.' },
verificationExpired: { id: 'sms_verification.expired', defaultMessage: 'Your SMS token has expired.' },
});
const Statuses = { const Statuses = {
IDLE: 'IDLE', IDLE: 'IDLE',
REQUESTED: 'REQUESTED', REQUESTED: 'REQUESTED',
@ -38,10 +45,7 @@ const SmsVerification = () => {
setStatus(Statuses.IDLE); setStatus(Statuses.IDLE);
dispatch( dispatch(
snackbar.error( snackbar.error(
intl.formatMessage({ intl.formatMessage(messages.verificationInvalid),
id: 'sms_verification.invalid',
defaultMessage: 'Please enter a valid phone number.',
}),
), ),
); );
return; return;
@ -50,18 +54,12 @@ const SmsVerification = () => {
dispatch(requestPhoneVerification(phone!)).then(() => { dispatch(requestPhoneVerification(phone!)).then(() => {
dispatch( dispatch(
snackbar.success( snackbar.success(
intl.formatMessage({ intl.formatMessage(messages.verificationSuccess),
id: 'sms_verification.success',
defaultMessage: 'A verification code has been sent to your phone number.',
}),
), ),
); );
setStatus(Statuses.REQUESTED); setStatus(Statuses.REQUESTED);
}).catch((error: AxiosError) => { }).catch((error: AxiosError) => {
const message = (error.response?.data as any)?.message || intl.formatMessage({ const message = (error.response?.data as any)?.message || intl.formatMessage(messages.verificationFail);
id: 'sms_verification.fail',
defaultMessage: 'Failed to send SMS message to your phone number.',
});
dispatch(snackbar.error(message)); dispatch(snackbar.error(message));
setStatus(Statuses.FAIL); setStatus(Statuses.FAIL);
@ -78,10 +76,7 @@ const SmsVerification = () => {
dispatch(confirmPhoneVerification(verificationCode)) dispatch(confirmPhoneVerification(verificationCode))
.catch(() => dispatch( .catch(() => dispatch(
snackbar.error( snackbar.error(
intl.formatMessage({ intl.formatMessage(messages.verificationExpired),
id: 'sms_verification.invalid',
defaultMessage: 'Your SMS token has expired.',
}),
), ),
)); ));
}; };
@ -97,7 +92,7 @@ const SmsVerification = () => {
<div> <div>
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-800 border-solid -mx-4 sm:-mx-10'> <div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-800 border-solid -mx-4 sm:-mx-10'>
<h1 className='text-center font-bold text-2xl'> <h1 className='text-center font-bold text-2xl'>
{intl.formatMessage({ id: 'sms_verification.sent.header', defaultMessage: 'Verification code' })} <FormattedMessage id='sms_verification.sent.header' defaultMessage='Verification code' />
</h1> </h1>
</div> </div>
@ -136,7 +131,9 @@ const SmsVerification = () => {
return ( return (
<div> <div>
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-800 border-solid -mx-4 sm:-mx-10'> <div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-gray-800 border-solid -mx-4 sm:-mx-10'>
<h1 className='text-center font-bold text-2xl'>{intl.formatMessage({ id: 'sms_verification.header', defaultMessage: 'Enter your phone number' })}</h1> <h1 className='text-center font-bold text-2xl'>
<FormattedMessage id='sms_verification.header' defaultMessage='Enter your phone number' />
</h1>
</div> </div>
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'> <div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>