Skip to content

Commit a161b25

Browse files
author
Your Name
committed
merge master with develop
2 parents 68e6594 + 2bab6c0 commit a161b25

File tree

11 files changed

+241
-154
lines changed

11 files changed

+241
-154
lines changed

changelog.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
### 0.14.0
2+
3+
- Fix: enforce font color (chrome bug) on text-area, based on theme. No more dark text on dark bg
4+
- Feat: moved to rich-textarea library to not re-invent the wheel on text area styling.
5+
This also allowed:
6+
- Better styling for error highliht
7+
- Additional tooltip with quick peek of the issue and and quick (up to 4) click to fix resolutions (sidebar gives more options if language tool provides)
8+
19
### 0.12.0
210

311
- Introduced a new environment variable `DISABLE_DICTIONARY`. When this variable is set to true, the functionality for adding words to the dictionary is disabled.

index.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// eslint-disable-next-line no-undef
2+
/* global process */
13
import express from "express";
24
import path from "path";
35
import bodyParser from "body-parser";
@@ -68,7 +70,10 @@ const handleProxyGET = (url, res, filter) => {
6870
fetch(url)
6971
.then((data) => data.json())
7072
.then((data) => res.send(filter ? filter(data) : data))
71-
.catch((error) => res.send(error));
73+
.catch((error) => {
74+
console.error("[PROXY GET ERROR]", error);
75+
res.status(500).send('Internal server error');
76+
});
7277
};
7378

7479
const handleProxyPost = (url, req, res) => {
@@ -85,7 +90,7 @@ const handleProxyPost = (url, req, res) => {
8590
})
8691
.catch((error) => {
8792
console.log({ error, url });
88-
res.send(error);
93+
res.status(500).send('Internal server error');
8994
});
9095
};
9196

@@ -111,7 +116,7 @@ const handleFormDataPost = (url, req, res, filter) => {
111116
})
112117
.catch((error) => {
113118
console.log({ error: error.message, url });
114-
res.send(error);
119+
res.status(500).send('Internal server error');
115120
});
116121
};
117122

