feat(gui): translate most of the client
This commit is contained in:
parent
5bfaddd388
commit
3760093617
|
@ -9,7 +9,6 @@ import { useStore } from 'zustand';
|
|||
|
||||
import { ImageResponse } from '../client.js';
|
||||
import { BLEND_SOURCES, ConfigContext, StateContext } from '../state.js';
|
||||
import { MODEL_LABELS, SCHEDULER_LABELS } from '../strings.js';
|
||||
import { range, visibleIndex } from '../utils.js';
|
||||
|
||||
export interface ImageCardProps {
|
||||
|
@ -99,8 +98,12 @@ export function ImageCard(props: ImageCardProps) {
|
|||
const [index, setIndex] = useState(0);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const model = mustDefault(MODEL_LABELS[params.model], params.model);
|
||||
const scheduler = mustDefault(SCHEDULER_LABELS[params.scheduler], params.scheduler);
|
||||
function getLabel(key: string, name: string) {
|
||||
return mustDefault(t(`${key}.${name}`), name);
|
||||
}
|
||||
|
||||
const model = getLabel('model', params.model);
|
||||
const scheduler = getLabel('scheduler', params.scheduler);
|
||||
|
||||
return <Card sx={{ maxWidth: config.params.width.default }} elevation={2}>
|
||||
<CardMedia sx={{ height: config.params.height.default }}
|
||||
|
@ -138,11 +141,11 @@ export function ImageCard(props: ImageCardProps) {
|
|||
</Tooltip>
|
||||
</GridItem>
|
||||
<GridItem xs={4}>Model: {model}</GridItem>
|
||||
<GridItem xs={4}>Scheduler: {scheduler}</GridItem>
|
||||
<GridItem xs={4}>Seed: {params.seed}</GridItem>
|
||||
<GridItem xs={4}>CFG: {params.cfg}</GridItem>
|
||||
<GridItem xs={4}>Steps: {params.steps}</GridItem>
|
||||
<GridItem xs={4}>Size: {size.width}x{size.height}</GridItem>
|
||||
<GridItem xs={4}>{t('parameter.scheduler')}: {scheduler}</GridItem>
|
||||
<GridItem xs={4}>{t('parameter.seed')}: {params.seed}</GridItem>
|
||||
<GridItem xs={4}>{t('parameter.cfg')}: {params.cfg}</GridItem>
|
||||
<GridItem xs={4}>{t('parameter.steps')}: {params.steps}</GridItem>
|
||||
<GridItem xs={4}>{t('parameter.size')}: {size.width}x{size.height}</GridItem>
|
||||
<GridItem xs={12}>
|
||||
<Box textAlign='left'>{params.prompt}</Box>
|
||||
</GridItem>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import { Link, Typography } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
|
||||
export function Logo() {
|
||||
return <Typography variant='h3' gutterBottom>
|
||||
<Link href='https://github.com/ssube/onnx-web' target='_blank' underline='hover'>ONNX Web</Link>
|
||||
</Typography>;
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import { Box, Button, Container, Link, Stack, Typography } from '@mui/material';
|
||||
import { Box, Button, Container, Stack, Typography } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { STATE_KEY } from '../state';
|
||||
|
||||
import { STATE_KEY } from '../state.js';
|
||||
import { Logo } from './Logo.js';
|
||||
|
||||
export interface OnnxErrorProps {
|
||||
children?: ReactNode;
|
||||
|
@ -19,9 +21,7 @@ export function OnnxError(props: OnnxErrorProps) {
|
|||
return (
|
||||
<Container>
|
||||
<Box sx={{ my: 4 }}>
|
||||
<Typography variant='h3' gutterBottom>
|
||||
<Link href='https://github.com/ssube/onnx-web' target='_blank' underline='hover'>ONNX Web</Link>
|
||||
</Typography>
|
||||
<Logo />
|
||||
</Box>
|
||||
<Box sx={{ my: 4 }}>
|
||||
<Stack spacing={2}>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { useHash } from 'react-use/lib/useHash';
|
|||
|
||||
import { ModelControl } from './control/ModelControl.js';
|
||||
import { ImageHistory } from './ImageHistory.js';
|
||||
import { Logo } from './Logo.js';
|
||||
import { Blend } from './tab/Blend.js';
|
||||
import { Img2Img } from './tab/Img2Img.js';
|
||||
import { Inpaint } from './tab/Inpaint.js';
|
||||
|
@ -41,9 +42,7 @@ export function OnnxWeb() {
|
|||
return (
|
||||
<Container>
|
||||
<Box sx={{ my: 4 }}>
|
||||
<Typography variant='h3' gutterBottom>
|
||||
<Link href='https://github.com/ssube/onnx-web' target='_blank' underline='hover'>ONNX Web</Link>
|
||||
</Typography>
|
||||
<Logo />
|
||||
</Box>
|
||||
<Box sx={{ mx: 4, my: 4 }}>
|
||||
<ModelControl />
|
||||
|
|
|
@ -3,13 +3,13 @@ import { Casino } from '@mui/icons-material';
|
|||
import { Button, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { BaseImgParams } from '../../client.js';
|
||||
import { STALE_TIME } from '../../config.js';
|
||||
import { ClientContext, ConfigContext, OnnxState, StateContext } from '../../state.js';
|
||||
import { SCHEDULER_LABELS } from '../../strings.js';
|
||||
import { NumericField } from '../input/NumericField.js';
|
||||
import { PromptInput } from '../input/PromptInput.js';
|
||||
import { QueryList } from '../input/QueryList.js';
|
||||
|
@ -27,6 +27,7 @@ export function ImageControl(props: ImageControlProps) {
|
|||
const { params } = mustExist(useContext(ConfigContext));
|
||||
const state = mustExist(useContext(StateContext));
|
||||
const controlState = useStore(state, props.selector);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const client = mustExist(useContext(ClientContext));
|
||||
const schedulers = useQuery('schedulers', async () => client.schedulers(), {
|
||||
|
@ -37,8 +38,8 @@ export function ImageControl(props: ImageControlProps) {
|
|||
<Stack direction='row' spacing={4}>
|
||||
<QueryList
|
||||
id='schedulers'
|
||||
labels={SCHEDULER_LABELS}
|
||||
name='Scheduler'
|
||||
labelKey='scheduler'
|
||||
name={t('parameter.scheduler')}
|
||||
query={{
|
||||
result: schedulers,
|
||||
}}
|
||||
|
@ -54,7 +55,7 @@ export function ImageControl(props: ImageControlProps) {
|
|||
/>
|
||||
<NumericField
|
||||
decimal
|
||||
label='Eta'
|
||||
label={t('parameter.eta')}
|
||||
min={params.eta.min}
|
||||
max={params.eta.max}
|
||||
step={params.eta.step}
|
||||
|
@ -69,7 +70,7 @@ export function ImageControl(props: ImageControlProps) {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Batch Size'
|
||||
label={t('parameter.batch')}
|
||||
min={params.batch.min}
|
||||
max={params.batch.max}
|
||||
step={params.batch.step}
|
||||
|
@ -87,7 +88,7 @@ export function ImageControl(props: ImageControlProps) {
|
|||
<Stack direction='row' spacing={4}>
|
||||
<NumericField
|
||||
decimal
|
||||
label='CFG'
|
||||
label={t('parameter.cfg')}
|
||||
min={params.cfg.min}
|
||||
max={params.cfg.max}
|
||||
step={params.cfg.step}
|
||||
|
@ -102,7 +103,7 @@ export function ImageControl(props: ImageControlProps) {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Steps'
|
||||
label={t('parameter.steps')}
|
||||
min={params.steps.min}
|
||||
max={params.steps.max}
|
||||
step={params.steps.step}
|
||||
|
@ -117,7 +118,7 @@ export function ImageControl(props: ImageControlProps) {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Seed'
|
||||
label={t('parameter.seed')}
|
||||
min={params.seed.min}
|
||||
max={params.seed.max}
|
||||
step={params.seed.step}
|
||||
|
@ -144,7 +145,7 @@ export function ImageControl(props: ImageControlProps) {
|
|||
}
|
||||
}}
|
||||
>
|
||||
New Seed
|
||||
{t('parameter.newSeed')}
|
||||
</Button>
|
||||
</Stack>
|
||||
<PromptInput
|
||||
|
|
|
@ -2,12 +2,12 @@ import { mustExist } from '@apextoaster/js-utils';
|
|||
import { Checkbox, FormControlLabel, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { STALE_TIME } from '../../config.js';
|
||||
import { ClientContext, StateContext } from '../../state.js';
|
||||
import { INVERSION_LABELS, MODEL_LABELS, PLATFORM_LABELS } from '../../strings.js';
|
||||
import { QueryList } from '../input/QueryList.js';
|
||||
|
||||
export function ModelControl() {
|
||||
|
@ -16,6 +16,7 @@ export function ModelControl() {
|
|||
const params = useStore(state, (s) => s.model);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setModel = useStore(state, (s) => s.setModel);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const models = useQuery('models', async () => client.models(), {
|
||||
staleTime: STALE_TIME,
|
||||
|
@ -27,8 +28,8 @@ export function ModelControl() {
|
|||
return <Stack direction='row' spacing={2}>
|
||||
<QueryList
|
||||
id='platforms'
|
||||
labels={PLATFORM_LABELS}
|
||||
name='Platform'
|
||||
labelKey='platform'
|
||||
name={t('parameter.platform')}
|
||||
query={{
|
||||
result: platforms,
|
||||
}}
|
||||
|
@ -41,8 +42,8 @@ export function ModelControl() {
|
|||
/>
|
||||
<QueryList
|
||||
id='diffusion'
|
||||
labels={MODEL_LABELS}
|
||||
name='Diffusion Model'
|
||||
labelKey='model'
|
||||
name={t('modelType.diffusion')}
|
||||
query={{
|
||||
result: models,
|
||||
selector: (result) => result.diffusion,
|
||||
|
@ -56,8 +57,8 @@ export function ModelControl() {
|
|||
/>
|
||||
<QueryList
|
||||
id='inversion'
|
||||
labels={INVERSION_LABELS}
|
||||
name='Textual Inversion'
|
||||
labelKey='model'
|
||||
name={t('modelType.inversion')}
|
||||
query={{
|
||||
result: models,
|
||||
selector: (result) => result.inversion,
|
||||
|
@ -72,8 +73,8 @@ export function ModelControl() {
|
|||
/>
|
||||
<QueryList
|
||||
id='upscaling'
|
||||
labels={MODEL_LABELS}
|
||||
name='Upscaling Model'
|
||||
labelKey='model'
|
||||
name={t('modelType.upscaling')}
|
||||
query={{
|
||||
result: models,
|
||||
selector: (result) => result.upscaling,
|
||||
|
@ -87,8 +88,8 @@ export function ModelControl() {
|
|||
/>
|
||||
<QueryList
|
||||
id='correction'
|
||||
labels={MODEL_LABELS}
|
||||
name='Correction Model'
|
||||
labelKey='model'
|
||||
name={t('modelType.correction')}
|
||||
query={{
|
||||
result: models,
|
||||
selector: (result) => result.correction,
|
||||
|
@ -101,7 +102,7 @@ export function ModelControl() {
|
|||
}}
|
||||
/>
|
||||
<FormControlLabel
|
||||
label='Long Prompt Weighting'
|
||||
label={t('parameter.lpw')}
|
||||
control={<Checkbox
|
||||
checked={params.lpw}
|
||||
value='check'
|
||||
|
|
|
@ -2,6 +2,7 @@ import { mustExist } from '@apextoaster/js-utils';
|
|||
import { Checkbox, FormControlLabel, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { ConfigContext, StateContext } from '../../state.js';
|
||||
|
@ -13,14 +14,15 @@ export function OutpaintControl() {
|
|||
const outpaint = useStore(state, (s) => s.outpaint);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setOutpaint = useStore(state, (s) => s.setOutpaint);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Stack direction='row' spacing={4}>
|
||||
<FormControlLabel
|
||||
label='Outpaint'
|
||||
label={t('parameter.outpaint.label')}
|
||||
control={<Checkbox
|
||||
checked={outpaint.enabled}
|
||||
value='check'
|
||||
onChange={(event) => {
|
||||
onChange={(_event) => {
|
||||
setOutpaint({
|
||||
enabled: outpaint.enabled === false,
|
||||
});
|
||||
|
@ -28,7 +30,7 @@ export function OutpaintControl() {
|
|||
/>}
|
||||
/>
|
||||
<NumericField
|
||||
label='Left'
|
||||
label={t('parameter.outpaint.left')}
|
||||
disabled={outpaint.enabled === false}
|
||||
min={0}
|
||||
max={params.width.max}
|
||||
|
@ -41,7 +43,7 @@ export function OutpaintControl() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Right'
|
||||
label={t('parameter.outpaint.right')}
|
||||
disabled={outpaint.enabled === false}
|
||||
min={0}
|
||||
max={params.width.max}
|
||||
|
@ -54,7 +56,7 @@ export function OutpaintControl() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Top'
|
||||
label={t('parameter.outpaint.top')}
|
||||
disabled={outpaint.enabled === false}
|
||||
min={0}
|
||||
max={params.height.max}
|
||||
|
@ -67,7 +69,7 @@ export function OutpaintControl() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Bottom'
|
||||
label={t('parameter.outpaint.bottom')}
|
||||
disabled={outpaint.enabled === false}
|
||||
min={0}
|
||||
max={params.height.max}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { mustExist } from '@apextoaster/js-utils';
|
||||
import { Checkbox, FormControl, FormControlLabel, InputLabel, MenuItem, Select, Stack } from '@mui/material';
|
||||
import { startCase } from 'lodash';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { ConfigContext, StateContext } from '../../state.js';
|
||||
|
@ -14,10 +14,11 @@ export function UpscaleControl() {
|
|||
const upscale = useStore(state, (s) => s.upscale);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setUpscale = useStore(state, (s) => s.setUpscale);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Stack direction='row' spacing={4}>
|
||||
<FormControlLabel
|
||||
label='Upscale'
|
||||
label={t('parameter.upscale.label')}
|
||||
control={<Checkbox
|
||||
checked={upscale.enabled}
|
||||
value='check'
|
||||
|
@ -29,7 +30,7 @@ export function UpscaleControl() {
|
|||
/>}
|
||||
/>
|
||||
<NumericField
|
||||
label='Denoise'
|
||||
label={t('parameter.upscale.denoise')}
|
||||
decimal
|
||||
disabled={upscale.enabled === false}
|
||||
min={params.denoise.min}
|
||||
|
@ -43,7 +44,7 @@ export function UpscaleControl() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Scale'
|
||||
label={t('parameter.upscale.scale')}
|
||||
disabled={upscale.enabled === false}
|
||||
min={params.scale.min}
|
||||
max={params.scale.max}
|
||||
|
@ -56,7 +57,7 @@ export function UpscaleControl() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Outscale'
|
||||
label={t('parameter.upscale.outscale')}
|
||||
disabled={upscale.enabled === false}
|
||||
min={params.outscale.min}
|
||||
max={params.outscale.max}
|
||||
|
@ -69,7 +70,7 @@ export function UpscaleControl() {
|
|||
}}
|
||||
/>
|
||||
<FormControlLabel
|
||||
label='Face Correction'
|
||||
label={t('parameter.correction.label')}
|
||||
control={<Checkbox
|
||||
checked={upscale.faces}
|
||||
value='check'
|
||||
|
@ -81,7 +82,7 @@ export function UpscaleControl() {
|
|||
/>}
|
||||
/>
|
||||
<NumericField
|
||||
label='Strength'
|
||||
label={t('parameter.correction.strength')}
|
||||
decimal
|
||||
disabled={upscale.faces === false}
|
||||
min={params.faceStrength.min}
|
||||
|
@ -95,7 +96,7 @@ export function UpscaleControl() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Outscale'
|
||||
label={t('parameter.correction.outscale')}
|
||||
disabled={upscale.faces === false}
|
||||
min={params.faceOutscale.min}
|
||||
max={params.faceOutscale.max}
|
||||
|
@ -111,7 +112,7 @@ export function UpscaleControl() {
|
|||
<InputLabel id={'upscale-order'}>Upscale Order</InputLabel>
|
||||
<Select
|
||||
labelId={'upscale-order'}
|
||||
label={'Upscale Order'}
|
||||
label={t('parameter.upscale.order')}
|
||||
value={upscale.upscaleOrder}
|
||||
onChange={(e) => {
|
||||
setUpscale({
|
||||
|
@ -119,8 +120,8 @@ export function UpscaleControl() {
|
|||
});
|
||||
}}
|
||||
>
|
||||
{params.upscaleOrder.keys.map((name) =>
|
||||
<MenuItem key={name} value={name}>{startCase(name)}</MenuItem>)
|
||||
{Object.entries(params.upscaleOrder.keys).map(([key, name]) =>
|
||||
<MenuItem key={key} value={key}>{t(`upscaleOrder.${name}`)}</MenuItem>)
|
||||
}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { doesExist, Maybe, mustDefault, mustExist } from '@apextoaster/js-utils'
|
|||
import { PhotoCamera } from '@mui/icons-material';
|
||||
import { Button, Stack, Typography } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export interface ImageInputProps {
|
||||
filter: string;
|
||||
|
@ -14,6 +15,8 @@ export interface ImageInputProps {
|
|||
}
|
||||
|
||||
export function ImageInput(props: ImageInputProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
function renderImage() {
|
||||
if (doesExist(props.image)) {
|
||||
if (mustDefault(props.hideSelection, false)) {
|
||||
|
@ -28,7 +31,7 @@ export function ImageInput(props: ImageInputProps) {
|
|||
}}
|
||||
/>;
|
||||
} else {
|
||||
return <Typography>Please select an image.</Typography>;
|
||||
return <Typography>{t('input.image.empty')}</Typography>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Download, FormatColorFill, Gradient, InvertColors, Save, Undo } from '@
|
|||
import { Button, Stack, Typography } from '@mui/material';
|
||||
import { throttle } from 'lodash';
|
||||
import React, { RefObject, useContext, useEffect, useMemo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { SAVE_TIME } from '../../config.js';
|
||||
|
@ -201,6 +202,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
const brush = useStore(state, (s) => s.brush);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setBrush = useStore(state, (s) => s.setBrush);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (dirty.current) {
|
||||
|
@ -308,14 +310,11 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
onMouseUp={finishPainting}
|
||||
onMouseMove={drawMouse}
|
||||
/>
|
||||
<Typography variant='body1'>
|
||||
Black pixels in the mask will stay the same, white pixels will be replaced. The masked pixels will be blended
|
||||
with the noise source before the diffusion model runs, giving it more variety to use.
|
||||
</Typography>
|
||||
<Typography variant='body1'>{t('mask.help')}</Typography>
|
||||
<Stack>
|
||||
<Stack direction='row' spacing={4}>
|
||||
<NumericField
|
||||
label='Brush Color'
|
||||
label={t('parameter.brush.color')}
|
||||
min={COLORS.black}
|
||||
max={COLORS.white}
|
||||
step={1}
|
||||
|
@ -325,7 +324,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Brush Size'
|
||||
label={t('parameter.brush.size')}
|
||||
min={1}
|
||||
max={64}
|
||||
step={1}
|
||||
|
@ -336,7 +335,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
/>
|
||||
<NumericField
|
||||
decimal
|
||||
label='Brush Strength'
|
||||
label={t('parameter.brush.strength')}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
|
@ -353,7 +352,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
onClick={() => {
|
||||
drawFill(floodBlack);
|
||||
}}>
|
||||
Fill with black
|
||||
{t('mask.fill.black')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='outlined'
|
||||
|
@ -361,7 +360,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
onClick={() => {
|
||||
drawFill(floodWhite);
|
||||
}}>
|
||||
Fill with white
|
||||
{t('mask.fill.white')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='outlined'
|
||||
|
@ -369,7 +368,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
onClick={() => {
|
||||
drawFill(floodInvert);
|
||||
}}>
|
||||
Invert
|
||||
{t('mask.invert')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='outlined'
|
||||
|
@ -377,7 +376,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
onClick={() => {
|
||||
drawFill(floodBelow);
|
||||
}}>
|
||||
Gray to black
|
||||
{t('mask.gray.black')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='outlined'
|
||||
|
@ -385,7 +384,7 @@ export function MaskCanvas(props: MaskCanvasProps) {
|
|||
onClick={() => {
|
||||
drawFill(floodAbove);
|
||||
}}>
|
||||
Gray to white
|
||||
{t('mask.gray.white')}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { doesExist } from '@apextoaster/js-utils';
|
||||
import { Slider, Stack, TextField } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function parseNumber(num: string, decimal = false): number {
|
||||
if (decimal) {
|
||||
|
@ -24,14 +25,15 @@ export interface ImageControlProps {
|
|||
|
||||
export function NumericField(props: ImageControlProps) {
|
||||
const { decimal = false, disabled = false, label, min, max, step, value } = props;
|
||||
|
||||
const error = (value < min) || (value > max);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Stack spacing={2}>
|
||||
<TextField
|
||||
error={error}
|
||||
label={label}
|
||||
helperText={error && 'Out of range'}
|
||||
helperText={error && t('input.numeric.error.range')}
|
||||
disabled={disabled}
|
||||
variant='outlined'
|
||||
type='number'
|
||||
|
|
|
@ -2,6 +2,7 @@ import { doesExist, Maybe } from '@apextoaster/js-utils';
|
|||
import { TextField } from '@mui/material';
|
||||
import { Stack } from '@mui/system';
|
||||
import * as React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export interface PromptValue {
|
||||
prompt: string;
|
||||
|
@ -19,18 +20,25 @@ export function PromptInput(props: PromptInputProps) {
|
|||
const promptLength = prompt.split(' ').length;
|
||||
const error = promptLength > PROMPT_LIMIT;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
function promptHelper() {
|
||||
const params = {
|
||||
current: promptLength,
|
||||
max: PROMPT_LIMIT,
|
||||
};
|
||||
|
||||
if (error) {
|
||||
return `Too many tokens: ${promptLength}/${PROMPT_LIMIT}`;
|
||||
return t('input.prompt.error.length', params);
|
||||
} else {
|
||||
return `Tokens: ${promptLength}/${PROMPT_LIMIT}`;
|
||||
return t('input.prompt.tokens', params);
|
||||
}
|
||||
}
|
||||
|
||||
return <Stack spacing={2}>
|
||||
<TextField
|
||||
error={error}
|
||||
label='Prompt'
|
||||
label={t('parameter.prompt')}
|
||||
helperText={promptHelper()}
|
||||
variant='outlined'
|
||||
value={prompt}
|
||||
|
@ -44,7 +52,7 @@ export function PromptInput(props: PromptInputProps) {
|
|||
}}
|
||||
/>
|
||||
<TextField
|
||||
label='Negative Prompt'
|
||||
label={t('parameter.negativePrompt')}
|
||||
variant='outlined'
|
||||
value={negativePrompt}
|
||||
onChange={(event) => {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { doesExist, mustDefault, mustExist } from '@apextoaster/js-utils';
|
|||
import { Alert, FormControl, InputLabel, MenuItem, Select, Typography } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
|
||||
export interface QueryListComplete {
|
||||
|
@ -15,7 +16,7 @@ export interface QueryListFilter<T> {
|
|||
|
||||
export interface QueryListProps<T> {
|
||||
id: string;
|
||||
labels: Record<string, string>;
|
||||
labelKey: string;
|
||||
name: string;
|
||||
value: string;
|
||||
|
||||
|
@ -47,9 +48,11 @@ export function filterQuery<T>(query: QueryListComplete | QueryListFilter<T>, sh
|
|||
}
|
||||
|
||||
export function QueryList<T>(props: QueryListProps<T>) {
|
||||
const { labels, query, showEmpty = false, value } = props;
|
||||
const { labelKey, query, showEmpty = false, value } = props;
|
||||
const { result } = query;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
function firstValidValue(): string {
|
||||
if (doesExist(value) && data.includes(value)) {
|
||||
return value;
|
||||
|
@ -58,6 +61,10 @@ export function QueryList<T>(props: QueryListProps<T>) {
|
|||
}
|
||||
}
|
||||
|
||||
function getLabel(name: string) {
|
||||
return mustDefault(t(`${labelKey}.${name}`), name);
|
||||
}
|
||||
|
||||
// update state when previous selection was invalid: https://github.com/ssube/onnx-web/issues/120
|
||||
useEffect(() => {
|
||||
if (result.status === 'success' && doesExist(result.data) && doesExist(props.onChange)) {
|
||||
|
@ -70,18 +77,20 @@ export function QueryList<T>(props: QueryListProps<T>) {
|
|||
|
||||
if (result.status === 'error') {
|
||||
if (result.error instanceof Error) {
|
||||
return <Alert severity='error'>Error: {result.error.message}</Alert>;
|
||||
return <Alert severity='error'>{t('input.list.error.specific', {
|
||||
message: result.error.message,
|
||||
})}</Alert>;
|
||||
} else {
|
||||
return <Alert severity='error'>Unknown Error</Alert>;
|
||||
return <Alert severity='error'>{t('input.list.error.unknown')}</Alert>;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.status === 'loading') {
|
||||
return <Typography>Loading...</Typography>;
|
||||
return <Typography>{t('input.list.loading')}</Typography>;
|
||||
}
|
||||
|
||||
if (result.status === 'idle') {
|
||||
return <Typography>Idle?</Typography>;
|
||||
return <Typography>{t('input.list.idle')}</Typography>;
|
||||
}
|
||||
|
||||
// else: success
|
||||
|
@ -100,7 +109,7 @@ export function QueryList<T>(props: QueryListProps<T>) {
|
|||
}
|
||||
}}
|
||||
>
|
||||
{data.map((name) => <MenuItem key={name} value={name}>{mustDefault(labels[name], name)}</MenuItem>)}
|
||||
{data.map((name) => <MenuItem key={name} value={name}>{getLabel(name)}</MenuItem>)}
|
||||
</Select>
|
||||
</FormControl>;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { mustDefault, mustExist } from '@apextoaster/js-utils';
|
|||
import { Box, Button, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
|
@ -37,6 +38,7 @@ export function Blend() {
|
|||
const setBlend = useStore(state, (s) => s.setBlend);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const sources = mustDefault(blend.sources, []);
|
||||
|
||||
|
@ -48,7 +50,7 @@ export function Blend() {
|
|||
filter={IMAGE_FILTER}
|
||||
image={sources[idx]}
|
||||
hideSelection={true}
|
||||
label='Source'
|
||||
label={t('input.image.source')}
|
||||
onChange={(file) => {
|
||||
const newSources = [...sources];
|
||||
newSources[idx] = file;
|
||||
|
@ -73,7 +75,7 @@ export function Blend() {
|
|||
disabled={sources.length === 0}
|
||||
variant='contained'
|
||||
onClick={() => upload.mutate()}
|
||||
>Generate</Button>
|
||||
>{t('generate')}</Button>
|
||||
</Stack>
|
||||
</Box>;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { doesExist, mustExist } from '@apextoaster/js-utils';
|
|||
import { Box, Button, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
|
@ -39,10 +40,11 @@ export function Img2Img() {
|
|||
const setImg2Img = useStore(state, (s) => s.setImg2Img);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Box>
|
||||
<Stack spacing={2}>
|
||||
<ImageInput filter={IMAGE_FILTER} image={source} label='Source' onChange={(file) => {
|
||||
<ImageInput filter={IMAGE_FILTER} image={source} label={t('input.image.source')} onChange={(file) => {
|
||||
setImg2Img({
|
||||
source: file,
|
||||
});
|
||||
|
@ -50,7 +52,7 @@ export function Img2Img() {
|
|||
<ImageControl selector={(s) => s.img2img} onChange={setImg2Img} />
|
||||
<NumericField
|
||||
decimal
|
||||
label='Strength'
|
||||
label={t('parameter.strength')}
|
||||
min={params.strength.min}
|
||||
max={params.strength.max}
|
||||
step={params.strength.step}
|
||||
|
@ -66,7 +68,7 @@ export function Img2Img() {
|
|||
disabled={doesExist(source) === false}
|
||||
variant='contained'
|
||||
onClick={() => upload.mutate()}
|
||||
>Generate</Button>
|
||||
>{t('generate')}</Button>
|
||||
</Stack>
|
||||
</Box>;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { doesExist, mustExist } from '@apextoaster/js-utils';
|
||||
import { Box, Button, FormControl, FormControlLabel, InputLabel, MenuItem, Select, Stack } from '@mui/material';
|
||||
import { capitalize } from 'lodash';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { IMAGE_FILTER, STALE_TIME } from '../../config.js';
|
||||
import { ClientContext, ConfigContext, StateContext } from '../../state.js';
|
||||
import { MASK_LABELS, NOISE_LABELS } from '../../strings.js';
|
||||
import { ImageControl } from '../control/ImageControl.js';
|
||||
import { OutpaintControl } from '../control/OutpaintControl.js';
|
||||
import { UpscaleControl } from '../control/UpscaleControl.js';
|
||||
|
@ -65,6 +64,7 @@ export function Inpaint() {
|
|||
const setInpaint = useStore(state, (s) => s.setInpaint);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const query = useQueryClient();
|
||||
const upload = useMutation(uploadSource, {
|
||||
|
@ -76,7 +76,7 @@ export function Inpaint() {
|
|||
<ImageInput
|
||||
filter={IMAGE_FILTER}
|
||||
image={source}
|
||||
label='Source'
|
||||
label={t('input.image.source')}
|
||||
hideSelection={true}
|
||||
onChange={(file) => {
|
||||
setInpaint({
|
||||
|
@ -87,7 +87,7 @@ export function Inpaint() {
|
|||
<ImageInput
|
||||
filter={IMAGE_FILTER}
|
||||
image={mask}
|
||||
label='Mask'
|
||||
label={t('input.image.mask')}
|
||||
hideSelection={true}
|
||||
onChange={(file) => {
|
||||
setInpaint({
|
||||
|
@ -111,7 +111,7 @@ export function Inpaint() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Strength'
|
||||
label={t('parameter.strength')}
|
||||
min={params.strength.min}
|
||||
max={params.strength.max}
|
||||
step={params.strength.step}
|
||||
|
@ -125,8 +125,9 @@ export function Inpaint() {
|
|||
<Stack direction='row' spacing={2}>
|
||||
<QueryList
|
||||
id='masks'
|
||||
labels={MASK_LABELS}
|
||||
name='Mask Filter'
|
||||
labelKey={'maskFilter'}
|
||||
showEmpty={true}
|
||||
name={t('parameter.maskFilter')}
|
||||
query={{
|
||||
result: masks,
|
||||
}}
|
||||
|
@ -139,8 +140,8 @@ export function Inpaint() {
|
|||
/>
|
||||
<QueryList
|
||||
id='noises'
|
||||
labels={NOISE_LABELS}
|
||||
name='Noise Source'
|
||||
labelKey={'noiseSource'}
|
||||
name={t('parameter.noiseSource')}
|
||||
query={{
|
||||
result: noises,
|
||||
}}
|
||||
|
@ -155,7 +156,7 @@ export function Inpaint() {
|
|||
<InputLabel id={'outpaint-tiling'}>Tile Order</InputLabel>
|
||||
<Select
|
||||
labelId={'outpaint-tiling'}
|
||||
label={'Tile Order'}
|
||||
label={t('parameter.tileOrder')}
|
||||
value={tileOrder}
|
||||
onChange={(e) => {
|
||||
setInpaint({
|
||||
|
@ -163,14 +164,14 @@ export function Inpaint() {
|
|||
});
|
||||
}}
|
||||
>
|
||||
{params.tileOrder.keys.map((name) =>
|
||||
<MenuItem key={name} value={name}>{capitalize(name)}</MenuItem>)
|
||||
{Object.entries(params.tileOrder.keys).map(([key, name]) =>
|
||||
<MenuItem key={key} value={key}>{t(`tileOrder.${name}`)}</MenuItem>)
|
||||
}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<FormControlLabel
|
||||
label='Fill Color'
|
||||
label={t('parameter.fillColor')}
|
||||
sx={{ mx: 1 }}
|
||||
control={
|
||||
<input
|
||||
|
@ -193,7 +194,7 @@ export function Inpaint() {
|
|||
disabled={doesExist(source) === false || doesExist(mask) === false}
|
||||
variant='contained'
|
||||
onClick={() => upload.mutate()}
|
||||
>Generate</Button>
|
||||
>{t('generate')}</Button>
|
||||
</Stack>
|
||||
</Box>;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Refresh } from '@mui/icons-material';
|
|||
import { Alert, Button, Stack, TextField } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { getApiRoot } from '../../config.js';
|
||||
|
@ -32,28 +33,29 @@ export function Settings() {
|
|||
|
||||
const [json, setJson] = useState(JSON.stringify(state, removeBlobs));
|
||||
const [root, setRoot] = useState(getApiRoot(config));
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Stack spacing={2}>
|
||||
<NumericField
|
||||
label='Image History'
|
||||
label={t('setting.history')}
|
||||
min={2}
|
||||
max={20}
|
||||
step={1}
|
||||
value={state.limit}
|
||||
onChange={(value) => state.setLimit(value)}
|
||||
/>
|
||||
<TextField variant='outlined' label='Default Prompt' value={state.defaults.prompt} onChange={(event) => {
|
||||
<TextField variant='outlined' label={t('setting.prompt')} value={state.defaults.prompt} onChange={(event) => {
|
||||
state.setDefaults({
|
||||
prompt: event.target.value,
|
||||
});
|
||||
}} />
|
||||
<TextField variant='outlined' label='Default Scheduler' value={state.defaults.scheduler} onChange={(event) => {
|
||||
<TextField variant='outlined' label={t('setting.scheduler')} value={state.defaults.scheduler} onChange={(event) => {
|
||||
state.setDefaults({
|
||||
scheduler: event.target.value,
|
||||
});
|
||||
}} />
|
||||
<Stack direction='row' spacing={2}>
|
||||
<TextField variant='outlined' label='API Server' value={root} onChange={(event) => {
|
||||
<TextField variant='outlined' label={t('setting.server')} value={root} onChange={(event) => {
|
||||
setRoot(event.target.value);
|
||||
}} />
|
||||
<Button variant='contained' startIcon={<Refresh />} onClick={() => {
|
||||
|
@ -61,28 +63,28 @@ export function Settings() {
|
|||
query.set('api', root);
|
||||
window.location.search = query.toString();
|
||||
}}>
|
||||
Connect
|
||||
{t('setting.connectServer')}
|
||||
</Button>
|
||||
<Alert variant='outlined' severity='success'>
|
||||
{config.params.version}
|
||||
</Alert>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<TextField variant='outlined' label='Client State' value={json} onChange={(event) => {
|
||||
<TextField variant='outlined' label={t('setting.state')} value={json} onChange={(event) => {
|
||||
setJson(event.target.value);
|
||||
}} />
|
||||
<Button variant='contained' startIcon={<Refresh />} onClick={() => {
|
||||
window.localStorage.setItem(STATE_KEY, json);
|
||||
window.location.reload();
|
||||
}}>
|
||||
Load
|
||||
{t('setting.loadState')}
|
||||
</Button>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Button onClick={() => state.resetTxt2Img()} color='warning'>Reset Txt2Img</Button>
|
||||
<Button onClick={() => state.resetImg2Img()} color='warning'>Reset Img2Img</Button>
|
||||
<Button onClick={() => state.resetInpaint()} color='warning'>Reset Inpaint</Button>
|
||||
<Button onClick={() => state.resetAll()} color='error'>Reset All</Button>
|
||||
<Button onClick={() => state.resetTxt2Img()} color='warning'>{t('setting.reset.txt2img')}</Button>
|
||||
<Button onClick={() => state.resetImg2Img()} color='warning'>{t('setting.reset.img2img')}</Button>
|
||||
<Button onClick={() => state.resetInpaint()} color='warning'>{t('setting.reset.inpaint')}</Button>
|
||||
<Button onClick={() => state.resetAll()} color='error'>{t('setting.reset.all')}</Button>
|
||||
</Stack>
|
||||
</Stack>;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { mustExist } from '@apextoaster/js-utils';
|
|||
import { Box, Button, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
|
@ -33,13 +34,14 @@ export function Txt2Img() {
|
|||
const setTxt2Img = useStore(state, (s) => s.setTxt2Img);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Box>
|
||||
<Stack spacing={2}>
|
||||
<ImageControl selector={(s) => s.txt2img} onChange={setTxt2Img} />
|
||||
<Stack direction='row' spacing={4}>
|
||||
<NumericField
|
||||
label='Width'
|
||||
label={t('parameter.width')}
|
||||
min={params.width.min}
|
||||
max={params.width.max}
|
||||
step={params.width.step}
|
||||
|
@ -51,7 +53,7 @@ export function Txt2Img() {
|
|||
}}
|
||||
/>
|
||||
<NumericField
|
||||
label='Height'
|
||||
label={t('parameter.height')}
|
||||
min={params.height.min}
|
||||
max={params.height.max}
|
||||
step={params.height.step}
|
||||
|
@ -67,7 +69,7 @@ export function Txt2Img() {
|
|||
<Button
|
||||
variant='contained'
|
||||
onClick={() => generate.mutate()}
|
||||
>Generate</Button>
|
||||
>{t('generate')}</Button>
|
||||
</Stack>
|
||||
</Box>;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { doesExist, mustExist } from '@apextoaster/js-utils';
|
|||
import { Box, Button, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
|
@ -35,13 +36,14 @@ export function Upscale() {
|
|||
const setSource = useStore(state, (s) => s.setUpscaleTab);
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <Box>
|
||||
<Stack spacing={2}>
|
||||
<ImageInput
|
||||
filter={IMAGE_FILTER}
|
||||
image={params.source}
|
||||
label='Source'
|
||||
label={t('input.image.source')}
|
||||
onChange={(file) => {
|
||||
setSource({
|
||||
source: file,
|
||||
|
@ -60,7 +62,7 @@ export function Upscale() {
|
|||
disabled={doesExist(params.source) === false}
|
||||
variant='contained'
|
||||
onClick={() => upload.mutate()}
|
||||
>Generate</Button>
|
||||
>{t('generate')}</Button>
|
||||
</Stack>
|
||||
</Box>;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ export interface ConfigNumber {
|
|||
|
||||
export interface ConfigString {
|
||||
default: string;
|
||||
keys: Array<string>;
|
||||
keys: Record<string, string>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -61,8 +61,11 @@ export async function main() {
|
|||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
resources: I18N_STRINGS,
|
||||
returnEmptyString: false,
|
||||
});
|
||||
|
||||
i18n.addResourceBundle(i18n.resolvedLanguage, 'model', params.model.keys);
|
||||
|
||||
// prep zustand with a slice for each tab, using local storage
|
||||
const {
|
||||
createBrushSlice,
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
// TODO: set up i18next
|
||||
export const MODEL_LABELS: Record<string, string> = {
|
||||
'stable-diffusion-onnx-v1-4': 'Stable Diffusion v1.4',
|
||||
'stable-diffusion-onnx-v1-5': 'Stable Diffusion v1.5',
|
||||
'stable-diffusion-onnx-v1-inpainting': 'SD Inpainting v1',
|
||||
'stable-diffusion-onnx-v2-0': 'Stable Diffusion v2.0',
|
||||
'stable-diffusion-onnx-v2-1': 'Stable Diffusion v2.1',
|
||||
'stable-diffusion-onnx-v2-inpainting': 'SD Inpainting v2',
|
||||
// upscaling
|
||||
'upscaling-real-esrgan-x2-plus': 'Real ESRGAN x2 Plus',
|
||||
'upscaling-real-esrgan-x4-plus': 'Real ESRGAN x4 Plus',
|
||||
'upscaling-real-esrgan-x4-v3': 'Real ESRGAN x4 v3',
|
||||
'upscaling-stable-diffusion-x4': 'Stable Diffusion x4',
|
||||
// correction
|
||||
'correction-codeformer': 'CodeFormer',
|
||||
'correction-gfpgan-v1-3': 'GFPGAN v1.3',
|
||||
// extras
|
||||
'diffusion-stablydiffused-aesthetic-v2-6': 'Aesthetic Mix v2.6',
|
||||
'diffusion-anything': 'Anything',
|
||||
'diffusion-anything-v3': 'Anything v3',
|
||||
'diffusion-anything-v4': 'Anything v4',
|
||||
'diffusion-darkvictorian': 'Dark Victorian',
|
||||
'diffusion-dreamlike-photoreal': 'Dreamlike Photoreal',
|
||||
'diffusion-dreamlike-photoreal-v1': 'Dreamlike Photoreal 1.0',
|
||||
'diffusion-dreamlike-photoreal-v2': 'Dreamlike Photoreal 2.0',
|
||||
'diffusion-ghibli': 'Ghibli',
|
||||
'diffusion-knollingcase': 'Knollingcase',
|
||||
'diffusion-openjourney': 'OpenJourney',
|
||||
'diffusion-openjourney-v1': 'OpenJourney v1',
|
||||
'diffusion-openjourney-v2': 'OpenJourney v2',
|
||||
'diffusion-pastel-mix': 'Pastel Mix',
|
||||
'diffusion-unstable-ink-dream-v6': 'Unstable Ink Dream v6',
|
||||
};
|
||||
|
||||
export const INVERSION_LABELS: Record<string, string> = {
|
||||
'': 'None',
|
||||
'inversion-cubex': 'Cubex',
|
||||
'inversion-birb': 'Birb Style',
|
||||
'inversion-line-art': 'Line Art',
|
||||
'inversion-minecraft': 'Minecraft Concept',
|
||||
};
|
||||
|
||||
export const PLATFORM_LABELS: Record<string, string> = {
|
||||
amd: 'AMD GPU',
|
||||
// eslint-disable-next-line id-blacklist
|
||||
any: 'Any Platform',
|
||||
cpu: 'CPU',
|
||||
cuda: 'CUDA',
|
||||
directml: 'DirectML',
|
||||
nvidia: 'Nvidia GPU',
|
||||
rocm: 'ROCm',
|
||||
};
|
||||
|
||||
export const SCHEDULER_LABELS: Record<string, string> = {
|
||||
'ddim': 'DDIM',
|
||||
'ddpm': 'DDPM',
|
||||
'deis-multi': 'DEIS Multistep',
|
||||
'dpm-multi': 'DPM Multistep',
|
||||
'dpm-single': 'DPM Singlestep',
|
||||
'euler': 'Euler',
|
||||
'euler-a': 'Euler Ancestral',
|
||||
'heun': 'Heun',
|
||||
'k-dpm-2-a': 'KDPM2 Ancestral',
|
||||
'k-dpm-2': 'KDPM2',
|
||||
'karras-ve': 'Karras Ve',
|
||||
'ipndm': 'iPNDM',
|
||||
'lms-discrete': 'LMS',
|
||||
'pndm': 'PNDM',
|
||||
};
|
||||
|
||||
export const NOISE_LABELS: Record<string, string> = {
|
||||
'fill-edge': 'Fill Edges',
|
||||
'fill-mask': 'Fill Masked',
|
||||
'gaussian': 'Gaussian Blur',
|
||||
'histogram': 'Histogram Noise',
|
||||
'normal': 'Gaussian Noise',
|
||||
'uniform': 'Uniform Noise',
|
||||
};
|
||||
|
||||
export const MASK_LABELS: Record<string, string> = {
|
||||
'none': 'None',
|
||||
'gaussian-multiply': 'Gaussian Multiply',
|
||||
'gaussian-screen': 'Gaussian Screen',
|
||||
};
|
|
@ -1,7 +1,18 @@
|
|||
import { I18N_STRINGS_EN, RequiredStrings } from './en.js';
|
||||
import { I18N_STRINGS_DE } from './de.js';
|
||||
import { I18N_STRINGS_EN } from './en.js';
|
||||
import { I18N_STRINGS_ES } from './es.js';
|
||||
import { I18N_STRINGS_FR } from './fr.js';
|
||||
|
||||
export const I18N_STRINGS: Record<string, RequiredStrings> = {
|
||||
// easy way to make sure all locales have the complete set of strings
|
||||
export type RequiredStrings = typeof I18N_STRINGS_EN['en']['translation'];
|
||||
|
||||
interface PartialLanguage {
|
||||
[key: string]: Omit<RequiredStrings, 'model' | 'platform' | 'scheduler'>;
|
||||
}
|
||||
|
||||
export const I18N_STRINGS: Record<string, PartialLanguage> = {
|
||||
...I18N_STRINGS_DE,
|
||||
...I18N_STRINGS_EN,
|
||||
...I18N_STRINGS_ES,
|
||||
...I18N_STRINGS_FR,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
* This is a machine translation and may have some mistakes.
|
||||
*
|
||||
* If you have a more accurate translation for any of these strings, please open an issue or pull request.
|
||||
*/
|
||||
export const I18N_STRINGS_DE = {
|
||||
de: {
|
||||
translation: {
|
||||
generate: 'Erzeugen',
|
||||
history: {
|
||||
empty: 'Keine neuere Geschichte. Drücken Sie Generieren, um ein Bild zu erstellen.',
|
||||
},
|
||||
input: {
|
||||
image: {
|
||||
empty: 'Bitte wählen Sie ein Bild aus',
|
||||
mask: 'Maskenbild',
|
||||
source: 'Quellbild',
|
||||
},
|
||||
list: {
|
||||
error: {
|
||||
specific: '',
|
||||
unknown: 'unbekannter Fehler',
|
||||
},
|
||||
idle: '',
|
||||
loading: '',
|
||||
},
|
||||
numeric: {
|
||||
error: {
|
||||
range: 'außerhalb der Reichweite',
|
||||
},
|
||||
},
|
||||
prompt: {
|
||||
tokens: '',
|
||||
error: {
|
||||
length: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
cancel: 'stornieren',
|
||||
progress: '{{current}} von {{total}} Schritten',
|
||||
unknown: 'vielen',
|
||||
},
|
||||
mask: {
|
||||
fill: {
|
||||
black: 'Mit Schwarz füllen',
|
||||
white: 'Weiß füllen',
|
||||
},
|
||||
gray: {
|
||||
black: 'Grau in schwarz umwandeln',
|
||||
white: 'Grau in weiß umwandeln',
|
||||
},
|
||||
help: '',
|
||||
invert: 'Farben umkehren',
|
||||
},
|
||||
maskFilter: {
|
||||
'gaussian-multiply': '',
|
||||
'gaussian-screen': '',
|
||||
},
|
||||
modelType: {
|
||||
correction: 'Korrekturmodelle',
|
||||
diffusion: 'Diffusionsmodelle',
|
||||
inversion: '',
|
||||
upscaling: 'Modelle vergrößern',
|
||||
},
|
||||
noiseSource: {
|
||||
'fill-edge': 'Kanten füllen',
|
||||
'fill-mask': 'Maskiert füllen',
|
||||
'gaussian': 'Gaußsche Unschärfe',
|
||||
'histogram': 'Histogrammrauschen',
|
||||
'normal': 'Gaußsches Rauschen',
|
||||
'uniform': 'gleichförmiges Rauschen',
|
||||
},
|
||||
parameter: {
|
||||
batch: 'Losgröße',
|
||||
brush: {
|
||||
color: 'Pinselfarbe',
|
||||
size: 'Pinselgröße',
|
||||
strength: 'Pinseldeckkraft',
|
||||
},
|
||||
cfg: '',
|
||||
eta: '',
|
||||
fillColor: 'Füllfarbe',
|
||||
height: 'Höhe',
|
||||
lpw: '',
|
||||
maskFilter: 'Maskenfilter',
|
||||
noiseSource: 'Lärmquelle',
|
||||
negativePrompt: 'Gegenprompt',
|
||||
newSeed: 'neue Saat',
|
||||
outpaint: {
|
||||
label: '',
|
||||
left: 'Links',
|
||||
right: 'Rechts',
|
||||
top: 'Top',
|
||||
bottom: 'Unterseite',
|
||||
},
|
||||
platform: '',
|
||||
prompt: 'Prompt',
|
||||
scheduler: 'Planer',
|
||||
seed: 'Saat',
|
||||
size: '',
|
||||
steps: 'Schritte',
|
||||
strength: 'Stärke',
|
||||
tileOrder: '',
|
||||
upscale: {
|
||||
label: '',
|
||||
denoise: 'Entrauschen',
|
||||
scale: 'Skala',
|
||||
order: '',
|
||||
outscale: 'Ausgangsskala',
|
||||
},
|
||||
width: 'Breite',
|
||||
correction: {
|
||||
label: 'Gesichtskorrektur',
|
||||
strength: 'Stärke',
|
||||
outscale: 'Ausgangsskala',
|
||||
},
|
||||
},
|
||||
setting: {
|
||||
connectServer: 'verbinden zum Server',
|
||||
history: 'Bildgeschichte',
|
||||
loadState: 'Laden',
|
||||
prompt: 'Standard-Eingabeaufforderung',
|
||||
reset: {
|
||||
all: 'Alles zurücksetzen',
|
||||
img2img: 'Img2img zurücksetzen',
|
||||
inpaint: 'Inpaint zurücksetzen',
|
||||
txt2img: 'Txt2img zurücksetzen',
|
||||
},
|
||||
scheduler: 'Standardplaner',
|
||||
server: 'API-Server',
|
||||
state: 'Kundenstatus',
|
||||
},
|
||||
tab: {
|
||||
blend: 'Mischung',
|
||||
img2img: '',
|
||||
inpaint: '',
|
||||
txt2txt: '',
|
||||
txt2img: '',
|
||||
upscale: 'Vergrößern',
|
||||
},
|
||||
tileOrder: {
|
||||
grid: 'Raster',
|
||||
spiral: 'Spiral',
|
||||
},
|
||||
tooltip: {
|
||||
delete: 'Löschen',
|
||||
next: 'Nächste',
|
||||
previous: 'Vorherige',
|
||||
save: 'Speichern',
|
||||
},
|
||||
upscaleOrder: {
|
||||
'correction-both': '',
|
||||
'correction-first': '',
|
||||
'correction-last': '',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -1,14 +1,198 @@
|
|||
export const I18N_STRINGS_EN = {
|
||||
en: {
|
||||
translation: {
|
||||
generate: 'Generate',
|
||||
history: {
|
||||
empty: 'No results. Press Generate to create an image.',
|
||||
empty: 'No recent history. Press Generate to create an image.',
|
||||
},
|
||||
input: {
|
||||
image: {
|
||||
empty: 'Please select an image.',
|
||||
mask: 'Mask',
|
||||
source: 'Source',
|
||||
},
|
||||
list: {
|
||||
error: {
|
||||
specific: 'Error: {{message}}',
|
||||
unknown: 'Unknown Error',
|
||||
},
|
||||
idle: 'Idle?',
|
||||
loading: 'Loading...',
|
||||
},
|
||||
numeric: {
|
||||
error: {
|
||||
range: 'Out of range',
|
||||
},
|
||||
},
|
||||
prompt: {
|
||||
tokens: 'Tokens: {{current}}/{{max}}',
|
||||
error: {
|
||||
length: 'Too many tokens: {{current}}/{{max}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
cancel: 'Cancel',
|
||||
progress: '{{current}} of {{total}} steps',
|
||||
unknown: 'many',
|
||||
},
|
||||
mask: {
|
||||
fill: {
|
||||
black: 'Fill with black',
|
||||
white: 'Fill with white',
|
||||
},
|
||||
gray: {
|
||||
black: 'Gray to black',
|
||||
white: 'Gray to white',
|
||||
},
|
||||
// eslint-disable-next-line max-len
|
||||
help: 'Black pixels in the mask will stay the same, white pixels will be replaced. The masked pixels will be blended with the noise source before the diffusion model runs, giving it more variety to use.',
|
||||
invert: 'Invert',
|
||||
},
|
||||
maskFilter: {
|
||||
'gaussian-multiply': 'Gaussian Multiply',
|
||||
'gaussian-screen': 'Gaussian Screen',
|
||||
},
|
||||
model: {
|
||||
'': 'None',
|
||||
// correction
|
||||
'correction-codeformer': 'CodeFormer',
|
||||
'correction-gfpgan-v1-3': 'GFPGAN v1.3',
|
||||
// diffusion
|
||||
'stable-diffusion-onnx-v1-4': 'Stable Diffusion v1.4',
|
||||
'stable-diffusion-onnx-v1-5': 'Stable Diffusion v1.5',
|
||||
'stable-diffusion-onnx-v1-inpainting': 'SD Inpainting v1',
|
||||
'stable-diffusion-onnx-v2-0': 'Stable Diffusion v2.0',
|
||||
'stable-diffusion-onnx-v2-1': 'Stable Diffusion v2.1',
|
||||
'stable-diffusion-onnx-v2-inpainting': 'SD Inpainting v2',
|
||||
// inversion
|
||||
'inversion-cubex': 'Cubex',
|
||||
'inversion-birb': 'Birb Style',
|
||||
'inversion-line-art': 'Line Art',
|
||||
'inversion-minecraft': 'Minecraft Concept',
|
||||
'inversion-ugly-sonic': 'Ugly Sonic',
|
||||
// upscaling
|
||||
'upscaling-real-esrgan-x2-plus': 'Real ESRGAN x2 Plus',
|
||||
'upscaling-real-esrgan-x4-plus': 'Real ESRGAN x4 Plus',
|
||||
'upscaling-real-esrgan-x4-v3': 'Real ESRGAN x4 v3',
|
||||
'upscaling-stable-diffusion-x4': 'Stable Diffusion x4',
|
||||
// extras
|
||||
'diffusion-stablydiffused-aesthetic-v2-6': 'Aesthetic Mix v2.6',
|
||||
'diffusion-anything': 'Anything',
|
||||
'diffusion-anything-v3': 'Anything v3',
|
||||
'diffusion-anything-v4': 'Anything v4',
|
||||
'diffusion-darkvictorian': 'Dark Victorian',
|
||||
'diffusion-dreamlike-photoreal': 'Dreamlike Photoreal',
|
||||
'diffusion-dreamlike-photoreal-v1': 'Dreamlike Photoreal 1.0',
|
||||
'diffusion-dreamlike-photoreal-v2': 'Dreamlike Photoreal 2.0',
|
||||
'diffusion-ghibli': 'Ghibli',
|
||||
'diffusion-knollingcase': 'Knollingcase',
|
||||
'diffusion-openjourney': 'OpenJourney',
|
||||
'diffusion-openjourney-v1': 'OpenJourney v1',
|
||||
'diffusion-openjourney-v2': 'OpenJourney v2',
|
||||
'diffusion-pastel-mix': 'Pastel Mix',
|
||||
'diffusion-unstable-ink-dream-v6': 'Unstable Ink Dream v6',
|
||||
},
|
||||
modelType: {
|
||||
correction: 'Correction Model',
|
||||
diffusion: 'Diffusion Model',
|
||||
inversion: 'Textual Inversion',
|
||||
upscaling: 'Upscaling Model',
|
||||
},
|
||||
noiseSource: {
|
||||
'fill-edge': 'Fill Edges',
|
||||
'fill-mask': 'Fill Masked',
|
||||
'gaussian': 'Gaussian Blur',
|
||||
'histogram': 'Histogram Noise',
|
||||
'normal': 'Gaussian Noise',
|
||||
'uniform': 'Uniform Noise',
|
||||
},
|
||||
parameter: {
|
||||
batch: 'Batch Size',
|
||||
brush: {
|
||||
color: 'Brush Color',
|
||||
size: 'Brush Size',
|
||||
strength: 'Brush Strength',
|
||||
},
|
||||
cfg: 'CFG',
|
||||
eta: 'Eta',
|
||||
fillColor: 'Fill Color',
|
||||
height: 'Height',
|
||||
lpw: 'Long Prompt Weighting',
|
||||
maskFilter: 'Mask Filter',
|
||||
noiseSource: 'Noise Source',
|
||||
negativePrompt: 'Negative Prompt',
|
||||
newSeed: 'New Seed',
|
||||
outpaint: {
|
||||
label: 'Outpaint',
|
||||
left: 'Left',
|
||||
right: 'Right',
|
||||
top: 'Top',
|
||||
bottom: 'Bottom',
|
||||
},
|
||||
platform: 'Platform',
|
||||
prompt: 'Prompt',
|
||||
scheduler: 'Scheduler',
|
||||
seed: 'Seed',
|
||||
size: 'Size',
|
||||
steps: 'Steps',
|
||||
strength: 'Strength',
|
||||
tileOrder: 'Tile Order',
|
||||
upscale: {
|
||||
label: 'Upscale',
|
||||
denoise: 'Denoise',
|
||||
scale: 'Scale',
|
||||
order: 'Upscale Order',
|
||||
outscale: 'Outscale',
|
||||
},
|
||||
width: 'Width',
|
||||
correction: {
|
||||
label: 'Face Correction',
|
||||
strength: 'Strength',
|
||||
outscale: 'Outscale',
|
||||
},
|
||||
},
|
||||
platform: {
|
||||
amd: 'AMD GPU',
|
||||
// eslint-disable-next-line id-blacklist
|
||||
any: 'Any Platform',
|
||||
cpu: 'CPU',
|
||||
cuda: 'CUDA',
|
||||
directml: 'DirectML',
|
||||
nvidia: 'Nvidia GPU',
|
||||
rocm: 'ROCm',
|
||||
},
|
||||
setting: {
|
||||
connectServer: 'Connect',
|
||||
history: 'Image History',
|
||||
loadState: 'Load',
|
||||
prompt: 'Default Prompt',
|
||||
reset: {
|
||||
all: 'Reset All',
|
||||
img2img: 'Reset Img2img',
|
||||
inpaint: 'Reset Inpaint',
|
||||
txt2img: 'Reset Txt2img',
|
||||
},
|
||||
scheduler: 'Default Scheduler',
|
||||
server: 'API Server',
|
||||
state: 'Client State',
|
||||
},
|
||||
scheduler: {
|
||||
'ddim': 'DDIM',
|
||||
'ddpm': 'DDPM',
|
||||
'deis-multi': 'DEIS Multistep',
|
||||
'dpm-multi': 'DPM Multistep',
|
||||
'dpm-single': 'DPM Singlestep',
|
||||
'euler': 'Euler',
|
||||
'euler-a': 'Euler Ancestral',
|
||||
'heun': 'Heun',
|
||||
'k-dpm-2-a': 'KDPM2 Ancestral',
|
||||
'k-dpm-2': 'KDPM2',
|
||||
'karras-ve': 'Karras Ve',
|
||||
'ipndm': 'iPNDM',
|
||||
'lms-discrete': 'LMS',
|
||||
'pndm': 'PNDM',
|
||||
},
|
||||
tab: {
|
||||
blend: 'Blend',
|
||||
img2img: 'Img2img',
|
||||
|
@ -17,15 +201,21 @@ export const I18N_STRINGS_EN = {
|
|||
txt2img: 'Txt2img',
|
||||
upscale: 'Upscale',
|
||||
},
|
||||
tileOrder: {
|
||||
grid: 'Grid',
|
||||
spiral: 'Spiral',
|
||||
},
|
||||
tooltip: {
|
||||
delete: 'Delete',
|
||||
next: 'EN Next',
|
||||
previous: 'EN Previous',
|
||||
next: 'Next',
|
||||
previous: 'Previous',
|
||||
save: 'Save',
|
||||
},
|
||||
upscaleOrder: {
|
||||
'correction-both': 'Correction Both',
|
||||
'correction-first': 'Correction First',
|
||||
'correction-last': 'Correction Last',
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// easy way to make sure all locales have the complete set of strings
|
||||
export type RequiredStrings = typeof I18N_STRINGS_EN['en'];
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
* This is a machine translation and may have some mistakes.
|
||||
*
|
||||
* If you have a more accurate translation for any of these strings, please open an issue or pull request.
|
||||
*/
|
||||
export const I18N_STRINGS_ES = {
|
||||
es: {
|
||||
translation: {
|
||||
generate: 'Generar',
|
||||
history: {
|
||||
empty: 'Sin antecedentes recientes. Presiona generar para crear una nueva imagen.',
|
||||
},
|
||||
input: {
|
||||
image: {
|
||||
empty: 'Por favor, seleccione una imagen.',
|
||||
mask: 'Máscara de imagen',
|
||||
source: 'Imagen de origen',
|
||||
},
|
||||
list: {
|
||||
error: {
|
||||
specific: 'Error: {{message}}',
|
||||
unknown: 'Error desconocido',
|
||||
},
|
||||
idle: '',
|
||||
loading: '',
|
||||
},
|
||||
numeric: {
|
||||
error: {
|
||||
range: 'Fuera de intervalo',
|
||||
},
|
||||
},
|
||||
prompt: {
|
||||
tokens: '',
|
||||
error: {
|
||||
length: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
cancel: 'Cancelar',
|
||||
progress: '{{current}} de {{total}} pasos',
|
||||
unknown: 'muchos',
|
||||
},
|
||||
mask: {
|
||||
fill: {
|
||||
black: 'Llenar con negro',
|
||||
white: 'Llenar con blanco',
|
||||
},
|
||||
gray: {
|
||||
black: 'Convertir gris a negro',
|
||||
white: 'Convertir gris a blanco',
|
||||
},
|
||||
help: '',
|
||||
invert: 'Colores invertidos',
|
||||
},
|
||||
maskFilter: {
|
||||
'gaussian-multiply': '',
|
||||
'gaussian-screen': '',
|
||||
},
|
||||
modelType: {
|
||||
correction: 'Modelo de corrección',
|
||||
diffusion: 'Modelo de difusión',
|
||||
inversion: '',
|
||||
upscaling: 'Modelo de aumento',
|
||||
},
|
||||
noiseSource: {
|
||||
'fill-edge': 'Rellena los bordes',
|
||||
'fill-mask': 'Rellena la máscara',
|
||||
'gaussian': 'Desenfoque gaussiano',
|
||||
'histogram': 'Ruido de histograma',
|
||||
'normal': 'Ruido gaussiano',
|
||||
'uniform': 'Ruido uniforme',
|
||||
},
|
||||
parameter: {
|
||||
batch: 'Tamaño del lote',
|
||||
brush: {
|
||||
color: 'Color del pincel',
|
||||
size: 'Tamaño del pincel',
|
||||
strength: 'Opacidad del pincel',
|
||||
},
|
||||
cfg: '',
|
||||
eta: '',
|
||||
fillColor: 'Color de relleno',
|
||||
height: 'Altura',
|
||||
lpw: '',
|
||||
maskFilter: 'Filtro de máscara',
|
||||
noiseSource: 'Fuente de ruido',
|
||||
negativePrompt: '',
|
||||
newSeed: '',
|
||||
outpaint: {
|
||||
label: '',
|
||||
left: 'Izquierda',
|
||||
right: 'Derecha',
|
||||
top: 'Top',
|
||||
bottom: 'Fondo',
|
||||
},
|
||||
platform: 'Plataforma de hardware',
|
||||
prompt: 'Aviso',
|
||||
scheduler: 'Planificador',
|
||||
seed: 'Semilla',
|
||||
size: '',
|
||||
steps: 'Pasos',
|
||||
strength: 'Fuerza',
|
||||
tileOrder: 'Orden de secciones',
|
||||
upscale: {
|
||||
label: 'Aumento',
|
||||
denoise: '',
|
||||
scale: 'Escala',
|
||||
order: '',
|
||||
outscale: 'Escala de producción',
|
||||
},
|
||||
width: 'Anchura',
|
||||
correction: {
|
||||
label: 'Corrección facial',
|
||||
strength: 'Fuerza',
|
||||
outscale: 'Escala de producción',
|
||||
},
|
||||
},
|
||||
setting: {
|
||||
connectServer: 'Conectar al servidor',
|
||||
history: 'Historia de la imagen',
|
||||
loadState: '',
|
||||
prompt: '',
|
||||
reset: {
|
||||
all: 'Resetear todo',
|
||||
img2img: 'Resetear img2img',
|
||||
inpaint: 'Resetear inpaint',
|
||||
txt2img: 'Resetear txt2img',
|
||||
},
|
||||
scheduler: 'Programador predeterminado',
|
||||
server: 'Servidor API',
|
||||
state: 'Estado del cliente',
|
||||
},
|
||||
tab: {
|
||||
blend: 'Mezclar',
|
||||
img2img: 'Img2img',
|
||||
inpaint: 'Inpaint',
|
||||
txt2txt: 'Txt2txt',
|
||||
txt2img: 'Txt2img',
|
||||
upscale: 'Aumentar',
|
||||
},
|
||||
tileOrder: {
|
||||
grid: 'Red',
|
||||
spiral: 'Espiral',
|
||||
},
|
||||
tooltip: {
|
||||
delete: 'Borrar',
|
||||
next: 'Próximo',
|
||||
previous: 'Anterior',
|
||||
save: 'Ahorrar',
|
||||
},
|
||||
upscaleOrder: {
|
||||
'correction-both': '',
|
||||
'correction-first': '',
|
||||
'correction-last': '',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -1,20 +1,159 @@
|
|||
/**
|
||||
* This is a machine translation and may have some mistakes.
|
||||
*
|
||||
* If you have a more accurate translation for any of these strings, please open an issue or pull request.
|
||||
*/
|
||||
export const I18N_STRINGS_FR = {
|
||||
fr: {
|
||||
translation: {
|
||||
generate: '',
|
||||
history: {
|
||||
empty: '',
|
||||
},
|
||||
input: {
|
||||
image: {
|
||||
empty: '',
|
||||
mask: '',
|
||||
source: '',
|
||||
},
|
||||
list: {
|
||||
error: {
|
||||
specific: '',
|
||||
unknown: '',
|
||||
},
|
||||
idle: '',
|
||||
loading: '',
|
||||
},
|
||||
numeric: {
|
||||
error: {
|
||||
range: '',
|
||||
},
|
||||
},
|
||||
prompt: {
|
||||
tokens: '',
|
||||
error: {
|
||||
length: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
cancel: '',
|
||||
progress: '',
|
||||
unknown: '',
|
||||
},
|
||||
mask: {
|
||||
fill: {
|
||||
black: '',
|
||||
white: '',
|
||||
},
|
||||
gray: {
|
||||
black: '',
|
||||
white: '',
|
||||
},
|
||||
help: '',
|
||||
invert: '',
|
||||
},
|
||||
maskFilter: {
|
||||
'gaussian-multiply': '',
|
||||
'gaussian-screen': '',
|
||||
},
|
||||
modelType: {
|
||||
correction: '',
|
||||
diffusion: '',
|
||||
inversion: '',
|
||||
upscaling: '',
|
||||
},
|
||||
noiseSource: {
|
||||
'fill-edge': '',
|
||||
'fill-mask': '',
|
||||
'gaussian': '',
|
||||
'histogram': '',
|
||||
'normal': '',
|
||||
'uniform': '',
|
||||
},
|
||||
parameter: {
|
||||
batch: '',
|
||||
brush: {
|
||||
color: '',
|
||||
size: '',
|
||||
strength: '',
|
||||
},
|
||||
cfg: '',
|
||||
eta: '',
|
||||
fillColor: '',
|
||||
height: '',
|
||||
lpw: '',
|
||||
maskFilter: '',
|
||||
noiseSource: '',
|
||||
negativePrompt: '',
|
||||
newSeed: '',
|
||||
outpaint: {
|
||||
label: '',
|
||||
left: '',
|
||||
right: '',
|
||||
top: '',
|
||||
bottom: '',
|
||||
},
|
||||
platform: '',
|
||||
prompt: '',
|
||||
scheduler: '',
|
||||
seed: '',
|
||||
size: '',
|
||||
steps: '',
|
||||
strength: '',
|
||||
tileOrder: '',
|
||||
upscale: {
|
||||
label: '',
|
||||
denoise: '',
|
||||
scale: '',
|
||||
order: '',
|
||||
outscale: '',
|
||||
},
|
||||
width: '',
|
||||
correction: {
|
||||
label: '',
|
||||
strength: '',
|
||||
outscale: '',
|
||||
},
|
||||
},
|
||||
setting: {
|
||||
connectServer: '',
|
||||
history: '',
|
||||
loadState: '',
|
||||
prompt: '',
|
||||
reset: {
|
||||
all: '',
|
||||
img2img: '',
|
||||
inpaint: '',
|
||||
txt2img: '',
|
||||
},
|
||||
scheduler: '',
|
||||
server: '',
|
||||
state: '',
|
||||
},
|
||||
tab: {
|
||||
blend: 'Blend',
|
||||
img2img: 'Img2img',
|
||||
inpaint: 'Inpaint',
|
||||
txt2txt: 'Txt2txt',
|
||||
txt2img: 'Txt2img',
|
||||
upscale: 'Upscale',
|
||||
blend: '',
|
||||
img2img: '',
|
||||
inpaint: '',
|
||||
txt2txt: '',
|
||||
txt2img: '',
|
||||
upscale: '',
|
||||
},
|
||||
tileOrder: {
|
||||
grid: '',
|
||||
spiral: '',
|
||||
},
|
||||
tooltip: {
|
||||
delete: 'Delete',
|
||||
next: 'FR-Next',
|
||||
previous: 'FR-Previous',
|
||||
save: 'Save',
|
||||
delete: '',
|
||||
next: '',
|
||||
previous: '',
|
||||
save: '',
|
||||
},
|
||||
}
|
||||
upscaleOrder: {
|
||||
'correction-both': '',
|
||||
'correction-first': '',
|
||||
'correction-last': '',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue