WIP(translate): translate converter category all tools

This commit is contained in:
Amery2010 2023-12-26 23:57:28 +08:00
parent 2ee3b01105
commit 2da11a7242
68 changed files with 716 additions and 174 deletions

View file

@ -31,7 +31,7 @@ export const i18nPlugin: Plugin = {
},
};
export const translate = function (localeKey: string) {
export const translate = function (localeKey: string, named?: Record<string, unknown>) {
// @ts-expect-error global
return i18n.global.t(localeKey);
return i18n.global.t(localeKey, named);
};

View file

@ -6,13 +6,15 @@ import { useDownloadFileFromBase64 } from '@/composable/downloadBase64';
import { useValidation } from '@/composable/validation';
import { isValidBase64 } from '@/utils/base64';
const { t } = useI18n();
const base64Input = ref('');
const { download } = useDownloadFileFromBase64({ source: base64Input });
const base64InputValidation = useValidation({
source: base64Input,
rules: [
{
message: 'Invalid base 64 string',
message: t('tools.base64-file-converter.invalidMessage'),
validator: value => isValidBase64(value.trim()),
},
],
@ -33,7 +35,7 @@ function downloadFile() {
const fileInput = ref() as Ref<File>;
const { base64: fileBase64 } = useBase64(fileInput);
const { copy: copyFileBase64 } = useCopy({ source: fileBase64, text: 'Base64 string copied to the clipboard' });
const { copy: copyFileBase64 } = useCopy({ source: fileBase64, text: t('tools.base64-file-converter.copied') });
async function onUpload(file: File) {
if (file) {
@ -43,11 +45,11 @@ async function onUpload(file: File) {
</script>
<template>
<c-card title="Base64 to file">
<c-card :title="t('tools.base64-file-converter.base64ToFile.title')">
<c-input-text
v-model:value="base64Input"
multiline
placeholder="Put your base64 file string here..."
:placeholder="t('tools.base64-file-converter.base64ToFile.placeholder')"
rows="5"
:validation="base64InputValidation"
mb-2
@ -55,18 +57,18 @@ async function onUpload(file: File) {
<div flex justify-center>
<c-button :disabled="base64Input === '' || !base64InputValidation.isValid" @click="downloadFile()">
Download file
{{ t('tools.base64-file-converter.buttons.downloadFile') }}
</c-button>
</div>
</c-card>
<c-card title="File to base64">
<c-file-upload title="Drag and drop a file here, or click to select a file" @file-upload="onUpload" />
<c-input-text :value="fileBase64" multiline readonly placeholder="File in base64 will be here" rows="5" my-2 />
<c-card :title="t('tools.base64-file-converter.fileToBase64.title')">
<c-file-upload :title="t('tools.base64-file-converter.fileToBase64.uploadTip')" @file-upload="onUpload" />
<c-input-text :value="fileBase64" multiline readonly :placeholder="t('tools.base64-file-converter.fileToBase64.placeholder')" rows="5" my-2 />
<div flex justify-center>
<c-button @click="copyFileBase64()">
Copy
{{ t('tools.base64-file-converter.buttons.copy') }}
</c-button>
</div>
</c-card>

View file

@ -1,10 +1,11 @@
import { FileDigit } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Base64 file converter',
name: translate('tools.base64-file-converter.title'),
path: '/base64-file-converter',
description: 'Convert string, files or images into a it\'s base64 representation.',
description: translate('tools.base64-file-converter.description'),
keywords: ['base64', 'converter', 'upload', 'image', 'file', 'conversion', 'web', 'data', 'format'],
component: () => import('./base64-file-converter.vue'),
icon: FileDigit,

View file

@ -0,0 +1,18 @@
tools:
base64-file-converter:
title: Base64 文件转换器
description: 将字符串、文件或图像转换为其 base64 表示形式。
base64ToFile:
title: Base64 转文件
placeholder: 在此处放置您的 base64 文件字符串...
fileToBase64:
title: 文件转 base64
placeholder: base64 文件将在此处
uploadTip: 拖放文件到此处,或点击选择文件
buttons:
downloadFile: 下载文件
copy: 复制
copied: 已复制 base64 字符串到剪贴板
invalidMessage: 无效的 base 64 字符串

View file

@ -6,18 +6,20 @@ import { withDefaultOnError } from '@/utils/defaults';
const encodeUrlSafe = useStorage('base64-string-converter--encode-url-safe', false);
const decodeUrlSafe = useStorage('base64-string-converter--decode-url-safe', false);
const { t } = useI18n();
const textInput = ref('');
const base64Output = computed(() => textToBase64(textInput.value, { makeUrlSafe: encodeUrlSafe.value }));
const { copy: copyTextBase64 } = useCopy({ source: base64Output, text: 'Base64 string copied to the clipboard' });
const { copy: copyTextBase64 } = useCopy({ source: base64Output, text: t('tools.base64-string-converter.base64Copied') });
const base64Input = ref('');
const textOutput = computed(() =>
withDefaultOnError(() => base64ToText(base64Input.value.trim(), { makeUrlSafe: decodeUrlSafe.value }), ''),
);
const { copy: copyText } = useCopy({ source: textOutput, text: 'String copied to the clipboard' });
const { copy: copyText } = useCopy({ source: textOutput, text: t('tools.base64-string-converter.stringCopied') });
const b64ValidationRules = [
{
message: 'Invalid base64 string',
message: t('tools.base64-string-converter.base64InvalidMessage'),
validator: (value: string) => isValidBase64(value.trim(), { makeUrlSafe: decodeUrlSafe.value }),
},
];
@ -25,56 +27,56 @@ const b64ValidationWatch = [decodeUrlSafe];
</script>
<template>
<c-card title="String to base64">
<n-form-item label="Encode URL safe" label-placement="left">
<c-card :title="t('tools.base64-string-converter.stringToBase64.title')">
<n-form-item :label="t('tools.base64-string-converter.stringToBase64.encodeUrl')" label-placement="left">
<n-switch v-model:value="encodeUrlSafe" />
</n-form-item>
<c-input-text
v-model:value="textInput"
multiline
placeholder="Put your string here..."
:placeholder="t('tools.base64-string-converter.stringToBase64.inputPlaceholder')"
rows="5"
label="String to encode"
:label="t('tools.base64-string-converter.stringToBase64.inputLabel')"
raw-text
mb-5
/>
<c-input-text
label="Base64 of string"
:label="t('tools.base64-string-converter.stringToBase64.outputLabel')"
:value="base64Output"
multiline
readonly
placeholder="The base64 encoding of your string will be here"
:placeholder="t('tools.base64-string-converter.stringToBase64.outputPlaceholder')"
rows="5"
mb-5
/>
<div flex justify-center>
<c-button @click="copyTextBase64()">
Copy base64
{{ t('tools.base64-string-converter.buttons.copyBase64') }}
</c-button>
</div>
</c-card>
<c-card title="Base64 to string">
<n-form-item label="Decode URL safe" label-placement="left">
<c-card :title="t('tools.base64-string-converter.base64ToString.title')">
<n-form-item :label="t('tools.base64-string-converter.base64ToString.decodeUrl')" label-placement="left">
<n-switch v-model:value="decodeUrlSafe" />
</n-form-item>
<c-input-text
v-model:value="base64Input"
multiline
placeholder="Your base64 string..."
:placeholder="t('tools.base64-string-converter.base64ToString.inputPlaceholder')"
rows="5"
:validation-rules="b64ValidationRules"
:validation-watch="b64ValidationWatch"
label="Base64 string to decode"
:label="t('tools.base64-string-converter.base64ToString.inputPlaceholder')"
mb-5
/>
<c-input-text
v-model:value="textOutput"
label="Decoded string"
placeholder="The decoded string will be here"
:label="t('tools.base64-string-converter.base64ToString.outputLabel')"
:placeholder="t('tools.base64-string-converter.base64ToString.outputPlaceholder')"
multiline
rows="5"
readonly
@ -83,7 +85,7 @@ const b64ValidationWatch = [decodeUrlSafe];
<div flex justify-center>
<c-button @click="copyText()">
Copy decoded string
{{ t('tools.base64-string-converter.buttons.copyDecodedString') }}
</c-button>
</div>
</c-card>

View file

@ -1,10 +1,11 @@
import { FileDigit } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Base64 string encoder/decoder',
name: translate('tools.base64-string-converter.title'),
path: '/base64-string-converter',
description: 'Simply encode and decode string into a their base64 representation.',
description: translate('tools.base64-string-converter.description'),
keywords: ['base64', 'converter', 'conversion', 'web', 'data', 'format', 'atob', 'btoa'],
component: () => import('./base64-string-converter.vue'),
icon: FileDigit,

View file

@ -0,0 +1,26 @@
tools:
base64-string-converter:
title: Base64 string encoder/decoder
description: Simply encode and decode string into a their base64 representation.
stringToBase64:
title: String to base64
encodeUrl: Encode URL safe
inputLabel: String to encode
inputPlaceholder: Put your string here...
outputLabel: Base64 of string
outputPlaceholder: The base64 encoding of your string will be here
base64ToString:
title: Base64 to string
decodeUrl: Decode URL safe
inputLabel: Base64 string to decode
inputPlaceholder: Your base64 string...
outputLabel: Decoded string
outputPlaceholder: The decoded string will be here
buttons:
copyBase64: Copy base64
copyDecodedString: Copy decoded string
base64Copied: Base64 string copied to the clipboard
stringCopied: String copied to the clipboard
base64InvalidMessage: Invalid base64 string

View file

@ -0,0 +1,26 @@
tools:
base64-string-converter:
title: Base64 字符串编码器/解码器
description: 简单地将字符串编码和解码为它们的 base64 表示形式。
stringToBase64:
title: 字符串转 base64
encodeUrl: URL 安全编码
inputLabel: 要编码的字符串
inputPlaceholder: 在此处放置您的字符串...
outputLabel: 字符串的 base64 编码
outputPlaceholder: 您的字符串的 base64 编码将在此处
base64ToString:
title: Base64 转字符串
decodeUrl: URL 安全解码
inputLabel: 要解码的 base64 字符串
inputPlaceholder: 您的 base64 字符串...
outputLabel: 解码后的字符串
outputPlaceholder: 解码后的字符串将在此处
buttons:
copyBase64: 复制 base64
copyDecodedString: 复制解码后的字符串
base64Copied: 已复制 base64 字符串到剪贴板
stringCopied: 字符串已复制到剪贴板
base64InvalidMessage: 无效的 base64 字符串

View file

@ -18,63 +18,65 @@ const baseConfig = {
stripRegexp: /[^A-Za-zÀ-ÖØ-öø-ÿ]+/gi,
};
const { t } = useI18n();
const input = ref('lorem ipsum dolor sit amet');
const formats = computed(() => [
{
label: 'Lowercase:',
label: t('tools.case-converter.lowercase'),
value: input.value.toLocaleLowerCase(),
},
{
label: 'Uppercase:',
label: t('tools.case-converter.uppercase'),
value: input.value.toLocaleUpperCase(),
},
{
label: 'Camelcase:',
label: t('tools.case-converter.camelcase'),
value: camelCase(input.value, baseConfig),
},
{
label: 'Capitalcase:',
label: t('tools.case-converter.capitalcase'),
value: capitalCase(input.value, baseConfig),
},
{
label: 'Constantcase:',
label: t('tools.case-converter.constantcase'),
value: constantCase(input.value, baseConfig),
},
{
label: 'Dotcase:',
label: t('tools.case-converter.dotcase'),
value: dotCase(input.value, baseConfig),
},
{
label: 'Headercase:',
label: t('tools.case-converter.headercase'),
value: headerCase(input.value, baseConfig),
},
{
label: 'Nocase:',
label: t('tools.case-converter.nocase'),
value: noCase(input.value, baseConfig),
},
{
label: 'Paramcase:',
label: t('tools.case-converter.paramcase'),
value: paramCase(input.value, baseConfig),
},
{
label: 'Pascalcase:',
label: t('tools.case-converter.pascalcase'),
value: pascalCase(input.value, baseConfig),
},
{
label: 'Pathcase:',
label: t('tools.case-converter.pathcase'),
value: pathCase(input.value, baseConfig),
},
{
label: 'Sentencecase:',
label: t('tools.case-converter.sentencecase'),
value: sentenceCase(input.value, baseConfig),
},
{
label: 'Snakecase:',
label: t('tools.case-converter.snakecase'),
value: snakeCase(input.value, baseConfig),
},
{
label: 'Mockingcase:',
label: t('tools.case-converter.mockingcase'),
value: input.value
.split('')
.map((char, index) => (index % 2 === 0 ? char.toUpperCase() : char.toLowerCase()))
@ -93,8 +95,8 @@ const inputLabelAlignmentConfig = {
<c-card>
<c-input-text
v-model:value="input"
label="Your string:"
placeholder="Your string..."
:label="t('tools.case-converter.inputLabel')"
:placeholder="t('tools.case-converter.inputPlaceholder')"
raw-text
v-bind="inputLabelAlignmentConfig"
/>

View file

@ -1,10 +1,11 @@
import { LetterCaseToggle } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Case converter',
name: translate('tools.case-converter.title'),
path: '/case-converter',
description: 'Change the case of a string and chose between different formats',
description: translate('tools.case-converter.description'),
keywords: [
'case',
'converter',

View file

@ -0,0 +1,22 @@
tools:
case-converter:
title: Case converter
description: Change the case of a string and chose between different formats
inputLabel: 'Your string:'
inputPlaceholder: Your string...
lowercase: 'Lowercase:'
uppercase: 'Uppercase:'
camelcase: 'Camelcase:'
capitalcase: 'Capitalcase:'
constantcase: 'Constantcase:'
dotcase: 'Dotcase:'
headercase: 'Headercase:'
nocase: 'Nocase:'
paramcase: 'Paramcase:'
pascalcase: 'Pascalcase:'
pathcase: 'Pathcase:'
sentencecase: 'Sentencecase:'
snakecase: 'Snakecase:'
mockingcase: 'Mockingcase:'

View file

@ -0,0 +1,22 @@
tools:
case-converter:
title: 大小写转换器
description: 更改字符串的大小写,并在不同格式之间进行选择
inputLabel: '您的字符串:'
inputPlaceholder: 您的字符串...
lowercase: '小写:'
uppercase: '大写:'
camelcase: '驼峰式:'
capitalcase: '首字母大写:'
constantcase: '常量式:'
dotcase: '点式:'
headercase: '标题式:'
nocase: '无格式:'
paramcase: '参数式:'
pascalcase: '帕斯卡式:'
pathcase: '路径式:'
sentencecase: '句式:'
snakecase: '蛇式:'
mockingcase: '嘲讽式:'

View file

@ -1,6 +1,7 @@
import { type Colord, colord } from 'colord';
import { withDefaultOnError } from '@/utils/defaults';
import { useValidation } from '@/composable/validation';
import { translate } from '@/plugins/i18n.plugin';
export { removeAlphaChannelWhenOpaque, buildColorFormat };
@ -13,7 +14,7 @@ function buildColorFormat({
parse = value => colord(value),
format,
placeholder,
invalidMessage = `Invalid ${label.toLowerCase()} format.`,
invalidMessage = translate('tools.color-converter.invalidMessage', { format: label.toLowerCase() }),
type = 'text',
}: {
label: string

View file

@ -10,9 +10,11 @@ import { buildColorFormat } from './color-converter.models';
extend([cmykPlugin, hwbPlugin, namesPlugin, lchPlugin]);
const { t } = useI18n();
const formats = {
picker: buildColorFormat({
label: 'color picker',
label: t('tools.color-converter.colorPicker'),
format: (v: Colord) => v.toHex(),
type: 'color-picker',
}),
@ -47,7 +49,7 @@ const formats = {
placeholder: 'e.g. cmyk(0, 100%, 100%, 0)',
}),
name: buildColorFormat({
label: 'name',
label: t('tools.color-converter.name'),
format: (v: Colord) => v.toName({ closest: true }) ?? 'Unknown',
placeholder: 'e.g. red',
}),

View file

@ -1,10 +1,11 @@
import { Palette } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Color converter',
name: translate('tools.color-converter.title'),
path: '/color-converter',
description: 'Convert color between the different formats (hex, rgb, hsl and css name)',
description: translate('tools.color-converter.description'),
keywords: ['color', 'converter'],
component: () => import('./color-converter.vue'),
icon: Palette,

View file

@ -0,0 +1,9 @@
tools:
color-converter:
title: Color converter
description: Convert color between the different formats (hex, rgb, hsl and css name).
colorPicker: color picker
name: name
invalidMessage: 'Invalid {format} format.'

View file

@ -0,0 +1,9 @@
tools:
color-converter:
title: 颜色转换器
description: 在不同格式之间转换颜色十六进制、RGB、HSL 和 CSS 名称)。
colorPicker: 颜色选择器
name: 名称
invalidMessage: '无效的 {format} 格式。'

View file

@ -29,67 +29,69 @@ import {
import { withDefaultOnError } from '@/utils/defaults';
import { useValidation } from '@/composable/validation';
const { t } = useI18n();
const inputDate = ref('');
const toDate: ToDateMapper = date => new Date(date);
const formats: DateFormat[] = [
{
name: 'JS locale date string',
name: t('tools.date-converter.localDate'),
fromDate: date => date.toString(),
toDate,
formatMatcher: () => false,
},
{
name: 'ISO 8601',
name: t('tools.date-converter.ISO8601'),
fromDate: formatISO,
toDate: parseISO,
formatMatcher: date => isISO8601DateTimeString(date),
},
{
name: 'ISO 9075',
name: t('tools.date-converter.ISO9075'),
fromDate: formatISO9075,
toDate: parseISO,
formatMatcher: date => isISO9075DateString(date),
},
{
name: 'RFC 3339',
name: t('tools.date-converter.RFC3339'),
fromDate: formatRFC3339,
toDate,
formatMatcher: date => isRFC3339DateString(date),
},
{
name: 'RFC 7231',
name: t('tools.date-converter.RFC7231'),
fromDate: formatRFC7231,
toDate,
formatMatcher: date => isRFC7231DateString(date),
},
{
name: 'Unix timestamp',
name: t('tools.date-converter.unixTimestamp'),
fromDate: date => String(getUnixTime(date)),
toDate: sec => fromUnixTime(+sec),
formatMatcher: date => isUnixTimestamp(date),
},
{
name: 'Timestamp',
name: t('tools.date-converter.timestamp'),
fromDate: date => String(getTime(date)),
toDate: ms => parseJSON(+ms),
formatMatcher: date => isTimestamp(date),
},
{
name: 'UTC format',
name: t('tools.date-converter.UTCformat'),
fromDate: date => date.toUTCString(),
toDate,
formatMatcher: date => isUTCDateString(date),
},
{
name: 'Mongo ObjectID',
name: t('tools.date-converter.mongoObjectID'),
fromDate: date => `${Math.floor(date.getTime() / 1000).toString(16)}0000000000000000`,
toDate: objectId => new Date(Number.parseInt(objectId.substring(0, 8), 16) * 1000),
formatMatcher: date => isMongoObjectId(date),
},
{
name: 'Excel date/time',
name: t('tools.date-converter.excelDate'),
fromDate: date => dateToExcelFormat(date),
toDate: excelFormatToDate,
formatMatcher: isExcelFormat,
@ -126,7 +128,7 @@ const validation = useValidation({
watch: [formatIndex],
rules: [
{
message: 'This date is invalid for this format',
message: t('tools.date-converter.invalidMessage'),
validator: value =>
withDefaultOnError(() => {
if (value === '') {
@ -155,7 +157,7 @@ function formatDateUsingFormatter(formatter: (date: Date) => string, date?: Date
<c-input-text
v-model:value="inputDate"
autofocus
placeholder="Put your date string here..."
:placeholder="t('tools.date-converter.inputPlaceholder')"
clearable
test-id="date-time-converter-input"
:validation="validation"
@ -180,7 +182,7 @@ function formatDateUsingFormatter(formatter: (date: Date) => string, date?: Date
label-position="left"
label-align="right"
:value="formatDateUsingFormatter(fromDate, normalizedDate)"
placeholder="Invalid date..."
:placeholder="t('tools.date-converter.invalidDatePlaceholder')"
:test-id="name"
readonly
mt-2

View file

@ -1,10 +1,11 @@
import { Calendar } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Date-time converter',
name: translate('tools.date-converter.title'),
path: '/date-converter',
description: 'Convert date and time into the various different formats',
description: translate('tools.date-converter.description'),
keywords: ['date', 'time', 'converter', 'iso', 'utc', 'timezone', 'year', 'month', 'day', 'minute', 'seconde'],
component: () => import('./date-time-converter.vue'),
icon: Calendar,

View file

@ -0,0 +1,20 @@
tools:
date-converter:
title: Date-time converter
description: Convert date and time into the various different formats.
inputPlaceholder: Put your date string here...
invalidDatePlaceholder: Invalid date...
localDate: JS locale date string
ISO8601: ISO 8601
ISO9075: ISO 9075
RFC3339: RFC 3339
RFC7231: RFC 7231
unixTimestamp: Unix timestamp
timestamp: Timestamp
UTCformat: UTC format
mongoObjectID: Mongo ObjectID
excelDate: Excel date/time
invalidMessage: This date is invalid for this format

View file

@ -0,0 +1,20 @@
tools:
date-converter:
title: 日期时间转换器
description: 将日期和时间转换为各种不同的格式。
inputPlaceholder: 在此处输入日期字符串...
invalidDatePlaceholder: 无效的日期...
localDate: JS 本地日期字符串
ISO8601: ISO 8601
ISO9075: ISO 9075
RFC3339: RFC 3339
RFC7231: RFC 7231
unixTimestamp: Unix 时间戳
timestamp: 时间戳
UTCformat: UTC 格式
mongoObjectID: Mongo ObjectID
excelDate: Excel 日期/时间
invalidMessage: 该日期不适用于此格式

View file

@ -1,10 +1,11 @@
import { ArrowsLeftRight } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Integer base converter',
name: translate('tools.base-converter.title'),
path: '/base-converter',
description: 'Convert number between different bases (decimal, hexadecimal, binary, octal, base64, ...)',
description: translate('tools.base-converter.description'),
keywords: ['integer', 'number', 'base', 'conversion', 'decimal', 'hexadecimal', 'binary', 'octal', 'base64'],
component: () => import('./integer-base-converter.vue'),
icon: ArrowsLeftRight,

View file

@ -1,3 +1,5 @@
import { translate } from '@/plugins/i18n.plugin';
export function convertBase({ value, fromBase, toBase }: { value: string; fromBase: number; toBase: number }) {
const range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split('');
const fromRange = range.slice(0, fromBase);
@ -7,7 +9,7 @@ export function convertBase({ value, fromBase, toBase }: { value: string; fromBa
.reverse()
.reduce((carry: number, digit: string, index: number) => {
if (!fromRange.includes(digit)) {
throw new Error(`Invalid digit "${digit}" for base ${fromBase}.`);
throw new Error(translate('tools.base-converter.invalidMessage', { digit, fromBase }));
}
return (carry += fromRange.indexOf(digit) * fromBase ** index);
}, 0);

View file

@ -11,6 +11,8 @@ const inputProps = {
'mb-2': '',
} as const;
const { t } = useI18n();
const input = ref('42');
const inputBase = ref(10);
const outputBase = ref(42);
@ -34,10 +36,10 @@ const error = computed(() =>
<template>
<div>
<c-card>
<c-input-text v-model:value="input" label="Input number" placeholder="Put your number here (ex: 42)" label-position="left" label-width="110px" mb-2 label-align="right" />
<c-input-text v-model:value="input" :label="t('tools.base-converter.inputLabel')" :placeholder="t('tools.base-converter.inputPlaceholder')" label-position="left" label-width="110px" mb-2 label-align="right" />
<n-form-item label="Input base" label-placement="left" label-width="110" :show-feedback="false">
<n-input-number v-model:value="inputBase" max="64" min="2" placeholder="Put your input base here (ex: 10)" w-full />
<n-form-item :label="t('tools.base-converter.inputBaseLabel')" label-placement="left" label-width="110" :show-feedback="false">
<n-input-number v-model:value="inputBase" max="64" min="2" :placeholder="t('tools.base-converter.inputBasePlaceholder')" w-full />
</n-form-item>
<n-alert v-if="error" style="margin-top: 25px" type="error">
@ -46,43 +48,43 @@ const error = computed(() =>
<n-divider />
<InputCopyable
label="Binary (2)"
:label="t('tools.base-converter.binaryLabel')"
v-bind="inputProps"
:value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 2 })"
placeholder="Binary version will be here..."
:placeholder="t('tools.base-converter.binaryPlaceholder')"
/>
<InputCopyable
label="Octal (8)"
:label="t('tools.base-converter.octalLabel')"
v-bind="inputProps"
:value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 8 })"
placeholder="Octal version will be here..."
:placeholder="t('tools.base-converter.octalPlaceholder')"
/>
<InputCopyable
label="Decimal (10)"
:label="t('tools.base-converter.decimalLabel')"
v-bind="inputProps"
:value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 10 })"
placeholder="Decimal version will be here..."
:placeholder="t('tools.base-converter.decimalPlaceholder')"
/>
<InputCopyable
label="Hexadecimal (16)"
:label="t('tools.base-converter.hexadecimalLabel')"
v-bind="inputProps"
:value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 16 })"
placeholder="Hexadecimal version will be here..."
:placeholder="t('tools.base-converter.hexadecimalPlaceholder')"
/>
<InputCopyable
label="Base64 (64)"
:label="t('tools.base-converter.base64Label')"
v-bind="inputProps"
:value="errorlessConvert({ value: input, fromBase: inputBase, toBase: 64 })"
placeholder="Base64 version will be here..."
:placeholder="t('tools.base-converter.base64Placeholder')"
/>
<div flex items-baseline>
<n-input-group style="width: 160px; margin-right: 10px">
<n-input-group-label> Custom: </n-input-group-label>
<n-input-group-label> {{ t('tools.base-converter.custom') }} </n-input-group-label>
<n-input-number v-model:value="outputBase" max="64" min="2" />
</n-input-group>
@ -90,7 +92,7 @@ const error = computed(() =>
flex-1
v-bind="inputProps"
:value="errorlessConvert({ value: input, fromBase: inputBase, toBase: outputBase })"
:placeholder="`Base ${outputBase} will be here...`"
:placeholder="t('tools.base-converter.copyable', { outputBase })"
/>
</div>
</c-card>

View file

@ -0,0 +1,24 @@
tools:
base-converter:
title: Integer base converter
description: Convert number between different bases (decimal, hexadecimal, binary, octal, base64, ...)
inputLabel: Input number
inputPlaceholder: 'Put your number here (ex: 42)'
inputBaseLabel: Input base
inputBasePlaceholder: 'Put your input base here (ex: 10)'
binaryLabel: Binary (2)
binaryPlaceholder: Binary version will be here...
octalLabel: Octal (8)
octalPlaceholder: Octal version will be here...
decimalLabel: Decimal (10)
decimalPlaceholder: Decimal version will be here...
hexadecimalLabel: Hexadecimal (16)
hexadecimalPlaceholder: Hexadecimal version will be here...
base64Label: Base64 (64)
base64Placeholder: Base64 version will be here...
custom: 'Custom:'
copyable: Base {outputBase} will be here...
invalidMessage: 'Invalid digit "{digit}" for base {fromBase}.'

View file

@ -0,0 +1,24 @@
tools:
base-converter:
title: 整数进制转换器
description: 在不同进制十进制、十六进制、二进制、八进制、base64 等)之间转换数字
inputLabel: 输入数字
inputPlaceholder: '在此处输入您的数字例如42'
inputBaseLabel: 输入进制
inputBasePlaceholder: '在此处输入您的输入进制例如10'
binaryLabel: 二进制2
binaryPlaceholder: 二进制版本将显示在这里...
octalLabel: 八进制8
octalPlaceholder: 八进制版本将显示在这里...
decimalLabel: 十进制10
decimalPlaceholder: 十进制版本将显示在这里...
hexadecimalLabel: 十六进制16
hexadecimalPlaceholder: 十六进制版本将显示在这里...
base64Label: Base6464
base64Placeholder: Base64版本将显示在这里...
custom: '自定义:'
copyable: 输出进制 {outputBase} 将显示在这里...
invalidMessage: '无效的数字 "{digit}",对于进制 {fromBase}。'

View file

@ -1,10 +1,11 @@
import { Braces } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'JSON to TOML',
name: translate('tools.json-to-toml.title'),
path: '/json-to-toml',
description: 'Parse and convert JSON to TOML.',
description: translate('tools.json-to-toml.description'),
keywords: ['json', 'parse', 'toml', 'convert', 'transform'],
component: () => import('./json-to-toml.vue'),
icon: Braces,

View file

@ -4,6 +4,8 @@ import JSON5 from 'json5';
import { withDefaultOnError } from '../../utils/defaults';
import type { UseValidationRule } from '@/composable/validation';
const { t } = useI18n();
const convertJsonToToml = (value: string) => [stringifyToml(JSON5.parse(value))].flat().join('\n').trim();
const transformer = (value: string) => value.trim() === '' ? '' : withDefaultOnError(() => convertJsonToToml(value), '');
@ -11,16 +13,16 @@ const transformer = (value: string) => value.trim() === '' ? '' : withDefaultOnE
const rules: UseValidationRule<string>[] = [
{
validator: (v: string) => v === '' || JSON5.parse(v),
message: 'Provided JSON is not valid.',
message: t('tools.json-to-toml.invalidMessage'),
},
];
</script>
<template>
<format-transformer
input-label="Your JSON"
input-placeholder="Paste your JSON here..."
output-label="TOML from your JSON"
:input-label="t('tools.json-to-toml.inputLabel')"
:input-placeholder="t('tools.json-to-toml.inputPlaceholder')"
:output-label="t('tools.json-to-toml.outputLabel')"
output-language="toml"
:input-validation-rules="rules"
:transformer="transformer"

View file

@ -0,0 +1,10 @@
tools:
json-to-toml:
title: JSON to TOML
description: Parse and convert JSON to TOML.
inputLabel: Your JSON
inputPlaceholder: Paste your JSON here...
outputLabel: TOML from your JSON
invalidMessage: Provided JSON is not valid.

View file

@ -0,0 +1,10 @@
tools:
json-to-toml:
title: JSON 转 TOML
description: 解析并转换 JSON 到 TOML.
inputLabel: 您的 JSON
inputPlaceholder: 在这里粘贴您的 JSON...
outputLabel: 从您的 JSON 得到的 TOML
invalidMessage: 提供的 JSON 不合法。

View file

@ -1,10 +1,11 @@
import { Braces } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'JSON to YAML converter',
name: translate('tools.json-to-yaml-converter.title'),
path: '/json-to-yaml-converter',
description: 'Simply convert JSON to YAML with this live online converter.',
description: translate('tools.json-to-yaml-converter.description'),
keywords: ['yaml', 'to', 'json'],
component: () => import('./json-to-yaml.vue'),
icon: Braces,

View file

@ -5,21 +5,23 @@ import type { UseValidationRule } from '@/composable/validation';
import { isNotThrowing } from '@/utils/boolean';
import { withDefaultOnError } from '@/utils/defaults';
const { t } = useI18n();
const transformer = (value: string) => withDefaultOnError(() => stringify(JSON5.parse(value)), '');
const rules: UseValidationRule<string>[] = [
{
validator: (value: string) => value === '' || isNotThrowing(() => stringify(JSON5.parse(value))),
message: 'Provided JSON is not valid.',
message: t('tools.json-to-yaml-converter.invalidMessage'),
},
];
</script>
<template>
<format-transformer
input-label="Your JSON"
input-placeholder="Paste your JSON here..."
output-label="YAML from your JSON"
:input-label="t('tools.json-to-yaml-converter.inputLabel')"
:input-placeholder="t('tools.json-to-yaml-converter.inputPlaceholder')"
:output-label="t('tools.json-to-yaml-converter.outputLabel')"
output-language="yaml"
:input-validation-rules="rules"
:transformer="transformer"

View file

@ -0,0 +1,10 @@
tools:
json-to-yaml-converter:
title: JSON to YAML converter
description: Simply convert JSON to YAML with this live online converter.
inputLabel: Your JSON
inputPlaceholder: Paste your JSON here...
outputLabel: YAML from your JSON
invalidMessage: Provided JSON is not valid.

View file

@ -0,0 +1,10 @@
tools:
json-to-yaml-converter:
title: JSON 转 YAML
description: 解析并转换 JSON 到 YAML.
inputLabel: 您的 JSON
inputPlaceholder: 在这里粘贴您的 JSON...
outputLabel: 从您的 JSON 得到的 YAML
invalidMessage: 提供的 JSON 不合法。

View file

@ -1,11 +1,11 @@
import { List } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'List converter',
name: translate('tools.list-converter.title'),
path: '/list-converter',
description:
'This tool can process column-based data and apply various changes (transpose, add prefix and suffix, reverse list, sort list, lowercase values, truncate values) to each row.',
description: translate('tools.list-converter.description'),
keywords: ['list', 'converter', 'sort', 'reverse', 'prefix', 'suffix', 'lowercase', 'truncate'],
component: () => import('./list-converter.vue'),
icon: List,

View file

@ -3,14 +3,16 @@ import { useStorage } from '@vueuse/core';
import { convert } from './list-converter.models';
import type { ConvertOptions } from './list-converter.types';
const { t } = useI18n();
const sortOrderOptions = [
{
label: 'Sort ascending',
label: t('tools.list-converter.sortOrder.asc'),
value: 'asc',
disabled: false,
},
{
label: 'Sort descending',
label: t('tools.list-converter.sortOrder.desc'),
value: 'desc',
disabled: false,
},
@ -41,14 +43,14 @@ function transformer(value: string) {
<c-card>
<div flex>
<div>
<n-form-item label="Trim list items" label-placement="left" label-width="150" :show-feedback="false" mb-2>
<n-form-item :label="t('tools.list-converter.trimListItems')" label-placement="left" label-width="150" :show-feedback="false" mb-2>
<n-switch v-model:value="conversionConfig.trimItems" />
</n-form-item>
<n-form-item label="Remove duplicates" label-placement="left" label-width="150" :show-feedback="false" mb-2>
<n-form-item :label="t('tools.list-converter.removeDuplicates')" label-placement="left" label-width="150" :show-feedback="false" mb-2>
<n-switch v-model:value="conversionConfig.removeDuplicates" data-test-id="removeDuplicates" />
</n-form-item>
<n-form-item
label="Convert to lowercase"
:label="t('tools.list-converter.convertToLowercase')"
label-placement="left"
label-width="150"
:show-feedback="false"
@ -56,14 +58,14 @@ function transformer(value: string) {
>
<n-switch v-model:value="conversionConfig.lowerCase" />
</n-form-item>
<n-form-item label="Keep line breaks" label-placement="left" label-width="150" :show-feedback="false" mb-2>
<n-form-item :label="t('tools.list-converter.keepLineBreaks')" label-placement="left" label-width="150" :show-feedback="false" mb-2>
<n-switch v-model:value="conversionConfig.keepLineBreaks" />
</n-form-item>
</div>
<div flex-1>
<c-select
v-model:value="conversionConfig.sortList"
label="Sort list"
:label="t('tools.list-converter.sortListLabel')"
label-position="left"
label-width="120px"
label-align="right"
@ -72,40 +74,40 @@ function transformer(value: string) {
w-full
:disabled="conversionConfig.reverseList"
data-test-id="sortList"
placeholder="Sort alphabetically"
:placeholder="t('tools.list-converter.sortListPlaceholder')"
/>
<c-input-text
v-model:value="conversionConfig.separator"
label="Separator"
:label="t('tools.list-converter.separatorLabel')"
label-position="left"
label-width="120px"
label-align="right"
mb-2
placeholder=","
:placeholder="t('tools.list-converter.separatorPlaceholder')"
/>
<n-form-item label="Wrap item" label-placement="left" label-width="120" :show-feedback="false" mb-2>
<n-form-item :label="t('tools.list-converter.wrapItem')" label-placement="left" label-width="120" :show-feedback="false" mb-2>
<c-input-text
v-model:value="conversionConfig.itemPrefix"
placeholder="Item prefix"
:placeholder="t('tools.list-converter.itemPrefix')"
test-id="itemPrefix"
/>
<c-input-text
v-model:value="conversionConfig.itemSuffix"
placeholder="Item suffix"
:placeholder="t('tools.list-converter.itemSuffix')"
test-id="itemSuffix"
/>
</n-form-item>
<n-form-item label="Wrap list" label-placement="left" label-width="120" :show-feedback="false" mb-2>
<c-input-text
v-model:value="conversionConfig.listPrefix"
placeholder="List prefix"
:placeholder="t('tools.list-converter.listPrefix')"
test-id="listPrefix"
/>
<c-input-text
v-model:value="conversionConfig.listSuffix"
placeholder="List suffix"
:placeholder="t('tools.list-converter.listSuffix')"
test-id="listSuffix"
/>
</n-form-item>
@ -115,9 +117,9 @@ function transformer(value: string) {
</div>
</div>
<format-transformer
input-label="Your input data"
input-placeholder="Paste your input data here..."
output-label="Your transformed data"
:input-label="t('tools.list-converter.inputLabel')"
:input-placeholder="t('tools.list-converter.inputPlaceholder')"
:output-label="t('tools.list-converter.outputLabel')"
:transformer="transformer"
/>
</template>

View file

@ -0,0 +1,28 @@
tools:
list-converter:
title: List converter
description: This tool can process column-based data and apply various changes (transpose, add prefix and suffix, reverse list, sort list, lowercase values, truncate values) to each row.
trimListItems: Trim list items
removeDuplicates: Remove duplicates
convertToLowercase: Convert to lowercase
keepLineBreaks: Keep line breaks
sortListLabel: Sort list
sortListPlaceholder: Sort alphabetically
separatorLabel: Separator
separatorPlaceholder: ','
wrapItem: Wrap item
itemPrefix: Item prefix
itemSuffix: Item suffix
wrapList: Wrap list
listPrefix: List prefix
listSuffix: List suffix
inputLabel: Your input data
inputPlaceholder: Paste your input data here...
outputLabel: Your transformed data
sortOrder:
asc: Sort ascending
desc: Sort descending

View file

@ -0,0 +1,28 @@
tools:
list-converter:
title: 列表转换器
description: 该工具可以处理基于列的数据,并对每一行应用各种更改(转置、添加前缀和后缀、反转列表、排序列表、小写值、截断值)。
trimListItems: 裁剪列表项
removeDuplicates: 删除重复项
convertToLowercase: 转换为小写
keepLineBreaks: 保留换行符
sortListLabel: 排序列表
sortListPlaceholder: 按字母顺序排序
separatorLabel: 分隔符
separatorPlaceholder: ','
wrapItem: 包装条目
itemPrefix: 条目前缀
itemSuffix: 条目后缀
wrapList: 包装列表
listPrefix: 列表前缀
listSuffix: 列表后缀
inputLabel: 您的输入数据
inputPlaceholder: 在此处粘贴您的输入数据...
outputLabel: 您的转换后的数据
sortOrder:
asc: 升序排序
desc: 降序排序

View file

@ -1,10 +1,11 @@
import { LetterX } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Roman numeral converter',
name: translate('tools.roman-numeral-converter.title'),
path: '/roman-numeral-converter',
description: 'Convert Roman numerals to numbers and convert numbers to Roman numerals.',
description: translate('tools.roman-numeral-converter.description'),
keywords: ['roman', 'arabic', 'converter', 'X', 'I', 'V', 'L', 'C', 'D', 'M'],
component: () => import('./roman-numeral-converter.vue'),
icon: LetterX,

View file

@ -0,0 +1,13 @@
tools:
roman-numeral-converter:
title: Roman numeral converter
description: Convert Roman numerals to numbers and convert numbers to Roman numerals.
arabicToRoman: Arabic to roman
romanToArabic: Roman to arabic
copy: Copy
validationNumeral: We can only convert numbers between {min} and {max}
validationRoman: The input you entered is not a valid roman number
copyRoman: Roman number copied to the clipboard
copyArabic: Arabic number copied to the clipboard

View file

@ -0,0 +1,13 @@
tools:
roman-numeral-converter:
title: 罗马数字转换器
description: 将罗马数字转换为阿拉伯数字,以及将阿拉伯数字转换为罗马数字。
arabicToRoman: 阿拉伯数字转罗马数字
romanToArabic: 罗马数字转阿拉伯数字
copy: 复制
validationNumeral: 我们只能转换 {min} 到 {max} 之间的数字
validationRoman: 您输入的内容不是有效的罗马数字
copyRoman: 罗马数字已复制到剪贴板
copyArabic: 阿拉伯数字已复制到剪贴板

View file

@ -9,6 +9,8 @@ import {
import { useCopy } from '@/composable/copy';
import { useValidation } from '@/composable/validation';
const { t } = useI18n();
const inputNumeral = ref(42);
const outputRoman = computed(() => arabicToRoman(inputNumeral.value));
@ -17,7 +19,7 @@ const { attrs: validationNumeral } = useValidation({
rules: [
{
validator: value => value >= MIN_ARABIC_TO_ROMAN && value <= MAX_ARABIC_TO_ROMAN,
message: `We can only convert numbers between ${MIN_ARABIC_TO_ROMAN.toLocaleString()} and ${MAX_ARABIC_TO_ROMAN.toLocaleString()}`,
message: t('tools.roman-numeral-converter.validationNumeral', { min: MIN_ARABIC_TO_ROMAN.toLocaleString(), max: MAX_ARABIC_TO_ROMAN.toLocaleString() }),
},
],
});
@ -30,18 +32,18 @@ const validationRoman = useValidation({
rules: [
{
validator: value => isValidRomanNumber(value),
message: 'The input you entered is not a valid roman number',
message: t('tools.roman-numeral-converter.validationRoman'),
},
],
});
const { copy: copyRoman } = useCopy({ source: outputRoman, text: 'Roman number copied to the clipboard' });
const { copy: copyArabic } = useCopy({ source: () => String(outputNumeral), text: 'Arabic number copied to the clipboard' });
const { copy: copyRoman } = useCopy({ source: outputRoman, text: t('tools.roman-numeral-converter.copyRoman') });
const { copy: copyArabic } = useCopy({ source: () => String(outputNumeral), text: t('tools.roman-numeral-converter.copyArabic') });
</script>
<template>
<div>
<c-card title="Arabic to roman">
<c-card :title="t('tools.roman-numeral-converter.arabicToRoman')">
<div flex items-center justify-between>
<n-form-item v-bind="validationNumeral as any">
<n-input-number v-model:value="inputNumeral" :min="1" style="width: 200px" :show-button="false" />
@ -50,11 +52,11 @@ const { copy: copyArabic } = useCopy({ source: () => String(outputNumeral), text
{{ outputRoman }}
</div>
<c-button autofocus :disabled="validationNumeral.validationStatus === 'error'" @click="copyRoman()">
Copy
{{ t('tools.roman-numeral-converter.copy') }}
</c-button>
</div>
</c-card>
<c-card title="Roman to arabic" mt-5>
<c-card :title="t('tools.roman-numeral-converter.romanToArabic')" mt-5>
<div flex items-center justify-between>
<c-input-text v-model:value="inputRoman" style="width: 200px" :validation="validationRoman" />
@ -62,7 +64,7 @@ const { copy: copyArabic } = useCopy({ source: () => String(outputNumeral), text
{{ outputNumeral }}
</div>
<c-button :disabled="!validationRoman.isValid" @click="copyArabic()">
Copy
{{ t('tools.roman-numeral-converter.copy') }}
</c-button>
</div>
</c-card>

View file

@ -1,10 +1,11 @@
import { Binary } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Text to ASCII binary',
name: translate('tools.text-to-binary.title'),
path: '/text-to-binary',
description: 'Convert text to its ASCII binary representation and vice versa.',
description: translate('tools.text-to-binary.description'),
keywords: ['text', 'to', 'binary', 'converter', 'encode', 'decode', 'ascii'],
component: () => import('./text-to-binary.vue'),
icon: Binary,

View file

@ -0,0 +1,22 @@
tools:
text-to-binary:
title: Text to ASCII binary
description: Convert text to its ASCII binary representation and vice versa.
textToBinary:
title: Text to ASCII binary
inputLabel: Enter text to convert to binary
inputPlaceholder: e.g. "Hello world"
outputLabel: Binary from your text
outputPlaceholder: The binary representation of your text will be here
copyBinary: Copy binary to clipboard
binaryToText:
title: ASCII binary to text
inputLabel: Enter binary to convert to text
inputPlaceholder: e.g. "01001000 01100101 01101100 01101100 01101111"
outputLabel: Text from your binary
outputPlaceholder: The text representation of your binary will be here
copyText: Copy text to clipboard
invalidMessage: Binary should be a valid ASCII binary string with multiples of 8 bits
invalidBinaryString: Invalid binary string

View file

@ -0,0 +1,22 @@
tools:
text-to-binary:
title: 文本转 ASCII 二进制
description: 将文本转换为其 ASCII 二进制表示,反之亦然。
textToBinary:
title: 文本转 ASCII 二进制
inputLabel: 输入要转换为二进制的文本
inputPlaceholder: 例如 "Hello world"
outputLabel: 您的文本的二进制
outputPlaceholder: 您的文本的二进制表示将显示在这里
copyBinary: 复制二进制到剪贴板
binaryToText:
title: ASCII 二进制转文本
inputLabel: 输入要转换为文本的二进制
inputPlaceholder: 例如 "01001000 01100101 01101100 01101100 01101111"
outputLabel: 您的二进制的文本
outputPlaceholder: 您的二进制的文本表示将显示在这里
copyText: 复制文本到剪贴板
invalidMessage: 二进制应为有效的 ASCII 二进制字符串,且位数为 8 的倍数
invalidBinaryString: 无效的二进制字符串

View file

@ -1,3 +1,5 @@
import { translate } from '@/plugins/i18n.plugin';
export { convertTextToAsciiBinary, convertAsciiBinaryToText };
function convertTextToAsciiBinary(text: string, { separator = ' ' }: { separator?: string } = {}): string {
@ -11,7 +13,7 @@ function convertAsciiBinaryToText(binary: string): string {
const cleanBinary = binary.replace(/[^01]/g, '');
if (cleanBinary.length % 8) {
throw new Error('Invalid binary string');
throw new Error(translate('tools.text-to-binary.invalidBinaryString'));
}
return cleanBinary

View file

@ -4,6 +4,8 @@ import { withDefaultOnError } from '@/utils/defaults';
import { useCopy } from '@/composable/copy';
import { isNotThrowing } from '@/utils/boolean';
const { t } = useI18n();
const inputText = ref('');
const binaryFromText = computed(() => convertTextToAsciiBinary(inputText.value));
const { copy: copyBinary } = useCopy({ source: binaryFromText });
@ -13,29 +15,29 @@ const textFromBinary = computed(() => withDefaultOnError(() => convertAsciiBinar
const inputBinaryValidationRules = [
{
validator: (value: string) => isNotThrowing(() => convertAsciiBinaryToText(value)),
message: 'Binary should be a valid ASCII binary string with multiples of 8 bits',
message: t('tools.text-to-binary.invalidMessage'),
},
];
const { copy: copyText } = useCopy({ source: textFromBinary });
</script>
<template>
<c-card title="Text to ASCII binary">
<c-input-text v-model:value="inputText" multiline placeholder="e.g. 'Hello world'" label="Enter text to convert to binary" autosize autofocus raw-text test-id="text-to-binary-input" />
<c-input-text v-model:value="binaryFromText" label="Binary from your text" multiline raw-text readonly mt-2 placeholder="The binary representation of your text will be here" test-id="text-to-binary-output" />
<c-card :title="t('tools.text-to-binary.textToBinary.title')">
<c-input-text v-model:value="inputText" multiline :placeholder="t('tools.text-to-binary.textToBinary.inputPlaceholder')" label="t('tools.text-to-binary.textToBinary.inputLabel')" autosize autofocus raw-text test-id="text-to-binary-input" />
<c-input-text v-model:value="binaryFromText" :label="t('tools.text-to-binary.textToBinary.outputLabel')" multiline raw-text readonly mt-2 :placeholder="t('tools.text-to-binary.textToBinary.outputPlaceholder')" test-id="text-to-binary-output" />
<div mt-2 flex justify-center>
<c-button :disabled="!binaryFromText" @click="copyBinary()">
Copy binary to clipboard
{{ t('tools.text-to-binary.textToBinary.copyBinary') }}
</c-button>
</div>
</c-card>
<c-card title="ASCII binary to text">
<c-input-text v-model:value="inputBinary" multiline placeholder="e.g. '01001000 01100101 01101100 01101100 01101111'" label="Enter binary to convert to text" autosize raw-text :validation-rules="inputBinaryValidationRules" test-id="binary-to-text-input" />
<c-input-text v-model:value="textFromBinary" label="Text from your binary" multiline raw-text readonly mt-2 placeholder="The text representation of your binary will be here" test-id="binary-to-text-output" />
<c-card :title="t('tools.text-to-binary.binaryToText.title')">
<c-input-text v-model:value="inputBinary" multiline :placeholder="t('tools.text-to-binary.binaryToText.inputPlaceholder')" :label="t('tools.text-to-binary.binaryToText.inputLabel')" autosize raw-text :validation-rules="inputBinaryValidationRules" test-id="binary-to-text-input" />
<c-input-text v-model:value="textFromBinary" :label="t('tools.text-to-binary.binaryToText.outputLabel')" multiline raw-text readonly mt-2 :placeholder="t('tools.text-to-binary.binaryToText.outputPlaceholder')" test-id="binary-to-text-output" />
<div mt-2 flex justify-center>
<c-button :disabled="!textFromBinary" @click="copyText()">
Copy text to clipboard
{{ t('tools.text-to-binary.binaryToText.copyText') }}
</c-button>
</div>
</c-card>

View file

@ -1,10 +1,11 @@
import { Speakerphone } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'Text to NATO alphabet',
name: translate('tools.text-to-nato-alphabet.title'),
path: '/text-to-nato-alphabet',
description: 'Transform text into NATO phonetic alphabet for oral transmission.',
description: translate('tools.text-to-nato-alphabet.description'),
keywords: ['string', 'nato', 'alphabet', 'phonetic', 'oral', 'transmission'],
component: () => import('./text-to-nato-alphabet.vue'),
icon: Speakerphone,

View file

@ -0,0 +1,11 @@
tools:
text-to-nato-alphabet:
title: Text to NATO alphabet
description: Transform text into NATO phonetic alphabet for oral transmission.
inputLabel: Your text to convert to NATO phonetic alphabet
inputPlaceholder: Put your text here...
outputLabel: Your text in NATO phonetic alphabet
copy: Copy NATO string
copied: NATO alphabet string copied.

View file

@ -0,0 +1,11 @@
tools:
text-to-nato-alphabet:
title: 文本转换为北约音标字母
description: 将文本转换为北约音标字母,用于口头传输。
inputLabel: 要转换为北约音标字母的文本
inputPlaceholder: 在这里输入您的文本...
outputLabel: 北约音标字母文本
copy: 复制北约字符串
copied: 已复制北约音标字母字符串。

View file

@ -2,24 +2,26 @@
import { textToNatoAlphabet } from './text-to-nato-alphabet.service';
import { useCopy } from '@/composable/copy';
const { t } = useI18n();
const input = ref('');
const natoText = computed(() => textToNatoAlphabet({ text: input.value }));
const { copy } = useCopy({ source: natoText, text: 'NATO alphabet string copied.' });
const { copy } = useCopy({ source: natoText, text: t('tools.text-to-nato-alphabet.copied') });
</script>
<template>
<div>
<c-input-text
v-model:value="input"
label="Your text to convert to NATO phonetic alphabet"
placeholder="Put your text here..."
:label="t('tools.text-to-nato-alphabet.inputLabel')"
:placeholder="t('tools.text-to-nato-alphabet.inputPlaceholder')"
clearable
mb-5
/>
<div v-if="natoText">
<div mb-2>
Your text in NATO phonetic alphabet
{{ t('tools.text-to-nato-alphabet.outputLabel') }}
</div>
<c-card>
{{ natoText }}
@ -27,7 +29,7 @@ const { copy } = useCopy({ source: natoText, text: 'NATO alphabet string copied.
<div mt-3 flex justify-center>
<c-button autofocus @click="copy()">
Copy NATO string
{{ t('tools.text-to-nato-alphabet.copy') }}
</c-button>
</div>
</div>

View file

@ -1,11 +1,12 @@
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
import BracketIcon from '~icons/mdi/code-brackets';
export const tool = defineTool({
name: 'TOML to JSON',
name: translate('tools.toml-to-json.title'),
path: '/toml-to-json',
description: 'Parse and convert TOML to JSON.',
description: translate('tools.toml-to-json.description'),
keywords: ['toml', 'json', 'convert', 'online', 'transform', 'parser'],
component: () => import('./toml-to-json.vue'),
icon: BracketIcon,

View file

@ -0,0 +1,10 @@
tools:
toml-to-json:
title: TOML to JSON
description: Parse and convert TOML to JSON.
inputLabel: Your TOML
inputPlaceholder: Paste your TOML here...
outputLabel: JSON from your TOML
inValidMessage: Provided TOML is not valid.

View file

@ -0,0 +1,10 @@
tools:
toml-to-json:
title: TOML 转 JSON
description: 解析并转换 TOML 到 JSON。
inputLabel: 您的 TOML
inputPlaceholder: 在这里粘贴您的 TOML...
outputLabel: 从您的 TOML 得到的 JSON
inValidMessage: 提供的 TOML 不合法。

View file

@ -4,21 +4,23 @@ import { withDefaultOnError } from '../../utils/defaults';
import { isValidToml } from './toml.services';
import type { UseValidationRule } from '@/composable/validation';
const { t } = useI18n();
const transformer = (value: string) => value === '' ? '' : withDefaultOnError(() => JSON.stringify(parseToml(value), null, 3), '');
const rules: UseValidationRule<string>[] = [
{
validator: isValidToml,
message: 'Provided TOML is not valid.',
message: t('tools.toml-to-json.inValidMessage'),
},
];
</script>
<template>
<format-transformer
input-label="Your TOML"
input-placeholder="Paste your TOML here..."
output-label="JSON from your TOML"
:input-label="t('tools.toml-to-json.inputLabel')"
:input-placeholder="t('tools.toml-to-json.inputPlaceholder')"
:output-label="t('tools.toml-to-json.outputLabel')"
output-language="json"
:input-validation-rules="rules"
:transformer="transformer"

View file

@ -1,10 +1,12 @@
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
import BracketIcon from '~icons/mdi/code-brackets';
export const tool = defineTool({
name: 'TOML to YAML',
name: translate('tools.toml-to-yaml.title'),
path: '/toml-to-yaml',
description: 'Parse and convert TOML to YAML.',
description: translate('tools.toml-to-yaml.description'),
keywords: ['toml', 'yaml', 'convert', 'online', 'transform', 'parse'],
component: () => import('./toml-to-yaml.vue'),
icon: BracketIcon,

View file

@ -0,0 +1,10 @@
tools:
toml-to-yaml:
title: TOML to YAML
description: Parse and convert TOML to YAML.
inputLabel: Your TOML
inputPlaceholder: Paste your TOML here...
outputLabel: YAML from your TOML
inValidMessage: Provided TOML is not valid.

View file

@ -0,0 +1,10 @@
tools:
toml-to-yaml:
title: TOML 转 YAML
description: 解析并转换 TOML 到 YAML。
inputLabel: 您的 TOML
inputPlaceholder: 在这里粘贴您的 TOML...
outputLabel: 从您的 TOML 得到的 YAML
inValidMessage: 提供的 TOML 不合法。

View file

@ -5,21 +5,23 @@ import { withDefaultOnError } from '../../utils/defaults';
import { isValidToml } from '../toml-to-json/toml.services';
import type { UseValidationRule } from '@/composable/validation';
const { t } = useI18n();
const transformer = (value: string) => value.trim() === '' ? '' : withDefaultOnError(() => stringifyToYaml(parseToml(value)), '');
const rules: UseValidationRule<string>[] = [
{
validator: isValidToml,
message: 'Provided TOML is not valid.',
message: t('tools.toml-to-yaml.inValidMessage'),
},
];
</script>
<template>
<format-transformer
input-label="Your TOML"
input-placeholder="Paste your TOML here..."
output-label="YAML from your TOML"
:input-label="t('tools.toml-to-yaml.inputLabel')"
:input-placeholder="t('tools.toml-to-yaml.inputPlaceholder')"
:output-label="t('tools.toml-to-yaml.outputLabel')"
output-language="yaml"
:input-validation-rules="rules"
:transformer="transformer"

View file

@ -1,10 +1,11 @@
import { AlignJustified } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'YAML to JSON converter',
name: translate('tools.yaml-to-json-converter.title'),
path: '/yaml-to-json-converter',
description: 'Simply convert YAML to JSON with this live online converter.',
description: translate('tools.yaml-to-json-converter.description'),
keywords: ['yaml', 'to', 'json'],
component: () => import('./yaml-to-json.vue'),
icon: AlignJustified,

View file

@ -0,0 +1,10 @@
tools:
yaml-to-json-converter:
title: YAML to JSON converter
description: Simply convert YAML to JSON with this live online converter.
inputLabel: Your YAML
inputPlaceholder: Paste your YAML here...
outputLabel: JSON from your YAML
inValidMessage: Provided YAML is not valid.

View file

@ -0,0 +1,10 @@
tools:
yaml-to-json-converter:
title: YAML 转 JSON
description: 解析并转换 YAML 到 JSON。
inputLabel: 您的 YAML
inputPlaceholder: 在这里粘贴你的 YAML...
outputLabel: 从您的 YAML 得到的 JSON
inValidMessage: 提供的 YAML 不合法。

View file

@ -4,6 +4,8 @@ import type { UseValidationRule } from '@/composable/validation';
import { isNotThrowing } from '@/utils/boolean';
import { withDefaultOnError } from '@/utils/defaults';
const { t } = useI18n();
function transformer(value: string) {
return withDefaultOnError(() => {
const obj = parseYaml(value);
@ -14,16 +16,16 @@ function transformer(value: string) {
const rules: UseValidationRule<string>[] = [
{
validator: (value: string) => isNotThrowing(() => parseYaml(value)),
message: 'Provided YAML is not valid.',
message: t('tools.yaml-to-json-converter.inValidMessage'),
},
];
</script>
<template>
<format-transformer
input-label="Your YAML"
input-placeholder="Paste your yaml here..."
output-label="JSON from your YAML"
:input-label="t('tools.yaml-to-json-converter.inputLabel')"
:input-placeholder="t('tools.yaml-to-json-converter.inputPlaceholder')"
:output-label="t('tools.yaml-to-json-converter.outputLabel')"
output-language="json"
:input-validation-rules="rules"
:transformer="transformer"

View file

@ -1,10 +1,11 @@
import { AlignJustified } from '@vicons/tabler';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';
export const tool = defineTool({
name: 'YAML to TOML',
name: translate('tools.yaml-to-toml.title'),
path: '/yaml-to-toml',
description: 'Parse and convert YAML to TOML.',
description: translate('tools.yaml-to-toml.title'),
keywords: ['yaml', 'to', 'toml', 'convert', 'transform'],
component: () => import('./yaml-to-toml.vue'),
icon: AlignJustified,

View file

@ -0,0 +1,11 @@
tools:
yaml-to-toml:
title: YAML to TOML
description: Parse and convert YAML to TOML.
inputLabel: Your YAML
inputPlaceholder: Paste your YAML here...
outputLabel: TOML from your YAML
inValidMessage: Provided YAML is not valid.

View file

@ -0,0 +1,10 @@
tools:
yaml-to-toml:
title: YAML 转 TOML
description: 解析并转换 YAML 到 TOML。
inputLabel: 您的 YAML
inputPlaceholder: 在这里粘贴您的 YAML...
outputLabel: 从您的 YAML 得到的 TOML
inValidMessage: 提供的 YAML 不合法。

View file

@ -4,6 +4,8 @@ import { parse as parseYaml } from 'yaml';
import { withDefaultOnError } from '../../utils/defaults';
import type { UseValidationRule } from '@/composable/validation';
const { t } = useI18n();
const convertYamlToToml = (value: string) => [stringifyToml(parseYaml(value))].flat().join('\n').trim();
const transformer = (value: string) => value.trim() === '' ? '' : withDefaultOnError(() => convertYamlToToml(value), '');
@ -11,16 +13,16 @@ const transformer = (value: string) => value.trim() === '' ? '' : withDefaultOnE
const rules: UseValidationRule<string>[] = [
{
validator: (v: string) => v === '' || parseYaml(v),
message: 'Provided JSON is not valid.',
message: t('tools.yaml-to-toml.inValidMessage'),
},
];
</script>
<template>
<format-transformer
input-label="Your YAML"
input-placeholder="Paste your YAML here..."
output-label="TOML from your YAML"
:input-label="t('tools.yaml-to-toml.inputLabel')"
:input-placeholder="t('tools.yaml-to-toml.inputPlaceholder')"
:output-label="t('tools.yaml-to-toml.outputLabel')"
output-language="toml"
:input-validation-rules="rules"
:transformer="transformer"