feat(i18n): translate server messages (#40626)

This commit is contained in:
Tom
2021-01-07 12:36:51 -06:00
committed by Mrugesh Mohapatra
parent 77022b8a56
commit 072a7ce6c6
11 changed files with 64 additions and 98 deletions

View File

@ -60,34 +60,6 @@ export function getFallbackFrontEndDate(completedChallenges, completedDate) {
return latestCertDate ? latestCertDate : completedDate;
}
const noNameMessage = dedent`
We need your name so we can put it on your certification.
Add your name to your account settings and click the save button.
Then we can issue your certification.
`;
const notCertifiedMessage = name => dedent`
It looks like you have not completed the necessary steps.
Please complete the required projects to claim the
${name} Certification
`;
const alreadyClaimedMessage = name => dedent`
It looks like you already have claimed the ${name} Certification
`;
const successMessage = (username, name) => dedent`
@${username}, you have successfully claimed
the ${name} Certification!
Congratulations on behalf of the freeCodeCamp.org team!
`;
const failureMessage = name => dedent`
Something went wrong with the verification of ${name}, please try again.
If you continue to receive this error, you can send a message to
support@freeCodeCamp.org to get help.
`;
function ifNoSuperBlock404(req, res, next) {
const { superBlock } = req.body;
if (superBlock && superBlocks.includes(superBlock)) {
@ -309,19 +281,31 @@ function createVerifyCert(certTypeIds, app) {
.flatMap(challenge => {
const certName = certText[certType];
if (user[certType]) {
return Observable.just(alreadyClaimedMessage(certName));
return Observable.just({
type: 'info',
message: 'flash.msg-27',
variables: { name: certName }
});
}
// certificate doesn't exist or
// connection error
if (!challenge) {
reportError(`Error claiming ${certName}`);
return Observable.just(failureMessage(certName));
return Observable.just({
type: 'danger',
message: 'flash.msg-29',
variables: { name: certName }
});
}
const { id, tests, challengeType } = challenge;
if (!canClaim(tests, user.completedChallenges)) {
return Observable.just(notCertifiedMessage(certName));
return Observable.just({
type: 'info',
message: 'flash.msg-26',
variables: { name: certName }
});
}
const updateData = {
@ -337,7 +321,10 @@ function createVerifyCert(certTypeIds, app) {
};
if (!user.name) {
return Observable.just(noNameMessage);
return Observable.just({
type: 'info',
message: 'flash.msg-25'
});
}
// set here so sendCertifiedEmail works properly
// not used otherwise
@ -362,15 +349,19 @@ function createVerifyCert(certTypeIds, app) {
log(pledgeOrMessage);
}
log('Certificates updated');
return successMessage(user.username, certName);
return {
type: 'success',
message: 'flash.msg-28',
variables: {
username: user.username,
name: certName
}
};
});
})
.subscribe(message => {
return res.status(200).json({
response: {
type: message.includes('Congratulations') ? 'success' : 'info',
message
},
response: message,
isCertMap: getUserIsCertMap(user),
// send back the completed challenges
// NOTE: we could just send back the latest challenge, but this
@ -426,8 +417,8 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message:
'We could not find a user with the username "' + username + '"'
message: 'flash.msg-31',
variables: { username: username }
}
]
});
@ -439,10 +430,7 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message: dedent`
This user needs to add their name to their account
in order for others to be able to view their certification.
`
message: 'flash.msg-32'
}
]
});
@ -453,9 +441,7 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message:
'This user is not eligible for freeCodeCamp.org ' +
'certifications at this time'
message: 'flash.msg-33'
}
]
});
@ -466,11 +452,8 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message: dedent`
${username} has chosen to make their portfolio
private. They will need to make their portfolio public
in order for others to be able to view their certification.
`
message: 'flash.msg-34',
variables: { username: username }
}
]
});
@ -481,11 +464,8 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message: dedent`
${username} has chosen to make their certifications
private. They will need to make their certifications public
in order for others to be able to view them.
`
message: 'flash.msg-35',
variables: { username: username }
}
]
});
@ -496,9 +476,8 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message: dedent`
${username} has not yet agreed to our Academic Honesty Pledge.
`
message: 'flash.msg-36',
variables: { username: username }
}
]
});
@ -545,9 +524,8 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message: `
It looks like user ${username} is not ${certText[certType]} certified
`
message: 'flash.msg-37',
variables: { username: username, cert: certText[certType] }
}
]
});

View File

