From f30aeb45eb180004a871241231490a7482119698 Mon Sep 17 00:00:00 2001 From: Learncold Date: Wed, 5 Nov 2025 15:12:58 +0900 Subject: [PATCH 1/6] Add unicode encoder/decoder tool --- public/locales/en/string.json | 17 ++ src/pages/tools/string/index.ts | 2 + src/pages/tools/string/unicode/index.tsx | 131 +++++++++++++ src/pages/tools/string/unicode/meta.ts | 15 ++ src/pages/tools/string/unicode/service.ts | 28 +++ src/pages/tools/string/unicode/types.ts | 4 + .../string/unicode/unicode.service.test.ts | 178 ++++++++++++++++++ 7 files changed, 375 insertions(+) create mode 100644 src/pages/tools/string/unicode/index.tsx create mode 100644 src/pages/tools/string/unicode/meta.ts create mode 100644 src/pages/tools/string/unicode/service.ts create mode 100644 src/pages/tools/string/unicode/types.ts create mode 100644 src/pages/tools/string/unicode/unicode.service.test.ts diff --git a/public/locales/en/string.json b/public/locales/en/string.json index c6176c1..9037edc 100644 --- a/public/locales/en/string.json +++ b/public/locales/en/string.json @@ -307,5 +307,22 @@ "shortDescription": "Quickly URL-escape a string.", "title": "String URL encoder" } + }, + "unicode": { + "title": "Unicode Encoder/Decoder", + "description": "Encode text to Unicode escape sequences and decode them back.", + "shortDescription": "Encode or decode text using Unicode escape sequences.", + "longDescription": "This tool allows you to encode plain text into Unicode escape sequences (e.g., \\uXXXX) and decode them back. You can choose to output the hexadecimal digits in either uppercase or lowercase for encoding.", + "inputTitle": "Input", + "resultTitle": "Output", + "optionsTitle": "Options", + "caseOptionsTitle": "Case Options", + "encode": "Unicode Encode", + "decode": "Unicode Decode", + "uppercase": "Uppercase Hex", + "toolInfo": { + "title": "What is Unicode Escape?", + "description": "Unicode escape sequences are used to represent characters that may not be available in the character set of the document. They are written as '\\u' followed by four hexadecimal digits." + } } } diff --git a/src/pages/tools/string/index.ts b/src/pages/tools/string/index.ts index 1134b14..ac067c9 100644 --- a/src/pages/tools/string/index.ts +++ b/src/pages/tools/string/index.ts @@ -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 ]; diff --git a/src/pages/tools/string/unicode/index.tsx b/src/pages/tools/string/unicode/index.tsx new file mode 100644 index 0000000..bd74fd1 --- /dev/null +++ b/src/pages/tools/string/unicode/index.tsx @@ -0,0 +1,131 @@ +import { Box, FormControlLabel, Switch } 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 { useTranslation } from 'react-i18next'; + +const initialValues: InitialValuesType = { + mode: 'encode', + uppercase: false +}; + +const exampleCards: CardExampleType[] = [ + { + 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, + longDescription +}: ToolComponentProps) { + const { t } = useTranslation('string'); + const [input, setInput] = useState(''); + const [result, setResult] = useState(''); + + const compute = (values: InitialValuesType, input: string) => { + if (!input) return; + setResult(unicode(input, values.mode === 'encode', values.uppercase)); + }; + + const getGroups: GetGroupsType = ({ + values, + updateField + }) => [ + { + title: t('unicode.optionsTitle'), + component: ( + + updateField('mode', 'encode')} + checked={values.mode === 'encode'} + title={t('unicode.encode')} + /> + updateField('mode', 'decode')} + checked={values.mode === 'decode'} + title={t('unicode.decode')} + /> + + ) + }, + { + title: t('unicode.caseOptionsTitle'), + component: ( + + updateField('uppercase', e.target.checked)} + disabled={values.mode === 'decode'} + /> + } + label={t('unicode.uppercase')} + /> + + ) + } + ]; + return ( + + } + resultComponent={ + + } + initialValues={initialValues} + exampleCards={exampleCards} + getGroups={getGroups} + setInput={setInput} + compute={compute} + toolInfo={{ + title: t('unicode.toolInfo.title'), + description: t('unicode.toolInfo.description') + }} + /> + ); +} diff --git a/src/pages/tools/string/unicode/meta.ts b/src/pages/tools/string/unicode/meta.ts new file mode 100644 index 0000000..069d5fa --- /dev/null +++ b/src/pages/tools/string/unicode/meta.ts @@ -0,0 +1,15 @@ +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', + longDescription: 'string:unicode.longDescription' + }, + path: 'unicode', + icon: 'mdi:unicode', + keywords: ['unicode'], + component: lazy(() => import('./index')) +}); diff --git a/src/pages/tools/string/unicode/service.ts b/src/pages/tools/string/unicode/service.ts new file mode 100644 index 0000000..9943f64 --- /dev/null +++ b/src/pages/tools/string/unicode/service.ts @@ -0,0 +1,28 @@ +import { InitialValuesType } from './types'; + +export function main(input: string, options: InitialValuesType): string { + return input; +} + +export function unicode( + input: string, + encode: boolean, + uppercase: boolean +): string { + if (encode) { + let result = ''; + for (let i = 0; i < input.length; i++) { + let hex = input.charCodeAt(i).toString(16); + hex = ('0000' + hex).slice(-4); + if (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)); + }); + } +} diff --git a/src/pages/tools/string/unicode/types.ts b/src/pages/tools/string/unicode/types.ts new file mode 100644 index 0000000..dd39d11 --- /dev/null +++ b/src/pages/tools/string/unicode/types.ts @@ -0,0 +1,4 @@ +export type InitialValuesType = { + mode: 'encode' | 'decode'; + uppercase: boolean; +}; diff --git a/src/pages/tools/string/unicode/unicode.service.test.ts b/src/pages/tools/string/unicode/unicode.service.test.ts new file mode 100644 index 0000000..97f90a3 --- /dev/null +++ b/src/pages/tools/string/unicode/unicode.service.test.ts @@ -0,0 +1,178 @@ +import { expect, describe, it } from 'vitest'; +import { unicode } from './service'; + +describe('unicode', () => { + it('should encode a English string to lowercase hex correctly', () => { + const input = 'Hello, World!'; + const result = unicode(input, true, false); + expect(result).toBe( + '\\u0048\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064\\u0021' + ); + }); + + it('should encode a English string to uppercase hex correctly', () => { + const input = 'Hello, World!'; + const result = unicode(input, true, true); + expect(result).toBe( + '\\u0048\\u0065\\u006C\\u006C\\u006F\\u002C\\u0020\\u0057\\u006F\\u0072\\u006C\\u0064\\u0021' + ); + }); + + it('should decode a English lowercase hex string correctly', () => { + const input = + '\\u0048\\u0065\\u006c\\u006c\\u006f\\u002c\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064\\u0021'; + const result = unicode(input, false, false); + expect(result).toBe('Hello, World!'); + }); + + it('should decode a English uppercase hex string correctly', () => { + const input = + '\\u0048\\u0065\\u006C\\u006C\\u006F\\u002C\\u0020\\u0057\\u006F\\u0072\\u006C\\u0064\\u0021'; + const result = unicode(input, false, false); + expect(result).toBe('Hello, World!'); + }); + + it('should encode a Korean string to lowercase hex correctly', () => { + const input = '안녕하세요, 세계!'; + const result = unicode(input, true, 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, true, 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, false, 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, false, false); + expect(result).toBe('안녕하세요, 세계!'); + }); + + it('should encode a Japanese string to lowercase hex correctly', () => { + const input = 'こんにちは、世界!'; + const result = unicode(input, true, 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, true, 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, false, 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, false, false); + expect(result).toBe('こんにちは、世界!'); + }); + + it('should encode a Chinese string to lowercase hex correctly', () => { + const input = '你好,世界!'; + const result = unicode(input, true, 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, true, 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, false, 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, false, false); + expect(result).toBe('你好,世界!'); + }); + + it('should encode a Russian string to lowercase hex correctly', () => { + const input = 'Привет, мир!'; + const result = unicode(input, true, 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, true, 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, false, 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, false, false); + expect(result).toBe('Привет, мир!'); + }); + + it('should encode a Spanish string to lowercase hex correctly', () => { + const input = '¡Hola, Mundo!'; + const result = unicode(input, true, 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, true, 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, false, 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, false, false); + expect(result).toBe('¡Hola, Mundo!'); + }); +}); From 8cc7986c7f461faffcfa85c8cb3080dc6a61b6fa Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 30 Nov 2025 17:55:49 +0100 Subject: [PATCH 2/6] tests: rewritten test file to match main function struct --- .../string/unicode/unicode.service.test.ts | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/pages/tools/string/unicode/unicode.service.test.ts b/src/pages/tools/string/unicode/unicode.service.test.ts index 97f90a3..1d43163 100644 --- a/src/pages/tools/string/unicode/unicode.service.test.ts +++ b/src/pages/tools/string/unicode/unicode.service.test.ts @@ -2,39 +2,39 @@ import { expect, describe, it } from 'vitest'; import { unicode } from './service'; describe('unicode', () => { - it('should encode a English string to lowercase hex correctly', () => { + it('should encode an English string to lowercase hex correctly', () => { const input = 'Hello, World!'; - const result = unicode(input, true, false); + 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 a English string to uppercase hex correctly', () => { + it('should encode an English string to uppercase hex correctly', () => { const input = 'Hello, World!'; - const result = unicode(input, true, true); + 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 a English lowercase hex string correctly', () => { + 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, false, false); + const result = unicode(input, { mode: 'decode', uppercase: false }); expect(result).toBe('Hello, World!'); }); - it('should decode a English uppercase hex string correctly', () => { + 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, false, false); + 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, true, false); + const result = unicode(input, { mode: 'encode', uppercase: false }); expect(result).toBe( '\\uc548\\ub155\\ud558\\uc138\\uc694\\u002c\\u0020\\uc138\\uacc4\\u0021' ); @@ -42,7 +42,7 @@ describe('unicode', () => { it('should encode a Korean string to uppercase hex correctly', () => { const input = '안녕하세요, 세계!'; - const result = unicode(input, true, true); + const result = unicode(input, { mode: 'encode', uppercase: true }); expect(result).toBe( '\\uC548\\uB155\\uD558\\uC138\\uC694\\u002C\\u0020\\uC138\\uACC4\\u0021' ); @@ -51,20 +51,20 @@ describe('unicode', () => { 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, false, false); + 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, false, false); + 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, true, false); + const result = unicode(input, { mode: 'encode', uppercase: false }); expect(result).toBe( '\\u3053\\u3093\\u306b\\u3061\\u306f\\u3001\\u4e16\\u754c\\uff01' ); @@ -72,7 +72,7 @@ describe('unicode', () => { it('should encode a Japanese string to uppercase hex correctly', () => { const input = 'こんにちは、世界!'; - const result = unicode(input, true, true); + const result = unicode(input, { mode: 'encode', uppercase: true }); expect(result).toBe( '\\u3053\\u3093\\u306B\\u3061\\u306F\\u3001\\u4E16\\u754C\\uFF01' ); @@ -81,44 +81,44 @@ describe('unicode', () => { it('should decode a Japanese lowercase hex string correctly', () => { const input = '\\u3053\\u3093\\u306b\\u3061\\u306f\\u3001\\u4e16\\u754c\\uff01'; - const result = unicode(input, false, false); + 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, false, false); + 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, true, false); + 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, true, true); + 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, false, false); + 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, false, false); + 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, true, false); + const result = unicode(input, { mode: 'encode', uppercase: false }); expect(result).toBe( '\\u041f\\u0440\\u0438\\u0432\\u0435\\u0442\\u002c\\u0020\\u043c\\u0438\\u0440\\u0021' ); @@ -126,7 +126,7 @@ describe('unicode', () => { it('should encode a Russian string to uppercase hex correctly', () => { const input = 'Привет, мир!'; - const result = unicode(input, true, true); + const result = unicode(input, { mode: 'encode', uppercase: true }); expect(result).toBe( '\\u041F\\u0440\\u0438\\u0432\\u0435\\u0442\\u002C\\u0020\\u043C\\u0438\\u0440\\u0021' ); @@ -135,20 +135,20 @@ describe('unicode', () => { 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, false, false); + 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, false, false); + 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, true, false); + const result = unicode(input, { mode: 'encode', uppercase: false }); expect(result).toBe( '\\u00a1\\u0048\\u006f\\u006c\\u0061\\u002c\\u0020\\u004d\\u0075\\u006e\\u0064\\u006f\\u0021' ); @@ -156,7 +156,7 @@ describe('unicode', () => { it('should encode a Spanish string to uppercase hex correctly', () => { const input = '¡Hola, Mundo!'; - const result = unicode(input, true, true); + const result = unicode(input, { mode: 'encode', uppercase: true }); expect(result).toBe( '\\u00A1\\u0048\\u006F\\u006C\\u0061\\u002C\\u0020\\u004D\\u0075\\u006E\\u0064\\u006F\\u0021' ); @@ -165,14 +165,14 @@ describe('unicode', () => { 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, false, false); + 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, false, false); + const result = unicode(input, { mode: 'decode', uppercase: false }); expect(result).toBe('¡Hola, Mundo!'); }); }); From ef034f2b8b94a9ba60ce8a9a18b7febc778f3062 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 30 Nov 2025 17:56:43 +0100 Subject: [PATCH 3/6] chore: void input edge case added to service --- src/pages/tools/string/unicode/service.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/pages/tools/string/unicode/service.ts b/src/pages/tools/string/unicode/service.ts index 9943f64..818f832 100644 --- a/src/pages/tools/string/unicode/service.ts +++ b/src/pages/tools/string/unicode/service.ts @@ -1,20 +1,13 @@ import { InitialValuesType } from './types'; -export function main(input: string, options: InitialValuesType): string { - return input; -} - -export function unicode( - input: string, - encode: boolean, - uppercase: boolean -): string { - if (encode) { +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 (uppercase) { + if (options.uppercase) { hex = hex.toUpperCase(); } result += '\\u' + hex; From 6ad57674ea512b69a7c27914a30bf626b258c243 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 30 Nov 2025 17:57:48 +0100 Subject: [PATCH 4/6] chore: keywords added to list --- src/pages/tools/string/unicode/meta.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/tools/string/unicode/meta.ts b/src/pages/tools/string/unicode/meta.ts index 069d5fa..8aa0c6a 100644 --- a/src/pages/tools/string/unicode/meta.ts +++ b/src/pages/tools/string/unicode/meta.ts @@ -5,11 +5,10 @@ export const tool = defineTool('string', { i18n: { name: 'string:unicode.title', description: 'string:unicode.description', - shortDescription: 'string:unicode.shortDescription', - longDescription: 'string:unicode.longDescription' + shortDescription: 'string:unicode.shortDescription' }, path: 'unicode', icon: 'mdi:unicode', - keywords: ['unicode'], + keywords: ['unicode', 'encode', 'decode', 'escape', 'text'], component: lazy(() => import('./index')) }); From 009a0dd6ad329041cfe11c7ce09774852a031188 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 30 Nov 2025 17:59:06 +0100 Subject: [PATCH 5/6] chore: checkbox used instead of switch --- src/pages/tools/string/unicode/index.tsx | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/pages/tools/string/unicode/index.tsx b/src/pages/tools/string/unicode/index.tsx index bd74fd1..1a38e87 100644 --- a/src/pages/tools/string/unicode/index.tsx +++ b/src/pages/tools/string/unicode/index.tsx @@ -1,4 +1,4 @@ -import { Box, FormControlLabel, Switch } from '@mui/material'; +import { Box } from '@mui/material'; import { useState } from 'react'; import ToolContent from '@components/ToolContent'; import { ToolComponentProps } from '@tools/defineTool'; @@ -9,6 +9,7 @@ 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 = { @@ -51,17 +52,13 @@ const exampleCards: CardExampleType[] = [ } } ]; -export default function Unicode({ - title, - longDescription -}: ToolComponentProps) { +export default function Unicode({ title }: ToolComponentProps) { const { t } = useTranslation('string'); const [input, setInput] = useState(''); const [result, setResult] = useState(''); const compute = (values: InitialValuesType, input: string) => { - if (!input) return; - setResult(unicode(input, values.mode === 'encode', values.uppercase)); + setResult(unicode(input, values)); }; const getGroups: GetGroupsType = ({ @@ -89,15 +86,10 @@ export default function Unicode({ title: t('unicode.caseOptionsTitle'), component: ( - updateField('uppercase', e.target.checked)} - disabled={values.mode === 'decode'} - /> - } - label={t('unicode.uppercase')} + updateField('uppercase', value)} + title={t('unicode.uppercase')} /> ) From 80662c59c61bc98836061121af979884e6c10316 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 30 Nov 2025 18:00:03 +0100 Subject: [PATCH 6/6] locales: desc minor changes --- public/locales/en/string.json | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/public/locales/en/string.json b/public/locales/en/string.json index 9037edc..deb649a 100644 --- a/public/locales/en/string.json +++ b/public/locales/en/string.json @@ -309,20 +309,19 @@ } }, "unicode": { - "title": "Unicode Encoder/Decoder", - "description": "Encode text to Unicode escape sequences and decode them back.", - "shortDescription": "Encode or decode text using Unicode escape sequences.", - "longDescription": "This tool allows you to encode plain text into Unicode escape sequences (e.g., \\uXXXX) and decode them back. You can choose to output the hexadecimal digits in either uppercase or lowercase for encoding.", + "title": "Unicode Encoder / Decoder", "inputTitle": "Input", - "resultTitle": "Output", - "optionsTitle": "Options", + "resultTitle": "Processed Output", + "optionsTitle": "Mode", "caseOptionsTitle": "Case Options", - "encode": "Unicode Encode", - "decode": "Unicode Decode", + "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": "What is Unicode Escape?", - "description": "Unicode escape sequences are used to represent characters that may not be available in the character set of the document. They are written as '\\u' followed by four hexadecimal digits." + "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." } } }