Skip to content

fix: translation on select problem type #1798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -21,7 +21,9 @@ const AnswerWidget = ({
<FormattedMessage {...messages.answerWidgetTitle} />
</div>
<div className="small">
{intl.formatMessage(messages.answerHelperText, { helperText: problemStaticData.description })}
{intl.formatMessage(messages.answerHelperText, {
helperText: intl.formatMessage(problemStaticData.description),
})}
</div>
</div>
<AnswersContainer problemType={problemType} />
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import {
AdvancedProblemType,
AdvanceProblems,
AdvanceProblemsStatus,
ProblemType,
ProblemTypeKeys,
} from '../../../../../data/constants/problem';
@@ -54,25 +55,29 @@ const AdvanceTypeSelect: React.FC<Props> = ({
className="px-4"
>
{Object.entries(AdvanceProblems).map(([type, data]) => {
if (data.status !== '') {
if (data.status !== AdvanceProblemsStatus.empty) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels odd to me for a couple reasons:

  • Internationalizing an empty string seems unnecessary
  • We aren't using intl here, so wouldn't this end up checking for the object instead of the string?

I'd think sticking to '' would be simpler and continue to work. Did you run into something that made that not work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it is kind of strange, but the status of AdvanceProblems is now a AdvanceProblemsStatus.

return (
<ActionRow className="border-primary-100 border-bottom m-0 py-3 w-100" key={type}>
<Form.Radio id={type} value={type}>
{intl.formatMessage(messages.advanceProblemTypeLabel, { problemType: data.title })}
{intl.formatMessage(messages.advanceProblemTypeLabel, {
problemType: intl.formatMessage(data.titleMessage),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate on the title vs titleMessage stuff? I see down in problem.ts you've added titleMessage and set title to use the defaultMessage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of titleMessage was to prevent having to create further code refactor on the references of the problem.ts file.
But still kind of using the existing design of Object Oriented idea of the ProblemTypes and AdvanceProblems.
And extracting the i18n to a proper defineMessages so the formatjs can detect them.
So, when you want to present them to the user, I just replace the title with titleMessage on a intl.formatMessage(...).

})}
</Form.Radio>
<ActionRow.Spacer />
<OverlayTrigger
placement="right"
overlay={(
<Tooltip id={`tooltip-adv-${type}`}>
<div className="text-left">
{intl.formatMessage(messages.supportStatusTooltipMessage, { supportStatus: data.status.replace(' ', '_') })}
{intl.formatMessage(messages.supportStatusTooltipMessage, { supportStatus: data.status.defaultMessage.replace(' ', '_') })}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this using the default message instead of an internationalized version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the supportStatusTooltipMessage is a select, so to decide which one should be shown the key is the default value one i18n or Not_supported or Provisional. I prefer not to change too much the existing code.
The replace(' ', '_') probably is because the select from i18n don't allow the key to have whitespace.

https://github.com/fccn/frontend-app-authoring/blob/a1bd09fd7abeba421eadde96362caa48340289d5/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.ts#L30-L46

When I add the translation to pt-pt locale on src/i18n/messages/frontend-app-course-authoring/pt_PT.json:

"authoring.problemEditor.advanceProblem.supportStatus.tooltipMessage": "{supportStatus, select, Provisional {As ferramentas suportadas provisoriamente podem não ter a robustez de funcionalidade que os seus cursos exigem. O edX não tem controlo sobre a qualidade do software ou do conteúdo que pode ser fornecido utilizando estas ferramentas. Teste estas ferramentas cuidadosamente antes de as utilizar no seu curso, especialmente em secções com classificação. A documentação completa pode não estar disponível para as ferramentas suportadas provisoriamente, ou a documentação pode estar disponível a partir de outras fontes que não a edX.} Not_supported {As ferramentas sem suporte não são mantidas pela edX e podem ser descontinuadas no futuro. Não são recomendadas para utilização em cursos devido à não conformidade com um ou mais dos requisitos básicos, tais como testes, acessibilidade, internacionalização e documentação.} other { } }",

It shows correctly has:

image
image

</div>
</Tooltip>
)}
>
<div className="text-gray-500">
{intl.formatMessage(messages.problemSupportStatus, { supportStatus: data.status })}
{intl.formatMessage(messages.problemSupportStatus, {
supportStatus: intl.formatMessage(data.status),
})}
</div>
</OverlayTrigger>
</ActionRow>
@@ -81,7 +86,9 @@ const AdvanceTypeSelect: React.FC<Props> = ({
return (
<ActionRow className="border-primary-100 border-bottom m-0 py-3 w-100" key={type}>
<Form.Radio id={type} value={type}>
{intl.formatMessage(messages.advanceProblemTypeLabel, { problemType: data.title })}
{intl.formatMessage(messages.advanceProblemTypeLabel, {
problemType: intl.formatMessage(data.titleMessage),
})}
</Form.Radio>
<ActionRow.Spacer />
</ActionRow>
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ const Preview = ({
return (
<Container style={{ width: '494px', height: '400px' }} className="bg-light-300 rounded p-4">
<div className="small">
{intl.formatMessage(messages.previewTitle, { previewTitle: data.title })}
{intl.formatMessage(messages.previewTitle, { previewTitle: intl.formatMessage(data.titleMessage) })}
</div>
<Image
fluid
@@ -30,7 +30,9 @@ const Preview = ({
alt={intl.formatMessage(messages.previewAltText, { problemType })}
/>
<div className="mb-3">
{intl.formatMessage(messages.previewDescription, { previewDescription: data.previewDescription })}
{intl.formatMessage(messages.previewDescription, {
previewDescription: intl.formatMessage(data.previewDescription),
})}
</div>
<Hyperlink
destination={data.helpLink}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Button, Container } from '@openedx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';

// SelectableBox in paragon has a bug where you can't change selection. So we override it
import SelectableBox from '../../../../../sharedComponents/SelectableBox';
@@ -22,6 +22,7 @@ const ProblemTypeSelect: React.FC<Props> = ({
selected,
setSelected,
}) => {
const intl = useIntl();
const handleChange = e => setSelected(e.target.value);
const handleClick = () => setSelected(AdvanceProblemKeys.BLANK);
const settings = { type: 'radio' };
@@ -45,7 +46,7 @@ const ProblemTypeSelect: React.FC<Props> = ({
value={key}
{...settings}
>
{ProblemTypes[key].title}
{intl.formatMessage(ProblemTypes[key].titleMessage)}
</SelectableBox>
)
: null
129 changes: 129 additions & 0 deletions src/editors/data/constants/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
import { ProblemTypeKeys, AdvanceProblemKeys } from './problemTypes';

export const ProblemTypesTitleMessages = defineMessages({
[ProblemTypeKeys.SINGLESELECT]: {
id: 'authoring.problemeditor.problemtype.title.singleselect',
defaultMessage: 'Single select',
},
[ProblemTypeKeys.MULTISELECT]: {
id: 'authoring.problemeditor.problemtype.title.multiSelect',
defaultMessage: 'Multi-select',
},
[ProblemTypeKeys.DROPDOWN]: {
id: 'authoring.problemeditor.problemtype.title.dropdown',
defaultMessage: 'Dropdown',
},
[ProblemTypeKeys.NUMERIC]: {
id: 'authoring.problemeditor.problemtype.title.numeric',
defaultMessage: 'Numerical input',
},
[ProblemTypeKeys.TEXTINPUT]: {
id: 'authoring.problemeditor.problemtype.title.textInput',
defaultMessage: 'Text input',
},
[ProblemTypeKeys.ADVANCED]: {
id: 'authoring.problemeditor.problemtype.title.advanced',
defaultMessage: 'Advanced Problem',
},
});

export const ProblemTypesPreviewDescription = defineMessages({
[ProblemTypeKeys.SINGLESELECT]: {
id: 'authoring.problemeditor.problemtype.previewDescription.singleselect',
defaultMessage: 'Learners must select the correct answer from a list of possible options.',
},
[ProblemTypeKeys.MULTISELECT]: {
id: 'authoring.problemeditor.problemtype.previewDescription.multiselect',
defaultMessage: 'Learners must select all correct answers from a list of possible options.',
},
[ProblemTypeKeys.DROPDOWN]: {
id: 'authoring.problemeditor.problemtype.previewDescription.dropdown',
defaultMessage: 'Learners must select the correct answer from a list of possible options',
},
[ProblemTypeKeys.NUMERIC]: {
id: 'authoring.problemeditor.problemtype.previewDescription.numeric',
defaultMessage: 'Specify one or more correct numeric answers, submitted in a response field.',
},
[ProblemTypeKeys.TEXTINPUT]: {
id: 'authoring.problemeditor.problemtype.previewDescription.textinput',
defaultMessage: 'Specify one or more correct text answers, including numbers and special characters, submitted in a response field.',
},
[ProblemTypeKeys.ADVANCED]: {
id: 'authoring.problemeditor.problemtype.previewDescription.advanced',
defaultMessage: 'Specify an advanced problem.',
},
});

export const ProblemTypesDescription = defineMessages({
[ProblemTypeKeys.SINGLESELECT]: {
id: 'authoring.problemeditor.problemtype.description.singleselect',
defaultMessage: 'Enter your single select answers below and select which choices are correct. Learners must choose one correct answer.',
},
[ProblemTypeKeys.MULTISELECT]: {
id: 'authoring.problemeditor.problemtype.description.multiselect',
defaultMessage: 'Enter your multi select answers below and select which choices are correct. Learners must choose all correct answers.',
},
[ProblemTypeKeys.DROPDOWN]: {
id: 'authoring.problemeditor.problemtype.description.dropdown',
defaultMessage: 'Enter your dropdown answers below and select which choice is correct. Learners must select one correct answer.',
},
[ProblemTypeKeys.NUMERIC]: {
id: 'authoring.problemeditor.problemtype.description.numeric',
defaultMessage: 'Enter correct numerical input answers below. Learners must enter one correct answer.',
},
[ProblemTypeKeys.TEXTINPUT]: {
id: 'authoring.problemeditor.problemtype.description.textinput',
defaultMessage: 'Enter your text input answers below and select which choices are correct. Learners must enter one correct answer.',
},
[ProblemTypeKeys.ADVANCED]: {
id: 'authoring.problemeditor.problemtype.description.advanced',
defaultMessage: 'An Advanced Problem Type.',
},
});

export const AdvanceProblemsTitleMessages = defineMessages({
[AdvanceProblemKeys.BLANK]: {
id: 'authoring.problemeditor.settings.advanceProblems.blank',
defaultMessage: 'Blank problem',
},
[AdvanceProblemKeys.CIRCUITSCHEMATIC]: {
id: 'authoring.problemeditor.settings.advanceProblems.circuitSchematic',
defaultMessage: 'Circuit schematic builder',
},
[AdvanceProblemKeys.JSINPUT]: {
id: 'authoring.problemeditor.settings.advanceProblems.jsInput',
defaultMessage: 'Custom JavaScript display and grading',
},
[AdvanceProblemKeys.CUSTOMGRADER]: {
id: 'authoring.problemeditor.settings.advanceProblems.customGrader',
defaultMessage: 'Custom Python-evaluated input',
},
[AdvanceProblemKeys.IMAGE]: {
id: 'authoring.problemeditor.settings.advanceProblems.image',
defaultMessage: 'Image mapped input',
},
[AdvanceProblemKeys.FORMULA]: {
id: 'authoring.problemeditor.settings.advanceProblems.formula',
defaultMessage: 'Math expression input',
},
[AdvanceProblemKeys.PROBLEMWITHHINT]: {
id: 'authoring.problemeditor.settings.advanceProblems.problemWithHint',
defaultMessage: 'Problem with adaptive hint',
},
});

export const AdvanceProblemsStatus = defineMessages({
empty: {
id: 'authoring.problemeditor.settings.advanceProblems.status.empty',
defaultMessage: '',
},
notSupported: {
id: 'authoring.problemeditor.settings.advanceProblems.status.notSupported',
defaultMessage: 'Not supported',
},
provisional: {
id: 'authoring.problemeditor.settings.advanceProblems.status.provisional',
defaultMessage: 'Provisional',
},
});
Loading