@ -53,13 +53,12 @@ export default function settingsController(app) {
const standardErrorMessage = {
type: 'danger',
message:
'Something went wrong updating your account. Please check and try again'
message: 'flash.msg-9'
};
const standardSuccessMessage = {
type: 'success',
message: 'We have updated your preferences'
message: 'flash.msg-10'
};
const createStandardHandler = (req, res, next) => err => {
@ -196,7 +195,7 @@ function createUpdateMyUsername(app) {
if (username === user.username) {
return res.json({
type: 'info',
message: 'Username is already associated with this account'
message: 'flash.msg-16'
});
}
const validation = isValidUsername(username);
@ -213,7 +212,7 @@ function createUpdateMyUsername(app) {
if (exists) {
return res.json({
type: 'info',
message: 'Username is already associated with a different account'
message: 'flash.msg-17'
});
}
@ -222,9 +221,11 @@ function createUpdateMyUsername(app) {
res.status(500).json(standardErrorMessage);
return next(err);
}
return res.status(200).json({
type: 'success',
message: `We have updated your username to ${username}`
message: `flash.msg-18`,
variables: { username: username }
});
});
};
@ -244,10 +245,7 @@ const updatePrivacyTerms = (req, res, next) => {
res.status(500).json(standardErrorMessage);
return next(err);
}
return res.status(200).json({
type: 'success',
message: `We have updated your preferences.`
});
return res.status(200).json(standardSuccessMessage);
});
};

View File

@ -216,7 +216,7 @@ function createPostReportUserProfile(app) {
if (!username || !report || report === '') {
return res.json({
type: 'danger',
message: 'Check if you have provided a username and a report'
message: 'flash.msg-44'
});
}
return Email.send$(
@ -246,8 +246,9 @@ function createPostReportUserProfile(app) {
}
return res.json({
typer: 'info',
message: `A report was sent to the team with ${user.email} in copy.`
type: 'info',
message: 'flash.msg-45',
variables: { email: user.email }
});
}
);

View File

@ -451,7 +451,7 @@
"msg-33": "This user is not eligible for freeCodeCamp.org certifications at this time.",
"msg-34": "{{username}} has chosen to make their portfolio private. They will need to make their portfolio public in order for others to be able to view their certification.",
"msg-35": "{{username}} has chosen to make their certifications private. They will need to make their certifications public in order for others to be able to view them.",
"msg-36": "{{username}} has not yet agrees to our Academic Honesty Pledge.",
"msg-36": "{{username}} has not yet agreed to our Academic Honesty Pledge.",
"msg-37": "It looks like user {{username}} is not {{cert}} certified",
"msg-38": "That does not appear to be a valid challenge submission",
"msg-39": "You have not provided the valid links for us to inspect your work.",

View File

@ -7,10 +7,7 @@ import { useTranslation } from 'react-i18next';
import './flash.css';
function Flash({ flashMessage, onClose }) {
// flash messages coming from the server are already translated
// messages on the client get translated here and need a
// needsTranslating variable set to true with the object
const { type, message, id, needsTranslating = false } = flashMessage;
const { type, message, id, variables = {} } = flashMessage;
const { t } = useTranslation();
const [flashMessageHeight, setFlashMessageHeight] = useState(null);
@ -38,7 +35,7 @@ function Flash({ flashMessage, onClose }) {
className='flash-message'
onDismiss={handleClose}
>
{needsTranslating ? t(`${message}`) : message}
{t(message, variables)}
</Alert>
</CSSTransition>
</TransitionGroup>
@ -59,7 +56,7 @@ Flash.propTypes = {
id: PropTypes.string,
type: PropTypes.string,
message: PropTypes.string,
needsTranslating: PropTypes.bool
variables: PropTypes.object
}),
onClose: PropTypes.func.isRequired
};

View File

@ -140,8 +140,7 @@ const isCertMapSelector = createSelector(
const honestyInfoMessage = {
type: 'info',
message: 'flash.msg-1',
needsTranslating: true
message: 'flash.msg-1'
};
const initialState = {

View File

@ -12,8 +12,7 @@ function* deleteAccountSaga() {
yield put(
createFlashMessage({
type: 'info',
message: 'flash.msg-5',
needsTranslating: true
message: 'flash.msg-5'
})
);
// remove current user information from application state
@ -30,8 +29,7 @@ function* resetProgressSaga() {
yield put(
createFlashMessage({
type: 'info',
message: 'flash.msg-6',
needsTranslating: true
message: 'flash.msg-6'
})
);
// refresh current user data in application state

View File

@ -33,16 +33,14 @@ export function handle400Error(e, options = { redirectTo: '/' }) {
return {
...flash,
type: 'warn',
message: 'flash.msg-7',
needsTranslating: true
message: 'flash.msg-7'
};
}
case 404: {
return {
...flash,
type: 'info',
message: 'flash.msg-8',
needsTranslating: true
message: 'flash.msg-8'
};
}
default: {

View File

@ -1,5 +1,4 @@
export default {
type: 'danger',
message: 'flash.msg-2',
needsTranslating: true
message: 'flash.msg-2'
};

View File

@ -1,5 +1,4 @@
export default {
type: 'danger',
message: 'flash.msg-3',
needsTranslating: true
message: 'flash.msg-3'
};

View File

@ -1,5 +1,4 @@
export default {
type: 'danger',
message: 'flash.msg-4',
needsTranslating: true
message: 'flash.msg-4'
};