fix: remove TODO tips in locales

This commit is contained in:
jialin
2025-03-17 20:25:03 +08:00
parent 2287196746
commit 08b3c9d1ac
7 changed files with 131 additions and 90 deletions
@@ -31,6 +31,7 @@ export default function useDrawing(props: {
const autoScale = useRef<number>(1); const autoScale = useRef<number>(1);
const baseScale = useRef<number>(1); const baseScale = useRef<number>(1);
const contentPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); const contentPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
const maskStorkeRef = useRef<Stroke[]>([]);
const disabled = useMemo(() => { const disabled = useMemo(() => {
return isDisabled || invertMask || !!maskUpload?.length; return isDisabled || invertMask || !!maskUpload?.length;
@@ -40,6 +41,10 @@ export default function useDrawing(props: {
strokesRef.current = strokes; strokesRef.current = strokes;
}; };
const setMaskStrokes = (strokes: Stroke[]) => {
maskStorkeRef.current = strokes;
};
const inpaintArea = useCallback( const inpaintArea = useCallback(
(data: Uint8ClampedArray<ArrayBufferLike>) => { (data: Uint8ClampedArray<ArrayBufferLike>) => {
for (let i = 0; i < data.length; i += 4) { for (let i = 0; i < data.length; i += 4) {
@@ -61,7 +66,7 @@ export default function useDrawing(props: {
}, []); }, []);
const generateMask = useCallback(() => { const generateMask = useCallback(() => {
if (strokesRef.current.length === 0) { if (strokesRef.current.length === 0 && maskStorkeRef.current.length === 0) {
return null; return null;
} }
const overlayCanvas = overlayCanvasRef.current!; const overlayCanvas = overlayCanvasRef.current!;
@@ -180,7 +185,6 @@ export default function useDrawing(props: {
stroke.forEach((point, i) => { stroke.forEach((point, i) => {
const { x, y } = getTransformedPoint(point.x, point.y); const { x, y } = getTransformedPoint(point.x, point.y);
console.log('Drawing point:');
ctx.lineWidth = getTransformLineWidth(point.lineWidth); ctx.lineWidth = getTransformLineWidth(point.lineWidth);
if (i === 0) { if (i === 0) {
ctx.moveTo(x, y); ctx.moveTo(x, y);
@@ -374,6 +378,8 @@ export default function useDrawing(props: {
mouseDownState, mouseDownState,
autoScale, autoScale,
baseScale, baseScale,
maskStorkeRef,
setMaskStrokes,
fitView, fitView,
setStrokes, setStrokes,
resetCanvas, resetCanvas,
+4
View File
@@ -21,6 +21,10 @@
cursor: none !important; cursor: none !important;
} }
.overlay-canvas.overlay-canvas--disabled:hover {
cursor: default !important;
}
.upload-mask { .upload-mask {
&:hover { &:hover {
.close-btn { .close-btn {
+82 -64
View File
@@ -1,3 +1,4 @@
import classNames from 'classnames';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import React, { import React, {
forwardRef, forwardRef,
@@ -56,6 +57,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
const translatePos = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); const translatePos = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
const negativeMaskRef = useRef<boolean>(false); const negativeMaskRef = useRef<boolean>(false);
const [invertMask, setInvertMask] = useState<boolean>(false); const [invertMask, setInvertMask] = useState<boolean>(false);
const timer = useRef<any>(null);
const { const {
canvasRef, canvasRef,
@@ -66,6 +68,8 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
mouseDownState, mouseDownState,
autoScale, autoScale,
baseScale, baseScale,
maskStorkeRef,
setMaskStrokes,
draw, draw,
drawStroke, drawStroke,
startDrawing, startDrawing,
@@ -131,20 +135,25 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
options: { options: {
lineWidth?: number; lineWidth?: number;
color: string; color: string;
compositeOperation: 'source-over' | 'destination-out';
} }
) => { ) => {
const { color, compositeOperation } = options; const { color } = options;
ctx.globalCompositeOperation = compositeOperation;
stroke.forEach((point) => { stroke.forEach((point) => {
const { x, y } = getTransformedPoint(point.x, point.y); const { x, y } = getTransformedPoint(point.x, point.y);
ctx.save();
const width = getTransformLineWidth(point.lineWidth); const width = getTransformLineWidth(point.lineWidth);
ctx.fillStyle = color;
ctx.save();
// erase the previous stroke
ctx.globalCompositeOperation = 'destination-out';
ctx.fillRect(x - width / 2, y - width / 2, width, width); ctx.fillRect(x - width / 2, y - width / 2, width, width);
// draw the new stroke
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = color;
ctx.fillRect(x - width / 2, y - width / 2, width, width);
ctx.restore(); ctx.restore();
}); });
}, },
@@ -159,76 +168,81 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
console.log('Resetting strokes', currentStroke.current); console.log('Resetting strokes', currentStroke.current);
}, []); }, []);
const redrawStrokes = useCallback( const loadMaskPixs = (strokes: Stroke[]) => {
(strokes: Stroke[], type?: string) => { clearOverlayCanvas();
console.log('Redrawing strokes:', strokes, type); if (!strokes.length) {
clearOverlayCanvas(); return;
if (!strokes.length) { }
return; console.log('loadin mask pixs:');
} const overlayCanvas = overlayCanvasRef.current!;
const overlayCtx = overlayCanvas!.getContext('2d')!;
const overlayCanvas = overlayCanvasRef.current!; setTransform();
const overlayCtx = overlayCanvas!.getContext('2d')!; strokes?.forEach((stroke: Point[], index) => {
drawFillRect(overlayCtx, stroke, {
// clear offscreen canvas color: COLOR
setTransform();
strokes?.forEach((stroke: Point[], index) => {
overlayCtx.save();
drawStroke(overlayCtx, stroke, {
color: COLOR,
compositeOperation: 'destination-out'
});
drawStroke(overlayCtx, stroke, {
color: COLOR,
compositeOperation: 'source-over'
});
overlayCtx.restore();
}); });
}, });
[drawStroke] };
); const redrawStrokes = (strokes: Stroke[], type?: string) => {
console.log('Redrawing strokes:', strokes, type);
clearOverlayCanvas();
if (!strokes.length) {
return;
}
const loadMaskPixs = useCallback( const overlayCanvas = overlayCanvasRef.current!;
(strokes: Stroke[], type?: string) => {
clearOverlayCanvas();
if (!strokes.length) {
return;
}
console.log('loadin mask pixs:');
const overlayCanvas = overlayCanvasRef.current!;
const overlayCtx = overlayCanvas!.getContext('2d')!;
setTransform(); const overlayCtx = overlayCanvas!.getContext('2d')!;
strokes?.forEach((stroke: Point[], index) => { // clear offscreen canvas
overlayCtx.save();
drawFillRect(overlayCtx, stroke, {
color: COLOR,
compositeOperation: 'destination-out'
});
drawFillRect(overlayCtx, stroke, { setTransform();
color: COLOR, overlayCtx.save();
compositeOperation: 'source-over' loadMaskPixs(maskStorkeRef.current);
});
overlayCtx.restore(); strokes?.forEach((stroke: Point[], index) => {
drawStroke(overlayCtx, stroke, {
color: COLOR,
compositeOperation: 'destination-out'
}); });
},
[drawFillRect] drawStroke(overlayCtx, stroke, {
); color: COLOR,
compositeOperation: 'source-over'
});
});
overlayCtx.restore();
};
const undo = () => { const undo = () => {
if (strokesRef.current.length === 0) return; if (
strokesRef.current.length === 0 &&
maskStorkeRef.current.length === 0
) {
clearOverlayCanvas();
return;
}
const newStrokes = strokesRef.current.slice(0, -1); const newStrokes = strokesRef.current.slice(0, -1);
console.log('New strokes:', newStrokes, strokesRef.current);
setStrokes(newStrokes); setStrokes(newStrokes);
redrawStrokes(newStrokes); console.log(
'newstrokes=======',
newStrokes.length,
maskStorkeRef.current.length
);
if (strokesRef.current.length) {
clearTimeout(timer.current);
timer.current = setTimeout(() => {
redrawStrokes(strokesRef.current);
}, 100);
} else if (maskStorkeRef.current.length) {
loadMaskPixs(maskStorkeRef.current);
setMaskStrokes([]);
}
}; };
const downloadOriginImage = () => { const downloadOriginImage = () => {
@@ -424,6 +438,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
// mouse up // mouse up
window.addEventListener('mouseup', handleMouseUp); window.addEventListener('mouseup', handleMouseUp);
return () => { return () => {
clearTimeout(timer.current);
window.removeEventListener('keydown', handleUndoShortcut); window.removeEventListener('keydown', handleUndoShortcut);
window.removeEventListener('mousedown', handleMouseDown); window.removeEventListener('mousedown', handleMouseDown);
window.removeEventListener('mouseup', handleMouseUp); window.removeEventListener('mouseup', handleMouseUp);
@@ -439,7 +454,8 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
clearMask: handleDeleteMask, clearMask: handleDeleteMask,
loadMaskPixs(strokes: Stroke[]) { loadMaskPixs(strokes: Stroke[]) {
setStrokes(strokes); setMaskStrokes(strokes);
setStrokes([]);
loadMaskPixs(strokes); loadMaskPixs(strokes);
} }
})); }));
@@ -494,7 +510,9 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
<canvas ref={canvasRef} style={{ position: 'absolute', zIndex: 1 }} /> <canvas ref={canvasRef} style={{ position: 'absolute', zIndex: 1 }} />
<canvas <canvas
ref={overlayCanvasRef} ref={overlayCanvasRef}
className="overlay-canvas" className={classNames('overlay-canvas', {
'overlay-canvas--disabled': disabled
})}
style={{ position: 'absolute', zIndex: 10, cursor: 'none' }} style={{ position: 'absolute', zIndex: 10, cursor: 'none' }}
onMouseDown={(event) => { onMouseDown={(event) => {
mouseDownState.current = true; mouseDownState.current = true;
+4 -14
View File
@@ -24,24 +24,14 @@ To add a new language configuration, follow these steps:
- Open the `.ts` file in the **new directory**. - Open the `.ts` file in the **new directory**.
- For each key-value pair: - For each key-value pair:
- If a translation is available, replace the value with the translated text. - If a translation is available, replace the value with the translated text.
- If no translation is available yet, **replace the value with** `TODO: Translate key "<original-key>"`. - If no translation is available, keep the `English` value as default.
- This ensures that the key is visible for contributors to know exactly what needs to be translated.
**Example:** - **Note**: Keeping the English text as the default ensures the application remains functional even if some translations are missing.
```ts
export default {
'playground.image.mask.upload':
'TODO: Translate key "playground.image.mask.upload"',
'welcome.message': 'TODO: Translate key "welcome.message"'
};
```
- **Important**: The `TODO` message should include the original key in quotes so that contributors can easily identify which key needs translation without needing to look at the code itself.
## 4. **Finalize the Configuration** ## 4. **Finalize the Configuration**
- Review and ensure all translations are complete. - Review and ensure all translations are complete.
- If any translations are missing, contributors can later replace `"TODO: Translate key '...'` with the correct translation. - If any translations are missing, they will default to `English`.
- Your new language configuration is now ready for use! - Your new language configuration is now ready for use!
+13 -6
View File
@@ -81,7 +81,7 @@ export default {
'models.form.filePath': 'Путь к модели', 'models.form.filePath': 'Путь к модели',
'models.form.backendVersion': 'Версия бэкенда', 'models.form.backendVersion': 'Версия бэкенда',
'models.form.backendVersion.tips': 'models.form.backendVersion.tips':
'TODO: Translate key "models.form.backendVersion.tips"', 'To use the desired version of vLLM/llama-box/vox-box, the system will automatically create a virtual environment in the online environment to install the corresponding version. After a GPUStack upgrade, the backend version will remain fixed. {link}',
'models.form.gpuselector': 'Селектор GPU', 'models.form.gpuselector': 'Селектор GPU',
'models.form.backend.llamabox': 'models.form.backend.llamabox':
'Для моделей формата GGUF. Поддержка Linux, macOS и Windows.', 'Для моделей формата GGUF. Поддержка Linux, macOS и Windows.',
@@ -110,10 +110,17 @@ export default {
'models.table.vllmAcrossworker': 'vLLM между воркерами', 'models.table.vllmAcrossworker': 'vLLM между воркерами',
'models.form.releases': 'Релизы', 'models.form.releases': 'Релизы',
'models.form.moreparameters': 'Описание параметров', 'models.form.moreparameters': 'Описание параметров',
'models.table.vram.allocated': 'models.table.vram.allocated': 'Allocated VRAM',
'TODO: Translate key "models.table.vram.allocated"',
'models.form.backend.warning': 'models.form.backend.warning':
'TODO: Translate key "models.form.backend.warning"', 'The backend for GGUF format models uses llama-box.',
'models.form.backend.warning.llamabox': 'models.form.backend.warning.llamabox': `To use the llama-box backend, specify the full path to the model file (e.g.,<span style="font-weight: 700">/data/models/model.gguf</span>). For sharded models, provide the path to the first shard (e.g.,<span style="font-weight: 700">/data/models/model-00001-of-00004.gguf</span>).`
"TODO: Translate key 'models.form.backend.warning.llamabox'"
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. models.form.backendVersion.tips
// 2. models.form.backend.warning
// 3. models.form.backend.warning.llamabox
// 4. models.table.vram.allocated
// ========== End of To-Do List ==========
+11 -3
View File
@@ -137,14 +137,22 @@ export default {
'playground.image.edit': 'Редактировать', 'playground.image.edit': 'Редактировать',
'playground.image.fitview': 'Подогнать размер', 'playground.image.fitview': 'Подогнать размер',
'playground.chat.aithought': 'Рассуждение (CoT)', 'playground.chat.aithought': 'Рассуждение (CoT)',
'playground.chat.thinking': 'TODO: Translate key "playground.chat.thinking"', 'playground.chat.thinking': 'Thinking...',
'playground.image.mask.uploaded': 'Маска загружена', 'playground.image.mask.uploaded': 'Маска загружена',
'playground.image.mask.upload': 'playground.image.mask.upload':
'TODO: Translate key "playground.image.mask.upload"', 'Upload Mask: No additional drawing allowed after upload.',
'playground.params.frequency_penalty.tips': `Число от -2.0 до 2.0. Положительные значения снижают вероятность повторения токенов, уже часто встречающихся в тексте, уменьшая склонность модели дословно повторять одни и те же фразы.`, 'playground.params.frequency_penalty.tips': `Число от -2.0 до 2.0. Положительные значения снижают вероятность повторения токенов, уже часто встречающихся в тексте, уменьшая склонность модели дословно повторять одни и те же фразы.`,
'playground.params.presence_penalty.tips': `Число от -2.0 до 2.0. Положительные значения снижают вероятность повторения любых токенов, присутствующих в тексте, повышая склонность модели к обсуждению новых тем.`, 'playground.params.presence_penalty.tips': `Число от -2.0 до 2.0. Положительные значения снижают вероятность повторения любых токенов, присутствующих в тексте, повышая склонность модели к обсуждению новых тем.`,
'playground.image.origin': 'Оригинал', 'playground.image.origin': 'Оригинал',
'playground.image.mask': 'Маска', 'playground.image.mask': 'Маска',
'playground.image.negativeMask.tips': 'playground.image.negativeMask.tips':
'TODO: Translate key "playground.image.negativeMask.tips"' '1. After selection, no further masking can be drawn; therefore, you should draw the mask first and then check the option.\n 2. Once a mask image is uploaded, no further masks can be generated.'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. playground.chat.thinking
// 2. playground.image.mask.upload
// 3. playground.image.negativeMask.tips
// ========== End of To-Do List ==========
@@ -183,6 +183,14 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
return <GPUCard data={data}></GPUCard>; return <GPUCard data={data}></GPUCard>;
}; };
const tagRender = (props: any) => {
if (props.isMaxTag) {
return props.label;
}
const parent = _.split(props.value, '__RC_CASCADER_SPLIT__')?.[0];
return `${parent} / ${props?.label}`;
};
const collapseItems = useMemo(() => { const collapseItems = useMemo(() => {
const children = ( const children = (
<> <>
@@ -313,7 +321,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
onClose={props.onClose} onClose={props.onClose}
maxWidth={240} maxWidth={240}
> >
{props.label} {tagRender(props)}
</AutoTooltip> </AutoTooltip>
); );
}} }}