diff --git a/.changeset/soft-pans-attend.md b/.changeset/soft-pans-attend.md new file mode 100644 index 0000000000..5cfc98ddaf --- /dev/null +++ b/.changeset/soft-pans-attend.md @@ -0,0 +1,6 @@ +--- +"@khanacademy/math-input": minor +"@khanacademy/perseus": minor +--- + +Allow learners to type trig operators in any language in the Expression widget diff --git a/packages/math-input/src/components/input/mathquill-instance.ts b/packages/math-input/src/components/input/mathquill-instance.ts index 1e930089bd..3ae21f2588 100644 --- a/packages/math-input/src/components/input/mathquill-instance.ts +++ b/packages/math-input/src/components/input/mathquill-instance.ts @@ -26,12 +26,17 @@ const createBaseConfig = (): MathFieldConfig => ({ "arccos", "arcsin", "arctan", + "arctg", "arg", "cos", + "cosec", + "cossec", "cosh", "cot", + "cotg", "coth", "csc", + "ctg", "deg", "det", "dim", @@ -58,6 +63,7 @@ const createBaseConfig = (): MathFieldConfig => ({ "sup", "tan", "tanh", + "tg", ].join(" "), // Pop the cursor out of super/subscripts on arithmetic operators diff --git a/packages/perseus/src/widgets/__tests__/expression.test.tsx b/packages/perseus/src/widgets/__tests__/expression.test.tsx index 8a582ab1f9..dc1e134c61 100644 --- a/packages/perseus/src/widgets/__tests__/expression.test.tsx +++ b/packages/perseus/src/widgets/__tests__/expression.test.tsx @@ -198,16 +198,6 @@ describe("Expression Widget", function () { const item = expressionItemWithAnswer("sin(x)"); assertIncorrect(item, "2"); }); - - it("treats sen as equivalent to sin", () => { - const item = expressionItemWithAnswer("sin(x)"); - assertCorrect(item, "sen x"); - }); - - it("treats multiple usages of sen as equivalent to sin", () => { - const item = expressionItemWithAnswer("sin(sin(x))"); - assertCorrect(item, "sen(sen(x))"); - }); }); describe("analytics", () => { @@ -256,6 +246,48 @@ describe("Expression Widget", function () { assertKeypadVersion(Object.freeze({}), "MATH_INPUT_KEYPAD_V2"); }); }); + + describe("international trig operators", () => { + it("treats sen as equivalent to sin", () => { + const item = expressionItemWithAnswer("sin(x)"); + assertCorrect(item, "sen x"); + }); + + it("works when multiple operators are present", () => { + const item = expressionItemWithAnswer("sin(sin(x))"); + assertCorrect(item, "sen(sen(x))"); + }); + + it("treats arctg as equivalent to arctan", () => { + const item = expressionItemWithAnswer("arctan(x)"); + assertCorrect(item, "arctg x"); + }); + + it("treats cosec as equivalent to csc", () => { + const item = expressionItemWithAnswer("csc(x)"); + assertCorrect(item, "cosec x"); + }); + + it("treats cossec as equivalent to csc", () => { + const item = expressionItemWithAnswer("csc(x)"); + assertCorrect(item, "cossec x"); + }); + + it("treats cotg as equivalent to cot", () => { + const item = expressionItemWithAnswer("cot(x)"); + assertCorrect(item, "cotg x"); + }); + + it("treats ctg as equivalent to cot", () => { + const item = expressionItemWithAnswer("cot(x)"); + assertCorrect(item, "ctg x"); + }); + + it("treats tg as equivalent to tan", () => { + const item = expressionItemWithAnswer("tan(x)"); + assertCorrect(item, "tg x"); + }); + }); }); describe("getOneCorrectAnswerFromRubric", () => { diff --git a/packages/perseus/src/widgets/expression.tsx b/packages/perseus/src/widgets/expression.tsx index a9f6417bf7..b9574d7ded 100644 --- a/packages/perseus/src/widgets/expression.tsx +++ b/packages/perseus/src/widgets/expression.tsx @@ -35,11 +35,25 @@ type InputPath = ReadonlyArray; const ERROR_TITLE = i18n._("Oops!"); const ERROR_MESSAGE = i18n._("Sorry, I don't understand that!"); +// Map of international operator names to their English equivalents +const englishOperators = { + arctg: "arctan", + cosec: "csc", + cossec: "csc", + cotg: "cot", + ctg: "cot", + sen: "sin", + tg: "tan", +}; + const anglicizeOperators = (tex: string): string => { // sen is used instead of sin in some languages, e.g. Portuguese. // To ensure that answers in various languages are graded correctly, we // convert operators to their Englishy forms. - return tex.replace(/\\operatorname{sen}/g, "\\sin "); + return tex.replace( + /\\operatorname{([a-z]+)}/g, + (_, op) => `\\${englishOperators[op] ?? op} `, + ); }; const normalizeTex = (tex: string): string => {