mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 13:57:10 -04:00
WIP(translate): translate converter category all tools
This commit is contained in:
parent
2ee3b01105
commit
2da11a7242
68 changed files with 716 additions and 174 deletions
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
18
src/tools/base64-file-converter/locales/en.yml
Normal file
18
src/tools/base64-file-converter/locales/en.yml
Normal 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 字符串
|
0
src/tools/base64-file-converter/locales/zh.yml
Normal file
0
src/tools/base64-file-converter/locales/zh.yml
Normal 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>
|
||||
|
|
|
@ -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,
|
||||
|
|
26
src/tools/base64-string-converter/locales/en.yml
Normal file
26
src/tools/base64-string-converter/locales/en.yml
Normal 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
|
26
src/tools/base64-string-converter/locales/zh.yml
Normal file
26
src/tools/base64-string-converter/locales/zh.yml
Normal 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 字符串
|
|
@ -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"
|
||||
/>
|
||||
|
|
|
@ -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',
|
||||
|
|
22
src/tools/case-converter/locales/en.yml
Normal file
22
src/tools/case-converter/locales/en.yml
Normal 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:'
|
22
src/tools/case-converter/locales/zh.yml
Normal file
22
src/tools/case-converter/locales/zh.yml
Normal 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: '嘲讽式:'
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
}),
|
||||
|
|
|
@ -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,
|
||||
|
|
9
src/tools/color-converter/locales/en.yml
Normal file
9
src/tools/color-converter/locales/en.yml
Normal 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.'
|
9
src/tools/color-converter/locales/zh.yml
Normal file
9
src/tools/color-converter/locales/zh.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
tools:
|
||||
color-converter:
|
||||
title: 颜色转换器
|
||||
description: 在不同格式之间转换颜色(十六进制、RGB、HSL 和 CSS 名称)。
|
||||
|
||||
colorPicker: 颜色选择器
|
||||
name: 名称
|
||||
|
||||
invalidMessage: '无效的 {format} 格式。'
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
20
src/tools/date-time-converter/locales/en.yml
Normal file
20
src/tools/date-time-converter/locales/en.yml
Normal 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
|
20
src/tools/date-time-converter/locales/zh.yml
Normal file
20
src/tools/date-time-converter/locales/zh.yml
Normal 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: 该日期不适用于此格式
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
24
src/tools/integer-base-converter/locales/en.yml
Normal file
24
src/tools/integer-base-converter/locales/en.yml
Normal 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}.'
|
24
src/tools/integer-base-converter/locales/zh.yml
Normal file
24
src/tools/integer-base-converter/locales/zh.yml
Normal 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: Base64(64)
|
||||
base64Placeholder: Base64版本将显示在这里...
|
||||
|
||||
custom: '自定义:'
|
||||
copyable: 输出进制 {outputBase} 将显示在这里...
|
||||
invalidMessage: '无效的数字 "{digit}",对于进制 {fromBase}。'
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
10
src/tools/json-to-toml/locales/en.yml
Normal file
10
src/tools/json-to-toml/locales/en.yml
Normal 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.
|
10
src/tools/json-to-toml/locales/zh.yml
Normal file
10
src/tools/json-to-toml/locales/zh.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
json-to-toml:
|
||||
title: JSON 转 TOML
|
||||
description: 解析并转换 JSON 到 TOML.
|
||||
|
||||
inputLabel: 您的 JSON
|
||||
inputPlaceholder: 在这里粘贴您的 JSON...
|
||||
outputLabel: 从您的 JSON 得到的 TOML
|
||||
|
||||
invalidMessage: 提供的 JSON 不合法。
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
10
src/tools/json-to-yaml-converter/locales/en.yml
Normal file
10
src/tools/json-to-yaml-converter/locales/en.yml
Normal 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.
|
10
src/tools/json-to-yaml-converter/locales/zh.yml
Normal file
10
src/tools/json-to-yaml-converter/locales/zh.yml
Normal 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 不合法。
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
28
src/tools/list-converter/locales/en.yml
Normal file
28
src/tools/list-converter/locales/en.yml
Normal 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
|
28
src/tools/list-converter/locales/zh.yml
Normal file
28
src/tools/list-converter/locales/zh.yml
Normal 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: 降序排序
|
|
@ -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,
|
||||
|
|
13
src/tools/roman-numeral-converter/locales/en.yml
Normal file
13
src/tools/roman-numeral-converter/locales/en.yml
Normal 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
|
13
src/tools/roman-numeral-converter/locales/zh.yml
Normal file
13
src/tools/roman-numeral-converter/locales/zh.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
tools:
|
||||
roman-numeral-converter:
|
||||
title: 罗马数字转换器
|
||||
description: 将罗马数字转换为阿拉伯数字,以及将阿拉伯数字转换为罗马数字。
|
||||
|
||||
arabicToRoman: 阿拉伯数字转罗马数字
|
||||
romanToArabic: 罗马数字转阿拉伯数字
|
||||
copy: 复制
|
||||
|
||||
validationNumeral: 我们只能转换 {min} 到 {max} 之间的数字
|
||||
validationRoman: 您输入的内容不是有效的罗马数字
|
||||
copyRoman: 罗马数字已复制到剪贴板
|
||||
copyArabic: 阿拉伯数字已复制到剪贴板
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
22
src/tools/text-to-binary/locales/en.yml
Normal file
22
src/tools/text-to-binary/locales/en.yml
Normal 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
|
22
src/tools/text-to-binary/locales/zh.yml
Normal file
22
src/tools/text-to-binary/locales/zh.yml
Normal 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: 无效的二进制字符串
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
11
src/tools/text-to-nato-alphabet/locales/en.yml
Normal file
11
src/tools/text-to-nato-alphabet/locales/en.yml
Normal 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.
|
11
src/tools/text-to-nato-alphabet/locales/zh.yml
Normal file
11
src/tools/text-to-nato-alphabet/locales/zh.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
tools:
|
||||
text-to-nato-alphabet:
|
||||
title: 文本转换为北约音标字母
|
||||
description: 将文本转换为北约音标字母,用于口头传输。
|
||||
|
||||
inputLabel: 要转换为北约音标字母的文本
|
||||
inputPlaceholder: 在这里输入您的文本...
|
||||
outputLabel: 北约音标字母文本
|
||||
copy: 复制北约字符串
|
||||
|
||||
copied: 已复制北约音标字母字符串。
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
10
src/tools/toml-to-json/locales/en.yml
Normal file
10
src/tools/toml-to-json/locales/en.yml
Normal 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.
|
10
src/tools/toml-to-json/locales/zh.yml
Normal file
10
src/tools/toml-to-json/locales/zh.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
toml-to-json:
|
||||
title: TOML 转 JSON
|
||||
description: 解析并转换 TOML 到 JSON。
|
||||
|
||||
inputLabel: 您的 TOML
|
||||
inputPlaceholder: 在这里粘贴您的 TOML...
|
||||
outputLabel: 从您的 TOML 得到的 JSON
|
||||
|
||||
inValidMessage: 提供的 TOML 不合法。
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
10
src/tools/toml-to-yaml/locales/en.yml
Normal file
10
src/tools/toml-to-yaml/locales/en.yml
Normal 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.
|
10
src/tools/toml-to-yaml/locales/zh.yml
Normal file
10
src/tools/toml-to-yaml/locales/zh.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
toml-to-yaml:
|
||||
title: TOML 转 YAML
|
||||
description: 解析并转换 TOML 到 YAML。
|
||||
|
||||
inputLabel: 您的 TOML
|
||||
inputPlaceholder: 在这里粘贴您的 TOML...
|
||||
outputLabel: 从您的 TOML 得到的 YAML
|
||||
|
||||
inValidMessage: 提供的 TOML 不合法。
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
10
src/tools/yaml-to-json-converter/locales/en.yml
Normal file
10
src/tools/yaml-to-json-converter/locales/en.yml
Normal 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.
|
10
src/tools/yaml-to-json-converter/locales/zh.yml
Normal file
10
src/tools/yaml-to-json-converter/locales/zh.yml
Normal 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 不合法。
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
11
src/tools/yaml-to-toml/locales/en.yml
Normal file
11
src/tools/yaml-to-toml/locales/en.yml
Normal 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.
|
||||
|
10
src/tools/yaml-to-toml/locales/zh.yml
Normal file
10
src/tools/yaml-to-toml/locales/zh.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
tools:
|
||||
yaml-to-toml:
|
||||
title: YAML 转 TOML
|
||||
description: 解析并转换 YAML 到 TOML。
|
||||
|
||||
inputLabel: 您的 YAML
|
||||
inputPlaceholder: 在这里粘贴您的 YAML...
|
||||
outputLabel: 从您的 YAML 得到的 TOML
|
||||
|
||||
inValidMessage: 提供的 YAML 不合法。
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue