Compare commits

...

7 Commits

Author SHA1 Message Date
Ibrahima G. Coulibaly
7cec37b7fe
Merge pull request #297 from iib0011/fix-278
Fix 278
2025-12-04 19:13:05 +01:00
Chesterkxng
80662c59c6 locales: desc minor changes 2025-11-30 18:00:03 +01:00
Chesterkxng
009a0dd6ad chore: checkbox used instead of switch 2025-11-30 17:59:06 +01:00
Chesterkxng
6ad57674ea chore: keywords added to list 2025-11-30 17:57:48 +01:00
Chesterkxng
ef034f2b8b chore: void input edge case added to service 2025-11-30 17:56:43 +01:00
Chesterkxng
8cc7986c7f tests: rewritten test file to match main function struct 2025-11-30 17:55:49 +01:00
Learncold
f30aeb45eb Add unicode encoder/decoder tool 2025-11-05 15:12:58 +09:00
7 changed files with 358 additions and 0 deletions

View File

@ -307,5 +307,21 @@
"shortDescription": "Quickly URL-escape a string.",
"title": "String URL encoder"
}
},
"unicode": {
"title": "Unicode Encoder / Decoder",
"inputTitle": "Input",
"resultTitle": "Processed Output",
"optionsTitle": "Mode",
"caseOptionsTitle": "Case Options",
"encode": "Encode",
"decode": "Decode",
"uppercase": "Uppercase Hex",
"description": "Convert text to Unicode escape sequences or decode them back to readable text.",
"shortDescription": "Encode or decode text using Unicode escape sequences.",
"toolInfo": {
"title": "Unicode Encoder / Decoder",
"description": "This tool lets you convert plain text into Unicode escape sequences (e.g., \\uXXXX) and decode Unicode escape sequences back into standard text. You can also choose whether the hexadecimal output is formatted in uppercase or lowercase when encoding."
}
}
}

View File

@ -21,6 +21,7 @@ import { tool as stringCensor } from './censor/meta';
import { tool as stringPasswordGenerator } from './password-generator/meta';
import { tool as stringEncodeUrl } from './url-encode/meta';
import { tool as StringDecodeUrl } from './url-decode/meta';
import { tool as stringUnicode } from './unicode/meta';
export const stringTools = [
stringSplit,
@ -45,5 +46,6 @@ export const stringTools = [
stringPasswordGenerator,
stringEncodeUrl,
StringDecodeUrl,
stringUnicode,
stringHiddenCharacterDetector
];

View File

@ -0,0 +1,123 @@
import { Box } from '@mui/material';
import { useState } from 'react';
import ToolContent from '@components/ToolContent';
import { ToolComponentProps } from '@tools/defineTool';
import ToolTextInput from '@components/input/ToolTextInput';
import ToolTextResult from '@components/result/ToolTextResult';
import { GetGroupsType } from '@components/options/ToolOptions';
import { CardExampleType } from '@components/examples/ToolExamples';
import { unicode } from './service';
import { InitialValuesType } from './types';
import SimpleRadio from '@components/options/SimpleRadio';
import CheckboxWithDesc from '@components/options/CheckboxWithDesc';
import { useTranslation } from 'react-i18next';
const initialValues: InitialValuesType = {
mode: 'encode',
uppercase: false
};
const exampleCards: CardExampleType<InitialValuesType>[] = [
{
title: 'Encode to Unicode Escape',
description: 'Encode plain text to Unicode escape sequences.',
sampleText: 'Hello, World!',
sampleResult:
'\\u0048\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064\\u0021',
sampleOptions: {
mode: 'encode',
uppercase: false
}
},
{
title: 'Encode to Unicode Escape (Uppercase)',
description: 'Encode plain text to uppercase Unicode escape sequences.',
sampleText: 'Hello, World!',
sampleResult:
'\\u0048\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064\\u0021'.toUpperCase(),
sampleOptions: {
mode: 'encode',
uppercase: true
}
},
{
title: 'Decode Unicode Escape',
description: 'Decode Unicode escape sequences back to plain text.',
sampleText:
'\\u0048\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064\\u0021',
sampleResult: 'Hello, World!',
sampleOptions: {
mode: 'decode',
uppercase: false
}
}
];
export default function Unicode({ title }: ToolComponentProps) {
const { t } = useTranslation('string');
const [input, setInput] = useState<string>('');
const [result, setResult] = useState<string>('');
const compute = (values: InitialValuesType, input: string) => {
setResult(unicode(input, values));
};
const getGroups: GetGroupsType<InitialValuesType> = ({
values,
updateField
}) => [
{
title: t('unicode.optionsTitle'),
component: (
<Box>
<SimpleRadio
onClick={() => updateField('mode', 'encode')}
checked={values.mode === 'encode'}
title={t('unicode.encode')}
/>
<SimpleRadio
onClick={() => updateField('mode', 'decode')}
checked={values.mode === 'decode'}
title={t('unicode.decode')}
/>
</Box>
)
},
{
title: t('unicode.caseOptionsTitle'),
component: (
<Box>
<CheckboxWithDesc
checked={values.uppercase}
onChange={(value) => updateField('uppercase', value)}
title={t('unicode.uppercase')}
/>
</Box>
)
}
];
return (
<ToolContent
title={title}
input={input}
inputComponent={
<ToolTextInput
value={input}
onChange={setInput}
title={t('unicode.inputTitle')}
/>
}
resultComponent={
<ToolTextResult value={result} title={t('unicode.resultTitle')} />
}
initialValues={initialValues}
exampleCards={exampleCards}
getGroups={getGroups}
setInput={setInput}
compute={compute}
toolInfo={{
title: t('unicode.toolInfo.title'),
description: t('unicode.toolInfo.description')
}}
/>
);
}

View File

@ -0,0 +1,14 @@
import { defineTool } from '@tools/defineTool';
import { lazy } from 'react';
export const tool = defineTool('string', {
i18n: {
name: 'string:unicode.title',
description: 'string:unicode.description',
shortDescription: 'string:unicode.shortDescription'
},
path: 'unicode',
icon: 'mdi:unicode',
keywords: ['unicode', 'encode', 'decode', 'escape', 'text'],
component: lazy(() => import('./index'))
});

View File

@ -0,0 +1,21 @@
import { InitialValuesType } from './types';
export function unicode(input: string, options: InitialValuesType): string {
if (!input) return '';
if (options.mode === 'encode') {
let result = '';
for (let i = 0; i < input.length; i++) {
let hex = input.charCodeAt(i).toString(16);
hex = ('0000' + hex).slice(-4);
if (options.uppercase) {
hex = hex.toUpperCase();
}
result += '\\u' + hex;
}
return result;
} else {
return input.replace(/\\u([\dA-Fa-f]{4})/g, (match, grp) => {
return String.fromCharCode(parseInt(grp, 16));
});
}
}

View File

@ -0,0 +1,4 @@
export type InitialValuesType = {
mode: 'encode' | 'decode';
uppercase: boolean;
};

View File

@ -0,0 +1,178 @@
import { expect, describe, it } from 'vitest';
import { unicode } from './service';
describe('unicode', () => {
it('should encode an English string to lowercase hex correctly', () => {
const input = 'Hello, World!';
const result = unicode(input, { mode: 'encode', uppercase: false });
expect(result).toBe(
'\\u0048\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064\\u0021'
);
});
it('should encode an English string to uppercase hex correctly', () => {
const input = 'Hello, World!';
const result = unicode(input, { mode: 'encode', uppercase: true });
expect(result).toBe(
'\\u0048\\u0065\\u006C\\u006C\\u006F\\u002C\\u0020\\u0057\\u006F\\u0072\\u006C\\u0064\\u0021'
);
});
it('should decode an English lowercase hex string correctly', () => {
const input =
'\\u0048\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('Hello, World!');
});
it('should decode an English uppercase hex string correctly', () => {
const input =
'\\u0048\\u0065\\u006C\\u006C\\u006F\\u002C\\u0020\\u0057\\u006F\\u0072\\u006C\\u0064\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('Hello, World!');
});
it('should encode a Korean string to lowercase hex correctly', () => {
const input = '안녕하세요, 세계!';
const result = unicode(input, { mode: 'encode', uppercase: false });
expect(result).toBe(
'\\uc548\\ub155\\ud558\\uc138\\uc694\\u002c\\u0020\\uc138\\uacc4\\u0021'
);
});
it('should encode a Korean string to uppercase hex correctly', () => {
const input = '안녕하세요, 세계!';
const result = unicode(input, { mode: 'encode', uppercase: true });
expect(result).toBe(
'\\uC548\\uB155\\uD558\\uC138\\uC694\\u002C\\u0020\\uC138\\uACC4\\u0021'
);
});
it('should decode a Korean lowercase hex string correctly', () => {
const input =
'\\uc548\\ub155\\ud558\\uc138\\uc694\\u002c\\u0020\\uc138\\uacc4\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('안녕하세요, 세계!');
});
it('should decode a Korean uppercase hex string correctly', () => {
const input =
'\\uC548\\uB155\\uD558\\uC138\\uC694\\u002C\\u0020\\uC138\\uACC4\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('안녕하세요, 세계!');
});
it('should encode a Japanese string to lowercase hex correctly', () => {
const input = 'こんにちは、世界!';
const result = unicode(input, { mode: 'encode', uppercase: false });
expect(result).toBe(
'\\u3053\\u3093\\u306b\\u3061\\u306f\\u3001\\u4e16\\u754c\\uff01'
);
});
it('should encode a Japanese string to uppercase hex correctly', () => {
const input = 'こんにちは、世界!';
const result = unicode(input, { mode: 'encode', uppercase: true });
expect(result).toBe(
'\\u3053\\u3093\\u306B\\u3061\\u306F\\u3001\\u4E16\\u754C\\uFF01'
);
});
it('should decode a Japanese lowercase hex string correctly', () => {
const input =
'\\u3053\\u3093\\u306b\\u3061\\u306f\\u3001\\u4e16\\u754c\\uff01';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('こんにちは、世界!');
});
it('should decode a Japanese uppercase hex string correctly', () => {
const input =
'\\u3053\\u3093\\u306B\\u3061\\u306F\\u3001\\u4E16\\u754C\\uFF01';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('こんにちは、世界!');
});
it('should encode a Chinese string to lowercase hex correctly', () => {
const input = '你好,世界!';
const result = unicode(input, { mode: 'encode', uppercase: false });
expect(result).toBe('\\u4f60\\u597d\\uff0c\\u4e16\\u754c\\uff01');
});
it('should encode a Chinese string to uppercase hex correctly', () => {
const input = '你好,世界!';
const result = unicode(input, { mode: 'encode', uppercase: true });
expect(result).toBe('\\u4F60\\u597D\\uFF0C\\u4E16\\u754C\\uFF01');
});
it('should decode a Chinese lowercase hex string correctly', () => {
const input = '\\u4f60\\u597d\\uff0c\\u4e16\\u754c\\uff01';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('你好,世界!');
});
it('should decode a Chinese uppercase hex string correctly', () => {
const input = '\\u4F60\\u597D\\uFF0C\\u4E16\\u754C\\uFF01';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('你好,世界!');
});
it('should encode a Russian string to lowercase hex correctly', () => {
const input = 'Привет, мир!';
const result = unicode(input, { mode: 'encode', uppercase: false });
expect(result).toBe(
'\\u041f\\u0440\\u0438\\u0432\\u0435\\u0442\\u002c\\u0020\\u043c\\u0438\\u0440\\u0021'
);
});
it('should encode a Russian string to uppercase hex correctly', () => {
const input = 'Привет, мир!';
const result = unicode(input, { mode: 'encode', uppercase: true });
expect(result).toBe(
'\\u041F\\u0440\\u0438\\u0432\\u0435\\u0442\\u002C\\u0020\\u043C\\u0438\\u0440\\u0021'
);
});
it('should decode a Russian lowercase hex string correctly', () => {
const input =
'\\u041f\\u0440\\u0438\\u0432\\u0435\\u0442\\u002c\\u0020\\u043c\\u0438\\u0440\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('Привет, мир!');
});
it('should decode a Russian uppercase hex string correctly', () => {
const input =
'\\u041F\\u0440\\u0438\\u0432\\u0435\\u0442\\u002C\\u0020\\u043C\\u0438\\u0440\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('Привет, мир!');
});
it('should encode a Spanish string to lowercase hex correctly', () => {
const input = '¡Hola, Mundo!';
const result = unicode(input, { mode: 'encode', uppercase: false });
expect(result).toBe(
'\\u00a1\\u0048\\u006f\\u006c\\u0061\\u002c\\u0020\\u004d\\u0075\\u006e\\u0064\\u006f\\u0021'
);
});
it('should encode a Spanish string to uppercase hex correctly', () => {
const input = '¡Hola, Mundo!';
const result = unicode(input, { mode: 'encode', uppercase: true });
expect(result).toBe(
'\\u00A1\\u0048\\u006F\\u006C\\u0061\\u002C\\u0020\\u004D\\u0075\\u006E\\u0064\\u006F\\u0021'
);
});
it('should decode a Spanish lowercase hex string correctly', () => {
const input =
'\\u00a1\\u0048\\u006f\\u006c\\u0061\\u002c\\u0020\\u004d\\u0075\\u006e\\u0064\\u006f\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('¡Hola, Mundo!');
});
it('should decode a Spanish uppercase hex string correctly', () => {
const input =
'\\u00A1\\u0048\\u006F\\u006C\\u0061\\u002C\\u0020\\u004D\\u0075\\u006E\\u0064\\u006F\\u0021';
const result = unicode(input, { mode: 'decode', uppercase: false });
expect(result).toBe('¡Hola, Mundo!');
});
});