fix: i18n tsc

This commit is contained in:
Ibrahima G. Coulibaly
2025-07-13 13:01:02 +01:00
parent 21c4f44d4e
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
.aider*
.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 { darkTheme, lightTheme } from '../config/muiConfig';
import ScrollToTopButton from './ScrollToTopButton';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18n';
export type Mode = 'dark' | 'light' | 'system';
@@ -44,32 +46,34 @@ function App() {
}, []);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<SnackbarProvider
maxSnack={5}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
>
<CustomSnackBarProvider>
<BrowserRouter>
<Navbar
mode={mode}
onChangeMode={() => {
setMode((prev) => nextMode(prev));
localStorage.setItem('theme', nextMode(mode));
}}
/>
<Suspense fallback={<Loading />}>
<AppRoutes />
</Suspense>
</BrowserRouter>
</CustomSnackBarProvider>
</SnackbarProvider>
<ScrollToTopButton />
</ThemeProvider>
<I18nextProvider i18n={i18n}>
<ThemeProvider theme={theme}>
<CssBaseline />
<SnackbarProvider
maxSnack={5}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
>
<CustomSnackBarProvider>
<BrowserRouter>
<Navbar
mode={mode}
onChangeMode={() => {
setMode((prev) => nextMode(prev));
localStorage.setItem('theme', nextMode(mode));
}}
/>
<Suspense fallback={<Loading />}>
<AppRoutes />
</Suspense>
</BrowserRouter>
</CustomSnackBarProvider>
</SnackbarProvider>
<ScrollToTopButton />
</ThemeProvider>
</I18nextProvider>
);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -41,7 +41,7 @@ const splitOperators: {
];
export default function FindUnique({ title }: ToolComponentProps) {
const { t } = useTranslation();
const { t } = useTranslation('list');
const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>('');
const compute = (optionsValues: typeof initialValues, input: any) => {
@@ -81,18 +81,18 @@ export default function FindUnique({ title }: ToolComponentProps) {
input={input}
inputComponent={
<ToolTextInput
title={t('list:group.inputTitle')}
title={t('group.inputTitle')}
value={input}
onChange={setInput}
/>
}
resultComponent={
<ToolTextResult title={t('list:group.resultTitle')} value={result} />
<ToolTextResult title={t('group.resultTitle')} value={result} />
}
initialValues={initialValues}
getGroups={({ values, updateField }) => [
{
title: t('list:group.inputItemSeparator'),
title: t('group.inputItemSeparator'),
component: (
<Box>
{splitOperators.map(({ title, description, type }) => (
@@ -107,7 +107,7 @@ export default function FindUnique({ title }: ToolComponentProps) {
/>
))}
<TextFieldWithDesc
description={t('list:group.splitSeparatorDescription')}
description={t('group.splitSeparatorDescription')}
value={values.splitSeparator}
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: (
<Box>
<TextFieldWithDesc
value={values.groupNumber}
description={t('list:group.groupNumberDescription')}
description={t('group.groupNumberDescription')}
type={'number'}
onOwnChange={(value) =>
updateField('groupNumber', formatNumber(value, 1))
@@ -128,46 +128,46 @@ export default function FindUnique({ title }: ToolComponentProps) {
/>
<TextFieldWithDesc
value={values.itemSeparator}
description={t('list:group.itemSeparatorDescription')}
description={t('group.itemSeparatorDescription')}
onOwnChange={(value) => updateField('itemSeparator', value)}
/>
<TextFieldWithDesc
value={values.groupSeparator}
description={t('list:group.groupSeparatorDescription')}
description={t('group.groupSeparatorDescription')}
onOwnChange={(value) => updateField('groupSeparator', value)}
/>
<TextFieldWithDesc
value={values.leftWrap}
description={t('list:group.leftWrapDescription')}
description={t('group.leftWrapDescription')}
onOwnChange={(value) => updateField('leftWrap', value)}
/>
<TextFieldWithDesc
value={values.rightWrap}
description={t('list:group.rightWrapDescription')}
description={t('group.rightWrapDescription')}
onOwnChange={(value) => updateField('rightWrap', value)}
/>
</Box>
)
},
{
title: t('list:group.emptyItemsAndPadding'),
title: t('group.emptyItemsAndPadding'),
component: (
<Box>
<CheckboxWithDesc
title={t('list:group.deleteEmptyItems')}
description={t('list:group.deleteEmptyItemsDescription')}
title={t('group.deleteEmptyItems')}
description={t('group.deleteEmptyItemsDescription')}
checked={values.deleteEmptyItems}
onChange={(value) => updateField('deleteEmptyItems', value)}
/>
<CheckboxWithDesc
title={t('list:group.padNonFullGroups')}
description={t('list:group.padNonFullGroupsDescription')}
title={t('group.padNonFullGroups')}
description={t('group.padNonFullGroupsDescription')}
checked={values.padNonFullGroup}
onChange={(value) => updateField('padNonFullGroup', value)}
/>
<TextFieldWithDesc
value={values.paddingChar}
description={t('list:group.paddingCharDescription')}
description={t('group.paddingCharDescription')}
onOwnChange={(value) => updateField('paddingChar', value)}
/>
</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": {
"title": "Reverse 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."
}
},
"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": {
"title": "Find Unique",
"description": "Find unique items in a list.",
"inputTitle": "Input list",
"resultTitle": "Unique items",
"uniqueOptions": "Unique Options",
"showUnique": "Show Unique",
"showUniqueDescription": "Show only unique items",
"showDuplicates": "Show Duplicates",
"showDuplicatesDescription": "Show only duplicate items",
"toolInfo": {
"title": "Find Unique",
"description": "This tool allows you to find unique items in a list. You can show unique items or duplicate items."
}
"inputTitle": "Input List",
"resultTitle": "Unique Items",
"inputListDelimiter": "Input List Delimiter",
"delimiterDescription": "Set a delimiting symbol or regular expression.",
"outputListDelimiter": "Output List Delimiter",
"trimItems": "Trim List Items",
"trimItemsDescription": "Remove leading and trailing spaces before comparing items.",
"skipEmptyItems": "Skip Empty Items",
"skipEmptyItemsDescription": "Don't include the empty list items in the output.",
"uniqueItemOptions": "Unique Item Options",
"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": {
"title": "Shuffle List",
@@ -111,5 +60,104 @@
"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."
}
},
"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) {
const { t } = useTranslation();
const { t } = useTranslation('list');
const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>('');
@@ -121,7 +121,7 @@ export default function Reverse({ title }: ToolComponentProps) {
updateField
}) => [
{
title: t('list:reverse.splitterMode'),
title: t('reverse.splitterMode'),
component: (
<Box>
{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: (
<Box>
<TextFieldWithDesc
description={t('list:reverse.itemSeparatorDescription')}
description={t('reverse.itemSeparatorDescription')}
value={values.splitSeparator}
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: (
<Box>
<TextFieldWithDesc
description={t('list:reverse.outputSeparatorDescription')}
description={t('reverse.outputSeparatorDescription')}
value={values.joinSeparator}
onOwnChange={(val) => updateField('joinSeparator', val)}
/>
@@ -179,17 +179,17 @@ export default function Reverse({ title }: ToolComponentProps) {
setInput={setInput}
inputComponent={
<ToolTextInput
title={t('list:reverse.inputTitle')}
title={t('reverse.inputTitle')}
value={input}
onChange={setInput}
/>
}
resultComponent={
<ToolTextResult title={t('list:reverse.resultTitle')} value={result} />
<ToolTextResult title={t('reverse.resultTitle')} value={result} />
}
toolInfo={{
title: t('list:reverse.toolInfo.title'),
description: t('list:reverse.toolInfo.description')
title: t('reverse.toolInfo.title'),
description: t('reverse.toolInfo.description')
}}
exampleCards={exampleCards}
/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ const initialValues = {
};
export default function ToMorse() {
const { t } = useTranslation();
const { t } = useTranslation('string');
const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>('');
const computeOptions = (optionsValues: typeof initialValues, input: any) => {
@@ -22,34 +22,31 @@ export default function ToMorse() {
return (
<ToolContent
title={t('string:toMorse.title')}
title={t('toMorse.title')}
initialValues={initialValues}
compute={computeOptions}
input={input}
setInput={setInput}
inputComponent={<ToolTextInput value={input} onChange={setInput} />}
resultComponent={
<ToolTextResult
title={t('string:toMorse.resultTitle')}
value={result}
/>
<ToolTextResult title={t('toMorse.resultTitle')} value={result} />
}
getGroups={({ values, updateField }) => [
{
title: t('string:toMorse.shortSignal'),
title: t('toMorse.shortSignal'),
component: (
<TextFieldWithDesc
description={t('string:toMorse.dotSymbolDescription')}
description={t('toMorse.dotSymbolDescription')}
value={values.dotSymbol}
onOwnChange={(val) => updateField('dotSymbol', val)}
/>
)
},
{
title: t('string:toMorse.longSignal'),
title: t('toMorse.longSignal'),
component: (
<TextFieldWithDesc
description={t('string:toMorse.dashSymbolDescription')}
description={t('toMorse.dashSymbolDescription')}
value={values.dashSymbol}
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) {
const { t } = useTranslation();
const { t } = useTranslation('string');
const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>('');
@@ -81,31 +81,31 @@ export default function Truncate({ title }: ToolComponentProps) {
updateField
}) => [
{
title: t('string:truncate.truncationSide'),
title: t('truncate.truncationSide'),
component: (
<Box>
<SimpleRadio
onClick={() => updateField('truncationSide', 'right')}
checked={values.truncationSide === 'right'}
title={t('string:truncate.rightSideTruncation')}
description={t('string:truncate.rightSideDescription')}
title={t('truncate.rightSideTruncation')}
description={t('truncate.rightSideDescription')}
/>
<SimpleRadio
onClick={() => updateField('truncationSide', 'left')}
checked={values.truncationSide === 'left'}
title={t('string:truncate.leftSideTruncation')}
description={t('string:truncate.leftSideDescription')}
title={t('truncate.leftSideTruncation')}
description={t('truncate.leftSideDescription')}
/>
</Box>
)
},
{
title: t('string:truncate.lengthAndLines'),
title: t('truncate.lengthAndLines'),
component: (
<Box>
<TextFieldWithDesc
description={t('string:truncate.maxLengthDescription')}
placeholder={t('string:truncate.numberPlaceholder')}
description={t('truncate.maxLengthDescription')}
placeholder={t('truncate.numberPlaceholder')}
value={values.maxLength}
onOwnChange={(val) => updateField('maxLength', val)}
type={'number'}
@@ -113,25 +113,25 @@ export default function Truncate({ title }: ToolComponentProps) {
<CheckboxWithDesc
onChange={(val) => updateField('lineByLine', val)}
checked={values.lineByLine}
title={t('string:truncate.lineByLineTruncating')}
description={t('string:truncate.lineByLineDescription')}
title={t('truncate.lineByLineTruncating')}
description={t('truncate.lineByLineDescription')}
/>
</Box>
)
},
{
title: t('string:truncate.suffixAndAffix'),
title: t('truncate.suffixAndAffix'),
component: (
<Box>
<CheckboxWithDesc
onChange={(val) => updateField('addIndicator', val)}
checked={values.addIndicator}
title={t('string:truncate.addTruncationIndicator')}
title={t('truncate.addTruncationIndicator')}
description={''}
/>
<TextFieldWithDesc
description={t('string:truncate.indicatorDescription')}
placeholder={t('string:truncate.charactersPlaceholder')}
description={t('truncate.indicatorDescription')}
placeholder={t('truncate.charactersPlaceholder')}
value={values.indicator}
onOwnChange={(val) => updateField('indicator', val)}
type={'text'}
@@ -151,20 +151,17 @@ export default function Truncate({ title }: ToolComponentProps) {
setInput={setInput}
inputComponent={
<ToolTextInput
title={t('string:truncate.inputTitle')}
title={t('truncate.inputTitle')}
value={input}
onChange={setInput}
/>
}
resultComponent={
<ToolTextResult
title={t('string:truncate.resultTitle')}
value={result}
/>
<ToolTextResult title={t('truncate.resultTitle')} value={result} />
}
toolInfo={{
title: t('string:truncate.toolInfo.title'),
description: t('string:truncate.toolInfo.description')
title: t('truncate.toolInfo.title'),
description: t('truncate.toolInfo.description')
}}
exampleCards={exampleCards}
/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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