fix: i18n tsc

This commit is contained in:
Ibrahima G. Coulibaly 2025-07-13 13:01:02 +01:00
commit 2bcd88cfd1
60 changed files with 1359 additions and 884 deletions

2
.gitignore vendored
View file

@ -42,3 +42,5 @@ yarn-error.log*
dist.zip dist.zip
.aider* .aider*
.qodo .qodo
error.txt

861
.idea/workspace.xml generated

File diff suppressed because it is too large Load diff

33
@types/i18n.d.ts vendored Normal file
View file

@ -0,0 +1,33 @@
// types/i18next.d.ts
import 'i18next';
import enGlobal from '../src/i18n/en.json';
import enList from '../src/pages/tools/list/i18n/en.json';
import enString from '../src/pages/tools/string/i18n/en.json';
import enCsv from '../src/pages/tools/csv/i18n/en.json';
import enJson from '../src/pages/tools/json/i18n/en.json';
import enPdf from '../src/pages/tools/pdf/i18n/en.json';
import enImage from '../src/pages/tools/image/i18n/en.json';
import enAudio from '../src/pages/tools/audio/i18n/en.json';
import enVideo from '../src/pages/tools/video/i18n/en.json';
import enNumber from '../src/pages/tools/number/i18n/en.json';
import enTime from '../src/pages/tools/time/i18n/en.json';
import enXml from '../src/pages/tools/xml/i18n/en.json';
declare module 'i18next' {
interface CustomTypeOptions {
resources: {
translation: typeof enGlobal;
list: typeof enList;
string: typeof enString;
csv: typeof enCsv;
json: typeof enJson;
pdf: typeof enPdf;
image: typeof enImage;
audio: typeof enAudio;
video: typeof enVideo;
number: typeof enNumber;
time: typeof enTime;
xml: typeof enXml;
};
}
}

View file

@ -10,6 +10,8 @@ import { tools } from '../tools';
import './index.css'; import './index.css';
import { darkTheme, lightTheme } from '../config/muiConfig'; import { darkTheme, lightTheme } from '../config/muiConfig';
import ScrollToTopButton from './ScrollToTopButton'; import ScrollToTopButton from './ScrollToTopButton';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18n';
export type Mode = 'dark' | 'light' | 'system'; export type Mode = 'dark' | 'light' | 'system';
@ -44,32 +46,34 @@ function App() {
}, []); }, []);
return ( return (
<ThemeProvider theme={theme}> <I18nextProvider i18n={i18n}>
<CssBaseline /> <ThemeProvider theme={theme}>
<SnackbarProvider <CssBaseline />
maxSnack={5} <SnackbarProvider
anchorOrigin={{ maxSnack={5}
vertical: 'bottom', anchorOrigin={{
horizontal: 'right' vertical: 'bottom',
}} horizontal: 'right'
> }}
<CustomSnackBarProvider> >
<BrowserRouter> <CustomSnackBarProvider>
<Navbar <BrowserRouter>
mode={mode} <Navbar
onChangeMode={() => { mode={mode}
setMode((prev) => nextMode(prev)); onChangeMode={() => {
localStorage.setItem('theme', nextMode(mode)); setMode((prev) => nextMode(prev));
}} localStorage.setItem('theme', nextMode(mode));
/> }}
<Suspense fallback={<Loading />}> />
<AppRoutes /> <Suspense fallback={<Loading />}>
</Suspense> <AppRoutes />
</BrowserRouter> </Suspense>
</CustomSnackBarProvider> </BrowserRouter>
</SnackbarProvider> </CustomSnackBarProvider>
<ScrollToTopButton /> </SnackbarProvider>
</ThemeProvider> <ScrollToTopButton />
</ThemeProvider>
</I18nextProvider>
); );
} }

View file

