website: show language in text area (#1296)

* website: show language in text area

When the language hasn't been detected (too little text) the langauge that it will be submitted as is shown. When we detect the language is not what will be submitted we show the detected language in red. The tooltip informs the user that they don't appear to be writing in the correct language.

Note: this replaces the modal dialog that we use to popup if the language appeared to differ.

* website: Don't suggest the user change the language
This commit is contained in:
Adrian Cowan
2023-02-07 22:17:53 +11:00
committed by GitHub
parent ab82da7d74
commit 52af7ba13b
4 changed files with 79 additions and 67 deletions
+22
View File
@@ -0,0 +1,22 @@
{
"writing_wrong_langauge_a_b": "You appear to be writing in {{detected_lang}} but this will be submitted as {{submit_lang}}.",
"submitted_as": "This will be submitted as {{submit_lang}}",
"lang_ar": "Arabic",
"lang_bn": "Bengali",
"lang_ca": "Catalan",
"lang_de": "German",
"lang_en": "English",
"lang_es": "Spanish",
"lang_fr": "French",
"lang_hu": "Hungarian",
"lang_it": "Italian",
"lang_ja": "Japanese",
"lang_ko": "Korean",
"lang_pl": "Polish",
"lang_pt-BR": "Brazilian Portugese",
"lang_ru": "Russian",
"lang_tr": "Turkish",
"lang_uk-UA": "Ukrainian",
"lang_vi": "Vietnamese",
"lang_zh": "Chinese"
}
@@ -1,23 +1,12 @@
import {} from "@chakra-ui/react";
import { Tooltip } from "@chakra-ui/react";
import { Progress, Stack, Textarea, TextareaProps, useColorModeValue } from "@chakra-ui/react";
import lande from "lande";
import { LanguageAbbreviations } from "src/lib/iso6393";
import { useCookies } from "react-cookie";
import { useTranslation } from "next-i18next";
import React from "react";
import {
Progress,
Stack,
Textarea,
TextareaProps,
useColorModeValue,
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
useDisclosure,
} from "@chakra-ui/react";
import { useCookies } from "react-cookie";
import { getTypeSafei18nKey } from "src/lib/i18n";
import { LanguageAbbreviations } from "src/lib/iso6393";
import { colors } from "src/styles/Theme/colors";
interface TrackedTextboxProps {
text: string;
@@ -30,55 +19,23 @@ interface TrackedTextboxProps {
onTextChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
}
const killEvent = (e) => e.stopPropagation();
export const TrackedTextarea = (props: TrackedTextboxProps) => {
const [wordLimitForLangDetection, setWordLimitForLangDetection] = React.useState(10);
const { t } = useTranslation("language");
const wordLimitForLangDetection = 4;
const backgroundColor = useColorModeValue("gray.100", "gray.900");
const [cookies] = useCookies(["NEXT_LOCALE"]);
const wordCount = (props.text.match(/\w+/g) || []).length;
const { isOpen, onOpen, onClose } = useDisclosure();
const currentLanguage = cookies["NEXT_LOCALE"];
const closeTemporaryIgnoreLanguageDetection = () => {
setWordLimitForLangDetection(2 * wordCount);
onClose();
};
console.log("", wordCount, wordLimitForLangDetection);
if (wordCount > wordLimitForLangDetection) {
let mostProbableLanguage;
const detectLang = (text: string) => {
try {
mostProbableLanguage = LanguageAbbreviations[lande(props.text)[0][0]];
return LanguageAbbreviations[lande(text)[0][0]];
} catch (error) {
mostProbableLanguage = "";
return currentLanguage;
}
/*const mostProbableLanguage = lande(props.text);*/
if (mostProbableLanguage !== currentLanguage) {
setTimeout(() => {
onOpen();
}, 200);
return (
<>
<Modal isOpen={isOpen} onClose={closeTemporaryIgnoreLanguageDetection} size="xl" scrollBehavior={"inside"}>
{/* we kill the event here to disable drag and drop, since it is in the same container */}
<ModalOverlay onMouseDown={killEvent}>
<ModalContent alignItems="center">
<ModalHeader>Switch Language?</ModalHeader>
<ModalCloseButton />
<ModalBody>
Do you want to switch language? The detected language is <b>{mostProbableLanguage}</b>, whereas your
chosen language is <b>{currentLanguage}</b>. The language can be changed on the top right.
</ModalBody>
</ModalContent>
</ModalOverlay>
</Modal>
</>
);
}
}
};
const detectedLang = wordCount > wordLimitForLangDetection ? detectLang(props.text) : currentLanguage;
const wrongLanguage = detectedLang !== currentLanguage;
let progressColor: string;
switch (true) {
@@ -92,17 +49,46 @@ export const TrackedTextarea = (props: TrackedTextboxProps) => {
progressColor = "green";
}
const problemColor = useColorModeValue(colors.light.problem, colors.dark.problem);
return (
<Stack direction={"column"}>
<Textarea
backgroundColor={backgroundColor}
border="none"
data-cy="reply"
p="4"
value={props.text}
onChange={props.onTextChange}
{...props.textareaProps}
/>
<div style={{ position: "relative" }}>
<Textarea
backgroundColor={backgroundColor}
border="none"
data-cy="reply"
p="4"
value={props.text}
onChange={props.onTextChange}
{...props.textareaProps}
/>
<div
style={{
fontSize: "0.7em",
fontWeight: "bold",
color: wrongLanguage ? problemColor : "gray",
position: "absolute",
top: 0,
marginTop: "0.1em",
left: 0, // Attach to left and right and align to end to support rtl languages
right: 0,
marginInlineEnd: "0.5em",
textAlign: "end",
zIndex: 1, // Appear above the text box when it has focus
textTransform: "uppercase",
}}
>
<Tooltip
label={t(wrongLanguage ? "writing_wrong_langauge_a_b" : "submitted_as", {
submit_lang: t(getTypeSafei18nKey(`lang_${currentLanguage}`), currentLanguage),
detected_lang: t(getTypeSafei18nKey(`lang_${detectedLang}`), detectedLang),
})}
>
{detectedLang}
</Tooltip>
</div>
</div>
<Progress
size={"md"}
height={"2"}
+2
View File
@@ -2,11 +2,13 @@ export const colors = {
light: {
bg: "rgb(250,250,250)",
text: "black",
problem: "#E53E3E",
active: "blue.400",
},
dark: {
bg: "gray.900",
text: "white",
problem: "#FC8181",
active: "blue.500",
},
"dark-blue-btn": {
+2
View File
@@ -2,6 +2,7 @@ import type common from "public/locales/en/common.json";
import type dashboard from "public/locales/en/dashboard.json";
import type index from "public/locales/en/index.json";
import type labelling from "public/locales/en/labelling.json";
import type language from "public/locales/en/language.json";
import type leaderboard from "public/locales/en/leaderboard.json";
import type message from "public/locales/en/message.json";
import type side_menu from "public/locales/en/side_menu.json";
@@ -18,6 +19,7 @@ declare module "i18next" {
tasks: typeof tasks;
message: typeof message;
labelling: typeof labelling;
language: typeof language;
side_menu: typeof side_menu;
tos: typeof tos;
};