Live language feedback (#1071)

* Add live language detection using 'lande' in TrackedTextarea.

* Remove 'Disable Language Detection'.

* Re-run linter.
This commit is contained in:
Korbinian Pöppel
2023-02-05 07:10:53 +01:00
committed by GitHub
parent 3b61a26c9c
commit 7fac0d70c8
4 changed files with 282 additions and 3 deletions
+27
View File
@@ -32,6 +32,7 @@
"eslint-plugin-simple-import-sort": "^8.0.0",
"focus-visible": "^5.2.0",
"framer-motion": "^6.5.1",
"lande": "^1.0.10",
"lucide-react": "^0.105.0",
"next": "13.0.6",
"next-auth": "^4.18.6",
@@ -26611,6 +26612,14 @@
"node": ">= 8"
}
},
"node_modules/lande": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/lande/-/lande-1.0.10.tgz",
"integrity": "sha512-yT52DQh+UV2pEp08jOYrA4drDv0DbjpiRyZYgl25ak9G2cVR2AimzrqkYQWrD9a7Ud+qkAcaiDDoNH9DXfHPmw==",
"dependencies": {
"toygrad": "^2.6.0"
}
},
"node_modules/language-subtag-registry": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
@@ -36420,6 +36429,11 @@
"node": ">=0.8"
}
},
"node_modules/toygrad": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/toygrad/-/toygrad-2.6.0.tgz",
"integrity": "sha512-g4zBmlSbvzOE5FOILxYkAybTSxijKLkj1WoNqVGnbMcWDyj4wWQ+eYSr3ik7XOpIgMq/7eBcPRTJX3DM2E0YMg=="
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -58708,6 +58722,14 @@
"integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==",
"dev": true
},
"lande": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/lande/-/lande-1.0.10.tgz",
"integrity": "sha512-yT52DQh+UV2pEp08jOYrA4drDv0DbjpiRyZYgl25ak9G2cVR2AimzrqkYQWrD9a7Ud+qkAcaiDDoNH9DXfHPmw==",
"requires": {
"toygrad": "^2.6.0"
}
},
"language-subtag-registry": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
@@ -65936,6 +65958,11 @@
"punycode": "^2.1.1"
}
},
"toygrad": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/toygrad/-/toygrad-2.6.0.tgz",
"integrity": "sha512-g4zBmlSbvzOE5FOILxYkAybTSxijKLkj1WoNqVGnbMcWDyj4wWQ+eYSr3ik7XOpIgMq/7eBcPRTJX3DM2E0YMg=="
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+1
View File
@@ -50,6 +50,7 @@
"eslint-plugin-simple-import-sort": "^8.0.0",
"focus-visible": "^5.2.0",
"framer-motion": "^6.5.1",
"lande": "^1.0.10",
"lucide-react": "^0.105.0",
"next": "13.0.6",
"next-auth": "^4.18.6",
@@ -1,4 +1,23 @@
import { Progress, Stack, Textarea, TextareaProps, useColorModeValue } from "@chakra-ui/react";
import {} from "@chakra-ui/react";
import lande from "lande";
import { LanguageAbbreviations } from "src/lib/iso6393";
import { useCookies } from "react-cookie";
import React from "react";
import {
Progress,
Stack,
Textarea,
TextareaProps,
useColorModeValue,
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
useDisclosure,
} from "@chakra-ui/react";
interface TrackedTextboxProps {
text: string;
@@ -11,10 +30,55 @@ interface TrackedTextboxProps {
onTextChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
}
export const TrackedTextarea = (props: TrackedTextboxProps) => {
const backgroundColor = useColorModeValue("gray.100", "gray.900");
const killEvent = (e) => e.stopPropagation();
export const TrackedTextarea = (props: TrackedTextboxProps) => {
const [wordLimitForLangDetection, setWordLimitForLangDetection] = React.useState(10);
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;
try {
mostProbableLanguage = LanguageAbbreviations[lande(props.text)[0][0]];
} catch (error) {
mostProbableLanguage = "";
}
/*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>
</>
);
}
}
let progressColor: string;
switch (true) {
+187
View File
@@ -0,0 +1,187 @@
export const LanguageAbbreviations = {
aar: "aa",
abk: "ab",
afr: "af",
aka: "ak",
alb: "sq",
amh: "am",
ara: "ar",
arg: "an",
hye: "hy",
asm: "as",
ava: "av",
ave: "ae",
aym: "ay",
aze: "az",
bak: "ba",
bam: "bm",
eus: "eu",
bel: "be",
ben: "bn",
bih: "bh",
bis: "bi",
tib: "bo",
bos: "bs",
bre: "br",
bul: "bg",
mya: "my",
cat: "ca",
cze: "cs",
cha: "ch",
che: "ce",
zho: "zh",
chu: "cu",
chv: "cv",
cor: "kw",
cos: "co",
cre: "cr",
wel: "cy",
dan: "da",
ger: "de",
deu: "de",
div: "dv",
dut: "nl",
dzo: "dz",
gre: "el",
eng: "en",
epo: "eo",
est: "et",
ewe: "ee",
fao: "fo",
per: "fa",
fij: "fj",
fin: "fi",
fra: "fr",
fry: "fy",
ful: "ff",
geo: "ka",
gla: "gd",
gle: "ga",
glg: "gl",
glv: "gv",
grn: "gn",
guj: "gu",
hat: "ht",
hau: "ha",
heb: "he",
her: "hz",
hin: "hi",
hmo: "ho",
hrv: "hr",
hun: "hu",
ibo: "ig",
ice: "is",
ido: "io",
iii: "ii",
iku: "iu",
ile: "ie",
ina: "ia",
ind: "id",
ipk: "ik",
ita: "it",
jav: "jv",
jpn: "ja",
kal: "kl",
kan: "kn",
kas: "ks",
kau: "kr",
kaz: "kk",
khm: "km",
kik: "ki",
kin: "rw",
kir: "ky",
kom: "kv",
kon: "kg",
kor: "ko",
kua: "kj",
kur: "ku",
lao: "lo",
lat: "la",
lav: "lv",
lim: "li",
lin: "ln",
lit: "lt",
ltz: "lb",
lub: "lu",
lug: "lg",
mkd: "mk",
mah: "mh",
mal: "ml",
mri: "mi",
mar: "mr",
may: "ms",
mlg: "mg",
mlt: "mt",
mon: "mn",
nau: "na",
nav: "nv",
nbl: "nr",
nde: "nd",
ndo: "ng",
nep: "ne",
nno: "nn",
nob: "nb",
nor: "no",
nya: "ny",
oci: "oc",
oji: "oj",
ori: "or",
orm: "om",
oss: "os",
pan: "pa",
pli: "pi",
pol: "pl",
por: "pt",
pus: "ps",
que: "qu",
roh: "rm",
ron: "ro",
run: "rn",
rus: "ru",
sag: "sg",
san: "sa",
sin: "si",
slk: "sk",
slv: "sl",
sme: "se",
smo: "sm",
sna: "sn",
snd: "sd",
som: "so",
sot: "st",
spa: "es",
srd: "sc",
srp: "sr",
ssw: "ss",
sun: "su",
swa: "sw",
swe: "sv",
tah: "ty",
tam: "ta",
tat: "tt",
tel: "te",
tgk: "tg",
tgl: "tl",
tha: "th",
tir: "ti",
ton: "to",
tsn: "tn",
tso: "ts",
tuk: "tk",
tur: "tr",
twi: "tw",
uig: "ug",
ukr: "uk",
urd: "ur",
uzb: "uz",
ven: "ve",
vie: "vi",
vol: "vo",
wln: "wa",
wol: "wo",
xho: "xh",
yid: "yi",
yor: "yo",
zha: "za",
zul: "zu",
};