@ -65,7 +65,7 @@ const resources = {
}; };
i18n i18n
.use(Backend) // .use(Backend)
.use(initReactI18next) .use(initReactI18next)
.init({ .init({
resources, resources,

View file

@ -1,7 +1,6 @@
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import 'tailwindcss/tailwind.css'; import 'tailwindcss/tailwind.css';
import App from 'components/App'; import App from 'components/App';
import './i18n';
const container = document.getElementById('root') as HTMLDivElement; const container = document.getElementById('root') as HTMLDivElement;
const root = createRoot(container); const root = createRoot(container);

View file

@ -26,7 +26,7 @@ export default function ChangeSpeed({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('audio');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -51,20 +51,20 @@ export default function ChangeSpeed({
updateField updateField
}) => [ }) => [
{ {
title: t('audio:changeSpeed.newAudioSpeed'), title: t('changeSpeed.newAudioSpeed'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.newSpeed.toString()} value={values.newSpeed.toString()}
onOwnChange={(val) => updateField('newSpeed', Number(val))} onOwnChange={(val) => updateField('newSpeed', Number(val))}
description={t('audio:changeSpeed.speedDescription')} description={t('changeSpeed.speedDescription')}
type="number" type="number"
/> />
</Box> </Box>
) )
}, },
{ {
title: t('audio:changeSpeed.outputFormat'), title: t('changeSpeed.outputFormat'),
component: ( component: (
<Box mt={2}> <Box mt={2}>
<RadioGroup <RadioGroup
@ -98,19 +98,19 @@ export default function ChangeSpeed({
<ToolAudioInput <ToolAudioInput
value={input} value={input}
onChange={setInput} onChange={setInput}
title={t('audio:changeSpeed.inputTitle')} title={t('changeSpeed.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
loading ? ( loading ? (
<ToolFileResult <ToolFileResult
title={t('audio:changeSpeed.settingSpeed')} title={t('changeSpeed.settingSpeed')}
value={null} value={null}
loading={true} loading={true}
/> />
) : ( ) : (
<ToolFileResult <ToolFileResult
title={t('audio:changeSpeed.resultTitle')} title={t('changeSpeed.resultTitle')}
value={result} value={result}
extension={result ? result.name.split('.').pop() : undefined} extension={result ? result.name.split('.').pop() : undefined}
/> />
@ -121,7 +121,7 @@ export default function ChangeSpeed({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('audio:changeSpeed.toolInfo.title', { title }), title: t('changeSpeed.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
/> />

View file

@ -18,7 +18,7 @@ export default function ExtractAudio({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('audio');
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [audioFile, setAudioFile] = useState<File | null>(null); const [audioFile, setAudioFile] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -29,7 +29,7 @@ export default function ExtractAudio({
}) => { }) => {
return [ return [
{ {
title: t('audio:extractAudio.outputFormat'), title: t('extractAudio.outputFormat'),
component: ( component: (
<Box> <Box>
<SelectWithDesc <SelectWithDesc
@ -42,7 +42,7 @@ export default function ExtractAudio({
{ label: 'MP3', value: 'mp3' }, { label: 'MP3', value: 'mp3' },
{ label: 'WAV', value: 'wav' } { label: 'WAV', value: 'wav' }
]} ]}
description={t('audio:extractAudio.outputFormatDescription')} description={t('extractAudio.outputFormatDescription')}
/> />
</Box> </Box>
) )
@ -71,19 +71,19 @@ export default function ExtractAudio({
<ToolVideoInput <ToolVideoInput
value={file} value={file}
onChange={setFile} onChange={setFile}
title={t('audio:extractAudio.inputTitle')} title={t('extractAudio.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
loading ? ( loading ? (
<ToolFileResult <ToolFileResult
title={t('audio:extractAudio.extractingAudio')} title={t('extractAudio.extractingAudio')}
value={null} value={null}
loading={true} loading={true}
/> />
) : ( ) : (
<ToolFileResult <ToolFileResult
title={t('audio:extractAudio.resultTitle')} title={t('extractAudio.resultTitle')}
value={audioFile} value={audioFile}
/> />
) )
@ -92,7 +92,7 @@ export default function ExtractAudio({
getGroups={getGroups} getGroups={getGroups}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('audio:extractAudio.toolInfo.title', { title }), title: t('extractAudio.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
setInput={setFile} setInput={setFile}

View file

@ -113,7 +113,7 @@ id,name,active
]; ];
export default function CsvToJson({ title }: ToolComponentProps) { export default function CsvToJson({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('csv');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -149,35 +149,35 @@ export default function CsvToJson({ title }: ToolComponentProps) {
exampleCards={exampleCards} exampleCards={exampleCards}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('csv:csvToJson.inputTitle')} title={t('csvToJson.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult
title={t('csv:csvToJson.resultTitle')} title={t('csvToJson.resultTitle')}
value={result} value={result}
extension={'json'} extension={'json'}
/> />
} }
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('csv:csvToJson.inputCsvFormat'), title: t('csvToJson.inputCsvFormat'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('csv:csvToJson.columnSeparator')} description={t('csvToJson.columnSeparator')}
value={values.delimiter} value={values.delimiter}
onOwnChange={(val) => updateField('delimiter', val)} onOwnChange={(val) => updateField('delimiter', val)}
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('csv:csvToJson.fieldQuote')} description={t('csvToJson.fieldQuote')}
onOwnChange={(val) => updateField('quote', val)} onOwnChange={(val) => updateField('quote', val)}
value={values.quote} value={values.quote}
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('csv:csvToJson.commentSymbol')} description={t('csvToJson.commentSymbol')}
value={values.comment} value={values.comment}
onOwnChange={(val) => updateField('comment', val)} onOwnChange={(val) => updateField('comment', val)}
/> />
@ -185,26 +185,26 @@ export default function CsvToJson({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('csv:csvToJson.conversionOptions'), title: t('csvToJson.conversionOptions'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
checked={values.useHeaders} checked={values.useHeaders}
onChange={(value) => updateField('useHeaders', value)} onChange={(value) => updateField('useHeaders', value)}
title={t('csv:csvToJson.useHeaders')} title={t('csvToJson.useHeaders')}
description={t('csv:csvToJson.useHeadersDescription')} description={t('csvToJson.useHeadersDescription')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.skipEmptyLines} checked={values.skipEmptyLines}
onChange={(value) => updateField('skipEmptyLines', value)} onChange={(value) => updateField('skipEmptyLines', value)}
title={t('csv:csvToJson.skipEmptyLines')} title={t('csvToJson.skipEmptyLines')}
description={t('csv:csvToJson.skipEmptyLinesDescription')} description={t('csvToJson.skipEmptyLinesDescription')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.dynamicTypes} checked={values.dynamicTypes}
onChange={(value) => updateField('dynamicTypes', value)} onChange={(value) => updateField('dynamicTypes', value)}
title={t('csv:csvToJson.dynamicTypes')} title={t('csvToJson.dynamicTypes')}
description={t('csv:csvToJson.dynamicTypesDescription')} description={t('csvToJson.dynamicTypesDescription')}
/> />
</Box> </Box>
) )

View file

@ -104,7 +104,7 @@ export default function FindIncompleteCsvRecords({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('csv');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -117,7 +117,7 @@ export default function FindIncompleteCsvRecords({
updateField updateField
}) => [ }) => [
{ {
title: t('csv:findIncompleteCsvRecords.csvInputOptions'), title: t('findIncompleteCsvRecords.csvInputOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
@ -145,13 +145,13 @@ export default function FindIncompleteCsvRecords({
) )
}, },
{ {
title: t('csv:findIncompleteCsvRecords.checkingOptions'), title: t('findIncompleteCsvRecords.checkingOptions'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
checked={values.emptyLines} checked={values.emptyLines}
onChange={(value) => updateField('emptyLines', value)} onChange={(value) => updateField('emptyLines', value)}
title={t('csv:findIncompleteCsvRecords.deleteLinesWithNoData')} title={t('findIncompleteCsvRecords.deleteLinesWithNoData')}
description={t( description={t(
'csv:findIncompleteCsvRecords.deleteLinesWithNoDataDescription' 'csv:findIncompleteCsvRecords.deleteLinesWithNoDataDescription'
)} )}
@ -160,7 +160,7 @@ export default function FindIncompleteCsvRecords({
<CheckboxWithDesc <CheckboxWithDesc
checked={values.emptyValues} checked={values.emptyValues}
onChange={(value) => updateField('emptyValues', value)} onChange={(value) => updateField('emptyValues', value)}
title={t('csv:findIncompleteCsvRecords.findEmptyValues')} title={t('findIncompleteCsvRecords.findEmptyValues')}
description={t( description={t(
'csv:findIncompleteCsvRecords.findEmptyValuesDescription' 'csv:findIncompleteCsvRecords.findEmptyValuesDescription'
)} )}
@ -169,7 +169,7 @@ export default function FindIncompleteCsvRecords({
<CheckboxWithDesc <CheckboxWithDesc
checked={values.messageLimit} checked={values.messageLimit}
onChange={(value) => updateField('messageLimit', value)} onChange={(value) => updateField('messageLimit', value)}
title={t('csv:findIncompleteCsvRecords.limitNumberOfMessages')} title={t('findIncompleteCsvRecords.limitNumberOfMessages')}
/> />
{values.messageLimit && ( {values.messageLimit && (
@ -193,14 +193,14 @@ export default function FindIncompleteCsvRecords({
input={input} input={input}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('csv:findIncompleteCsvRecords.inputTitle')} title={t('findIncompleteCsvRecords.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult
title={t('csv:findIncompleteCsvRecords.resultTitle')} title={t('findIncompleteCsvRecords.resultTitle')}
value={result} value={result}
/> />
} }
@ -210,7 +210,7 @@ export default function FindIncompleteCsvRecords({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('csv:findIncompleteCsvRecords.toolInfo.title', { title }), title: t('findIncompleteCsvRecords.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
/> />

View file

@ -123,7 +123,7 @@ export default function InsertCsvColumns({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('csv');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -145,7 +145,7 @@ export default function InsertCsvColumns({
updateField updateField
}) => [ }) => [
{ {
title: t('csv:insertCsvColumns.csvToInsert'), title: t('insertCsvColumns.csvToInsert'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
@ -153,40 +153,40 @@ export default function InsertCsvColumns({
rows={3} rows={3}
value={values.csvToInsert} value={values.csvToInsert}
onOwnChange={(val) => updateField('csvToInsert', val)} onOwnChange={(val) => updateField('csvToInsert', val)}
title={t('csv:insertCsvColumns.csvSeparator')} title={t('insertCsvColumns.csvSeparator')}
description={t('csv:insertCsvColumns.csvToInsertDescription')} description={t('insertCsvColumns.csvToInsertDescription')}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('csv:insertCsvColumns.csvOptions'), title: t('insertCsvColumns.csvOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.separator} value={values.separator}
onOwnChange={(val) => updateField('separator', val)} onOwnChange={(val) => updateField('separator', val)}
description={t('csv:insertCsvColumns.separatorDescription')} description={t('insertCsvColumns.separatorDescription')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.quoteChar} value={values.quoteChar}
onOwnChange={(val) => updateField('quoteChar', val)} onOwnChange={(val) => updateField('quoteChar', val)}
description={t('csv:insertCsvColumns.quoteCharDescription')} description={t('insertCsvColumns.quoteCharDescription')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.commentCharacter} value={values.commentCharacter}
onOwnChange={(val) => updateField('commentCharacter', val)} onOwnChange={(val) => updateField('commentCharacter', val)}
description={t('csv:insertCsvColumns.commentCharacterDescription')} description={t('insertCsvColumns.commentCharacterDescription')}
/> />
<SelectWithDesc <SelectWithDesc
selected={values.customFill} selected={values.customFill}
options={[ options={[
{ {
label: t('csv:insertCsvColumns.fillWithEmptyValues'), label: t('insertCsvColumns.fillWithEmptyValues'),
value: false value: false
}, },
{ {
label: t('csv:insertCsvColumns.fillWithCustomValues'), label: t('insertCsvColumns.fillWithCustomValues'),
value: true value: true
} }
]} ]}
@ -196,40 +196,40 @@ export default function InsertCsvColumns({
updateField('customFillValue', ''); // Reset custom fill value updateField('customFillValue', ''); // Reset custom fill value
} }
}} }}
description={t('csv:insertCsvColumns.customFillDescription')} description={t('insertCsvColumns.customFillDescription')}
/> />
{values.customFill && ( {values.customFill && (
<TextFieldWithDesc <TextFieldWithDesc
value={values.customFillValue} value={values.customFillValue}
onOwnChange={(val) => updateField('customFillValue', val)} onOwnChange={(val) => updateField('customFillValue', val)}
description={t('csv:insertCsvColumns.customFillValueDescription')} description={t('insertCsvColumns.customFillValueDescription')}
/> />
)} )}
</Box> </Box>
) )
}, },
{ {
title: t('csv:insertCsvColumns.positionOptions'), title: t('insertCsvColumns.positionOptions'),
component: ( component: (
<Box> <Box>
<SelectWithDesc <SelectWithDesc
selected={values.insertingPosition} selected={values.insertingPosition}
options={[ options={[
{ {
label: t('csv:insertCsvColumns.prependColumns'), label: t('insertCsvColumns.prependColumns'),
value: 'prepend' value: 'prepend'
}, },
{ {
label: t('csv:insertCsvColumns.appendColumns'), label: t('insertCsvColumns.appendColumns'),
value: 'append' value: 'append'
}, },
{ {
label: t('csv:insertCsvColumns.customPosition'), label: t('insertCsvColumns.customPosition'),
value: 'custom' value: 'custom'
} }
]} ]}
onChange={(value) => updateField('insertingPosition', value)} onChange={(value) => updateField('insertingPosition', value)}
description={t('csv:insertCsvColumns.insertingPositionDescription')} description={t('insertCsvColumns.insertingPositionDescription')}
/> />
{values.insertingPosition === 'custom' && ( {values.insertingPosition === 'custom' && (
@ -237,11 +237,11 @@ export default function InsertCsvColumns({
selected={values.customPostionOptions} selected={values.customPostionOptions}
options={[ options={[
{ {
label: t('csv:insertCsvColumns.headerName'), label: t('insertCsvColumns.headerName'),
value: 'headerName' value: 'headerName'
}, },
{ {
label: t('csv:insertCsvColumns.position'), label: t('insertCsvColumns.position'),
value: 'rowNumber' value: 'rowNumber'
} }
]} ]}
@ -258,7 +258,7 @@ export default function InsertCsvColumns({
selected={values.headerName} selected={values.headerName}
options={headerOptions} options={headerOptions}
onChange={(value) => updateField('headerName', value)} onChange={(value) => updateField('headerName', value)}
description={t('csv:insertCsvColumns.headerNameDescription')} description={t('insertCsvColumns.headerNameDescription')}
/> />
)} )}
@ -269,7 +269,7 @@ export default function InsertCsvColumns({
onOwnChange={(val) => onOwnChange={(val) =>
updateField('rowNumber', parseInt(val) || 0) updateField('rowNumber', parseInt(val) || 0)
} }
description={t('csv:insertCsvColumns.rowNumberDescription')} description={t('insertCsvColumns.rowNumberDescription')}
type="number" type="number"
/> />
)} )}
@ -283,14 +283,14 @@ export default function InsertCsvColumns({
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('csv:insertCsvColumns.inputTitle')} title={t('insertCsvColumns.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult
title={t('csv:insertCsvColumns.resultTitle')} title={t('insertCsvColumns.resultTitle')}
value={result} value={result}
extension={'csv'} extension={'csv'}
/> />
@ -301,8 +301,8 @@ export default function InsertCsvColumns({
input={input} input={input}
setInput={setInput} setInput={setInput}
toolInfo={{ toolInfo={{
title: t('csv:insertCsvColumns.toolInfo.title'), title: t('insertCsvColumns.toolInfo.title'),
description: t('csv:insertCsvColumns.toolInfo.description') description: t('insertCsvColumns.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -46,7 +46,7 @@ const validationSchema = Yup.object({
}); });
export default function ResizeImage({ title }: ToolComponentProps) { export default function ResizeImage({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('image');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
@ -60,20 +60,20 @@ export default function ResizeImage({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('image:resize.resizeMethod'), title: t('resize.resizeMethod'),
component: ( component: (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('resizeMethod', 'pixels')} onClick={() => updateField('resizeMethod', 'pixels')}
checked={values.resizeMethod === 'pixels'} checked={values.resizeMethod === 'pixels'}
description={t('image:resize.resizeByPixelsDescription')} description={t('resize.resizeByPixelsDescription')}
title={t('image:resize.resizeByPixels')} title={t('resize.resizeByPixels')}
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('resizeMethod', 'percentage')} onClick={() => updateField('resizeMethod', 'percentage')}
checked={values.resizeMethod === 'percentage'} checked={values.resizeMethod === 'percentage'}
description={t('image:resize.resizeByPercentageDescription')} description={t('resize.resizeByPercentageDescription')}
title={t('image:resize.resizeByPercentage')} title={t('resize.resizeByPercentage')}
/> />
</Box> </Box>
) )
@ -81,7 +81,7 @@ export default function ResizeImage({ title }: ToolComponentProps) {
...(values.resizeMethod === 'pixels' ...(values.resizeMethod === 'pixels'
? [ ? [
{ {
title: t('image:resize.dimensionType'), title: t('resize.dimensionType'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
@ -89,29 +89,29 @@ export default function ResizeImage({ title }: ToolComponentProps) {
onChange={(value) => onChange={(value) =>
updateField('maintainAspectRatio', value) updateField('maintainAspectRatio', value)
} }
description={t('image:resize.maintainAspectRatioDescription')} description={t('resize.maintainAspectRatioDescription')}
title={t('image:resize.maintainAspectRatio')} title={t('resize.maintainAspectRatio')}
/> />
{values.maintainAspectRatio && ( {values.maintainAspectRatio && (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('dimensionType', 'width')} onClick={() => updateField('dimensionType', 'width')}
checked={values.dimensionType === 'width'} checked={values.dimensionType === 'width'}
description={t('image:resize.setWidthDescription')} description={t('resize.setWidthDescription')}
title={t('image:resize.setWidth')} title={t('resize.setWidth')}
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('dimensionType', 'height')} onClick={() => updateField('dimensionType', 'height')}
checked={values.dimensionType === 'height'} checked={values.dimensionType === 'height'}
description={t('image:resize.setHeightDescription')} description={t('resize.setHeightDescription')}
title={t('image:resize.setHeight')} title={t('resize.setHeight')}
/> />
</Box> </Box>
)} )}
<TextFieldWithDesc <TextFieldWithDesc
value={values.width} value={values.width}
onOwnChange={(val) => updateField('width', val)} onOwnChange={(val) => updateField('width', val)}
description={t('image:resize.widthDescription')} description={t('resize.widthDescription')}
disabled={ disabled={
values.maintainAspectRatio && values.maintainAspectRatio &&
values.dimensionType === 'height' values.dimensionType === 'height'
@ -125,7 +125,7 @@ export default function ResizeImage({ title }: ToolComponentProps) {
<TextFieldWithDesc <TextFieldWithDesc
value={values.height} value={values.height}
onOwnChange={(val) => updateField('height', val)} onOwnChange={(val) => updateField('height', val)}
description={t('image:resize.heightDescription')} description={t('resize.heightDescription')}
disabled={ disabled={
values.maintainAspectRatio && values.maintainAspectRatio &&
values.dimensionType === 'width' values.dimensionType === 'width'
@ -142,13 +142,13 @@ export default function ResizeImage({ title }: ToolComponentProps) {
] ]
: [ : [
{ {
title: t('image:resize.percentage'), title: t('resize.percentage'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.percentage} value={values.percentage}
onOwnChange={(val) => updateField('percentage', val)} onOwnChange={(val) => updateField('percentage', val)}
description={t('image:resize.percentageDescription')} description={t('resize.percentageDescription')}
inputProps={{ inputProps={{
'data-testid': 'percentage-input', 'data-testid': 'percentage-input',
type: 'number', type: 'number',
@ -175,19 +175,19 @@ export default function ResizeImage({ title }: ToolComponentProps) {
value={input} value={input}
onChange={setInput} onChange={setInput}
accept={['image/jpeg', 'image/png', 'image/svg+xml', 'image/gif']} accept={['image/jpeg', 'image/png', 'image/svg+xml', 'image/gif']}
title={t('image:resize.inputTitle')} title={t('resize.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
<ToolFileResult <ToolFileResult
title={t('image:resize.resultTitle')} title={t('resize.resultTitle')}
value={result} value={result}
extension={input?.name.split('.').pop() || 'png'} extension={input?.name.split('.').pop() || 'png'}
/> />
} }
toolInfo={{ toolInfo={{
title: t('image:resize.toolInfo.title'), title: t('resize.toolInfo.title'),
description: t('image:resize.toolInfo.description') description: t('resize.toolInfo.description')
}} }}
/> />
); );

View file

@ -48,7 +48,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function MinifyJson({ title }: ToolComponentProps) { export default function MinifyJson({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('json');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -61,14 +61,14 @@ export default function MinifyJson({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('json:minify.inputTitle')} title={t('minify.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult
title={t('json:minify.resultTitle')} title={t('minify.resultTitle')}
value={result} value={result}
extension={'json'} extension={'json'}
/> />
@ -76,8 +76,8 @@ export default function MinifyJson({ title }: ToolComponentProps) {
initialValues={initialValues} initialValues={initialValues}
getGroups={null} getGroups={null}
toolInfo={{ toolInfo={{
title: t('json:minify.toolInfo.title'), title: t('minify.toolInfo.title'),
description: t('json:minify.toolInfo.description') description: t('minify.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -116,7 +116,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function PrettifyJson({ title }: ToolComponentProps) { export default function PrettifyJson({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('json');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -131,14 +131,14 @@ export default function PrettifyJson({ title }: ToolComponentProps) {
input={input} input={input}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('json:prettify.inputTitle')} title={t('prettify.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult
title={t('json:prettify.resultTitle')} title={t('prettify.resultTitle')}
value={result} value={result}
extension={'json'} extension={'json'}
/> />
@ -146,14 +146,14 @@ export default function PrettifyJson({ title }: ToolComponentProps) {
initialValues={initialValues} initialValues={initialValues}
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('json:prettify.indentation'), title: t('prettify.indentation'),
component: ( component: (
<Box> <Box>
<RadioWithTextField <RadioWithTextField
checked={values.indentationType === 'space'} checked={values.indentationType === 'space'}
title={t('json:prettify.useSpaces')} title={t('prettify.useSpaces')}
fieldName={'indentationType'} fieldName={'indentationType'}
description={t('json:prettify.useSpacesDescription')} description={t('prettify.useSpacesDescription')}
value={values.spacesCount.toString()} value={values.spacesCount.toString()}
onRadioClick={() => updateField('indentationType', 'space')} onRadioClick={() => updateField('indentationType', 'space')}
onTextChange={(val) => onTextChange={(val) =>
@ -163,8 +163,8 @@ export default function PrettifyJson({ title }: ToolComponentProps) {
<SimpleRadio <SimpleRadio
onClick={() => updateField('indentationType', 'tab')} onClick={() => updateField('indentationType', 'tab')}
checked={values.indentationType === 'tab'} checked={values.indentationType === 'tab'}
description={t('json:prettify.useTabsDescription')} description={t('prettify.useTabsDescription')}
title={t('json:prettify.useTabs')} title={t('prettify.useTabs')}
/> />
</Box> </Box>
) )
@ -174,8 +174,8 @@ export default function PrettifyJson({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
exampleCards={exampleCards} exampleCards={exampleCards}
toolInfo={{ toolInfo={{
title: t('json:prettify.toolInfo.title'), title: t('prettify.toolInfo.title'),
description: t('json:prettify.toolInfo.description') description: t('prettify.toolInfo.description')
}} }}
/> />
); );

View file

@ -47,7 +47,7 @@ const exampleCards: CardExampleType<{}>[] = [
]; ];
export default function ValidateJson({ title }: ToolComponentProps) { export default function ValidateJson({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('json');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -55,9 +55,9 @@ export default function ValidateJson({ title }: ToolComponentProps) {
const { valid, error } = validateJson(input); const { valid, error } = validateJson(input);
if (valid) { if (valid) {
setResult(t('json:validateJson.validJson')); setResult(t('validateJson.validJson'));
} else { } else {
setResult(t('json:validateJson.invalidJson', { error })); setResult(t('validateJson.invalidJson', { error }));
} }
}; };
@ -66,22 +66,19 @@ export default function ValidateJson({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('json:validateJson.inputTitle')} title={t('validateJson.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('validateJson.resultTitle')} value={result} />
title={t('json:validateJson.resultTitle')}
value={result}
/>
} }
initialValues={{}} initialValues={{}}
getGroups={null} getGroups={null}
toolInfo={{ toolInfo={{
title: t('json:validateJson.toolInfo.title'), title: t('validateJson.toolInfo.title'),
description: t('json:validateJson.toolInfo.description') description: t('validateJson.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -102,7 +102,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Duplicate({ title }: ToolComponentProps) { export default function Duplicate({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('list');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -136,53 +136,53 @@ export default function Duplicate({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('list:duplicate.splitOptions'), title: t('duplicate.splitOptions'),
component: ( component: (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('splitOperatorType', 'symbol')} onClick={() => updateField('splitOperatorType', 'symbol')}
checked={values.splitOperatorType === 'symbol'} checked={values.splitOperatorType === 'symbol'}
title={t('list:duplicate.splitBySymbol')} title={t('duplicate.splitBySymbol')}
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('splitOperatorType', 'regex')} onClick={() => updateField('splitOperatorType', 'regex')}
checked={values.splitOperatorType === 'regex'} checked={values.splitOperatorType === 'regex'}
title={t('list:duplicate.splitByRegex')} title={t('duplicate.splitByRegex')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.splitSeparator} value={values.splitSeparator}
onOwnChange={(val) => updateField('splitSeparator', val)} onOwnChange={(val) => updateField('splitSeparator', val)}
description={t('list:duplicate.splitSeparatorDescription')} description={t('duplicate.splitSeparatorDescription')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.joinSeparator} value={values.joinSeparator}
onOwnChange={(val) => updateField('joinSeparator', val)} onOwnChange={(val) => updateField('joinSeparator', val)}
description={t('list:duplicate.joinSeparatorDescription')} description={t('duplicate.joinSeparatorDescription')}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('list:duplicate.duplicationOptions'), title: t('duplicate.duplicationOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.copy} value={values.copy}
onOwnChange={(val) => updateField('copy', val)} onOwnChange={(val) => updateField('copy', val)}
description={t('list:duplicate.copyDescription')} description={t('duplicate.copyDescription')}
type="number" type="number"
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:duplicate.concatenate')} title={t('duplicate.concatenate')}
checked={values.concatenate} checked={values.concatenate}
onChange={(checked) => updateField('concatenate', checked)} onChange={(checked) => updateField('concatenate', checked)}
description={t('list:duplicate.concatenateDescription')} description={t('duplicate.concatenateDescription')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:duplicate.reverse')} title={t('duplicate.reverse')}
checked={values.reverse} checked={values.reverse}
onChange={(checked) => updateField('reverse', checked)} onChange={(checked) => updateField('reverse', checked)}
description={t('list:duplicate.reverseDescription')} description={t('duplicate.reverseDescription')}
/> />
</Box> </Box>
) )
@ -194,23 +194,20 @@ export default function Duplicate({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('list:duplicate.inputTitle')} title={t('duplicate.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('duplicate.resultTitle')} value={result} />
title={t('list:duplicate.resultTitle')}
value={result}
/>
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={getGroups} getGroups={getGroups}
validationSchema={validationSchema} validationSchema={validationSchema}
toolInfo={{ toolInfo={{
title: t('list:duplicate.toolInfo.title'), title: t('duplicate.toolInfo.title'),
description: t('list:duplicate.toolInfo.description') description: t('duplicate.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -36,7 +36,7 @@ const splitOperators: {
]; ];
export default function FindUnique() { export default function FindUnique() {
const { t } = useTranslation(); const { t } = useTranslation('list');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
const compute = (optionsValues: typeof initialValues, input: any) => { const compute = (optionsValues: typeof initialValues, input: any) => {
@ -66,27 +66,24 @@ export default function FindUnique() {
return ( return (
<ToolContent <ToolContent
title={t('list:findUnique.title')} title={t('findUnique.title')}
initialValues={initialValues} initialValues={initialValues}
compute={compute} compute={compute}
input={input} input={input}
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('list:findUnique.inputTitle')} title={t('findUnique.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('findUnique.resultTitle')} value={result} />
title={t('list:findUnique.resultTitle')}
value={result}
/>
} }
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('list:findUnique.inputListDelimiter'), title: t('findUnique.inputListDelimiter'),
component: ( component: (
<Box> <Box>
{splitOperators.map(({ title, description, type }) => ( {splitOperators.map(({ title, description, type }) => (
@ -99,7 +96,7 @@ export default function FindUnique() {
/> />
))} ))}
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:findUnique.delimiterDescription')} description={t('findUnique.delimiterDescription')}
value={values.splitSeparator} value={values.splitSeparator}
onOwnChange={(val) => updateField('splitSeparator', val)} onOwnChange={(val) => updateField('splitSeparator', val)}
/> />
@ -107,7 +104,7 @@ export default function FindUnique() {
) )
}, },
{ {
title: t('list:findUnique.outputListDelimiter'), title: t('findUnique.outputListDelimiter'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
@ -115,14 +112,14 @@ export default function FindUnique() {
onOwnChange={(value) => updateField('joinSeparator', value)} onOwnChange={(value) => updateField('joinSeparator', value)}
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:findUnique.trimItems')} title={t('findUnique.trimItems')}
description={t('list:findUnique.trimItemsDescription')} description={t('findUnique.trimItemsDescription')}
checked={values.trimItems} checked={values.trimItems}
onChange={(value) => updateField('trimItems', value)} onChange={(value) => updateField('trimItems', value)}
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:findUnique.skipEmptyItems')} title={t('findUnique.skipEmptyItems')}
description={t('list:findUnique.skipEmptyItemsDescription')} description={t('findUnique.skipEmptyItemsDescription')}
checked={values.deleteEmptyItems} checked={values.deleteEmptyItems}
onChange={(value) => updateField('deleteEmptyItems', value)} onChange={(value) => updateField('deleteEmptyItems', value)}
/> />
@ -130,20 +127,20 @@ export default function FindUnique() {
) )
}, },
{ {
title: t('list:findUnique.uniqueItemOptions'), title: t('findUnique.uniqueItemOptions'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:findUnique.findAbsolutelyUniqueItems')} title={t('findUnique.findAbsolutelyUniqueItems')}
description={t( description={t(
'list:findUnique.findAbsolutelyUniqueItemsDescription' 'findUnique.findAbsolutelyUniqueItemsDescription'
)} )}
checked={values.absolutelyUnique} checked={values.absolutelyUnique}
onChange={(value) => updateField('absolutelyUnique', value)} onChange={(value) => updateField('absolutelyUnique', value)}
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:findUnique.caseSensitiveItems')} title={t('findUnique.caseSensitiveItems')}
description={t('list:findUnique.caseSensitiveItemsDescription')} description={t('findUnique.caseSensitiveItemsDescription')}
checked={values.caseSensitive} checked={values.caseSensitive}
onChange={(value) => updateField('caseSensitive', value)} onChange={(value) => updateField('caseSensitive', value)}
/> />

View file

@ -41,7 +41,7 @@ const splitOperators: {
]; ];
export default function FindUnique({ title }: ToolComponentProps) { export default function FindUnique({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('list');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
const compute = (optionsValues: typeof initialValues, input: any) => { const compute = (optionsValues: typeof initialValues, input: any) => {
@ -81,18 +81,18 @@ export default function FindUnique({ title }: ToolComponentProps) {
input={input} input={input}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('list:group.inputTitle')} title={t('group.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('list:group.resultTitle')} value={result} /> <ToolTextResult title={t('group.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('list:group.inputItemSeparator'), title: t('group.inputItemSeparator'),
component: ( component: (
<Box> <Box>
{splitOperators.map(({ title, description, type }) => ( {splitOperators.map(({ title, description, type }) => (
@ -107,7 +107,7 @@ export default function FindUnique({ title }: ToolComponentProps) {
/> />
))} ))}
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:group.splitSeparatorDescription')} description={t('group.splitSeparatorDescription')}
value={values.splitSeparator} value={values.splitSeparator}
onOwnChange={(val) => updateField('splitSeparator', val)} onOwnChange={(val) => updateField('splitSeparator', val)}
/> />
@ -115,12 +115,12 @@ export default function FindUnique({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('list:group.groupSizeAndSeparators'), title: t('group.groupSizeAndSeparators'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.groupNumber} value={values.groupNumber}
description={t('list:group.groupNumberDescription')} description={t('group.groupNumberDescription')}
type={'number'} type={'number'}
onOwnChange={(value) => onOwnChange={(value) =>
updateField('groupNumber', formatNumber(value, 1)) updateField('groupNumber', formatNumber(value, 1))
@ -128,46 +128,46 @@ export default function FindUnique({ title }: ToolComponentProps) {
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.itemSeparator} value={values.itemSeparator}
description={t('list:group.itemSeparatorDescription')} description={t('group.itemSeparatorDescription')}
onOwnChange={(value) => updateField('itemSeparator', value)} onOwnChange={(value) => updateField('itemSeparator', value)}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.groupSeparator} value={values.groupSeparator}
description={t('list:group.groupSeparatorDescription')} description={t('group.groupSeparatorDescription')}
onOwnChange={(value) => updateField('groupSeparator', value)} onOwnChange={(value) => updateField('groupSeparator', value)}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.leftWrap} value={values.leftWrap}
description={t('list:group.leftWrapDescription')} description={t('group.leftWrapDescription')}
onOwnChange={(value) => updateField('leftWrap', value)} onOwnChange={(value) => updateField('leftWrap', value)}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.rightWrap} value={values.rightWrap}
description={t('list:group.rightWrapDescription')} description={t('group.rightWrapDescription')}
onOwnChange={(value) => updateField('rightWrap', value)} onOwnChange={(value) => updateField('rightWrap', value)}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('list:group.emptyItemsAndPadding'), title: t('group.emptyItemsAndPadding'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:group.deleteEmptyItems')} title={t('group.deleteEmptyItems')}
description={t('list:group.deleteEmptyItemsDescription')} description={t('group.deleteEmptyItemsDescription')}
checked={values.deleteEmptyItems} checked={values.deleteEmptyItems}
onChange={(value) => updateField('deleteEmptyItems', value)} onChange={(value) => updateField('deleteEmptyItems', value)}
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:group.padNonFullGroups')} title={t('group.padNonFullGroups')}
description={t('list:group.padNonFullGroupsDescription')} description={t('group.padNonFullGroupsDescription')}
checked={values.padNonFullGroup} checked={values.padNonFullGroup}
onChange={(value) => updateField('padNonFullGroup', value)} onChange={(value) => updateField('padNonFullGroup', value)}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.paddingChar} value={values.paddingChar}
description={t('list:group.paddingCharDescription')} description={t('group.paddingCharDescription')}
onOwnChange={(value) => updateField('paddingChar', value)} onOwnChange={(value) => updateField('paddingChar', value)}
/> />
</Box> </Box>

View file

@ -1,24 +1,4 @@
{ {
"group": {
"title": "Group List",
"description": "Group list items by common properties.",
"inputTitle": "Input list",
"resultTitle": "Grouped list",
"groupingOptions": "Grouping Options",
"groupByDescription": "Choose how to group the list items",
"groupByValue": "Group by Value",
"groupByValueDescription": "Group items that have the same value",
"groupByLength": "Group by Length",
"groupByLengthDescription": "Group items by their character length",
"groupByFirstChar": "Group by First Character",
"groupByFirstCharDescription": "Group items by their first character",
"groupByLastChar": "Group by Last Character",
"groupByLastCharDescription": "Group items by their last character",
"toolInfo": {
"title": "Group List",
"description": "This tool allows you to group list items by various criteria such as value, length, or character position. It's useful for organizing and categorizing data."
}
},
"reverse": { "reverse": {
"title": "Reverse List", "title": "Reverse List",
"description": "Reverse the order of items in a list.", "description": "Reverse the order of items in a list.",
@ -32,53 +12,22 @@
"description": "This tool allows you to reverse the order of items in a list. You can reverse the entire list or each line separately." "description": "This tool allows you to reverse the order of items in a list. You can reverse the entire list or each line separately."
} }
}, },
"sort": {
"title": "Sort List",
"description": "Sort list items in ascending or descending order.",
"inputTitle": "Input list",
"resultTitle": "Sorted list",
"sortOptions": "Sort Options",
"sortOrder": "Sort Order",
"ascending": "Ascending",
"descending": "Descending",
"sortType": "Sort Type",
"alphabetical": "Alphabetical",
"numerical": "Numerical",
"natural": "Natural",
"toolInfo": {
"title": "Sort List",
"description": "This tool allows you to sort list items in various orders and types. You can sort alphabetically, numerically, or using natural sorting."
}
},
"duplicate": {
"title": "Find Duplicates",
"description": "Find and remove duplicate items from a list.",
"inputTitle": "Input list",
"resultTitle": "Unique list",
"duplicateOptions": "Duplicate Options",
"removeDuplicates": "Remove Duplicates",
"removeDuplicatesDescription": "Remove duplicate items from the list",
"showDuplicates": "Show Duplicates",
"showDuplicatesDescription": "Show only the duplicate items",
"toolInfo": {
"title": "Find Duplicates",
"description": "This tool allows you to find and handle duplicate items in a list. You can remove duplicates or show only the duplicate items."
}
},
"findUnique": { "findUnique": {
"title": "Find Unique", "title": "Find Unique",
"description": "Find unique items in a list.", "inputTitle": "Input List",
"inputTitle": "Input list", "resultTitle": "Unique Items",
"resultTitle": "Unique items", "inputListDelimiter": "Input List Delimiter",
"uniqueOptions": "Unique Options", "delimiterDescription": "Set a delimiting symbol or regular expression.",
"showUnique": "Show Unique", "outputListDelimiter": "Output List Delimiter",
"showUniqueDescription": "Show only unique items", "trimItems": "Trim List Items",
"showDuplicates": "Show Duplicates", "trimItemsDescription": "Remove leading and trailing spaces before comparing items.",
"showDuplicatesDescription": "Show only duplicate items", "skipEmptyItems": "Skip Empty Items",
"toolInfo": { "skipEmptyItemsDescription": "Don't include the empty list items in the output.",
"title": "Find Unique", "uniqueItemOptions": "Unique Item Options",
"description": "This tool allows you to find unique items in a list. You can show unique items or duplicate items." "findAbsolutelyUniqueItems": "Find Absolutely Unique Items",
} "findAbsolutelyUniqueItemsDescription": "Display only those items of the list that exist in a single copy.",
"caseSensitiveItems": "Case Sensitive Items",
"caseSensitiveItemsDescription": "Output items with different case as unique elements in the list."
}, },
"shuffle": { "shuffle": {
"title": "Shuffle List", "title": "Shuffle List",
@ -111,5 +60,104 @@
"title": "List Wrapping", "title": "List Wrapping",
"description": "This tool allows you to add text before and after each item in a list. You can specify different text for the left and right sides, and control how the list is processed. It's useful for adding quotes, brackets, or other formatting to list items, preparing data for different formats, or creating structured text." "description": "This tool allows you to add text before and after each item in a list. You can specify different text for the left and right sides, and control how the list is processed. It's useful for adding quotes, brackets, or other formatting to list items, preparing data for different formats, or creating structured text."
} }
},
"sort": {
"inputTitle": "Input list",
"resultTitle": "Sorted list",
"inputItemSeparator": "Input item separator",
"splitSeparatorDescription": "Set a delimiting symbol or regular expression.",
"splitOperators": {
"symbol": {
"title": "Use a Symbol for Splitting",
"description": "Delimit input list items with a character."
},
"regex": {
"title": "Use a Regex for Splitting",
"description": "Delimit input list items with a regular expression."
}
},
"sortMethod": "Sort method",
"sortMethodDescription": "Select a sorting method.",
"sortOptions": {
"alphabetic": "Sort Alphabetically",
"numeric": "Sort Numerically",
"length": "Sort by Length"
},
"orderDescription": "Select a sorting order.",
"orderOptions": {
"increasing": "Increasing order",
"decreasing": "Decreasing order"
},
"caseSensitive": "Case Sensitive Sort",
"caseSensitiveDescription": "Sort uppercase and lowercase items separately. Capital letters precede lowercase letters in an ascending list. (Works only in alphabetical sorting mode.)",
"sortedItemProperties": "Sorted item properties",
"joinSeparatorDescription": "Use this symbol as a joiner between items in a sorted list.",
"removeDuplicates": "Remove duplicates",
"removeDuplicatesDescription": "Delete duplicate list items."
},
"group": {
"inputTitle": "Input list",
"resultTitle": "Grouped items",
"inputItemSeparator": "Input Item Separator",
"splitSeparatorDescription": "Set a delimiting symbol or regular expression.",
"splitOperators": {
"symbol": {
"title": "Use a Symbol for Splitting",
"description": "Delimit input list items with a character."
},
"regex": {
"title": "Use a Regex for Splitting",
"description": "Delimit input list items with a regular expression."
}
},
"groupSizeAndSeparators": "Group Size and Separators",
"groupNumberDescription": "Number of items in a group",
"itemSeparatorDescription": "Item separator character",
"groupSeparatorDescription": "Group separator character",
"leftWrapDescription": "Group's left wrap symbol.",
"rightWrapDescription": "Group's right wrap symbol.",
"emptyItemsAndPadding": "Empty Items and Padding",
"deleteEmptyItems": "Delete Empty Items",
"deleteEmptyItemsDescription": "Ignore empty items and don't include them in the groups.",
"padNonFullGroups": "Pad Non-full Groups",
"padNonFullGroupsDescription": "Fill non-full groups with a custom item (enter below).",
"paddingCharDescription": "Use this character or item to pad non-full groups."
},
"duplicate": {
"toolInfo": {
"title": "List Duplication",
"description": "This tool allows you to duplicate items in a list. You can specify the number of copies (including fractional values), control whether items are concatenated or interweaved, and even reverse the duplicated items. It's useful for creating repeated patterns, generating test data, or expanding lists with predictable content."
},
"inputTitle": "Input List",
"resultTitle": "Duplicated List",
"splitOptions": "Split Options",
"splitBySymbol": "Split by Symbol",
"splitByRegex": "Split by Regular Expression",
"splitSeparatorDescription": "Separator to split the list",
"joinSeparatorDescription": "Separator to join the duplicated list",
"duplicationOptions": "Duplication Options",
"copyDescription": "Number of copies (can be fractional)",
"concatenate": "Concatenate",
"concatenateDescription": "Concatenate copies (if unchecked, items will be interweaved)",
"reverse": "Reverse",
"reverseDescription": "Reverse the duplicated items",
"examples": {
"simple": {
"title": "Simple duplication",
"description": "This example shows how to duplicate a list of words."
},
"reverse": {
"title": "Reverse duplication",
"description": "This example shows how to duplicate a list in reverse order."
},
"interweave": {
"title": "Interweaving items",
"description": "This example shows how to interweave items instead of concatenating them."
},
"fractional": {
"title": "Fractional duplication",
"description": "This example shows how to duplicate a list with a fractional number of copies."
}
}
} }
} }

View file

@ -112,7 +112,7 @@ argument`,
]; ];
export default function Reverse({ title }: ToolComponentProps) { export default function Reverse({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('list');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -121,7 +121,7 @@ export default function Reverse({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('list:reverse.splitterMode'), title: t('reverse.splitterMode'),
component: ( component: (
<Box> <Box>
{splitOperators.map(({ title, description, type }) => ( {splitOperators.map(({ title, description, type }) => (
@ -137,11 +137,11 @@ export default function Reverse({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('list:reverse.itemSeparator'), title: t('reverse.itemSeparator'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:reverse.itemSeparatorDescription')} description={t('reverse.itemSeparatorDescription')}
value={values.splitSeparator} value={values.splitSeparator}
onOwnChange={(val) => updateField('splitSeparator', val)} onOwnChange={(val) => updateField('splitSeparator', val)}
/> />
@ -149,11 +149,11 @@ export default function Reverse({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('list:reverse.outputListOptions'), title: t('reverse.outputListOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:reverse.outputSeparatorDescription')} description={t('reverse.outputSeparatorDescription')}
value={values.joinSeparator} value={values.joinSeparator}
onOwnChange={(val) => updateField('joinSeparator', val)} onOwnChange={(val) => updateField('joinSeparator', val)}
/> />
@ -179,17 +179,17 @@ export default function Reverse({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('list:reverse.inputTitle')} title={t('reverse.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('list:reverse.resultTitle')} value={result} /> <ToolTextResult title={t('reverse.resultTitle')} value={result} />
} }
toolInfo={{ toolInfo={{
title: t('list:reverse.toolInfo.title'), title: t('reverse.toolInfo.title'),
description: t('list:reverse.toolInfo.description') description: t('reverse.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -33,7 +33,7 @@ const splitOperators: {
]; ];
export default function Shuffle() { export default function Shuffle() {
const { t } = useTranslation(); const { t } = useTranslation('list');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
const compute = (optionsValues: typeof initialValues, input: any) => { const compute = (optionsValues: typeof initialValues, input: any) => {
@ -53,24 +53,24 @@ export default function Shuffle() {
return ( return (
<ToolContent <ToolContent
title={t('list:shuffle.title')} title={t('shuffle.title')}
initialValues={initialValues} initialValues={initialValues}
compute={compute} compute={compute}
input={input} input={input}
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('list:shuffle.inputTitle')} title={t('shuffle.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('list:shuffle.resultTitle')} value={result} /> <ToolTextResult title={t('shuffle.resultTitle')} value={result} />
} }
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('list:shuffle.inputListSeparator'), title: t('shuffle.inputListSeparator'),
component: ( component: (
<Box> <Box>
{splitOperators.map(({ title, description, type }) => ( {splitOperators.map(({ title, description, type }) => (
@ -83,7 +83,7 @@ export default function Shuffle() {
/> />
))} ))}
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:shuffle.delimiterDescription')} description={t('shuffle.delimiterDescription')}
value={values.splitSeparator} value={values.splitSeparator}
onOwnChange={(val) => updateField('splitSeparator', val)} onOwnChange={(val) => updateField('splitSeparator', val)}
/> />
@ -91,11 +91,11 @@ export default function Shuffle() {
) )
}, },
{ {
title: t('list:shuffle.shuffledListLength'), title: t('shuffle.shuffledListLength'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:shuffle.outputLengthDescription')} description={t('shuffle.outputLengthDescription')}
value={values.length} value={values.length}
onOwnChange={(val) => updateField('length', val)} onOwnChange={(val) => updateField('length', val)}
/> />
@ -103,13 +103,13 @@ export default function Shuffle() {
) )
}, },
{ {
title: t('list:shuffle.shuffledListSeparator'), title: t('shuffle.shuffledListSeparator'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.joinSeparator} value={values.joinSeparator}
onOwnChange={(value) => updateField('joinSeparator', value)} onOwnChange={(value) => updateField('joinSeparator', value)}
description={t('list:shuffle.joinSeparatorDescription')} description={t('shuffle.joinSeparatorDescription')}
/> />
</Box> </Box>
) )

View file

@ -37,8 +37,8 @@ const splitOperators: {
} }
]; ];
export default function SplitText({ title }: ToolComponentProps) { export default function SortList({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('list');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
const compute = (optionsValues: typeof initialValues, input: any) => { const compute = (optionsValues: typeof initialValues, input: any) => {
@ -72,33 +72,31 @@ export default function SplitText({ title }: ToolComponentProps) {
input={input} input={input}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('list:sort.inputTitle')} title={t('sort.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('list:sort.resultTitle')} value={result} /> <ToolTextResult title={t('sort.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('list:sort.inputItemSeparator'), title: t('sort.inputItemSeparator'),
component: ( component: (
<Box> <Box>
{splitOperators.map(({ title, description, type }) => ( {splitOperators.map(({ title, description, type }) => (
<SimpleRadio <SimpleRadio
key={type} key={type}
onClick={() => updateField('splitSeparatorType', type)} onClick={() => updateField('splitSeparatorType', type)}
title={t(`list.sort.splitOperators.${type}.title`)} title={t(`sort.splitOperators.${type}.title`)}
description={t( description={t(`sort.splitOperators.${type}.description`)}
`list.sort.splitOperators.${type}.description`
)}
checked={values.splitSeparatorType === type} checked={values.splitSeparatorType === type}
/> />
))} ))}
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:sort.splitSeparatorDescription')} description={t('sort.splitSeparatorDescription')}
value={values.splitSeparator} value={values.splitSeparator}
onOwnChange={(val) => updateField('splitSeparator', val)} onOwnChange={(val) => updateField('splitSeparator', val)}
/> />
@ -106,45 +104,45 @@ export default function SplitText({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('list:sort.sortMethod'), title: t('sort.sortMethod'),
component: ( component: (
<Box> <Box>
<SelectWithDesc <SelectWithDesc
selected={values.sortingMethod} selected={values.sortingMethod}
options={[ options={[
{ {
label: t('list:sort.sortOptions.alphabetic'), label: t('sort.sortOptions.alphabetic'),
value: 'alphabetic' value: 'alphabetic'
}, },
{ {
label: t('list:sort.sortOptions.numeric'), label: t('sort.sortOptions.numeric'),
value: 'numeric' value: 'numeric'
}, },
{ label: t('list:sort.sortOptions.length'), value: 'length' } { label: t('sort.sortOptions.length'), value: 'length' }
]} ]}
onChange={(value) => updateField('sortingMethod', value)} onChange={(value) => updateField('sortingMethod', value)}
description={t('list:sort.sortMethodDescription')} description={t('sort.sortMethodDescription')}
/> />
<SelectWithDesc <SelectWithDesc
selected={values.increasing} selected={values.increasing}
options={[ options={[
{ {
label: t('list:sort.orderOptions.increasing'), label: t('sort.orderOptions.increasing'),
value: true value: true
}, },
{ {
label: t('list:sort.orderOptions.decreasing'), label: t('sort.orderOptions.decreasing'),
value: false value: false
} }
]} ]}
onChange={(value) => { onChange={(value) => {
updateField('increasing', value); updateField('increasing', value);
}} }}
description={t('list:sort.orderDescription')} description={t('sort.orderDescription')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:sort.caseSensitive')} title={t('sort.caseSensitive')}
description={t('list:sort.caseSensitiveDescription')} description={t('sort.caseSensitiveDescription')}
checked={values.caseSensitive} checked={values.caseSensitive}
onChange={(val) => updateField('caseSensitive', val)} onChange={(val) => updateField('caseSensitive', val)}
/> />
@ -152,17 +150,17 @@ export default function SplitText({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('list:sort.sortedItemProperties'), title: t('sort.sortedItemProperties'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('list:sort.joinSeparatorDescription')} description={t('sort.joinSeparatorDescription')}
value={values.joinSeparator} value={values.joinSeparator}
onOwnChange={(val) => updateField('joinSeparator', val)} onOwnChange={(val) => updateField('joinSeparator', val)}
/> />
<CheckboxWithDesc <CheckboxWithDesc
title={t('list:sort.removeDuplicates')} title={t('sort.removeDuplicates')}
description={t('list:sort.removeDuplicatesDescription')} description={t('sort.removeDuplicatesDescription')}
checked={values.removeDuplicated} checked={values.removeDuplicated}
onChange={(val) => updateField('removeDuplicated', val)} onChange={(val) => updateField('removeDuplicated', val)}
/> />

View file

@ -86,7 +86,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Wrap({ title }: ToolComponentProps) { export default function Wrap({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('list');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -119,50 +119,50 @@ export default function Wrap({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('list:wrap.splitOptions'), title: t('wrap.splitOptions'),
component: ( component: (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('splitOperatorType', 'symbol')} onClick={() => updateField('splitOperatorType', 'symbol')}
checked={values.splitOperatorType === 'symbol'} checked={values.splitOperatorType === 'symbol'}
title={t('list:wrap.splitBySymbol')} title={t('wrap.splitBySymbol')}
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('splitOperatorType', 'regex')} onClick={() => updateField('splitOperatorType', 'regex')}
checked={values.splitOperatorType === 'regex'} checked={values.splitOperatorType === 'regex'}
title={t('list:wrap.splitByRegex')} title={t('wrap.splitByRegex')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.splitSeparator} value={values.splitSeparator}
onOwnChange={(val) => updateField('splitSeparator', val)} onOwnChange={(val) => updateField('splitSeparator', val)}
description={t('list:wrap.splitSeparatorDescription')} description={t('wrap.splitSeparatorDescription')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.joinSeparator} value={values.joinSeparator}
onOwnChange={(val) => updateField('joinSeparator', val)} onOwnChange={(val) => updateField('joinSeparator', val)}
description={t('list:wrap.joinSeparatorDescription')} description={t('wrap.joinSeparatorDescription')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.deleteEmptyItems} checked={values.deleteEmptyItems}
onChange={(checked) => updateField('deleteEmptyItems', checked)} onChange={(checked) => updateField('deleteEmptyItems', checked)}
title={t('list:wrap.removeEmptyItems')} title={t('wrap.removeEmptyItems')}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('list:wrap.wrapOptions'), title: t('wrap.wrapOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.left} value={values.left}
onOwnChange={(val) => updateField('left', val)} onOwnChange={(val) => updateField('left', val)}
description={t('list:wrap.leftTextDescription')} description={t('wrap.leftTextDescription')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.right} value={values.right}
onOwnChange={(val) => updateField('right', val)} onOwnChange={(val) => updateField('right', val)}
description={t('list:wrap.rightTextDescription')} description={t('wrap.rightTextDescription')}
/> />
</Box> </Box>
) )
@ -174,20 +174,20 @@ export default function Wrap({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('list:wrap.inputTitle')} title={t('wrap.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('list:wrap.resultTitle')} value={result} /> <ToolTextResult title={t('wrap.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={getGroups} getGroups={getGroups}
validationSchema={validationSchema} validationSchema={validationSchema}
toolInfo={{ toolInfo={{
title: t('list:wrap.toolInfo.title'), title: t('wrap.toolInfo.title'),
description: t('list:wrap.toolInfo.description') description: t('wrap.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -71,7 +71,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function ArithmeticSequence({ title }: ToolComponentProps) { export default function ArithmeticSequence({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('number');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
return ( return (
@ -80,7 +80,7 @@ export default function ArithmeticSequence({ title }: ToolComponentProps) {
inputComponent={null} inputComponent={null}
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult
title={t('number:arithmeticSequence.resultTitle')} title={t('arithmeticSequence.resultTitle')}
value={result} value={result}
/> />
} }
@ -88,12 +88,12 @@ export default function ArithmeticSequence({ title }: ToolComponentProps) {
validationSchema={validationSchema} validationSchema={validationSchema}
exampleCards={exampleCards} exampleCards={exampleCards}
toolInfo={{ toolInfo={{
title: t('number:arithmeticSequence.toolInfo.title'), title: t('arithmeticSequence.toolInfo.title'),
description: t('number:arithmeticSequence.toolInfo.description') description: t('arithmeticSequence.toolInfo.description')
}} }}
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('number:arithmeticSequence.sequenceParameters'), title: t('arithmeticSequence.sequenceParameters'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
@ -124,10 +124,10 @@ export default function ArithmeticSequence({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('number:arithmeticSequence.outputFormat'), title: t('arithmeticSequence.outputFormat'),
component: ( component: (
<TextFieldWithDesc <TextFieldWithDesc
description={t('number:arithmeticSequence.separatorDescription')} description={t('arithmeticSequence.separatorDescription')}
value={values.separator} value={values.separator}
onOwnChange={(val) => updateField('separator', val)} onOwnChange={(val) => updateField('separator', val)}
/> />

View file

@ -15,7 +15,7 @@ const initialValues = {
}; };
export default function GenerateNumbers({ title }: ToolComponentProps) { export default function GenerateNumbers({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('number');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
const compute = (optionsValues: typeof initialValues) => { const compute = (optionsValues: typeof initialValues) => {
@ -36,23 +36,23 @@ export default function GenerateNumbers({ title }: ToolComponentProps) {
initialValues={initialValues} initialValues={initialValues}
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('number:generate.arithmeticSequenceOption'), title: t('generate.arithmeticSequenceOption'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('number:generate.startSequenceDescription')} description={t('generate.startSequenceDescription')}
value={values.firstValue} value={values.firstValue}
onOwnChange={(val) => updateField('firstValue', val)} onOwnChange={(val) => updateField('firstValue', val)}
type={'number'} type={'number'}
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('number:generate.stepDescription')} description={t('generate.stepDescription')}
value={values.step} value={values.step}
onOwnChange={(val) => updateField('step', val)} onOwnChange={(val) => updateField('step', val)}
type={'number'} type={'number'}
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('number:generate.numberOfElementsDescription')} description={t('generate.numberOfElementsDescription')}
value={values.numberOfNumbers} value={values.numberOfNumbers}
onOwnChange={(val) => updateField('numberOfNumbers', val)} onOwnChange={(val) => updateField('numberOfNumbers', val)}
type={'number'} type={'number'}
@ -61,10 +61,10 @@ export default function GenerateNumbers({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('number:generate.separator'), title: t('generate.separator'),
component: ( component: (
<TextFieldWithDesc <TextFieldWithDesc
description={t('number:generate.separatorDescription')} description={t('generate.separatorDescription')}
value={values.separator} value={values.separator}
onOwnChange={(val) => updateField('separator', val)} onOwnChange={(val) => updateField('separator', val)}
/> />
@ -73,10 +73,7 @@ export default function GenerateNumbers({ title }: ToolComponentProps) {
]} ]}
compute={compute} compute={compute}
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('generate.resultTitle')} value={result} />
title={t('number:generate.resultTitle')}
value={result}
/>
} }
/> />
); );

View file

@ -119,7 +119,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function SumNumbers({ title }: ToolComponentProps) { export default function SumNumbers({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('number');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -128,7 +128,7 @@ export default function SumNumbers({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('number:sum.numberExtraction'), title: t('sum.numberExtraction'),
component: extractionTypes.map( component: extractionTypes.map(
({ title, description, type, withTextField, textValueAccessor }) => ({ title, description, type, withTextField, textValueAccessor }) =>
withTextField ? ( withTextField ? (
@ -158,11 +158,11 @@ export default function SumNumbers({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('number:sum.runningSum'), title: t('sum.runningSum'),
component: ( component: (
<CheckboxWithDesc <CheckboxWithDesc
title={t('number:sum.printRunningSum')} title={t('sum.printRunningSum')}
description={t('number:sum.printRunningSumDescription')} description={t('sum.printRunningSumDescription')}
checked={values.printRunningSum} checked={values.printRunningSum}
onChange={(value) => updateField('printRunningSum', value)} onChange={(value) => updateField('printRunningSum', value)}
/> />
@ -175,13 +175,13 @@ export default function SumNumbers({ title }: ToolComponentProps) {
input={input} input={input}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('number:sum.inputTitle')} title={t('sum.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('number:sum.resultTitle')} value={result} /> <ToolTextResult title={t('sum.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={getGroups} getGroups={getGroups}
@ -191,8 +191,8 @@ export default function SumNumbers({ title }: ToolComponentProps) {
}} }}
setInput={setInput} setInput={setInput}
toolInfo={{ toolInfo={{
title: t('number:sum.toolInfo.title'), title: t('sum.toolInfo.title'),
description: t('number:sum.toolInfo.description') description: t('sum.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -10,7 +10,7 @@ import ToolFileResult from '@components/result/ToolFileResult';
import SimpleRadio from '@components/options/SimpleRadio'; import SimpleRadio from '@components/options/SimpleRadio';
import { CardExampleType } from '@components/examples/ToolExamples'; import { CardExampleType } from '@components/examples/ToolExamples';
import { PDFDocument } from 'pdf-lib'; import { PDFDocument } from 'pdf-lib';
import { CustomSnackBarContext } from '@contexts/CustomSnackBarContext'; import { CustomSnackBarContext } from '../../../../contexts/CustomSnackBarContext';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const initialValues: InitialValuesType = { const initialValues: InitialValuesType = {
@ -51,7 +51,7 @@ export default function CompressPdf({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('pdf');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [resultSize, setResultSize] = useState<string>(''); const [resultSize, setResultSize] = useState<string>('');
@ -80,7 +80,7 @@ export default function CompressPdf({
} catch (error) { } catch (error) {
console.error('Error getting PDF info:', error); console.error('Error getting PDF info:', error);
setFileInfo(null); setFileInfo(null);
showSnackBar(t('pdf:compressPdf.errorReadingPdf'), 'error'); showSnackBar(t('compressPdf.errorReadingPdf'), 'error');
} }
}; };
@ -112,7 +112,7 @@ export default function CompressPdf({
} catch (error) { } catch (error) {
console.error('Error compressing PDF:', error); console.error('Error compressing PDF:', error);
showSnackBar( showSnackBar(
t('pdf:compressPdf.errorCompressingPdf', { t('compressPdf.errorCompressingPdf', {
error: error instanceof Error ? error.message : String(error) error: error instanceof Error ? error.message : String(error)
}), }),
'error' 'error'
@ -130,18 +130,18 @@ export default function CompressPdf({
}[] = [ }[] = [
{ {
value: 'low', value: 'low',
label: t('pdf:compressPdf.lowCompression'), label: t('compressPdf.lowCompression'),
description: t('pdf:compressPdf.lowCompressionDescription') description: t('compressPdf.lowCompressionDescription')
}, },
{ {
value: 'medium', value: 'medium',
label: t('pdf:compressPdf.mediumCompression'), label: t('compressPdf.mediumCompression'),
description: t('pdf:compressPdf.mediumCompressionDescription') description: t('compressPdf.mediumCompressionDescription')
}, },
{ {
value: 'high', value: 'high',
label: t('pdf:compressPdf.highCompression'), label: t('compressPdf.highCompression'),
description: t('pdf:compressPdf.highCompressionDescription') description: t('compressPdf.highCompressionDescription')
} }
]; ];
@ -157,26 +157,26 @@ export default function CompressPdf({
value={input} value={input}
onChange={setInput} onChange={setInput}
accept={['application/pdf']} accept={['application/pdf']}
title={t('pdf:compressPdf.inputTitle')} title={t('compressPdf.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
<ToolFileResult <ToolFileResult
title={t('pdf:compressPdf.resultTitle')} title={t('compressPdf.resultTitle')}
value={result} value={result}
extension={'pdf'} extension={'pdf'}
loading={isProcessing} loading={isProcessing}
loadingText={t('pdf:compressPdf.compressingPdf')} loadingText={t('compressPdf.compressingPdf')}
/> />
} }
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('pdf:compressPdf.compressionSettings'), title: t('compressPdf.compressionSettings'),
component: ( component: (
<Box> <Box>
<Box> <Box>
<Typography variant="subtitle2" sx={{ mb: 1 }}> <Typography variant="subtitle2" sx={{ mb: 1 }}>
{t('pdf:compressPdf.compressionLevel')} {t('compressPdf.compressionLevel')}
</Typography> </Typography>
{compressionOptions.map((option) => ( {compressionOptions.map((option) => (
@ -201,16 +201,15 @@ export default function CompressPdf({
}} }}
> >
<Typography variant="body2"> <Typography variant="body2">
{t('pdf:compressPdf.fileSize')}:{' '} {t('compressPdf.fileSize')}:{' '}
<strong>{fileInfo.size}</strong> <strong>{fileInfo.size}</strong>
</Typography> </Typography>
<Typography variant="body2"> <Typography variant="body2">
{t('pdf:compressPdf.pages')}:{' '} {t('compressPdf.pages')}: <strong>{fileInfo.pages}</strong>
<strong>{fileInfo.pages}</strong>
</Typography> </Typography>
{resultSize && ( {resultSize && (
<Typography variant="body2"> <Typography variant="body2">
{t('pdf:compressPdf.compressedFileSize')}:{' '} {t('compressPdf.compressedFileSize')}:{' '}
<strong>{resultSize}</strong> <strong>{resultSize}</strong>
</Typography> </Typography>
)} )}

View file

@ -15,20 +15,6 @@
"description": "This tool allows you to combine multiple PDF files into a single document. You can choose how to sort the PDFs and the tool will merge them in the specified order." "description": "This tool allows you to combine multiple PDF files into a single document. You can choose how to sort the PDFs and the tool will merge them in the specified order."
} }
}, },
"compressPdf": {
"title": "Compress PDF",
"description": "Reduce PDF file size while maintaining quality.",
"inputTitle": "Input PDF",
"resultTitle": "Compressed PDF",
"compressingPdf": "Compressing PDF",
"compressionOptions": "Compression Options",
"qualityDescription": "Compression quality (1-100)",
"qualityPlaceholder": "Quality",
"toolInfo": {
"title": "Compress PDF",
"description": "This tool allows you to compress PDF files to reduce their size while maintaining acceptable quality. You can adjust the compression level to balance between file size and quality."
}
},
"splitPdf": { "splitPdf": {
"title": "Split PDF", "title": "Split PDF",
"description": "Extract specific pages from a PDF document.", "description": "Extract specific pages from a PDF document.",
@ -68,5 +54,29 @@
"title": "How to Use the Rotate PDF Tool", "title": "How to Use the Rotate PDF Tool",
"description": "This tool allows you to rotate pages in a PDF document. You can rotate all pages or specify individual pages to rotate. Choose a rotation angle: 90° Clockwise, 180° (Upside down), or 270° (90° Counter-clockwise). To rotate specific pages, uncheck \"Apply to all pages\" and enter page numbers or ranges separated by commas (e.g., 1,3,5-7)." "description": "This tool allows you to rotate pages in a PDF document. You can rotate all pages or specify individual pages to rotate. Choose a rotation angle: 90° Clockwise, 180° (Upside down), or 270° (90° Counter-clockwise). To rotate specific pages, uncheck \"Apply to all pages\" and enter page numbers or ranges separated by commas (e.g., 1,3,5-7)."
} }
},
"compressPdf": {
"inputTitle": "Input PDF",
"resultTitle": "Compressed PDF",
"compressingPdf": "Compressing PDF...",
"compressionSettings": "Compression Settings",
"compressionLevel": "Compression Level",
"lowCompression": "Low Compression",
"lowCompressionDescription": "Slightly reduce file size with minimal quality loss",
"mediumCompression": "Medium Compression",
"mediumCompressionDescription": "Balance between file size and quality",
"highCompression": "High Compression",
"highCompressionDescription": "Maximum file size reduction with some quality loss",
"fileSize": "Original File Size",
"compressedFileSize": "Compressed File Size",
"pages": "Number of Pages",
"errorReadingPdf": "Failed to read PDF file. Please make sure it is a valid PDF.",
"errorCompressingPdf": "Failed to compress PDF: {{error}}"
} }
} }

View file

@ -9,7 +9,7 @@ import ToolMultiPdfInput, {
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export default function MergePdf({ title }: ToolComponentProps) { export default function MergePdf({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('pdf');
const [input, setInput] = useState<MultiPdfInput[]>([]); const [input, setInput] = useState<MultiPdfInput[]>([]);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [isProcessing, setIsProcessing] = useState<boolean>(false); const [isProcessing, setIsProcessing] = useState<boolean>(false);
@ -44,23 +44,23 @@ export default function MergePdf({ title }: ToolComponentProps) {
setInput(pdfInputs); setInput(pdfInputs);
}} }}
accept={['application/pdf']} accept={['application/pdf']}
title={t('pdf:merge.inputTitle')} title={t('merge.inputTitle')}
type="pdf" type="pdf"
/> />
} }
getGroups={null} getGroups={null}
resultComponent={ resultComponent={
<ToolFileResult <ToolFileResult
title={t('pdf:merge.resultTitle')} title={t('merge.resultTitle')}
value={result} value={result}
extension={'pdf'} extension={'pdf'}
loading={isProcessing} loading={isProcessing}
loadingText={t('pdf:merge.loadingText')} loadingText={t('merge.loadingText')}
/> />
} }
toolInfo={{ toolInfo={{
title: t('pdf:merge.toolInfo.title'), title: t('merge.toolInfo.title'),
description: t('pdf:merge.toolInfo.description') description: t('merge.toolInfo.description')
}} }}
/> />
); );

View file

@ -58,7 +58,7 @@ export default function RotatePdf({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('pdf');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [isProcessing, setIsProcessing] = useState<boolean>(false); const [isProcessing, setIsProcessing] = useState<boolean>(false);
@ -92,7 +92,7 @@ export default function RotatePdf({
if (applyToAllPages) { if (applyToAllPages) {
setPageRangePreview( setPageRangePreview(
totalPages > 0 totalPages > 0
? t('pdf:rotatePdf.allPagesWillBeRotated', { count: totalPages }) ? t('rotatePdf.allPagesWillBeRotated', { count: totalPages })
: '' : ''
); );
return; return;
@ -105,7 +105,7 @@ export default function RotatePdf({
try { try {
const count = parsePageRanges(pageRanges, totalPages).length; const count = parsePageRanges(pageRanges, totalPages).length;
setPageRangePreview(t('pdf:rotatePdf.pagesWillBeRotated', { count })); setPageRangePreview(t('rotatePdf.pagesWillBeRotated', { count }));
} catch (error) { } catch (error) {
setPageRangePreview(''); setPageRangePreview('');
} }
@ -125,9 +125,9 @@ export default function RotatePdf({
} }
}; };
const angleOptions: { value: RotationAngle; label: string }[] = [ const angleOptions: { value: RotationAngle; label: string }[] = [
{ value: 90, label: t('pdf:rotatePdf.angleOptions.clockwise90') }, { value: 90, label: t('rotatePdf.angleOptions.clockwise90') },
{ value: 180, label: t('pdf:rotatePdf.angleOptions.upsideDown180') }, { value: 180, label: t('rotatePdf.angleOptions.upsideDown180') },
{ value: 270, label: t('pdf:rotatePdf.angleOptions.counterClockwise270') } { value: 270, label: t('rotatePdf.angleOptions.counterClockwise270') }
]; ];
return ( return (
<ToolContent <ToolContent
@ -142,25 +142,25 @@ export default function RotatePdf({
value={input} value={input}
onChange={setInput} onChange={setInput}
accept={['application/pdf']} accept={['application/pdf']}
title={t('pdf:rotatePdf.inputTitle')} title={t('rotatePdf.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
<ToolFileResult <ToolFileResult
title={t('pdf:rotatePdf.resultTitle')} title={t('rotatePdf.resultTitle')}
value={result} value={result}
extension={'pdf'} extension={'pdf'}
loading={isProcessing} loading={isProcessing}
loadingText={t('pdf:rotatePdf.rotatingPages')} loadingText={t('rotatePdf.rotatingPages')}
/> />
} }
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('pdf:rotatePdf.rotationSettings'), title: t('rotatePdf.rotationSettings'),
component: ( component: (
<Box> <Box>
<Typography variant="subtitle2" sx={{ mb: 1 }}> <Typography variant="subtitle2" sx={{ mb: 1 }}>
{t('pdf:rotatePdf.rotationAngle')} {t('rotatePdf.rotationAngle')}
</Typography> </Typography>
{angleOptions.map((angleOption) => ( {angleOptions.map((angleOption) => (
<SimpleRadio <SimpleRadio
@ -183,7 +183,7 @@ export default function RotatePdf({
}} }}
/> />
} }
label={t('pdf:rotatePdf.applyToAllPages')} label={t('rotatePdf.applyToAllPages')}
/> />
</Box> </Box>
@ -191,7 +191,7 @@ export default function RotatePdf({
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
{totalPages > 0 && ( {totalPages > 0 && (
<Typography variant="body2" sx={{ mb: 1 }}> <Typography variant="body2" sx={{ mb: 1 }}>
{t('pdf:rotatePdf.pdfPageCount', { count: totalPages })} {t('rotatePdf.pdfPageCount', { count: totalPages })}
</Typography> </Typography>
)} )}
<TextFieldWithDesc <TextFieldWithDesc
@ -199,8 +199,8 @@ export default function RotatePdf({
onOwnChange={(val) => { onOwnChange={(val) => {
updateField('pageRanges', val); updateField('pageRanges', val);
}} }}
description={t('pdf:rotatePdf.pageRangesDescription')} description={t('rotatePdf.pageRangesDescription')}
placeholder={t('pdf:rotatePdf.pageRangesPlaceholder')} placeholder={t('rotatePdf.pageRangesPlaceholder')}
/> />
{pageRangePreview && ( {pageRangePreview && (
<Typography <Typography
@ -218,8 +218,8 @@ export default function RotatePdf({
]} ]}
onValuesChange={onValuesChange} onValuesChange={onValuesChange}
toolInfo={{ toolInfo={{
title: t('pdf:rotatePdf.toolInfo.title'), title: t('rotatePdf.toolInfo.title'),
description: t('pdf:rotatePdf.toolInfo.description') description: t('rotatePdf.toolInfo.description')
}} }}
/> />
); );

View file

@ -49,7 +49,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function SplitPdf({ title }: ToolComponentProps) { export default function SplitPdf({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('pdf');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [isProcessing, setIsProcessing] = useState<boolean>(false); const [isProcessing, setIsProcessing] = useState<boolean>(false);
@ -85,7 +85,7 @@ export default function SplitPdf({ title }: ToolComponentProps) {
} }
try { try {
const count = parsePageRanges(pageRanges, totalPages).length; const count = parsePageRanges(pageRanges, totalPages).length;
setPageRangePreview(t('pdf:splitPdf.pageExtractionPreview', { count })); setPageRangePreview(t('splitPdf.pageExtractionPreview', { count }));
} catch (error) { } catch (error) {
setPageRangePreview(''); setPageRangePreview('');
} }
@ -118,26 +118,26 @@ export default function SplitPdf({ title }: ToolComponentProps) {
value={input} value={input}
onChange={setInput} onChange={setInput}
accept={['application/pdf']} accept={['application/pdf']}
title={t('pdf:splitPdf.inputTitle')} title={t('splitPdf.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
<ToolFileResult <ToolFileResult
title={t('pdf:splitPdf.resultTitle')} title={t('splitPdf.resultTitle')}
value={result} value={result}
extension={'pdf'} extension={'pdf'}
loading={isProcessing} loading={isProcessing}
loadingText={t('pdf:splitPdf.extractingPages')} loadingText={t('splitPdf.extractingPages')}
/> />
} }
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('pdf:splitPdf.pageSelection'), title: t('splitPdf.pageSelection'),
component: ( component: (
<Box> <Box>
{totalPages > 0 && ( {totalPages > 0 && (
<Typography variant="body2" sx={{ mb: 1 }}> <Typography variant="body2" sx={{ mb: 1 }}>
{t('pdf:splitPdf.pdfPageCount', { count: totalPages })} {t('splitPdf.pdfPageCount', { count: totalPages })}
</Typography> </Typography>
)} )}
<TextFieldWithDesc <TextFieldWithDesc
@ -145,8 +145,8 @@ export default function SplitPdf({ title }: ToolComponentProps) {
onOwnChange={(val) => { onOwnChange={(val) => {
updateField('pageRanges', val); updateField('pageRanges', val);
}} }}
description={t('pdf:splitPdf.pageRangesDescription')} description={t('splitPdf.pageRangesDescription')}
placeholder={t('pdf:splitPdf.pageRangesPlaceholder')} placeholder={t('splitPdf.pageRangesPlaceholder')}
/> />
{pageRangePreview && ( {pageRangePreview && (
<Typography <Typography
@ -162,8 +162,8 @@ export default function SplitPdf({ title }: ToolComponentProps) {
]} ]}
onValuesChange={onValuesChange} onValuesChange={onValuesChange}
toolInfo={{ toolInfo={{
title: t('pdf:splitPdf.toolInfo.title'), title: t('splitPdf.toolInfo.title'),
description: t('pdf:splitPdf.toolInfo.description') description: t('splitPdf.toolInfo.description')
}} }}
/> />
); );

View file

@ -34,7 +34,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Base64({ title }: ToolComponentProps) { export default function Base64({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -47,18 +47,18 @@ export default function Base64({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:base64.optionsTitle'), title: t('base64.optionsTitle'),
component: ( component: (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('mode', 'encode')} onClick={() => updateField('mode', 'encode')}
checked={values.mode === 'encode'} checked={values.mode === 'encode'}
title={t('string:base64.encode')} title={t('base64.encode')}
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('mode', 'decode')} onClick={() => updateField('mode', 'decode')}
checked={values.mode === 'decode'} checked={values.mode === 'decode'}
title={t('string:base64.decode')} title={t('base64.decode')}
/> />
</Box> </Box>
) )
@ -70,19 +70,19 @@ export default function Base64({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:base64.inputTitle')} title={t('base64.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('string:base64.resultTitle')} value={result} /> <ToolTextResult title={t('base64.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={getGroups} getGroups={getGroups}
toolInfo={{ toolInfo={{
title: t('string:base64.toolInfo.title'), title: t('base64.toolInfo.title'),
description: t('string:base64.toolInfo.description') description: t('base64.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -108,7 +108,7 @@ s
]; ];
export default function JoinText({ title }: ToolComponentProps) { export default function JoinText({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
const compute = (optionsValues: InitialValuesType, input: any) => { const compute = (optionsValues: InitialValuesType, input: any) => {
@ -121,18 +121,18 @@ export default function JoinText({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:join.textMergedOptions'), title: t('join.textMergedOptions'),
component: ( component: (
<TextFieldWithDesc <TextFieldWithDesc
placeholder={t('string:join.joinCharacterPlaceholder')} placeholder={t('join.joinCharacterPlaceholder')}
value={values['joinCharacter']} value={values['joinCharacter']}
onOwnChange={(value) => updateField(mergeOptions.accessor, value)} onOwnChange={(value) => updateField(mergeOptions.accessor, value)}
description={t('string:join.joinCharacterDescription')} description={t('join.joinCharacterDescription')}
/> />
) )
}, },
{ {
title: t('string:join.blankLinesAndTrailingSpaces'), title: t('join.blankLinesAndTrailingSpaces'),
component: blankTrailingOptions.map((option) => ( component: blankTrailingOptions.map((option) => (
<CheckboxWithDesc <CheckboxWithDesc
key={option.accessor} key={option.accessor}
@ -153,18 +153,18 @@ export default function JoinText({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:join.inputTitle')} title={t('join.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('string:join.resultTitle')} value={result} /> <ToolTextResult title={t('join.resultTitle')} value={result} />
} }
getGroups={getGroups} getGroups={getGroups}
toolInfo={{ toolInfo={{
title: t('string:join.toolInfo.title'), title: t('join.toolInfo.title'),
description: t('string:join.toolInfo.description') description: t('join.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -71,7 +71,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Quote({ title }: ToolComponentProps) { export default function Quote({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -95,33 +95,33 @@ export default function Quote({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:quote.quoteOptions'), title: t('quote.quoteOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.leftQuote} value={values.leftQuote}
onOwnChange={(val) => updateField('leftQuote', val)} onOwnChange={(val) => updateField('leftQuote', val)}
description={t('string:quote.leftQuoteDescription')} description={t('quote.leftQuoteDescription')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.rightQuote} value={values.rightQuote}
onOwnChange={(val) => updateField('rightQuote', val)} onOwnChange={(val) => updateField('rightQuote', val)}
description={t('string:quote.rightQuoteDescription')} description={t('quote.rightQuoteDescription')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.doubleQuotation} checked={values.doubleQuotation}
onChange={(checked) => updateField('doubleQuotation', checked)} onChange={(checked) => updateField('doubleQuotation', checked)}
title={t('string:quote.allowDoubleQuotation')} title={t('quote.allowDoubleQuotation')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.emptyQuoting} checked={values.emptyQuoting}
onChange={(checked) => updateField('emptyQuoting', checked)} onChange={(checked) => updateField('emptyQuoting', checked)}
title={t('string:quote.quoteEmptyLines')} title={t('quote.quoteEmptyLines')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.multiLine} checked={values.multiLine}
onChange={(checked) => updateField('multiLine', checked)} onChange={(checked) => updateField('multiLine', checked)}
title={t('string:quote.processAsMultiLine')} title={t('quote.processAsMultiLine')}
/> />
</Box> </Box>
) )
@ -133,19 +133,19 @@ export default function Quote({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:quote.inputTitle')} title={t('quote.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('string:quote.resultTitle')} value={result} /> <ToolTextResult title={t('quote.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={getGroups} getGroups={getGroups}
toolInfo={{ toolInfo={{
title: t('string:quote.toolInfo.title'), title: t('quote.toolInfo.title'),
description: t('string:quote.toolInfo.description') description: t('quote.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -49,7 +49,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Replacer({ title }: ToolComponentProps) { export default function Replacer({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -62,12 +62,12 @@ export default function Replacer({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:repeat.textRepetitions'), title: t('repeat.textRepetitions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:repeat.repeatAmountDescription')} description={t('repeat.repeatAmountDescription')}
placeholder={t('string:repeat.numberPlaceholder')} placeholder={t('repeat.numberPlaceholder')}
value={values.repeatAmount} value={values.repeatAmount}
onOwnChange={(val) => updateField('repeatAmount', val)} onOwnChange={(val) => updateField('repeatAmount', val)}
type={'number'} type={'number'}
@ -76,12 +76,12 @@ export default function Replacer({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('string:repeat.repetitionsDelimiter'), title: t('repeat.repetitionsDelimiter'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:repeat.delimiterDescription')} description={t('repeat.delimiterDescription')}
placeholder={t('string:repeat.delimiterPlaceholder')} placeholder={t('repeat.delimiterPlaceholder')}
value={values.delimiter} value={values.delimiter}
onOwnChange={(val) => updateField('delimiter', val)} onOwnChange={(val) => updateField('delimiter', val)}
type={'text'} type={'text'}
@ -101,17 +101,17 @@ export default function Replacer({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:repeat.inputTitle')} title={t('repeat.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('string:repeat.resultTitle')} value={result} /> <ToolTextResult title={t('repeat.resultTitle')} value={result} />
} }
toolInfo={{ toolInfo={{
title: t('string:repeat.toolInfo.title'), title: t('repeat.toolInfo.title'),
description: t('string:repeat.toolInfo.description') description: t('repeat.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -59,7 +59,7 @@ const exampleCards: CardExampleType<typeof initialValues>[] = [
]; ];
export default function Reverse({ title }: ToolComponentProps) { export default function Reverse({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -76,27 +76,27 @@ export default function Reverse({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:reverse.reversalOptions'), title: t('reverse.reversalOptions'),
component: [ component: [
<CheckboxWithDesc <CheckboxWithDesc
key="multiLine" key="multiLine"
checked={values.multiLine} checked={values.multiLine}
title={t('string:reverse.processMultiLine')} title={t('reverse.processMultiLine')}
description={t('string:reverse.processMultiLineDescription')} description={t('reverse.processMultiLineDescription')}
onChange={(val) => updateField('multiLine', val)} onChange={(val) => updateField('multiLine', val)}
/>, />,
<CheckboxWithDesc <CheckboxWithDesc
key="emptyItems" key="emptyItems"
checked={values.emptyItems} checked={values.emptyItems}
title={t('string:reverse.skipEmptyLines')} title={t('reverse.skipEmptyLines')}
description={t('string:reverse.skipEmptyLinesDescription')} description={t('reverse.skipEmptyLinesDescription')}
onChange={(val) => updateField('emptyItems', val)} onChange={(val) => updateField('emptyItems', val)}
/>, />,
<CheckboxWithDesc <CheckboxWithDesc
key="trim" key="trim"
checked={values.trim} checked={values.trim}
title={t('string:reverse.trimWhitespace')} title={t('reverse.trimWhitespace')}
description={t('string:reverse.trimWhitespaceDescription')} description={t('reverse.trimWhitespaceDescription')}
onChange={(val) => updateField('trim', val)} onChange={(val) => updateField('trim', val)}
/> />
] ]
@ -113,16 +113,13 @@ export default function Reverse({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:reverse.inputTitle')} title={t('reverse.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('reverse.resultTitle')} value={result} />
title={t('string:reverse.resultTitle')}
value={result}
/>
} }
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -31,7 +31,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Rot13({ title }: ToolComponentProps) { export default function Rot13({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -44,19 +44,19 @@ export default function Rot13({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:rot13.inputTitle')} title={t('rot13.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('string:rot13.resultTitle')} value={result} /> <ToolTextResult title={t('rot13.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={null} getGroups={null}
toolInfo={{ toolInfo={{
title: t('string:rot13.toolInfo.title'), title: t('rot13.toolInfo.title'),
description: t('string:rot13.toolInfo.description') description: t('rot13.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -64,7 +64,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Rotate({ title }: ToolComponentProps) { export default function Rotate({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -81,29 +81,29 @@ export default function Rotate({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:rotate.rotationOptions'), title: t('rotate.rotationOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.step} value={values.step}
onOwnChange={(val) => updateField('step', val)} onOwnChange={(val) => updateField('step', val)}
description={t('string:rotate.stepDescription')} description={t('rotate.stepDescription')}
type="number" type="number"
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('direction', 'right')} onClick={() => updateField('direction', 'right')}
checked={values.direction === 'right'} checked={values.direction === 'right'}
title={t('string:rotate.rotateRight')} title={t('rotate.rotateRight')}
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('direction', 'left')} onClick={() => updateField('direction', 'left')}
checked={values.direction === 'left'} checked={values.direction === 'left'}
title={t('string:rotate.rotateLeft')} title={t('rotate.rotateLeft')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.multiLine} checked={values.multiLine}
onChange={(checked) => updateField('multiLine', checked)} onChange={(checked) => updateField('multiLine', checked)}
title={t('string:rotate.processAsMultiLine')} title={t('rotate.processAsMultiLine')}
/> />
</Box> </Box>
) )
@ -115,19 +115,19 @@ export default function Rotate({ title }: ToolComponentProps) {
title={title} title={title}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:rotate.inputTitle')} title={t('rotate.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult title={t('string:rotate.resultTitle')} value={result} /> <ToolTextResult title={t('rotate.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={getGroups} getGroups={getGroups}
toolInfo={{ toolInfo={{
title: t('string:rotate.toolInfo.title'), title: t('rotate.toolInfo.title'),
description: t('string:rotate.toolInfo.description') description: t('rotate.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
input={input} input={input}

View file

@ -133,7 +133,7 @@ easy`,
]; ];
export default function SplitText({ title }: ToolComponentProps) { export default function SplitText({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -173,12 +173,12 @@ export default function SplitText({ title }: ToolComponentProps) {
input={input} input={input}
inputComponent={<ToolTextInput value={input} onChange={setInput} />} inputComponent={<ToolTextInput value={input} onChange={setInput} />}
resultComponent={ resultComponent={
<ToolTextResult title={t('string:split.resultTitle')} value={result} /> <ToolTextResult title={t('split.resultTitle')} value={result} />
} }
initialValues={initialValues} initialValues={initialValues}
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('string:split.splitSeparatorOptions'), title: t('split.splitSeparatorOptions'),
component: splitOperators.map(({ title, description, type }) => ( component: splitOperators.map(({ title, description, type }) => (
<RadioWithTextField <RadioWithTextField
key={type} key={type}
@ -193,7 +193,7 @@ export default function SplitText({ title }: ToolComponentProps) {
)) ))
}, },
{ {
title: t('string:split.outputSeparatorOptions'), title: t('split.outputSeparatorOptions'),
component: outputOptions.map((option) => ( component: outputOptions.map((option) => (
<TextFieldWithDesc <TextFieldWithDesc
key={option.accessor} key={option.accessor}

View file

@ -217,7 +217,7 @@ export default function Truncate({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -230,38 +230,38 @@ export default function Truncate({
updateField updateField
}) => [ }) => [
{ {
title: t('string:statistic.delimitersOptions'), title: t('statistic.delimitersOptions'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.sentenceDelimiters} value={values.sentenceDelimiters}
onOwnChange={(val) => updateField('sentenceDelimiters', val)} onOwnChange={(val) => updateField('sentenceDelimiters', val)}
placeholder={t('string:statistic.sentenceDelimitersPlaceholder')} placeholder={t('statistic.sentenceDelimitersPlaceholder')}
description={t('string:statistic.sentenceDelimitersDescription')} description={t('statistic.sentenceDelimitersDescription')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
value={values.wordDelimiters} value={values.wordDelimiters}
onOwnChange={(val) => updateField('wordDelimiters', val)} onOwnChange={(val) => updateField('wordDelimiters', val)}
placeholder={t('string:statistic.wordDelimitersPlaceholder')} placeholder={t('statistic.wordDelimitersPlaceholder')}
description={t('string:statistic.wordDelimitersDescription')} description={t('statistic.wordDelimitersDescription')}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('string:statistic.statisticsOptions'), title: t('statistic.statisticsOptions'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
checked={values.wordCount} checked={values.wordCount}
onChange={(value) => updateField('wordCount', value)} onChange={(value) => updateField('wordCount', value)}
title={t('string:statistic.wordFrequencyAnalysis')} title={t('statistic.wordFrequencyAnalysis')}
description={t('string:statistic.wordFrequencyAnalysisDescription')} description={t('statistic.wordFrequencyAnalysisDescription')}
/> />
<CheckboxWithDesc <CheckboxWithDesc
checked={values.characterCount} checked={values.characterCount}
onChange={(value) => updateField('characterCount', value)} onChange={(value) => updateField('characterCount', value)}
title={t('string:statistic.characterFrequencyAnalysis')} title={t('statistic.characterFrequencyAnalysis')}
description={t( description={t(
'string:statistic.characterFrequencyAnalysisDescription' 'string:statistic.characterFrequencyAnalysisDescription'
)} )}
@ -269,8 +269,8 @@ export default function Truncate({
<CheckboxWithDesc <CheckboxWithDesc
checked={values.emptyLines} checked={values.emptyLines}
onChange={(value) => updateField('emptyLines', value)} onChange={(value) => updateField('emptyLines', value)}
title={t('string:statistic.includeEmptyLines')} title={t('statistic.includeEmptyLines')}
description={t('string:statistic.includeEmptyLinesDescription')} description={t('statistic.includeEmptyLinesDescription')}
/> />
</Box> </Box>
) )
@ -287,19 +287,16 @@ export default function Truncate({
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:statistic.inputTitle')} title={t('statistic.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('statistic.resultTitle')} value={result} />
title={t('string:statistic.resultTitle')}
value={result}
/>
} }
toolInfo={{ toolInfo={{
title: t('string:statistic.toolInfo.title', { title }), title: t('statistic.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}

View file

@ -61,7 +61,7 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function Replacer({ title }: ToolComponentProps) { export default function Replacer({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -74,16 +74,16 @@ export default function Replacer({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:textReplacer.searchText'), title: t('textReplacer.searchText'),
component: ( component: (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('mode', 'text')} onClick={() => updateField('mode', 'text')}
checked={values.mode === 'text'} checked={values.mode === 'text'}
title={t('string:textReplacer.findPatternInText')} title={t('textReplacer.findPatternInText')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:textReplacer.searchPatternDescription')} description={t('textReplacer.searchPatternDescription')}
value={values.searchValue} value={values.searchValue}
onOwnChange={(val) => updateField('searchValue', val)} onOwnChange={(val) => updateField('searchValue', val)}
type={'text'} type={'text'}
@ -91,10 +91,10 @@ export default function Replacer({ title }: ToolComponentProps) {
<SimpleRadio <SimpleRadio
onClick={() => updateField('mode', 'regexp')} onClick={() => updateField('mode', 'regexp')}
checked={values.mode === 'regexp'} checked={values.mode === 'regexp'}
title={t('string:textReplacer.findPatternUsingRegexp')} title={t('textReplacer.findPatternUsingRegexp')}
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:textReplacer.regexpDescription')} description={t('textReplacer.regexpDescription')}
value={values.searchRegexp} value={values.searchRegexp}
onOwnChange={(val) => updateField('searchRegexp', val)} onOwnChange={(val) => updateField('searchRegexp', val)}
type={'text'} type={'text'}
@ -103,12 +103,12 @@ export default function Replacer({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('string:textReplacer.replaceText'), title: t('textReplacer.replaceText'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:textReplacer.replacePatternDescription')} description={t('textReplacer.replacePatternDescription')}
placeholder={t('string:textReplacer.newTextPlaceholder')} placeholder={t('textReplacer.newTextPlaceholder')}
value={values.replaceValue} value={values.replaceValue}
onOwnChange={(val) => updateField('replaceValue', val)} onOwnChange={(val) => updateField('replaceValue', val)}
type={'text'} type={'text'}
@ -128,20 +128,17 @@ export default function Replacer({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:textReplacer.inputTitle')} title={t('textReplacer.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('textReplacer.resultTitle')} value={result} />
title={t('string:textReplacer.resultTitle')}
value={result}
/>
} }
toolInfo={{ toolInfo={{
title: t('string:textReplacer.toolInfo.title'), title: t('textReplacer.toolInfo.title'),
description: t('string:textReplacer.toolInfo.description') description: t('textReplacer.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -12,7 +12,7 @@ const initialValues = {
}; };
export default function ToMorse() { export default function ToMorse() {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
const computeOptions = (optionsValues: typeof initialValues, input: any) => { const computeOptions = (optionsValues: typeof initialValues, input: any) => {
@ -22,34 +22,31 @@ export default function ToMorse() {
return ( return (
<ToolContent <ToolContent
title={t('string:toMorse.title')} title={t('toMorse.title')}
initialValues={initialValues} initialValues={initialValues}
compute={computeOptions} compute={computeOptions}
input={input} input={input}
setInput={setInput} setInput={setInput}
inputComponent={<ToolTextInput value={input} onChange={setInput} />} inputComponent={<ToolTextInput value={input} onChange={setInput} />}
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('toMorse.resultTitle')} value={result} />
title={t('string:toMorse.resultTitle')}
value={result}
/>
} }
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('string:toMorse.shortSignal'), title: t('toMorse.shortSignal'),
component: ( component: (
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:toMorse.dotSymbolDescription')} description={t('toMorse.dotSymbolDescription')}
value={values.dotSymbol} value={values.dotSymbol}
onOwnChange={(val) => updateField('dotSymbol', val)} onOwnChange={(val) => updateField('dotSymbol', val)}
/> />
) )
}, },
{ {
title: t('string:toMorse.longSignal'), title: t('toMorse.longSignal'),
component: ( component: (
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:toMorse.dashSymbolDescription')} description={t('toMorse.dashSymbolDescription')}
value={values.dashSymbol} value={values.dashSymbol}
onOwnChange={(val) => updateField('dashSymbol', val)} onOwnChange={(val) => updateField('dashSymbol', val)}
/> />

View file

@ -68,7 +68,7 @@ Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
]; ];
export default function Truncate({ title }: ToolComponentProps) { export default function Truncate({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -81,31 +81,31 @@ export default function Truncate({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('string:truncate.truncationSide'), title: t('truncate.truncationSide'),
component: ( component: (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('truncationSide', 'right')} onClick={() => updateField('truncationSide', 'right')}
checked={values.truncationSide === 'right'} checked={values.truncationSide === 'right'}
title={t('string:truncate.rightSideTruncation')} title={t('truncate.rightSideTruncation')}
description={t('string:truncate.rightSideDescription')} description={t('truncate.rightSideDescription')}
/> />
<SimpleRadio <SimpleRadio
onClick={() => updateField('truncationSide', 'left')} onClick={() => updateField('truncationSide', 'left')}
checked={values.truncationSide === 'left'} checked={values.truncationSide === 'left'}
title={t('string:truncate.leftSideTruncation')} title={t('truncate.leftSideTruncation')}
description={t('string:truncate.leftSideDescription')} description={t('truncate.leftSideDescription')}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('string:truncate.lengthAndLines'), title: t('truncate.lengthAndLines'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:truncate.maxLengthDescription')} description={t('truncate.maxLengthDescription')}
placeholder={t('string:truncate.numberPlaceholder')} placeholder={t('truncate.numberPlaceholder')}
value={values.maxLength} value={values.maxLength}
onOwnChange={(val) => updateField('maxLength', val)} onOwnChange={(val) => updateField('maxLength', val)}
type={'number'} type={'number'}
@ -113,25 +113,25 @@ export default function Truncate({ title }: ToolComponentProps) {
<CheckboxWithDesc <CheckboxWithDesc
onChange={(val) => updateField('lineByLine', val)} onChange={(val) => updateField('lineByLine', val)}
checked={values.lineByLine} checked={values.lineByLine}
title={t('string:truncate.lineByLineTruncating')} title={t('truncate.lineByLineTruncating')}
description={t('string:truncate.lineByLineDescription')} description={t('truncate.lineByLineDescription')}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('string:truncate.suffixAndAffix'), title: t('truncate.suffixAndAffix'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
onChange={(val) => updateField('addIndicator', val)} onChange={(val) => updateField('addIndicator', val)}
checked={values.addIndicator} checked={values.addIndicator}
title={t('string:truncate.addTruncationIndicator')} title={t('truncate.addTruncationIndicator')}
description={''} description={''}
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('string:truncate.indicatorDescription')} description={t('truncate.indicatorDescription')}
placeholder={t('string:truncate.charactersPlaceholder')} placeholder={t('truncate.charactersPlaceholder')}
value={values.indicator} value={values.indicator}
onOwnChange={(val) => updateField('indicator', val)} onOwnChange={(val) => updateField('indicator', val)}
type={'text'} type={'text'}
@ -151,20 +151,17 @@ export default function Truncate({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:truncate.inputTitle')} title={t('truncate.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('truncate.resultTitle')} value={result} />
title={t('string:truncate.resultTitle')}
value={result}
/>
} }
toolInfo={{ toolInfo={{
title: t('string:truncate.toolInfo.title'), title: t('truncate.toolInfo.title'),
description: t('string:truncate.toolInfo.description') description: t('truncate.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -36,7 +36,7 @@ const exampleCards: CardExampleType<typeof initialValues>[] = [
]; ];
export default function Uppercase({ title }: ToolComponentProps) { export default function Uppercase({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('string');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -57,16 +57,13 @@ export default function Uppercase({ title }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('string:uppercase.inputTitle')} title={t('uppercase.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult title={t('uppercase.resultTitle')} value={result} />
title={t('string:uppercase.resultTitle')}
value={result}
/>
} }
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -57,7 +57,7 @@ export default function ConvertDaysToHours({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('time');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -78,7 +78,7 @@ export default function ConvertDaysToHours({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('time:checkLeapYears.toolInfo.title', { title }), title: t('checkLeapYears.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}

View file

@ -63,7 +63,7 @@ export default function ConvertDaysToHours({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('time');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -76,14 +76,14 @@ export default function ConvertDaysToHours({
updateField updateField
}) => [ }) => [
{ {
title: t('time:convertDaysToHours.hoursName'), title: t('convertDaysToHours.hoursName'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
onChange={(val) => updateField('hoursFlag', val)} onChange={(val) => updateField('hoursFlag', val)}
checked={values.hoursFlag} checked={values.hoursFlag}
title={t('time:convertDaysToHours.addHoursName')} title={t('convertDaysToHours.addHoursName')}
description={t('time:convertDaysToHours.addHoursNameDescription')} description={t('convertDaysToHours.addHoursNameDescription')}
/> />
</Box> </Box>
) )
@ -101,8 +101,8 @@ export default function ConvertDaysToHours({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('time:convertDaysToHours.toolInfo.title'), title: t('convertDaysToHours.toolInfo.title'),
description: t('time:convertDaysToHours.toolInfo.description') description: t('convertDaysToHours.toolInfo.description')
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}
/> />

View file

@ -69,7 +69,7 @@ export default function SecondsToTime({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('time');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -82,14 +82,14 @@ export default function SecondsToTime({
updateField updateField
}) => [ }) => [
{ {
title: t('time:convertSecondsToTime.timePadding'), title: t('convertSecondsToTime.timePadding'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
onChange={(val) => updateField('paddingFlag', val)} onChange={(val) => updateField('paddingFlag', val)}
checked={values.paddingFlag} checked={values.paddingFlag}
title={t('time:convertSecondsToTime.addPadding')} title={t('convertSecondsToTime.addPadding')}
description={t('time:convertSecondsToTime.addPaddingDescription')} description={t('convertSecondsToTime.addPaddingDescription')}
/> />
</Box> </Box>
) )
@ -107,7 +107,7 @@ export default function SecondsToTime({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('time:convertSecondsToTime.toolInfo.title', { title }), title: t('convertSecondsToTime.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}

View file

@ -76,7 +76,7 @@ export default function TimeToSeconds({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('time');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -95,7 +95,7 @@ export default function TimeToSeconds({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('time:convertTimeToSeconds.toolInfo.title', { title }), title: t('convertTimeToSeconds.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}

View file

@ -121,12 +121,12 @@ const exampleCards: CardExampleType<InitialValuesType>[] = [
]; ];
export default function TimeBetweenDates() { export default function TimeBetweenDates() {
const { t } = useTranslation(); const { t } = useTranslation('time');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
return ( return (
<ToolContent <ToolContent
title={t('time:timeBetweenDates.title')} title={t('timeBetweenDates.title')}
inputComponent={null} inputComponent={null}
resultComponent={ resultComponent={
result ? ( result ? (
@ -155,28 +155,28 @@ export default function TimeBetweenDates() {
validationSchema={validationSchema} validationSchema={validationSchema}
exampleCards={exampleCards} exampleCards={exampleCards}
toolInfo={{ toolInfo={{
title: t('time:timeBetweenDates.toolInfo.title'), title: t('timeBetweenDates.toolInfo.title'),
description: t('time:timeBetweenDates.toolInfo.description') description: t('timeBetweenDates.toolInfo.description')
}} }}
getGroups={({ values, updateField }) => [ getGroups={({ values, updateField }) => [
{ {
title: t('time:timeBetweenDates.startDateTime'), title: t('timeBetweenDates.startDateTime'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('time:timeBetweenDates.startDate')} description={t('timeBetweenDates.startDate')}
value={values.startDate} value={values.startDate}
onOwnChange={(val) => updateField('startDate', val)} onOwnChange={(val) => updateField('startDate', val)}
type="date" type="date"
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('time:timeBetweenDates.startTime')} description={t('timeBetweenDates.startTime')}
value={values.startTime} value={values.startTime}
onOwnChange={(val) => updateField('startTime', val)} onOwnChange={(val) => updateField('startTime', val)}
type="time" type="time"
/> />
<SelectWithDesc <SelectWithDesc
description={t('time:timeBetweenDates.startTimezone')} description={t('timeBetweenDates.startTimezone')}
selected={values.startTimezone} selected={values.startTimezone}
onChange={(val: string) => updateField('startTimezone', val)} onChange={(val: string) => updateField('startTimezone', val)}
options={timezoneOptions} options={timezoneOptions}
@ -185,23 +185,23 @@ export default function TimeBetweenDates() {
) )
}, },
{ {
title: t('time:timeBetweenDates.endDateTime'), title: t('timeBetweenDates.endDateTime'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
description={t('time:timeBetweenDates.endDate')} description={t('timeBetweenDates.endDate')}
value={values.endDate} value={values.endDate}
onOwnChange={(val) => updateField('endDate', val)} onOwnChange={(val) => updateField('endDate', val)}
type="date" type="date"
/> />
<TextFieldWithDesc <TextFieldWithDesc
description={t('time:timeBetweenDates.endTime')} description={t('timeBetweenDates.endTime')}
value={values.endTime} value={values.endTime}
onOwnChange={(val) => updateField('endTime', val)} onOwnChange={(val) => updateField('endTime', val)}
type="time" type="time"
/> />
<SelectWithDesc <SelectWithDesc
description={t('time:timeBetweenDates.endTimezone')} description={t('timeBetweenDates.endTimezone')}
selected={values.endTimezone} selected={values.endTimezone}
onChange={(val: string) => updateField('endTimezone', val)} onChange={(val: string) => updateField('endTimezone', val)}
options={timezoneOptions} options={timezoneOptions}

View file

@ -68,7 +68,7 @@ export default function TruncateClockTime({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('time');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -88,13 +88,13 @@ export default function TruncateClockTime({
updateField updateField
}) => [ }) => [
{ {
title: t('time:truncateClockTime.truncationSide'), title: t('truncateClockTime.truncationSide'),
component: ( component: (
<Box> <Box>
<SimpleRadio <SimpleRadio
onClick={() => updateField('onlySecond', true)} onClick={() => updateField('onlySecond', true)}
checked={values.onlySecond} checked={values.onlySecond}
title={t('time:truncateClockTime.truncateOnlySeconds')} title={t('truncateClockTime.truncateOnlySeconds')}
description={t( description={t(
'time:truncateClockTime.truncateOnlySecondsDescription' 'time:truncateClockTime.truncateOnlySecondsDescription'
)} )}
@ -102,7 +102,7 @@ export default function TruncateClockTime({
<SimpleRadio <SimpleRadio
onClick={() => updateField('onlySecond', false)} onClick={() => updateField('onlySecond', false)}
checked={!values.onlySecond} checked={!values.onlySecond}
title={t('time:truncateClockTime.truncateMinutesAndSeconds')} title={t('truncateClockTime.truncateMinutesAndSeconds')}
description={t( description={t(
'time:truncateClockTime.truncateMinutesAndSecondsDescription' 'time:truncateClockTime.truncateMinutesAndSecondsDescription'
)} )}
@ -111,27 +111,27 @@ export default function TruncateClockTime({
) )
}, },
{ {
title: t('time:truncateClockTime.printDroppedComponents'), title: t('truncateClockTime.printDroppedComponents'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
onChange={(val) => updateField('zeroPrint', val)} onChange={(val) => updateField('zeroPrint', val)}
checked={values.zeroPrint} checked={values.zeroPrint}
title={t('time:truncateClockTime.zeroPrintTruncatedParts')} title={t('truncateClockTime.zeroPrintTruncatedParts')}
description={t('time:truncateClockTime.zeroPrintDescription')} description={t('truncateClockTime.zeroPrintDescription')}
/> />
</Box> </Box>
) )
}, },
{ {
title: t('time:truncateClockTime.timePadding'), title: t('truncateClockTime.timePadding'),
component: ( component: (
<Box> <Box>
<CheckboxWithDesc <CheckboxWithDesc
onChange={(val) => updateField('zeroPadding', val)} onChange={(val) => updateField('zeroPadding', val)}
checked={values.zeroPadding} checked={values.zeroPadding}
title={t('time:truncateClockTime.useZeroPadding')} title={t('truncateClockTime.useZeroPadding')}
description={t('time:truncateClockTime.zeroPaddingDescription')} description={t('truncateClockTime.zeroPaddingDescription')}
/> />
</Box> </Box>
) )
@ -149,7 +149,7 @@ export default function TruncateClockTime({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('time:truncateClockTime.toolInfo.title', { title }), title: t('truncateClockTime.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
exampleCards={exampleCards} exampleCards={exampleCards}

View file

@ -19,7 +19,7 @@ export default function ChangeSpeed({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('video');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -130,13 +130,13 @@ export default function ChangeSpeed({
updateField updateField
}) => [ }) => [
{ {
title: t('video:changeSpeed.newVideoSpeed'), title: t('changeSpeed.newVideoSpeed'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
value={values.newSpeed.toString()} value={values.newSpeed.toString()}
onOwnChange={(val) => updateField('newSpeed', Number(val))} onOwnChange={(val) => updateField('newSpeed', Number(val))}
description={t('video:changeSpeed.defaultMultiplier')} description={t('changeSpeed.defaultMultiplier')}
type="number" type="number"
/> />
</Box> </Box>
@ -151,19 +151,19 @@ export default function ChangeSpeed({
<ToolVideoInput <ToolVideoInput
value={input} value={input}
onChange={setInput} onChange={setInput}
title={t('video:changeSpeed.inputTitle')} title={t('changeSpeed.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
loading ? ( loading ? (
<ToolFileResult <ToolFileResult
title={t('video:changeSpeed.settingSpeed')} title={t('changeSpeed.settingSpeed')}
value={null} value={null}
loading={true} loading={true}
/> />
) : ( ) : (
<ToolFileResult <ToolFileResult
title={t('video:changeSpeed.resultTitle')} title={t('changeSpeed.resultTitle')}
value={result} value={result}
extension="mp4" extension="mp4"
/> />
@ -174,7 +174,7 @@ export default function ChangeSpeed({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('video:changeSpeed.toolInfo.title', { title }), title: t('changeSpeed.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
/> />

View file

@ -69,7 +69,7 @@ const presetOptions = [
]; ];
export default function CompressVideo({ title }: ToolComponentProps) { export default function CompressVideo({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('video');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -102,7 +102,7 @@ export default function CompressVideo({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('video:compress.resolution'), title: t('compress.resolution'),
component: ( component: (
<Box> <Box>
{resolutionOptions.map((option) => ( {resolutionOptions.map((option) => (
@ -119,7 +119,7 @@ export default function CompressVideo({ title }: ToolComponentProps) {
) )
}, },
{ {
title: t('video:compress.quality'), title: t('compress.quality'),
component: ( component: (
<Box sx={{ mb: 2 }}> <Box sx={{ mb: 2 }}>
<Slider <Slider
@ -131,9 +131,9 @@ export default function CompressVideo({ title }: ToolComponentProps) {
updateField('crf', typeof value === 'number' ? value : value[0]); updateField('crf', typeof value === 'number' ? value : value[0]);
}} }}
marks={{ marks={{
0: t('video:compress.lossless'), 0: t('compress.lossless'),
23: t('video:compress.default'), 23: t('compress.default'),
51: t('video:compress.worst') 51: t('compress.worst')
}} }}
/> />
</Box> </Box>
@ -162,16 +162,16 @@ export default function CompressVideo({ title }: ToolComponentProps) {
<ToolVideoInput <ToolVideoInput
value={input} value={input}
onChange={setInput} onChange={setInput}
title={t('video:compress.inputTitle')} title={t('compress.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
<ToolFileResult <ToolFileResult
title={t('video:compress.resultTitle')} title={t('compress.resultTitle')}
value={result} value={result}
extension={'mp4'} extension={'mp4'}
loading={loading} loading={loading}
loadingText={t('video:compress.loadingText')} loadingText={t('compress.loadingText')}
/> />
} }
initialValues={initialValues} initialValues={initialValues}

View file

@ -18,7 +18,7 @@ const initialValues: InitialValuesType = {
}; };
export default function CropVideo({ title }: ToolComponentProps) { export default function CropVideo({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('video');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -32,21 +32,21 @@ export default function CropVideo({ title }: ToolComponentProps) {
if (!videoDimensions) return ''; if (!videoDimensions) return '';
if (values.x < 0 || values.y < 0) { if (values.x < 0 || values.y < 0) {
return t('video:cropVideo.errorNonNegativeCoordinates'); return t('cropVideo.errorNonNegativeCoordinates');
} }
if (values.width <= 0 || values.height <= 0) { if (values.width <= 0 || values.height <= 0) {
return t('video:cropVideo.errorPositiveDimensions'); return t('cropVideo.errorPositiveDimensions');
} }
if (values.x + values.width > videoDimensions.width) { if (values.x + values.width > videoDimensions.width) {
return t('video:cropVideo.errorBeyondWidth', { return t('cropVideo.errorBeyondWidth', {
width: videoDimensions.width width: videoDimensions.width
}); });
} }
if (values.y + values.height > videoDimensions.height) { if (values.y + values.height > videoDimensions.height) {
return t('video:cropVideo.errorBeyondHeight', { return t('cropVideo.errorBeyondHeight', {
height: videoDimensions.height height: videoDimensions.height
}); });
} }
@ -74,7 +74,7 @@ export default function CropVideo({ title }: ToolComponentProps) {
setResult(croppedFile); setResult(croppedFile);
} catch (error) { } catch (error) {
console.error('Error cropping video:', error); console.error('Error cropping video:', error);
setProcessingError(t('video:cropVideo.errorCroppingVideo')); setProcessingError(t('cropVideo.errorCroppingVideo'));
} finally { } finally {
setLoading(false); setLoading(false);
} }
@ -90,26 +90,26 @@ export default function CropVideo({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('video:cropVideo.videoInformation'), title: t('cropVideo.videoInformation'),
component: ( component: (
<Box> <Box>
{videoDimensions ? ( {videoDimensions ? (
<Typography variant="body2" sx={{ mb: 2 }}> <Typography variant="body2" sx={{ mb: 2 }}>
{t('video:cropVideo.videoDimensions', { {t('cropVideo.videoDimensions', {
width: videoDimensions.width, width: videoDimensions.width,
height: videoDimensions.height height: videoDimensions.height
})} })}
</Typography> </Typography>
) : ( ) : (
<Typography variant="body2" sx={{ mb: 2 }}> <Typography variant="body2" sx={{ mb: 2 }}>
{t('video:cropVideo.loadVideoForDimensions')} {t('cropVideo.loadVideoForDimensions')}
</Typography> </Typography>
)} )}
</Box> </Box>
) )
}, },
{ {
title: t('video:cropVideo.cropCoordinates'), title: t('cropVideo.cropCoordinates'),
component: ( component: (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}> <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
{processingError && ( {processingError && (
@ -119,7 +119,7 @@ export default function CropVideo({ title }: ToolComponentProps) {
)} )}
<Box sx={{ display: 'flex', gap: 2 }}> <Box sx={{ display: 'flex', gap: 2 }}>
<TextField <TextField
label={t('video:cropVideo.xCoordinate')} label={t('cropVideo.xCoordinate')}
type="number" type="number"
value={values.x} value={values.x}
onChange={(e) => updateField('x', parseInt(e.target.value) || 0)} onChange={(e) => updateField('x', parseInt(e.target.value) || 0)}
@ -127,7 +127,7 @@ export default function CropVideo({ title }: ToolComponentProps) {
inputProps={{ min: 0 }} inputProps={{ min: 0 }}
/> />
<TextField <TextField
label={t('video:cropVideo.yCoordinate')} label={t('cropVideo.yCoordinate')}
type="number" type="number"
value={values.y} value={values.y}
onChange={(e) => updateField('y', parseInt(e.target.value) || 0)} onChange={(e) => updateField('y', parseInt(e.target.value) || 0)}
@ -137,7 +137,7 @@ export default function CropVideo({ title }: ToolComponentProps) {
</Box> </Box>
<Box sx={{ display: 'flex', gap: 2 }}> <Box sx={{ display: 'flex', gap: 2 }}>
<TextField <TextField
label={t('video:cropVideo.width')} label={t('cropVideo.width')}
type="number" type="number"
value={values.width} value={values.width}
onChange={(e) => onChange={(e) =>
@ -147,7 +147,7 @@ export default function CropVideo({ title }: ToolComponentProps) {
inputProps={{ min: 1 }} inputProps={{ min: 1 }}
/> />
<TextField <TextField
label={t('video:cropVideo.height')} label={t('cropVideo.height')}
type="number" type="number"
value={values.height} value={values.height}
onChange={(e) => onChange={(e) =>
@ -189,9 +189,7 @@ export default function CropVideo({ title }: ToolComponentProps) {
}) })
.catch((error) => { .catch((error) => {
console.error('Error getting video dimensions:', error); console.error('Error getting video dimensions:', error);
setProcessingError( setProcessingError(t('cropVideo.errorLoadingDimensions'));
t('video:cropVideo.errorLoadingDimensions')
);
}); });
} else { } else {
setVideoDimensions(null); setVideoDimensions(null);
@ -199,20 +197,20 @@ export default function CropVideo({ title }: ToolComponentProps) {
} }
setInput(video); setInput(video);
}} }}
title={t('video:cropVideo.inputTitle')} title={t('cropVideo.inputTitle')}
/> />
)} )}
resultComponent={ resultComponent={
loading ? ( loading ? (
<ToolFileResult <ToolFileResult
title={t('video:cropVideo.croppingVideo')} title={t('cropVideo.croppingVideo')}
value={null} value={null}
loading={true} loading={true}
extension={''} extension={''}
/> />
) : ( ) : (
<ToolFileResult <ToolFileResult
title={t('video:cropVideo.resultTitle')} title={t('cropVideo.resultTitle')}
value={result} value={result}
extension={'mp4'} extension={'mp4'}
/> />

View file

@ -31,7 +31,7 @@ const orientationOptions: { value: FlipOrientation; label: string }[] = [
]; ];
export default function FlipVideo({ title }: ToolComponentProps) { export default function FlipVideo({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('video');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -60,7 +60,7 @@ export default function FlipVideo({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('video:flip.orientation'), title: t('flip.orientation'),
component: ( component: (
<Box> <Box>
{orientationOptions.map((orientationOption) => ( {orientationOptions.map((orientationOption) => (
@ -86,20 +86,20 @@ export default function FlipVideo({ title }: ToolComponentProps) {
<ToolVideoInput <ToolVideoInput
value={input} value={input}
onChange={setInput} onChange={setInput}
title={t('video:flip.inputTitle')} title={t('flip.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
loading ? ( loading ? (
<ToolFileResult <ToolFileResult
title={t('video:flip.flippingVideo')} title={t('flip.flippingVideo')}
value={null} value={null}
loading={true} loading={true}
extension={''} extension={''}
/> />
) : ( ) : (
<ToolFileResult <ToolFileResult
title={t('video:flip.resultTitle')} title={t('flip.resultTitle')}
value={result} value={result}
extension={'mp4'} extension={'mp4'}
/> />

View file

@ -75,5 +75,12 @@
"title": "Crop Video", "title": "Crop Video",
"description": "This tool allows you to crop video files to remove unwanted areas. You can specify the crop area by setting the X, Y coordinates and width, height dimensions." "description": "This tool allows you to crop video files to remove unwanted areas. You can specify the crop area by setting the X, Y coordinates and width, height dimensions."
} }
},
"trim": {
"timestamps": "Timestamps",
"startTime": "Start Time",
"endTime": "End Time",
"inputTitle": "Input Video",
"resultTitle": "Trimmed Video"
} }
} }

View file

@ -22,7 +22,7 @@ const validationSchema = Yup.object({
}); });
export default function Loop({ title, longDescription }: ToolComponentProps) { export default function Loop({ title, longDescription }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('video');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -45,7 +45,7 @@ export default function Loop({ title, longDescription }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('video:loop.loops'), title: t('loop.loops'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
@ -53,7 +53,7 @@ export default function Loop({ title, longDescription }: ToolComponentProps) {
updateNumberField(value, 'loops', updateField) updateNumberField(value, 'loops', updateField)
} }
value={values.loops} value={values.loops}
label={t('video:loop.numberOfLoops')} label={t('loop.numberOfLoops')}
/> />
</Box> </Box>
) )
@ -68,14 +68,14 @@ export default function Loop({ title, longDescription }: ToolComponentProps) {
loading ? ( loading ? (
<ToolFileResult <ToolFileResult
value={null} value={null}
title={t('video:loop.loopingVideo')} title={t('loop.loopingVideo')}
loading={true} loading={true}
extension={''} extension={''}
/> />
) : ( ) : (
<ToolFileResult <ToolFileResult
value={result} value={result}
title={t('video:loop.resultTitle')} title={t('loop.resultTitle')}
extension={'mp4'} extension={'mp4'}
/> />
) )
@ -86,7 +86,7 @@ export default function Loop({ title, longDescription }: ToolComponentProps) {
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('video:loop.toolInfo.title', { title }), title: t('loop.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
/> />

View file

@ -28,7 +28,7 @@ const angleOptions: { value: RotationAngle; label: string }[] = [
{ value: 270, label: '270° (90° Counter-clockwise)' } { value: 270, label: '270° (90° Counter-clockwise)' }
]; ];
export default function RotateVideo({ title }: ToolComponentProps) { export default function RotateVideo({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('video');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -57,7 +57,7 @@ export default function RotateVideo({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('video:rotate.rotation'), title: t('rotate.rotation'),
component: ( component: (
<Box> <Box>
{angleOptions.map((angleOption) => ( {angleOptions.map((angleOption) => (
@ -83,20 +83,20 @@ export default function RotateVideo({ title }: ToolComponentProps) {
<ToolVideoInput <ToolVideoInput
value={input} value={input}
onChange={setInput} onChange={setInput}
title={t('video:rotate.inputTitle')} title={t('rotate.inputTitle')}
/> />
} }
resultComponent={ resultComponent={
loading ? ( loading ? (
<ToolFileResult <ToolFileResult
title={t('video:rotate.rotatingVideo')} title={t('rotate.rotatingVideo')}
value={null} value={null}
loading={true} loading={true}
extension={''} extension={''}
/> />
) : ( ) : (
<ToolFileResult <ToolFileResult
title={t('video:rotate.resultTitle')} title={t('rotate.resultTitle')}
value={result} value={result}
extension={'mp4'} extension={'mp4'}
/> />

View file

@ -29,7 +29,7 @@ const validationSchema = Yup.object({
}); });
export default function TrimVideo({ title }: ToolComponentProps) { export default function TrimVideo({ title }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('video');
const [input, setInput] = useState<File | null>(null); const [input, setInput] = useState<File | null>(null);
const [result, setResult] = useState<File | null>(null); const [result, setResult] = useState<File | null>(null);
@ -87,7 +87,7 @@ export default function TrimVideo({ title }: ToolComponentProps) {
updateField updateField
}) => [ }) => [
{ {
title: t('video:trim.timestamps'), title: t('trim.timestamps'),
component: ( component: (
<Box> <Box>
<TextFieldWithDesc <TextFieldWithDesc
@ -95,7 +95,7 @@ export default function TrimVideo({ title }: ToolComponentProps) {
updateNumberField(value, 'trimStart', updateField) updateNumberField(value, 'trimStart', updateField)
} }
value={values.trimStart} value={values.trimStart}
label={t('video:trim.startTime')} label={t('trim.startTime')}
sx={{ mb: 2, backgroundColor: 'background.paper' }} sx={{ mb: 2, backgroundColor: 'background.paper' }}
/> />
<TextFieldWithDesc <TextFieldWithDesc
@ -103,7 +103,7 @@ export default function TrimVideo({ title }: ToolComponentProps) {
updateNumberField(value, 'trimEnd', updateField) updateNumberField(value, 'trimEnd', updateField)
} }
value={values.trimEnd} value={values.trimEnd}
label={t('video:trim.endTime')} label={t('trim.endTime')}
/> />
</Box> </Box>
) )
@ -118,7 +118,7 @@ export default function TrimVideo({ title }: ToolComponentProps) {
<ToolVideoInput <ToolVideoInput
value={input} value={input}
onChange={setInput} onChange={setInput}
title={t('video:trim.inputTitle')} title={t('trim.inputTitle')}
showTrimControls={true} showTrimControls={true}
onTrimChange={(trimStart, trimEnd) => { onTrimChange={(trimStart, trimEnd) => {
setFieldValue('trimStart', trimStart); setFieldValue('trimStart', trimStart);
@ -131,7 +131,7 @@ export default function TrimVideo({ title }: ToolComponentProps) {
}} }}
resultComponent={ resultComponent={
<ToolFileResult <ToolFileResult
title={t('video:trim.resultTitle')} title={t('trim.resultTitle')}
value={result} value={result}
extension={'mp4'} extension={'mp4'}
/> />

View file

@ -1,4 +1,3 @@
import { Box } from '@mui/material';
import React, { useState } from 'react'; import React, { useState } from 'react';
import ToolContent from '@components/ToolContent'; import ToolContent from '@components/ToolContent';
import { ToolComponentProps } from '@tools/defineTool'; import { ToolComponentProps } from '@tools/defineTool';
@ -25,7 +24,7 @@ export default function XmlBeautifier({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('xml');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -39,15 +38,14 @@ export default function XmlBeautifier({
input={input} input={input}
inputComponent={ inputComponent={
<ToolTextInput <ToolTextInput
title={t('xml:beautifier.inputTitle')} title={t('xmlBeautifier.inputTitle')}
value={input} value={input}
onChange={setInput} onChange={setInput}
placeholder={t('xml:beautifier.placeholder')}
/> />
} }
resultComponent={ resultComponent={
<ToolTextResult <ToolTextResult
title={t('xml:beautifier.resultTitle')} title={t('xmlBeautifier.resultTitle')}
value={result} value={result}
extension="xml" extension="xml"
/> />
@ -58,7 +56,7 @@ export default function XmlBeautifier({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('xml:beautifier.toolInfo.title', { title }), title: t('xmlBeautifier.toolInfo.title', { title }),
description: longDescription description: longDescription
}} }}
/> />

View file

@ -32,7 +32,7 @@ export default function XmlValidator({
title, title,
longDescription longDescription
}: ToolComponentProps) { }: ToolComponentProps) {
const { t } = useTranslation(); const { t } = useTranslation('xml');
const [input, setInput] = useState<string>(''); const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>(''); const [result, setResult] = useState<string>('');
@ -48,7 +48,7 @@ export default function XmlValidator({
<ToolTextInput <ToolTextInput
value={input} value={input}
onChange={setInput} onChange={setInput}
placeholder={t('xml:xmlValidator.placeholder')} placeholder={t('xmlValidator.placeholder')}
/> />
} }
resultComponent={<ToolTextResult value={result} extension="txt" />} resultComponent={<ToolTextResult value={result} extension="txt" />}
@ -58,8 +58,8 @@ export default function XmlValidator({
setInput={setInput} setInput={setInput}
compute={compute} compute={compute}
toolInfo={{ toolInfo={{
title: t('xml:xmlValidator.toolInfo.title'), title: t('xmlValidator.toolInfo.title'),
description: t('xml:xmlValidator.toolInfo.description') description: t('xmlValidator.toolInfo.description')
}} }}
/> />
); );