feat(i18n): translate server messages (#40626)
This commit is contained in:
@ -60,34 +60,6 @@ export function getFallbackFrontEndDate(completedChallenges, completedDate) {
|
|||||||
return latestCertDate ? latestCertDate : 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) {
|
function ifNoSuperBlock404(req, res, next) {
|
||||||
const { superBlock } = req.body;
|
const { superBlock } = req.body;
|
||||||
if (superBlock && superBlocks.includes(superBlock)) {
|
if (superBlock && superBlocks.includes(superBlock)) {
|
||||||
@ -309,19 +281,31 @@ function createVerifyCert(certTypeIds, app) {
|
|||||||
.flatMap(challenge => {
|
.flatMap(challenge => {
|
||||||
const certName = certText[certType];
|
const certName = certText[certType];
|
||||||
if (user[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
|
// certificate doesn't exist or
|
||||||
// connection error
|
// connection error
|
||||||
if (!challenge) {
|
if (!challenge) {
|
||||||
reportError(`Error claiming ${certName}`);
|
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;
|
const { id, tests, challengeType } = challenge;
|
||||||
if (!canClaim(tests, user.completedChallenges)) {
|
if (!canClaim(tests, user.completedChallenges)) {
|
||||||
return Observable.just(notCertifiedMessage(certName));
|
return Observable.just({
|
||||||
|
type: 'info',
|
||||||
|
message: 'flash.msg-26',
|
||||||
|
variables: { name: certName }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateData = {
|
const updateData = {
|
||||||
@ -337,7 +321,10 @@ function createVerifyCert(certTypeIds, app) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!user.name) {
|
if (!user.name) {
|
||||||
return Observable.just(noNameMessage);
|
return Observable.just({
|
||||||
|
type: 'info',
|
||||||
|
message: 'flash.msg-25'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// set here so sendCertifiedEmail works properly
|
// set here so sendCertifiedEmail works properly
|
||||||
// not used otherwise
|
// not used otherwise
|
||||||
@ -362,15 +349,19 @@ function createVerifyCert(certTypeIds, app) {
|
|||||||
log(pledgeOrMessage);
|
log(pledgeOrMessage);
|
||||||
}
|
}
|
||||||
log('Certificates updated');
|
log('Certificates updated');
|
||||||
return successMessage(user.username, certName);
|
return {
|
||||||
|
type: 'success',
|
||||||
|
message: 'flash.msg-28',
|
||||||
|
variables: {
|
||||||
|
username: user.username,
|
||||||
|
name: certName
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.subscribe(message => {
|
.subscribe(message => {
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
response: {
|
response: message,
|
||||||
type: message.includes('Congratulations') ? 'success' : 'info',
|
|
||||||
message
|
|
||||||
},
|
|
||||||
isCertMap: getUserIsCertMap(user),
|
isCertMap: getUserIsCertMap(user),
|
||||||
// send back the completed challenges
|
// send back the completed challenges
|
||||||
// NOTE: we could just send back the latest challenge, but this
|
// NOTE: we could just send back the latest challenge, but this
|
||||||
@ -426,8 +417,8 @@ function createShowCert(app) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message:
|
message: 'flash.msg-31',
|
||||||
'We could not find a user with the username "' + username + '"'
|
variables: { username: username }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -439,10 +430,7 @@ function createShowCert(app) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: dedent`
|
message: 'flash.msg-32'
|
||||||
This user needs to add their name to their account
|
|
||||||
in order for others to be able to view their certification.
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -453,9 +441,7 @@ function createShowCert(app) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message:
|
message: 'flash.msg-33'
|
||||||
'This user is not eligible for freeCodeCamp.org ' +
|
|
||||||
'certifications at this time'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -466,11 +452,8 @@ function createShowCert(app) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: dedent`
|
message: 'flash.msg-34',
|
||||||
${username} has chosen to make their portfolio
|
variables: { username: username }
|
||||||
private. They will need to make their portfolio public
|
|
||||||
in order for others to be able to view their certification.
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -481,11 +464,8 @@ function createShowCert(app) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: dedent`
|
message: 'flash.msg-35',
|
||||||
${username} has chosen to make their certifications
|
variables: { username: username }
|
||||||
private. They will need to make their certifications public
|
|
||||||
in order for others to be able to view them.
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -496,9 +476,8 @@ function createShowCert(app) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: dedent`
|
message: 'flash.msg-36',
|
||||||
${username} has not yet agreed to our Academic Honesty Pledge.
|
variables: { username: username }
|
||||||
`
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -545,9 +524,8 @@ function createShowCert(app) {
|
|||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: `
|
message: 'flash.msg-37',
|
||||||
It looks like user ${username} is not ${certText[certType]} certified
|
variables: { username: username, cert: certText[certType] }
|
||||||
`
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -53,13 +53,12 @@ export default function settingsController(app) {
|
|||||||
|
|
||||||
const standardErrorMessage = {
|
const standardErrorMessage = {
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
message:
|
message: 'flash.msg-9'
|
||||||
'Something went wrong updating your account. Please check and try again'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const standardSuccessMessage = {
|
const standardSuccessMessage = {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: 'We have updated your preferences'
|
message: 'flash.msg-10'
|
||||||
};
|
};
|
||||||
|
|
||||||
const createStandardHandler = (req, res, next) => err => {
|
const createStandardHandler = (req, res, next) => err => {
|
||||||
@ -196,7 +195,7 @@ function createUpdateMyUsername(app) {
|
|||||||
if (username === user.username) {
|
if (username === user.username) {
|
||||||
return res.json({
|
return res.json({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: 'Username is already associated with this account'
|
message: 'flash.msg-16'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const validation = isValidUsername(username);
|
const validation = isValidUsername(username);
|
||||||
@ -213,7 +212,7 @@ function createUpdateMyUsername(app) {
|
|||||||
if (exists) {
|
if (exists) {
|
||||||
return res.json({
|
return res.json({
|
||||||
type: 'info',
|
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);
|
res.status(500).json(standardErrorMessage);
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
type: 'success',
|
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);
|
res.status(500).json(standardErrorMessage);
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
return res.status(200).json({
|
return res.status(200).json(standardSuccessMessage);
|
||||||
type: 'success',
|
|
||||||
message: `We have updated your preferences.`
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ function createPostReportUserProfile(app) {
|
|||||||
if (!username || !report || report === '') {
|
if (!username || !report || report === '') {
|
||||||
return res.json({
|
return res.json({
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
message: 'Check if you have provided a username and a report'
|
message: 'flash.msg-44'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Email.send$(
|
return Email.send$(
|
||||||
@ -246,8 +246,9 @@ function createPostReportUserProfile(app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
typer: 'info',
|
type: 'info',
|
||||||
message: `A report was sent to the team with ${user.email} in copy.`
|
message: 'flash.msg-45',
|
||||||
|
variables: { email: user.email }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -451,7 +451,7 @@
|
|||||||
"msg-33": "This user is not eligible for freeCodeCamp.org certifications at this time.",
|
"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-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-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-37": "It looks like user {{username}} is not {{cert}} certified",
|
||||||
"msg-38": "That does not appear to be a valid challenge submission",
|
"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.",
|
"msg-39": "You have not provided the valid links for us to inspect your work.",
|
||||||
|
@ -7,10 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import './flash.css';
|
import './flash.css';
|
||||||
|
|
||||||
function Flash({ flashMessage, onClose }) {
|
function Flash({ flashMessage, onClose }) {
|
||||||
// flash messages coming from the server are already translated
|
const { type, message, id, variables = {} } = flashMessage;
|
||||||
// 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 { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [flashMessageHeight, setFlashMessageHeight] = useState(null);
|
const [flashMessageHeight, setFlashMessageHeight] = useState(null);
|
||||||
|
|
||||||
@ -38,7 +35,7 @@ function Flash({ flashMessage, onClose }) {
|
|||||||
className='flash-message'
|
className='flash-message'
|
||||||
onDismiss={handleClose}
|
onDismiss={handleClose}
|
||||||
>
|
>
|
||||||
{needsTranslating ? t(`${message}`) : message}
|
{t(message, variables)}
|
||||||
</Alert>
|
</Alert>
|
||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
@ -59,7 +56,7 @@ Flash.propTypes = {
|
|||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
message: PropTypes.string,
|
message: PropTypes.string,
|
||||||
needsTranslating: PropTypes.bool
|
variables: PropTypes.object
|
||||||
}),
|
}),
|
||||||
onClose: PropTypes.func.isRequired
|
onClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
@ -140,8 +140,7 @@ const isCertMapSelector = createSelector(
|
|||||||
|
|
||||||
const honestyInfoMessage = {
|
const honestyInfoMessage = {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: 'flash.msg-1',
|
message: 'flash.msg-1'
|
||||||
needsTranslating: true
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
|
@ -12,8 +12,7 @@ function* deleteAccountSaga() {
|
|||||||
yield put(
|
yield put(
|
||||||
createFlashMessage({
|
createFlashMessage({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: 'flash.msg-5',
|
message: 'flash.msg-5'
|
||||||
needsTranslating: true
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// remove current user information from application state
|
// remove current user information from application state
|
||||||
@ -30,8 +29,7 @@ function* resetProgressSaga() {
|
|||||||
yield put(
|
yield put(
|
||||||
createFlashMessage({
|
createFlashMessage({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: 'flash.msg-6',
|
message: 'flash.msg-6'
|
||||||
needsTranslating: true
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// refresh current user data in application state
|
// refresh current user data in application state
|
||||||
|
@ -33,16 +33,14 @@ export function handle400Error(e, options = { redirectTo: '/' }) {
|
|||||||
return {
|
return {
|
||||||
...flash,
|
...flash,
|
||||||
type: 'warn',
|
type: 'warn',
|
||||||
message: 'flash.msg-7',
|
message: 'flash.msg-7'
|
||||||
needsTranslating: true
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case 404: {
|
case 404: {
|
||||||
return {
|
return {
|
||||||
...flash,
|
...flash,
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: 'flash.msg-8',
|
message: 'flash.msg-8'
|
||||||
needsTranslating: true
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export default {
|
export default {
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
message: 'flash.msg-2',
|
message: 'flash.msg-2'
|
||||||
needsTranslating: true
|
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export default {
|
export default {
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
message: 'flash.msg-3',
|
message: 'flash.msg-3'
|
||||||
needsTranslating: true
|
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export default {
|
export default {
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
message: 'flash.msg-4',
|
message: 'flash.msg-4'
|
||||||
needsTranslating: true
|
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user