package-lock.json

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sth-libretranslate",
33
"private": true,
4-
"version": "0.13.0",
4+
"version": "0.14.0",
55
"type": "module",
66
"scripts": {
77
"dev": "concurrently \"npm run node\" \"vite\"",
@@ -21,6 +21,7 @@
2121
"http-proxy-middleware": "^3.0.3",
2222
"react": "^18.2.0",
2323
"react-dom": "^18.2.0",
24+
"rich-textarea": "^0.26.5",
2425
"styled-components": "^6.1.11"
2526
},
2627
"devDependencies": {

src/languagecheck/App.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { useCallback, useEffect } from "react";
22
import { Autocomplete, Divider, Stack, TextField } from "@mui/material";
33
import "./App.css";
44
import { useDebounce } from "../common/useDebounce";
5-
import { TextBox } from "./Text";
65
import { useWindowSize } from "../common/useWindowSize";
76
import { API } from "./API";
87
import { Resolution } from "./Resolution";
98
import { LangChoice } from "../translate/types";
109
import { actions, useGrammar, useInitialiseGrammar } from "../store/grammar";
10+
import { Content } from "./Content";
1111

1212
export const SelectLanguage = ({ label }: { label?: string }) => {
1313
const { languages, language } = useGrammar();
@@ -37,7 +37,7 @@ export const SelectLanguage = ({ label }: { label?: string }) => {
3737
function App() {
3838
useInitialiseGrammar();
3939
const { question, language } = useGrammar();
40-
const q = useDebounce(question, 1000, () => actions.setTouched(false)) as string;
40+
const q = useDebounce(question, 1000) as string;
4141

4242
const check = useCallback((text: string, language: LangChoice) => {
4343
console.log("check");
@@ -51,7 +51,7 @@ function App() {
5151
actions.setAnswer(data);
5252
})
5353
.catch((e) => actions.setError(e.message));
54-
}, []);
54+
}, [actions, API]);
5555

5656
useEffect(() => {
5757
if (q.length > 1 && language) {
@@ -71,7 +71,8 @@ function App() {
7171
className="translation"
7272
>
7373
<div>
74-
<TextBox />
74+
<Content />
75+
{/* <TextBox /> */}
7576
</div>
7677
<Divider orientation="vertical" flexItem />
7778
<div style={{ position: "relative" }}>

src/languagecheck/Content.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { RichTextarea } from "rich-textarea";
2+
import { actions, useGrammar } from "../store/grammar";
3+
import { Options } from "./Options";
4+
5+
const HighlightText = () => {
6+
const { selection, answer, question: text } = useGrammar();
7+
const highlights = answer?.matches || [];
8+
let lastIndex = 0;
9+
const renderedHighlights = [];
10+
let counter = 0;
11+
12+
for (let i = 0; i < highlights.length; i++) {
13+
const { offset, length, replacements } = highlights[i];
14+
const nCount = text.substring(0, offset).match(/\\[ntrvf]/g)?.length ?? 0;
15+
const nOffset = nCount;
16+
if (offset > lastIndex) {
17+
// Add the text before the current highlight
18+
renderedHighlights.push(
19+
<span key={counter}>{text.substring(lastIndex, offset + nOffset)}</span>
20+
);
21+
counter = counter + 1;
22+
}
23+
24+
renderedHighlights.push(
25+
<Options
26+
key={counter}
27+
replacements={replacements}
28+
isSelected={selection === i}
29+
text={text.substring(nOffset + offset, nOffset + offset + length)}
30+
context={highlights[i]}
31+
index={i}
32+
/>
33+
);
34+
counter = counter + 1;
35+
36+
// Update lastIndex to the end of the current highlight
37+
lastIndex = offset + length + nOffset;
38+
}
39+
40+
// Add any remaining text after the last highlight
41+
if (lastIndex < text.length) {
42+
renderedHighlights.push(
43+
<span key={counter}>{text.substring(lastIndex)}</span>
44+
);
45+
counter = counter + 1;
46+
}
47+
return <div>{renderedHighlights}</div>;
48+
};
49+
50+
export const Content = () => {
51+
const { question } = useGrammar();
52+
53+
return (
54+
<RichTextarea
55+
value={question}
56+
style={{ width: "600px", height: "400px" }}
57+
onChange={(e) => actions.setQuestion(e.target.value)}
58+
>
59+
{() => <HighlightText />}
60+
</RichTextarea>
61+
);
62+
};

src/languagecheck/Options.tsx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import {
2+
Chip,
3+
Divider,
4+
styled,
5+
Tooltip,
6+
tooltipClasses,
7+
TooltipProps,
8+
Typography,
9+
} from "@mui/material";
10+
import { actions } from "../store/grammar";
11+
import Card from "@mui/material/Card";
12+
import CardActions from "@mui/material/CardActions";
13+
import CardContent from "@mui/material/CardContent";
14+
import { Match } from "./API";
15+
16+
const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => (
17+
<Tooltip {...props} classes={{ popper: className }} />
18+
))(() => ({
19+
[`& .${tooltipClasses.tooltip}`]: {
20+
backgroundColor: "transparent",
21+
},
22+
}));
23+
24+
type OptionsProps = {
25+
replacements: { value: string }[];
26+
isSelected: boolean;
27+
text: string;
28+
index: number;
29+
context: Match;
30+
};
31+
32+
export const Options = ({
33+
replacements,
34+
isSelected,
35+
text,
36+
index,
37+
context,
38+
}: OptionsProps) => {
39+
const handleFixPos = (value: string) => {
40+
actions.fixPos(value, index);
41+
};
42+
43+
return (
44+
<HtmlTooltip
45+
sx={{ background: "transparent" }}
46+
title={
47+
<div>
48+
<Card sx={{ minWidth: 275 }}>
49+
<CardContent>
50+
<Typography variant="h6" component="div">
51+
{context.shortMessage}
52+
</Typography>
53+
<Typography variant="body2">{context.message}</Typography>
54+
</CardContent>
55+
<Divider />
56+
<CardActions>
57+
{replacements.slice(0, 4).map((elem) => (
58+
<Chip
59+
key={elem.value}
60+
onClick={() => handleFixPos(elem.value)}
61+
label={elem.value}
62+
/>
63+
))}
64+
</CardActions>
65+
</Card>
66+
</div>
67+
}
68+
>
69+
<span
70+
style={{
71+
position: "relative",
72+
background: isSelected ? "rgba(255,0,0,0.3)" : "transparent",
73+
borderBottom: isSelected ? "none" : "2px solid rgba(255,0,0,0.5)",
74+
color: "#fff",
75+
left: 0,
76+
top: 0,
77+
borderRadius: isSelected ? "4px" : 0,
78+
cursor: "pointer",
79+
}}
80+
onClick={() => actions.setSelection(0)}
81+
>
82+
{text}
83+
</span>
84+
</HtmlTooltip>
85+
);
86+
};

src/languagecheck/Resolution.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,20 @@ const DisplayMatch = ({
2525
context,
2626
replacements,
2727
shortMessage,
28-
offset,
29-
length,
3028
fix,
3129
selected,
3230
setSelection,
3331
idx,
3432
rule,
35-
original,
3633
}: Match & {
3734
fix: Fix;
3835
selected: boolean;
3936
setSelection: () => void;
4037
idx: number;
41-
original: string;
4238
}) => {
43-
const { disableDictionary } = useSystemStatus()
44-
const fixPos = (value: string) => {
45-
const nCount =
46-
original.substring(0, offset).match(/\\[ntrvf]/g)?.length ?? 0;
47-
fix(offset + nCount, length, value, idx);
48-
};
39+
const { disableDictionary } = useSystemStatus();
40+
const { question, answer, selection } = useGrammar();
41+
4942
return (
5043
<Accordion expanded={selected}>
5144
<AccordionSummary
@@ -71,9 +64,30 @@ const DisplayMatch = ({
7164
<Divider sx={{ mt: 2, mb: 2 }} />
7265
{replacements.map((repl: { value: string }) => (
7366
<Chip
67+
key={repl.value}
7468
size="small"
7569
label={repl.value}
76-
onClick={() => fixPos(repl.value)}
70+
onClick={() => {
71+
if (!answer || selection === null) {
72+
return;
73+
}
74+
75+
const match = answer.matches[selection];
76+
if (!match) {
77+
return;
78+
}
79+
80+
// Count newline-like characters (\n, \t, etc.) before the offset
81+
const nCount = match.context.text.substring(0, match.context.offset).match(/\\[ntrvf]/g)?.length ?? 0;
82+
const adjustedStart = match.context.offset + nCount;
83+
84+
// Apply the fix to the question text
85+
const fixedQuestion = `${question.substring(0, adjustedStart)}${repl.value}${question.substring(adjustedStart + match.context.length)}`;
86+
87+
// Update the state
88+
actions.setQuestion(fixedQuestion);
89+
actions.popAnswer(selection);
90+
}}
7791
sx={{ marginRight: 1, marginBottom: 0.5, marginTop: 0.5 }}
7892
/>
7993
))}
@@ -153,7 +167,6 @@ export const Resolution = () => {
153167
selected={selection === i}
154168
setSelection={() => actions.setSelection(i)}
155169
idx={i}
156-
original={original}
157170
/>
158171
))}
159172
</div>

0 commit comments

Comments
 (0)