mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-06 06:17:11 -04:00
WIP(translate): Completed some page translation under web category
This commit is contained in:
parent
2da11a7242
commit
c6583ef013
90 changed files with 1112 additions and 341 deletions
|
@ -7,14 +7,17 @@ import BaseLayout from './base.layout.vue';
|
|||
import FavoriteButton from '@/components/FavoriteButton.vue';
|
||||
import type { Tool } from '@/tools/tools.types';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const route = useRoute();
|
||||
const i18nKey = computed<string>(() => route.path.trim().replace('/', ''));
|
||||
|
||||
const head = computed<HeadObject>(() => ({
|
||||
title: `${route.meta.name} - IT Tools`,
|
||||
title: `${t(`tools.${i18nKey.value}.title`)} - IT Tools`,
|
||||
meta: [
|
||||
{
|
||||
name: 'description',
|
||||
content: route.meta?.description as string,
|
||||
content: t(`tools.${i18nKey.value}.description`),
|
||||
},
|
||||
{
|
||||
name: 'keywords',
|
||||
|
@ -23,9 +26,7 @@ const head = computed<HeadObject>(() => ({
|
|||
],
|
||||
}));
|
||||
useHead(head);
|
||||
const { t } = useI18n();
|
||||
|
||||
const i18nKey = computed<string>(() => route.path.trim().replace('/', ''));
|
||||
const toolTitle = computed<string>(() => t(`tools.${i18nKey.value}.title`, String(route.meta.name)));
|
||||
const toolDescription = computed<string>(() => t(`tools.${i18nKey.value}.description`, String(route.meta.description)));
|
||||
</script>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { FileDigit } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.base64-file-converter.title'),
|
||||
name: t('tools.base64-file-converter.title'),
|
||||
path: '/base64-file-converter',
|
||||
description: translate('tools.base64-file-converter.description'),
|
||||
description: t('tools.base64-file-converter.description'),
|
||||
keywords: ['base64', 'converter', 'upload', 'image', 'file', 'conversion', 'web', 'data', 'format'],
|
||||
component: () => import('./base64-file-converter.vue'),
|
||||
icon: FileDigit,
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
tools:
|
||||
base64-file-converter:
|
||||
title: Base64 文件转换器
|
||||
description: 将字符串、文件或图像转换为其 base64 表示形式。
|
||||
title: Base64 file converter
|
||||
description: Convert string, files or images into a it's base64 representation.
|
||||
|
||||
base64ToFile:
|
||||
title: Base64 转文件
|
||||
placeholder: 在此处放置您的 base64 文件字符串...
|
||||
title: Base64 to file
|
||||
placeholder: Put your base64 file string here...
|
||||
fileToBase64:
|
||||
title: 文件转 base64
|
||||
placeholder: base64 文件将在此处
|
||||
uploadTip: 拖放文件到此处,或点击选择文件
|
||||
title: File to base64
|
||||
placeholder: File in base64 will be here
|
||||
uploadTip: Drag and drop a file here, or click to select a file
|
||||
buttons:
|
||||
downloadFile: 下载文件
|
||||
copy: 复制
|
||||
downloadFile: Download file
|
||||
copy: Copy
|
||||
|
||||
copied: 已复制 base64 字符串到剪贴板
|
||||
invalidMessage: 无效的 base 64 字符串
|
||||
copied: Base64 string copied to the clipboard
|
||||
invalidMessage: Invalid base 64 string
|
|
@ -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 字符串
|
|
@ -1,11 +1,11 @@
|
|||
import { FileDigit } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.base64-string-converter.title'),
|
||||
name: t('tools.base64-string-converter.title'),
|
||||
path: '/base64-string-converter',
|
||||
description: translate('tools.base64-string-converter.description'),
|
||||
description: t('tools.base64-string-converter.description'),
|
||||
keywords: ['base64', 'converter', 'conversion', 'web', 'data', 'format', 'atob', 'btoa'],
|
||||
component: () => import('./base64-string-converter.vue'),
|
||||
icon: FileDigit,
|
||||
|
|
|
@ -2,20 +2,21 @@
|
|||
import { useCopy } from '@/composable/copy';
|
||||
import { textToBase64 } from '@/utils/base64';
|
||||
|
||||
const { t } = useI18n();
|
||||
const username = ref('');
|
||||
const password = ref('');
|
||||
const header = computed(() => `Authorization: Basic ${textToBase64(`${username.value}:${password.value}`)}`);
|
||||
|
||||
const { copy } = useCopy({ source: header, text: 'Header copied to the clipboard' });
|
||||
const { copy } = useCopy({ source: header, text: t('tools.basic-auth-generator.copied') });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<c-input-text v-model:value="username" label="Username" placeholder="Your username..." clearable raw-text mb-5 />
|
||||
<c-input-text v-model:value="username" :label="t('tools.basic-auth-generator.username.inputLabel')" :placeholder="t('tools.basic-auth-generator.username.inputPlaceholder')" clearable raw-text mb-5 />
|
||||
<c-input-text
|
||||
v-model:value="password"
|
||||
label="Password"
|
||||
placeholder="Your password..."
|
||||
:label="t('tools.basic-auth-generator.password.inputLabel')"
|
||||
:placeholder="t('tools.basic-auth-generator.password.inputPlaceholder')"
|
||||
clearable
|
||||
raw-text
|
||||
mb-2
|
||||
|
@ -23,7 +24,7 @@ const { copy } = useCopy({ source: header, text: 'Header copied to the clipboard
|
|||
/>
|
||||
|
||||
<c-card>
|
||||
<n-statistic label="Authorization header:" class="header">
|
||||
<n-statistic :label="t('tools.basic-auth-generator.outputTitle')" class="header">
|
||||
<n-scrollbar x-scrollable style="max-width: 550px; margin-bottom: -10px; padding-bottom: 10px" trigger="none">
|
||||
{{ header }}
|
||||
</n-scrollbar>
|
||||
|
@ -31,7 +32,7 @@ const { copy } = useCopy({ source: header, text: 'Header copied to the clipboard
|
|||
</c-card>
|
||||
<div mt-5 flex justify-center>
|
||||
<c-button @click="copy()">
|
||||
Copy header
|
||||
{{ t('tools.basic-auth-generator.copyHeader') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { PasswordRound } from '@vicons/material';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Basic auth generator',
|
||||
name: t('tools.basic-auth-generator.title'),
|
||||
path: '/basic-auth-generator',
|
||||
description: 'Generate a base64 basic auth header from an username and a password.',
|
||||
description: t('tools.basic-auth-generator.description'),
|
||||
keywords: [
|
||||
'basic',
|
||||
'auth',
|
||||
|
|
15
src/tools/basic-auth-generator/locales/en.yml
Normal file
15
src/tools/basic-auth-generator/locales/en.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
tools:
|
||||
basic-auth-generator:
|
||||
title: Basic auth generator
|
||||
description: Generate a base64 basic auth header from an username and a password.
|
||||
|
||||
username:
|
||||
inputLabel: Username
|
||||
inputPlaceholder: Your username...
|
||||
password:
|
||||
inputLabel: Password
|
||||
inputPlaceholder: Your password...
|
||||
outputTitle: 'Authorization header:'
|
||||
copyHeader: Copy header
|
||||
|
||||
copied: Header copied to the clipboard
|
15
src/tools/basic-auth-generator/locales/zh.yml
Normal file
15
src/tools/basic-auth-generator/locales/zh.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
tools:
|
||||
basic-auth-generator:
|
||||
title: Basic auth 生成器
|
||||
description: 从用户名和密码生成一个 base64 基本授权头。
|
||||
|
||||
username:
|
||||
inputLabel: 用户名
|
||||
inputPlaceholder: 您的用户名...
|
||||
password:
|
||||
inputLabel: 密码
|
||||
inputPlaceholder: 您的密码...
|
||||
outputTitle: '授权头:'
|
||||
copyHeader: 复制授权头
|
||||
|
||||
copied: 授权头已复制到剪贴板
|
|
@ -1,11 +1,11 @@
|
|||
import { LockSquare } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.bcrypt.title'),
|
||||
name: t('tools.bcrypt.title'),
|
||||
path: '/bcrypt',
|
||||
description: translate('tools.bcrypt.description'),
|
||||
description: t('tools.bcrypt.description'),
|
||||
keywords: ['bcrypt', 'hash', 'compare', 'password', 'salt', 'round', 'storage', 'crypto'],
|
||||
component: () => import('./bcrypt.vue'),
|
||||
icon: LockSquare,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { AlignJustified } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.bip39-generator.title'),
|
||||
name: t('tools.bip39-generator.title'),
|
||||
path: '/bip39-generator',
|
||||
description: translate('tools.bip39-generator.description'),
|
||||
description: t('tools.bip39-generator.description'),
|
||||
keywords: ['BIP39', 'passphrase', 'generator', 'mnemonic', 'entropy'],
|
||||
component: () => import('./bip39-generator.vue'),
|
||||
icon: AlignJustified,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { LetterCaseToggle } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.case-converter.title'),
|
||||
name: t('tools.case-converter.title'),
|
||||
path: '/case-converter',
|
||||
description: translate('tools.case-converter.description'),
|
||||
description: t('tools.case-converter.description'),
|
||||
keywords: [
|
||||
'case',
|
||||
'converter',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { type Colord, colord } from 'colord';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import { useValidation } from '@/composable/validation';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export { removeAlphaChannelWhenOpaque, buildColorFormat };
|
||||
|
||||
|
@ -14,7 +14,7 @@ function buildColorFormat({
|
|||
parse = value => colord(value),
|
||||
format,
|
||||
placeholder,
|
||||
invalidMessage = translate('tools.color-converter.invalidMessage', { format: label.toLowerCase() }),
|
||||
invalidMessage = t('tools.color-converter.invalidMessage', { format: label.toLowerCase() }),
|
||||
type = 'text',
|
||||
}: {
|
||||
label: string
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Palette } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.color-converter.title'),
|
||||
name: t('tools.color-converter.title'),
|
||||
path: '/color-converter',
|
||||
description: translate('tools.color-converter.description'),
|
||||
description: t('tools.color-converter.description'),
|
||||
keywords: ['color', 'converter'],
|
||||
component: () => import('./color-converter.vue'),
|
||||
icon: Palette,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Calendar } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.date-converter.title'),
|
||||
name: t('tools.date-converter.title'),
|
||||
path: '/date-converter',
|
||||
description: translate('tools.date-converter.description'),
|
||||
description: t('tools.date-converter.description'),
|
||||
keywords: ['date', 'time', 'converter', 'iso', 'utc', 'timezone', 'year', 'month', 'day', 'minute', 'seconde'],
|
||||
component: () => import('./date-time-converter.vue'),
|
||||
icon: Calendar,
|
||||
|
|
|
@ -1,55 +1,56 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
const sections = [
|
||||
{
|
||||
name: 'Screen',
|
||||
name: t('tools.device-information.screen'),
|
||||
information: [
|
||||
{
|
||||
label: 'Screen size',
|
||||
label: t('tools.device-information.screenSize'),
|
||||
value: computed(() => `${window.screen.availWidth} x ${window.screen.availHeight}`),
|
||||
},
|
||||
{
|
||||
label: 'Orientation',
|
||||
label: t('tools.device-information.orientation'),
|
||||
value: computed(() => window.screen.orientation.type),
|
||||
},
|
||||
{
|
||||
label: 'Orientation angle',
|
||||
label: t('tools.device-information.orientationAngle'),
|
||||
value: computed(() => `${window.screen.orientation.angle}°`),
|
||||
},
|
||||
{
|
||||
label: 'Color depth',
|
||||
label: t('tools.device-information.colorDepth'),
|
||||
value: computed(() => `${window.screen.colorDepth} bits`),
|
||||
},
|
||||
{
|
||||
label: 'Pixel ratio',
|
||||
label: t('tools.device-information.pixelRatio'),
|
||||
value: computed(() => `${window.devicePixelRatio} dppx`),
|
||||
},
|
||||
{
|
||||
label: 'Window size',
|
||||
label: t('tools.device-information.windowSize'),
|
||||
value: computed(() => `${width.value} x ${height.value}`),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Device',
|
||||
name: t('tools.device-information.device'),
|
||||
information: [
|
||||
{
|
||||
label: 'Browser vendor',
|
||||
label: t('tools.device-information.browserVendor'),
|
||||
value: computed(() => navigator.vendor),
|
||||
},
|
||||
{
|
||||
label: 'Languages',
|
||||
label: t('tools.device-information.languages'),
|
||||
value: computed(() => navigator.languages.join(', ')),
|
||||
},
|
||||
{
|
||||
label: 'Platform',
|
||||
label: t('tools.device-information.platform'),
|
||||
value: computed(() => navigator.platform),
|
||||
},
|
||||
{
|
||||
label: 'User agent',
|
||||
label: t('tools.device-information.userAgent'),
|
||||
value: computed(() => navigator.userAgent),
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { DeviceDesktop } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Device information',
|
||||
name: t('tools.device-information.title'),
|
||||
path: '/device-information',
|
||||
description: 'Get information about your current device (screen size, pixel-ratio, user agent, ...)',
|
||||
description: t('tools.device-information.description'),
|
||||
keywords: [
|
||||
'device',
|
||||
'information',
|
||||
|
|
17
src/tools/device-information/locales/en.yml
Normal file
17
src/tools/device-information/locales/en.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
tools:
|
||||
device-information:
|
||||
title: Device information
|
||||
description: Get information about your current device (screen size, pixel-ratio, user agent, ...)
|
||||
|
||||
screen: Screen
|
||||
screenSize: Screen size
|
||||
orientation: Orientation
|
||||
orientationAngle: Orientation angle
|
||||
colorDepth: Color depth
|
||||
pixelRatio: Pixel ratio
|
||||
windowSize: Window size
|
||||
device: Device
|
||||
browserVendor: Browser vendor
|
||||
languages: Languages
|
||||
platform: Platform
|
||||
userAgent: User agent
|
17
src/tools/device-information/locales/zh.yml
Normal file
17
src/tools/device-information/locales/zh.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
tools:
|
||||
device-information:
|
||||
title: 设备信息
|
||||
description: 获取关于您当前设备的信息(屏幕大小、像素比、用户代理...)
|
||||
|
||||
screen: 屏幕
|
||||
screenSize: 屏幕尺寸
|
||||
orientation: 方向
|
||||
orientationAngle: 方向角度
|
||||
colorDepth: 色彩深度
|
||||
pixelRatio: 像素比
|
||||
windowSize: 窗口大小
|
||||
device: 设备
|
||||
browserVendor: 浏览器供应商
|
||||
languages: 语言
|
||||
platform: 平台
|
||||
userAgent: 用户代理
|
|
@ -1,11 +1,11 @@
|
|||
import { Lock } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.encryption.title'),
|
||||
name: t('tools.encryption.title'),
|
||||
path: '/encryption',
|
||||
description: translate('tools.encryption.description'),
|
||||
description: t('tools.encryption.description'),
|
||||
keywords: ['cypher', 'encipher', 'text', 'AES', 'TripleDES', 'Rabbit', 'RC4'],
|
||||
component: () => import('./encryption.vue'),
|
||||
icon: Lock,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { EyeOff } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.hash-text.title'),
|
||||
name: t('tools.hash-text.title'),
|
||||
path: '/hash-text',
|
||||
description: translate('tools.hash-text.description'),
|
||||
description: t('tools.hash-text.description'),
|
||||
keywords: [
|
||||
'hash',
|
||||
'digest',
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { ShortTextRound } from '@vicons/material';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.hmac-generator.title'),
|
||||
name: t('tools.hmac-generator.title'),
|
||||
path: '/hmac-generator',
|
||||
description: translate('tools.hmac-generator.description'),
|
||||
description: t('tools.hmac-generator.description'),
|
||||
keywords: ['hmac', 'generator', 'MD5', 'SHA1', 'SHA256', 'SHA224', 'SHA512', 'SHA384', 'SHA3', 'RIPEMD160'],
|
||||
component: () => import('./hmac-generator.vue'),
|
||||
icon: ShortTextRound,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { escape, unescape } from 'lodash';
|
|||
|
||||
import { useCopy } from '@/composable/copy';
|
||||
|
||||
const { t } = useI18n();
|
||||
const escapeInput = ref('<title>IT Tool</title>');
|
||||
const escapeOutput = computed(() => escape(escapeInput.value));
|
||||
const { copy: copyEscaped } = useCopy({ source: escapeOutput });
|
||||
|
@ -13,23 +14,23 @@ const { copy: copyUnescaped } = useCopy({ source: unescapeOutput });
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<c-card title="Escape html entities">
|
||||
<n-form-item label="Your string :">
|
||||
<c-card :title="t('tools.html-entities.escape.title')">
|
||||
<n-form-item :label="t('tools.html-entities.escape.inputLabel')">
|
||||
<c-input-text
|
||||
v-model:value="escapeInput"
|
||||
multiline
|
||||
placeholder="The string to escape"
|
||||
:placeholder="t('tools.html-entities.escape.inputPlaceholder')"
|
||||
rows="3"
|
||||
autosize
|
||||
raw-text
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="Your string escaped :">
|
||||
<n-form-item :label="t('tools.html-entities.escape.outputLabel')">
|
||||
<c-input-text
|
||||
multiline
|
||||
readonly
|
||||
placeholder="Your string escaped"
|
||||
:placeholder="t('tools.html-entities.escape.outputPlaceholder')"
|
||||
:value="escapeOutput"
|
||||
rows="3"
|
||||
autosize
|
||||
|
@ -38,28 +39,28 @@ const { copy: copyUnescaped } = useCopy({ source: unescapeOutput });
|
|||
|
||||
<div flex justify-center>
|
||||
<c-button @click="copyEscaped()">
|
||||
Copy
|
||||
{{ t('tools.html-entities.copy') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
<c-card title="Unescape html entities">
|
||||
<n-form-item label="Your escaped string :">
|
||||
<c-card :title="t('tools.html-entities.unescape.title')">
|
||||
<n-form-item :label="t('tools.html-entities.unescape.inputLabel')">
|
||||
<c-input-text
|
||||
v-model:value="unescapeInput"
|
||||
multiline
|
||||
placeholder="The string to unescape"
|
||||
:placeholder="t('tools.html-entities.unescape.inputPlaceholder')"
|
||||
rows="3"
|
||||
autosize
|
||||
raw-text
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="Your string unescaped :">
|
||||
<n-form-item :label="t('tools.html-entities.unescape.outputLabel')">
|
||||
<c-input-text
|
||||
:value="unescapeOutput"
|
||||
multiline
|
||||
readonly
|
||||
placeholder="Your string unescaped"
|
||||
:placeholder="t('tools.html-entities.unescape.outputPlaceholder')"
|
||||
rows="3"
|
||||
autosize
|
||||
/>
|
||||
|
@ -67,7 +68,7 @@ const { copy: copyUnescaped } = useCopy({ source: unescapeOutput });
|
|||
|
||||
<div flex justify-center>
|
||||
<c-button @click="copyUnescaped()">
|
||||
Copy
|
||||
{{ t('tools.html-entities.copy') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Code } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Escape html entities',
|
||||
name: t('tools.html-entities.title'),
|
||||
path: '/html-entities',
|
||||
description: 'Escape or unescape html entities (replace <,>, &, " and \' to their html version)',
|
||||
description: t('tools.html-entities.description'),
|
||||
keywords: ['html', 'entities', 'escape', 'unescape', 'special', 'characters', 'tags'],
|
||||
component: () => import('./html-entities.vue'),
|
||||
icon: Code,
|
||||
|
|
19
src/tools/html-entities/locales/en.yml
Normal file
19
src/tools/html-entities/locales/en.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
tools:
|
||||
html-entities:
|
||||
title: Escape html entities
|
||||
description: Escape or unescape html entities (replace <,>, &, " and \' to their html version)
|
||||
|
||||
escape:
|
||||
title: Escape html entities
|
||||
inputLabel: 'Your string :'
|
||||
inputPlaceholder: The string to escape
|
||||
outputLabel: 'Your string escaped :'
|
||||
outputPlaceholder: Your string escaped
|
||||
unescape:
|
||||
title: Unescape html entities
|
||||
inputLabel: 'Your escaped string :'
|
||||
inputPlaceholder: The string to unescape
|
||||
outputLabel: 'Your string unescaped :'
|
||||
outputPlaceholder: Your string unescaped
|
||||
|
||||
copy: Copy
|
19
src/tools/html-entities/locales/zh.yml
Normal file
19
src/tools/html-entities/locales/zh.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
tools:
|
||||
html-entities:
|
||||
title: 转义 HTML 实体
|
||||
description: 转义或取消转义 HTML 实体(将 <,>, &, " 和 \' 替换为它们的 HTML 版本)
|
||||
|
||||
escape:
|
||||
title: 转义 HTML 实体
|
||||
inputLabel: '输入字符串:'
|
||||
inputPlaceholder: 要转义的字符串
|
||||
outputLabel: '转义后的字符串:'
|
||||
outputPlaceholder: 转义后的字符串
|
||||
unescape:
|
||||
title: 取消转义 HTML 实体
|
||||
inputLabel: '输入转义后的字符串:'
|
||||
inputPlaceholder: 要取消转义的字符串
|
||||
outputLabel: '取消转义后的字符串:'
|
||||
outputPlaceholder: 取消转义后的字符串
|
||||
|
||||
copy: 复制
|
4
src/tools/html-wysiwyg-editor/locales/en.yml
Normal file
4
src/tools/html-wysiwyg-editor/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
html-wysiwyg-editor:
|
||||
title: HTML WYSIWYG editor
|
||||
description: Online HTML editor with feature-rich WYSIWYG editor, get the source code of the content immediately.
|
4
src/tools/http-status-codes/locales/en.yml
Normal file
4
src/tools/http-status-codes/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
http-status-codes:
|
||||
title: HTTP status codes
|
||||
description: The list of all HTTP status codes their name and their meaning.
|
|
@ -93,11 +93,11 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
caseConverter,
|
||||
textToNatoAlphabet,
|
||||
textToBinary,
|
||||
listConverter,
|
||||
yamlToJson,
|
||||
yamlToToml,
|
||||
jsonToYaml,
|
||||
jsonToToml,
|
||||
listConverter,
|
||||
tomlToJson,
|
||||
tomlToYaml,
|
||||
],
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { ArrowsLeftRight } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.base-converter.title'),
|
||||
name: t('tools.base-converter.title'),
|
||||
path: '/base-converter',
|
||||
description: translate('tools.base-converter.description'),
|
||||
description: t('tools.base-converter.description'),
|
||||
keywords: ['integer', 'number', 'base', 'conversion', 'decimal', 'hexadecimal', 'binary', 'octal', 'base64'],
|
||||
component: () => import('./integer-base-converter.vue'),
|
||||
icon: ArrowsLeftRight,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export function convertBase({ value, fromBase, toBase }: { value: string; fromBase: number; toBase: number }) {
|
||||
const range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split('');
|
||||
|
@ -9,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(translate('tools.base-converter.invalidMessage', { digit, fromBase }));
|
||||
throw new Error(t('tools.base-converter.invalidMessage', { digit, fromBase }));
|
||||
}
|
||||
return (carry += fromRange.indexOf(digit) * fromBase ** index);
|
||||
}, 0);
|
||||
|
|
4
src/tools/json-diff/locales/en.yml
Normal file
4
src/tools/json-diff/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
json-diff:
|
||||
title: JSON diff
|
||||
description: Compare two JSON objects and get the differences between them.
|
|
@ -1,11 +1,11 @@
|
|||
import { Braces } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.json-to-toml.title'),
|
||||
name: t('tools.json-to-toml.title'),
|
||||
path: '/json-to-toml',
|
||||
description: translate('tools.json-to-toml.description'),
|
||||
description: t('tools.json-to-toml.description'),
|
||||
keywords: ['json', 'parse', 'toml', 'convert', 'transform'],
|
||||
component: () => import('./json-to-toml.vue'),
|
||||
icon: Braces,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Braces } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.json-to-yaml-converter.title'),
|
||||
name: t('tools.json-to-yaml-converter.title'),
|
||||
path: '/json-to-yaml-converter',
|
||||
description: translate('tools.json-to-yaml-converter.description'),
|
||||
description: t('tools.json-to-yaml-converter.description'),
|
||||
keywords: ['yaml', 'to', 'json'],
|
||||
component: () => import('./json-to-yaml.vue'),
|
||||
icon: Braces,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Key } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'JWT parser',
|
||||
name: t('tools.jwt-parser.title'),
|
||||
path: '/jwt-parser',
|
||||
description: 'Parse and decode your JSON Web Token (jwt) and display its content.',
|
||||
description: t('tools.jwt-parser.description'),
|
||||
keywords: [
|
||||
'jwt',
|
||||
'parser',
|
||||
|
|
4
src/tools/jwt-parser/locales/en.yml
Normal file
4
src/tools/jwt-parser/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
jwt-parser:
|
||||
title: JWT parser
|
||||
description: Parse and decode your JSON Web Token (jwt) and display its content.
|
4
src/tools/keycode-info/locales/en.yml
Normal file
4
src/tools/keycode-info/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
keycode-info:
|
||||
title: Keycode info
|
||||
description: Find the javascript keycode, code, location and modifiers of any pressed key.
|
|
@ -1,11 +1,11 @@
|
|||
import { List } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.list-converter.title'),
|
||||
name: t('tools.list-converter.title'),
|
||||
path: '/list-converter',
|
||||
description: translate('tools.list-converter.description'),
|
||||
description: t('tools.list-converter.description'),
|
||||
keywords: ['list', 'converter', 'sort', 'reverse', 'prefix', 'suffix', 'lowercase', 'truncate'],
|
||||
component: () => import('./list-converter.vue'),
|
||||
icon: List,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Tags } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Open graph meta generator',
|
||||
name: t('tools.og-meta-generator.title'),
|
||||
path: '/og-meta-generator',
|
||||
description: 'Generate open-graph and socials html meta tags for your website.',
|
||||
description: t('tools.og-meta-generator.description'),
|
||||
keywords: [
|
||||
'meta',
|
||||
'tag',
|
||||
|
|
199
src/tools/meta-tag-generator/locales/en.yml
Normal file
199
src/tools/meta-tag-generator/locales/en.yml
Normal file
|
@ -0,0 +1,199 @@
|
|||
tools:
|
||||
og-meta-generator:
|
||||
title: Open graph meta generator
|
||||
description: Generate open-graph and socials html meta tags for your website.
|
||||
|
||||
yourMetaTags: Your meta tags
|
||||
|
||||
article:
|
||||
title: Article
|
||||
publishingDate:
|
||||
label: Publishing date
|
||||
placeholder: When the article was first published...
|
||||
modificationDate:
|
||||
label: Modification date
|
||||
placeholder: When the article was last changed...
|
||||
expirationDate:
|
||||
label: Expiration date
|
||||
placeholder: When the article is out of date after...
|
||||
author:
|
||||
label: Author
|
||||
placeholder: Writers of the article...
|
||||
section:
|
||||
label: Section
|
||||
placeholder: A high-level section name. E.g. Technology..
|
||||
tag:
|
||||
label: Tag
|
||||
placeholder: Tag words associated with this article...
|
||||
book:
|
||||
title: Book
|
||||
author:
|
||||
label: Author
|
||||
placeholder: Who wrote this book...
|
||||
ISBN:
|
||||
label: ISBN
|
||||
placeholder: The International Standard Book Number...
|
||||
releaseDate:
|
||||
label: Release date
|
||||
placeholder: The date the book was released...
|
||||
tag:
|
||||
label: Tag
|
||||
placeholder: Tag words associated with this book...
|
||||
image:
|
||||
title: Image
|
||||
imageUrl:
|
||||
label: Image url
|
||||
placeholder: The url of your website social image...
|
||||
imageAlt:
|
||||
label: Image alt
|
||||
placeholder: The alternative text of your website social image...
|
||||
width:
|
||||
label: Width
|
||||
placeholder: Width in px of your website social image...
|
||||
height:
|
||||
label: Height
|
||||
placeholder: Height in px of your website social image...
|
||||
albumDetails:
|
||||
title: Album details
|
||||
song:
|
||||
label: Song
|
||||
placeholder: The song on this album...
|
||||
disc:
|
||||
label: Disc
|
||||
placeholder: The same as music:album:disc but in reverse...
|
||||
track:
|
||||
label: Track
|
||||
placeholder: The same as music:album:track but in reverse...
|
||||
musician:
|
||||
label: Musician
|
||||
placeholder: The musician that made this song...
|
||||
releaseDate:
|
||||
label: Release date
|
||||
placeholder: The date the album was released...
|
||||
playlistDetails:
|
||||
title: Playlist details
|
||||
song:
|
||||
label: Song
|
||||
placeholder: The song on this album...
|
||||
disc:
|
||||
label: Disc
|
||||
placeholder: The same as music:album:disc but in reverse...
|
||||
track:
|
||||
label: Track
|
||||
placeholder: The same as music:album:track but in reverse...
|
||||
creator:
|
||||
label: Creator
|
||||
placeholder: The creator of this playlist...
|
||||
radioStationDetails:
|
||||
title: Radio station details
|
||||
creator:
|
||||
label: Creator
|
||||
placeholder: The creator of this radio station...
|
||||
songDetails:
|
||||
title: Song details
|
||||
duration:
|
||||
lebel: Duration
|
||||
placeholder: The duration of the song...
|
||||
album:
|
||||
lebel: Album
|
||||
placeholder: The album this song is from...
|
||||
disc:
|
||||
lebel: Disc
|
||||
placeholder: Which disc of the album this song is on...
|
||||
track:
|
||||
lebel: Track
|
||||
placeholder: Which track this song is...
|
||||
musician:
|
||||
lebel: Musician
|
||||
placeholder: The musician that made this song...
|
||||
profile:
|
||||
title: Profile
|
||||
firstName:
|
||||
lebel: First name
|
||||
placeholder: Enter the first name of the person...
|
||||
lastName:
|
||||
lebel: Last name
|
||||
placeholder: Enter the last name of the person...
|
||||
username:
|
||||
lebel: Username
|
||||
placeholder: Enter the username of the person...
|
||||
gender:
|
||||
lebel: Gender
|
||||
placeholder: Enter the gender of the person...
|
||||
twitter:
|
||||
title: Twitter
|
||||
card:
|
||||
label: Card type
|
||||
placeholder: The Twitter card type...
|
||||
summary: Summary
|
||||
summaryWithLargeImage: Summary with large image
|
||||
application: Application
|
||||
player: Player
|
||||
site:
|
||||
label: Site account
|
||||
placeholder: 'The name of the Twitter account of the site (ex: @ittoolsdottech)...'
|
||||
creator:
|
||||
label: Creator acc.
|
||||
placeholder: 'The name of the Twitter account of the creator (ex: @cthmsst)...'
|
||||
videoEpisode:
|
||||
title: Video episode details
|
||||
series:
|
||||
label: Series
|
||||
placeholder: Which series this episode belongs to...
|
||||
videoMovie:
|
||||
title: Movie details
|
||||
actor:
|
||||
label: Actor
|
||||
placeholder: Name of the actress/actor...
|
||||
actorRole:
|
||||
label: Actor role
|
||||
placeholder: The role they played...
|
||||
director:
|
||||
label: Director
|
||||
placeholder: Name of the director...
|
||||
writer:
|
||||
label: Writer
|
||||
placeholder: Writers of the movie...
|
||||
duration:
|
||||
label: Duration
|
||||
placeholder: The movie\'s length in seconds...
|
||||
releaseDate:
|
||||
label: Release date
|
||||
placeholder: The date the movie was released...
|
||||
tag:
|
||||
label: Tag
|
||||
placeholder: Tag words associated with this movie...
|
||||
videoOther:
|
||||
title: Other video details
|
||||
videoTVShow:
|
||||
title: TV show details
|
||||
website:
|
||||
title: General information
|
||||
pageType:
|
||||
label: Page type
|
||||
placeholder: Select the type of your website...
|
||||
pageTitle:
|
||||
label: Title
|
||||
placeholder: Enter the title of your website...
|
||||
description:
|
||||
label: Description
|
||||
placeholder: Enter the description of your website...
|
||||
url:
|
||||
label: Page URL
|
||||
placeholder: Enter the url of your website...
|
||||
web: Website
|
||||
article: Article
|
||||
book: Book
|
||||
profile: Profile
|
||||
music:
|
||||
label: Music
|
||||
song: Song
|
||||
musicAlbum: Music album
|
||||
playlist: Playlist
|
||||
radioStation: Radio station
|
||||
video:
|
||||
label: Music
|
||||
movie: Movie
|
||||
episode: Episode
|
||||
tvShow: TV show
|
||||
otherVideo: Other video
|
199
src/tools/meta-tag-generator/locales/zh.yml
Normal file
199
src/tools/meta-tag-generator/locales/zh.yml
Normal file
|
@ -0,0 +1,199 @@
|
|||
tools:
|
||||
og-meta-generator:
|
||||
title: 开放图谱元数据生成器
|
||||
description: 为您的网站生成开放图谱和社交网站的 HTML 元标记。
|
||||
|
||||
yourMetaTags: 您的元标记
|
||||
|
||||
article:
|
||||
title: 文章
|
||||
publishingDate:
|
||||
label: 发布日期
|
||||
placeholder: 文章首次发布的日期...
|
||||
modificationDate:
|
||||
label: 修改日期
|
||||
placeholder: 文章最后修改的日期...
|
||||
expirationDate:
|
||||
label: 过期日期
|
||||
placeholder: 文章失效日期...
|
||||
author:
|
||||
label: 作者
|
||||
placeholder: 文章的作者...
|
||||
section:
|
||||
label: 部分
|
||||
placeholder: 高级部分名称。例如:技术...
|
||||
tag:
|
||||
label: 标签
|
||||
placeholder: 与该文章相关的标签词...
|
||||
book:
|
||||
title: 书籍
|
||||
author:
|
||||
label: 作者
|
||||
placeholder: 谁写了这本书...
|
||||
ISBN:
|
||||
label: ISBN
|
||||
placeholder: 国际标准书号...
|
||||
releaseDate:
|
||||
label: 发行日期
|
||||
placeholder: 书籍发布日期...
|
||||
tag:
|
||||
label: 标签
|
||||
placeholder: 与该书籍相关的标签词...
|
||||
image:
|
||||
title: 图片
|
||||
imageUrl:
|
||||
label: 图片 URL
|
||||
placeholder: 您网站社交图片的 URL...
|
||||
imageAlt:
|
||||
label: 图片说明
|
||||
placeholder: 您网站社交图片的替代文本...
|
||||
width:
|
||||
label: 宽度
|
||||
placeholder: 您网站社交图片的宽度(像素)...
|
||||
height:
|
||||
label: 高度
|
||||
placeholder: 您网站社交图片的高度(像素)...
|
||||
albumDetails:
|
||||
title: 专辑详情
|
||||
song:
|
||||
label: 歌曲
|
||||
placeholder: 该专辑中的歌曲...
|
||||
disc:
|
||||
label: 光盘
|
||||
placeholder: 与音乐:专辑:光盘相同,但顺序相反...
|
||||
track:
|
||||
label: 曲目
|
||||
placeholder: 与音乐:专辑:曲目相同,但顺序相反...
|
||||
musician:
|
||||
label: 音乐家
|
||||
placeholder: 制作该歌曲的音乐家...
|
||||
releaseDate:
|
||||
label: 发行日期
|
||||
placeholder: 专辑发布日期...
|
||||
playlistDetails:
|
||||
title: 播放列表详情
|
||||
song:
|
||||
label: 歌曲
|
||||
placeholder: 该专辑中的歌曲...
|
||||
disc:
|
||||
label: 光盘
|
||||
placeholder: 与音乐:专辑:光盘相同,但顺序相反...
|
||||
track:
|
||||
label: 曲目
|
||||
placeholder: 与音乐:专辑:曲目相同,但顺序相反...
|
||||
creator:
|
||||
label: 创建者
|
||||
placeholder: 此播放列表的创建者...
|
||||
radioStationDetails:
|
||||
title: 电台详情
|
||||
creator:
|
||||
label: 创建者
|
||||
placeholder: 电台的创建者...
|
||||
songDetails:
|
||||
title: 歌曲详情
|
||||
duration:
|
||||
lebel: 时长
|
||||
placeholder: 歌曲的时长...
|
||||
album:
|
||||
lebel: 专辑
|
||||
placeholder: 歌曲所属的专辑...
|
||||
disc:
|
||||
lebel: 光盘
|
||||
placeholder: 歌曲所在专辑的光盘...
|
||||
track:
|
||||
lebel: 曲目
|
||||
placeholder: 歌曲的曲目...
|
||||
musician:
|
||||
lebel: 音乐家
|
||||
placeholder: 制作该歌曲的音乐家...
|
||||
profile:
|
||||
title: 个人资料
|
||||
firstName:
|
||||
lebel: 名字
|
||||
placeholder: 输入个人的名字...
|
||||
lastName:
|
||||
lebel: 姓氏
|
||||
placeholder: 输入个人的姓氏...
|
||||
username:
|
||||
lebel: 用户名
|
||||
placeholder: 输入个人的用户名...
|
||||
gender:
|
||||
lebel: 性别
|
||||
placeholder: 输入个人的性别...
|
||||
twitter:
|
||||
title: 推特
|
||||
card:
|
||||
label: 卡片类型
|
||||
placeholder: 推特卡片类型...
|
||||
summary: 摘要
|
||||
summaryWithLargeImage: 带大图的摘要
|
||||
application: 应用
|
||||
player: 播放器
|
||||
site:
|
||||
label: 网站账号
|
||||
placeholder: '网站的推特账号(例如:@ittoolsdottech)...'
|
||||
creator:
|
||||
label: 创建者账号
|
||||
placeholder: '创建者的推特账号(例如:@cthmsst)...'
|
||||
videoEpisode:
|
||||
title: 视频剧集详情
|
||||
series:
|
||||
label: 系列
|
||||
placeholder: 该剧集所属的系列...
|
||||
videoMovie:
|
||||
title: 电影详情
|
||||
actor:
|
||||
label: 演员
|
||||
placeholder: 女演员/男演员的名字...
|
||||
actorRole:
|
||||
label: 演员角色
|
||||
placeholder: 他们扮演的角色...
|
||||
director:
|
||||
label: 导演
|
||||
placeholder: 导演的名字...
|
||||
writer:
|
||||
label: 编剧
|
||||
placeholder: 电影的编剧...
|
||||
duration:
|
||||
label: 时长
|
||||
placeholder: 电影的长度(秒)...
|
||||
releaseDate:
|
||||
label: 发行日期
|
||||
placeholder: 电影的发布日期...
|
||||
tag:
|
||||
label: 标签
|
||||
placeholder: 与该电影相关的标签词...
|
||||
videoOther:
|
||||
title: 其他视频详情
|
||||
videoTVShow:
|
||||
title: 电视剧详情
|
||||
website:
|
||||
title: 常规信息
|
||||
pageType:
|
||||
label: 页面类型
|
||||
placeholder: 选择您网站的类型...
|
||||
pageTitle:
|
||||
label: 标题
|
||||
placeholder: 输入您网站的标题...
|
||||
description:
|
||||
label: 描述
|
||||
placeholder: 输入您网站的描述...
|
||||
url:
|
||||
label: 页面 URL
|
||||
placeholder: 输入您网站的 URL...
|
||||
web: 网站
|
||||
article: 文章
|
||||
book: 书籍
|
||||
profile: 个人资料
|
||||
music:
|
||||
label: 音乐
|
||||
song: 歌曲
|
||||
musicAlbum: 音乐专辑
|
||||
playlist: 播放列表
|
||||
radioStation: 电台
|
||||
video:
|
||||
label: 视频
|
||||
movie: 电影
|
||||
episode: 剧集
|
||||
tvShow: 电视剧
|
||||
otherVideo: 其他视频
|
|
@ -6,7 +6,7 @@ import type { OGSchemaType, OGSchemaTypeElementSelect } from './OGSchemaType.typ
|
|||
import TextareaCopyable from '@/components/TextareaCopyable.vue';
|
||||
|
||||
// Since type guards do not work in template
|
||||
|
||||
const { t } = useI18n();
|
||||
const metadata = ref<{ type: string; [k: string]: any }>({
|
||||
'type': 'website',
|
||||
'twitter:card': 'summary_large_image',
|
||||
|
@ -83,7 +83,7 @@ const metaTags = computed(() => {
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<n-form-item label="Your meta tags">
|
||||
<n-form-item :label="t('tools.og-meta-generator.yourMetaTags')">
|
||||
<TextareaCopyable :value="metaTags" language="html" />
|
||||
</n-form-item>
|
||||
</div>
|
||||
|
|
|
@ -1,33 +1,44 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const article: OGSchemaType = {
|
||||
name: 'Article',
|
||||
name: t('tools.og-meta-generator.article.title'),
|
||||
elements: [
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Publishing date',
|
||||
label: t('tools.og-meta-generator.article.publishingDate.label'),
|
||||
key: 'article:published_time',
|
||||
placeholder: 'When the article was first published...',
|
||||
placeholder: t('tools.og-meta-generator.article.publishingDate.placeholder'),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Modification date',
|
||||
label: t('tools.og-meta-generator.article.modificationDate.label'),
|
||||
key: 'article:modified_time',
|
||||
placeholder: 'When the article was last changed...',
|
||||
placeholder: t('tools.og-meta-generator.article.modificationDate.placeholder'),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Expiration date',
|
||||
label: t('tools.og-meta-generator.article.expirationDate.label'),
|
||||
key: 'article:expiration_time',
|
||||
placeholder: 'When the article is out of date after...',
|
||||
placeholder: t('tools.og-meta-generator.article.expirationDate.placeholder'),
|
||||
},
|
||||
{ type: 'input', label: 'Author', key: 'article:author', placeholder: 'Writers of the article...' },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Section',
|
||||
key: 'article:section',
|
||||
placeholder: 'A high-level section name. E.g. Technology..',
|
||||
label: t('tools.og-meta-generator.article.author.label'),
|
||||
key: 'article:author',
|
||||
placeholder: t('tools.og-meta-generator.article.author.placeholder'),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: t('tools.og-meta-generator.article.section.label'),
|
||||
key: 'article:section',
|
||||
placeholder: t('tools.og-meta-generator.article.section.placeholder'),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: t('tools.og-meta-generator.article.tag.label'),
|
||||
key: 'article:tag',
|
||||
placeholder: t('tools.og-meta-generator.article.tag.placeholder'),
|
||||
},
|
||||
{ type: 'input', label: 'Tag', key: 'article:tag', placeholder: 'Tag words associated with this article...' },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const book: OGSchemaType = {
|
||||
name: 'Book',
|
||||
name: t('tools.og-meta-generator.book.title'),
|
||||
elements: [
|
||||
{ type: 'input', label: 'Author', key: 'book:author', placeholder: 'Who wrote this book...' },
|
||||
{ type: 'input', label: 'ISBN', key: 'book:isbn', placeholder: 'The International Standard Book Number...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.book.author.label'), key: 'book:author', placeholder: t('tools.og-meta-generator.book.author.placeholder') },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.book.ISBN.label'), key: 'book:isbn', placeholder: t('tools.og-meta-generator.book.ISBN.placeholder') },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Release date',
|
||||
label: t('tools.og-meta-generator.book.releaseDate.label'),
|
||||
key: 'book:release_date',
|
||||
placeholder: 'The date the book was released...',
|
||||
placeholder: t('tools.og-meta-generator.book.releaseDate.placeholder'),
|
||||
},
|
||||
{ type: 'input', label: 'Tag', key: 'book:tag', placeholder: 'Tag words associated with this book...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.book.tag.label'), key: 'book:tag', placeholder: t('tools.og-meta-generator.book.tag.placeholder') },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const image: OGSchemaType = {
|
||||
name: 'Image',
|
||||
name: t('tools.og-meta-generator.image.title'),
|
||||
elements: [
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Image url',
|
||||
placeholder: 'The url of your website social image...',
|
||||
label: t('tools.og-meta-generator.image.imageUrl.label'),
|
||||
placeholder: t('tools.og-meta-generator.image.imageUrl.placeholder'),
|
||||
key: 'image',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Image alt',
|
||||
placeholder: 'The alternative text of your website social image...',
|
||||
label: t('tools.og-meta-generator.image.imageAlt.label'),
|
||||
placeholder: t('tools.og-meta-generator.image.imageAlt.placeholder'),
|
||||
key: 'image:alt',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Width',
|
||||
placeholder: 'Width in px of your website social image...',
|
||||
label: t('tools.og-meta-generator.image.width.label'),
|
||||
placeholder: t('tools.og-meta-generator.image.width.placeholder'),
|
||||
key: 'image:width',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Height',
|
||||
placeholder: 'Height in px of your website social image...',
|
||||
label: t('tools.og-meta-generator.image.height.label'),
|
||||
placeholder: t('tools.og-meta-generator.image.height.placeholder'),
|
||||
key: 'image:height',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const musicAlbum: OGSchemaType = {
|
||||
name: 'Album details',
|
||||
name: t('tools.og-meta-generator.albumDetails.title'),
|
||||
elements: [
|
||||
{ type: 'input', label: 'Song', key: 'music:song', placeholder: 'The song on this album...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.albumDetails.song.label'), key: 'music:song', placeholder: t('tools.og-meta-generator.albumDetails.song.placeholder') },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Disc',
|
||||
label: t('tools.og-meta-generator.albumDetails.disc.label'),
|
||||
key: 'music:song:disc',
|
||||
placeholder: 'The same as music:album:disc but in reverse...',
|
||||
placeholder: t('tools.og-meta-generator.albumDetails.disc.placeholder'),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Track',
|
||||
label: t('tools.og-meta-generator.albumDetails.track.label'),
|
||||
key: 'music:song:track',
|
||||
placeholder: 'The same as music:album:track but in reverse...',
|
||||
placeholder: t('tools.og-meta-generator.albumDetails.track.placeholder'),
|
||||
},
|
||||
{ type: 'input', label: 'Musician', key: 'music:musician', placeholder: 'The musician that made this song...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.albumDetails.musician.label'), key: 'music:musician', placeholder: t('tools.og-meta-generator.albumDetails.musician.placeholder') },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Release date',
|
||||
label: t('tools.og-meta-generator.albumDetails.releaseDate.label'),
|
||||
key: 'music:release_date',
|
||||
placeholder: 'The date the album was released...',
|
||||
placeholder: t('tools.og-meta-generator.albumDetails.releaseDate.placeholder'),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const musicPlaylist: OGSchemaType = {
|
||||
name: 'Playlist details',
|
||||
name: t('tools.og-meta-generator.playlistDetails.title'),
|
||||
elements: [
|
||||
{ type: 'input', label: 'Song', key: 'music:song', placeholder: 'The song on this album...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.playlistDetails.song.label'), key: 'music:song', placeholder: t('tools.og-meta-generator.playlistDetails.song.placeholder') },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Disc',
|
||||
label: t('tools.og-meta-generator.playlistDetails.disc.label'),
|
||||
key: 'music:song:disc',
|
||||
placeholder: 'The same as music:album:disc but in reverse...',
|
||||
placeholder: t('tools.og-meta-generator.playlistDetails.disc.placeholder'),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Track',
|
||||
label: t('tools.og-meta-generator.playlistDetails.track.label'),
|
||||
key: 'music:song:track',
|
||||
placeholder: 'The same as music:album:track but in reverse...',
|
||||
placeholder: t('tools.og-meta-generator.playlistDetails.track.placeholder'),
|
||||
},
|
||||
{ type: 'input', label: 'Creator', key: 'music:creator', placeholder: 'The creator of this playlist...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.playlistDetails.creator.label'), key: 'music:creator', placeholder: t('tools.og-meta-generator.playlistDetails.creator.placeholder') },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const musicRadioStation: OGSchemaType = {
|
||||
name: 'Radio station details',
|
||||
name: t('tools.og-meta-generator.radioStationDetails.title'),
|
||||
elements: [
|
||||
{ type: 'input', label: 'Creator', key: 'music:creator', placeholder: 'The creator of this radio station...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.radioStationDetails.creator.label'), key: 'music:creator', placeholder: t('tools.og-meta-generator.radioStationDetails.creator.placeholder') },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const musicSong: OGSchemaType = {
|
||||
name: 'Song details',
|
||||
name: t('tools.og-meta-generator.songDetails.title'),
|
||||
elements: [
|
||||
{ type: 'input', label: 'Duration', placeholder: 'The duration of the song...', key: 'music:duration' },
|
||||
{ type: 'input', label: 'Album', placeholder: 'The album this song is from...', key: 'music:album' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.songDetails.duration.lebel'), placeholder: t('tools.og-meta-generator.songDetails.duration.placeholder'), key: 'music:duration' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.songDetails.album.lebel'), placeholder: t('tools.og-meta-generator.songDetails.album.placeholder'), key: 'music:album' },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Disc',
|
||||
placeholder: 'Which disc of the album this song is on...',
|
||||
label: t('tools.og-meta-generator.songDetails.disc.lebel'),
|
||||
placeholder: t('tools.og-meta-generator.songDetails.disc.placeholder'),
|
||||
key: 'music:album:disk',
|
||||
},
|
||||
{ type: 'input', label: 'Track', placeholder: ' Which track this song is...', key: 'music:album:track' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.songDetails.track.lebel'), placeholder: t('tools.og-meta-generator.songDetails.track.placeholder'), key: 'music:album:track' },
|
||||
{
|
||||
type: 'input-multiple',
|
||||
label: 'Musician',
|
||||
placeholder: 'The musician that made this song...',
|
||||
label: t('tools.og-meta-generator.songDetails.musician.lebel'),
|
||||
placeholder: t('tools.og-meta-generator.songDetails.musician.placeholder'),
|
||||
key: 'music:musician',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const profile: OGSchemaType = {
|
||||
name: 'Profile',
|
||||
name: t('tools.og-meta-generator.profile.title'),
|
||||
elements: [
|
||||
{
|
||||
type: 'input',
|
||||
label: 'First name',
|
||||
placeholder: 'Enter the first name of the person...',
|
||||
label: t('tools.og-meta-generator.profile.firstName.lebel'),
|
||||
placeholder: t('tools.og-meta-generator.profile.firstName.placeholder'),
|
||||
key: 'profile:first_name',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Last name',
|
||||
placeholder: 'Enter the last name of the person...',
|
||||
label: t('tools.og-meta-generator.profile.lastName.lebel'),
|
||||
placeholder: t('tools.og-meta-generator.profile.lastName.placeholder'),
|
||||
key: 'profile:last_name',
|
||||
},
|
||||
{ type: 'input', label: 'Username', placeholder: 'Enter the username of the person...', key: 'profile:username' },
|
||||
{ type: 'input', label: 'Gender', placeholder: 'Enter the gender of the person...', key: 'profile:gender' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.profile.username.lebel'), placeholder: t('tools.og-meta-generator.profile.username.placeholder'), key: 'profile:username' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.profile.gender.lebel'), placeholder: t('tools.og-meta-generator.profile.gender.placeholder'), key: 'profile:gender' },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const twitter: OGSchemaType = {
|
||||
name: 'Twitter',
|
||||
name: t('tools.og-meta-generator.twitter.title'),
|
||||
elements: [
|
||||
{
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: 'Summary', value: 'summary' },
|
||||
{ label: 'Summary with large image', value: 'summary_large_image' },
|
||||
{ label: 'Application', value: 'app' },
|
||||
{ label: 'Player', value: 'player' },
|
||||
{ label: t('tools.og-meta-generator.twitter.card.summary'), value: 'summary' },
|
||||
{ label: t('tools.og-meta-generator.twitter.card.summaryWithLargeImage'), value: 'summary_large_image' },
|
||||
{ label: t('tools.og-meta-generator.twitter.card.application'), value: 'app' },
|
||||
{ label: t('tools.og-meta-generator.twitter.card.player'), value: 'player' },
|
||||
],
|
||||
label: 'Card type',
|
||||
placeholder: 'The Twitter card type...',
|
||||
label: t('tools.og-meta-generator.twitter.card.label'),
|
||||
placeholder: t('tools.og-meta-generator.twitter.card.placeholder'),
|
||||
key: 'twitter:card',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Site account',
|
||||
placeholder: 'The name of the Twitter account of the site (ex: @ittoolsdottech)...',
|
||||
label: t('tools.og-meta-generator.twitter.site.label'),
|
||||
placeholder: t('tools.og-meta-generator.twitter.site.placeholder'),
|
||||
key: 'twitter:site',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Creator acc.',
|
||||
placeholder: 'The name of the Twitter account of the creator (ex: @cthmsst)...',
|
||||
label: t('tools.og-meta-generator.twitter.creator.label'),
|
||||
placeholder: t('tools.og-meta-generator.twitter.creator.placeholder'),
|
||||
key: 'twitter:creator',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { videoMovie } from './videoMovie';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const videoEpisode: OGSchemaType = {
|
||||
name: 'Video episode details',
|
||||
name: t('tools.og-meta-generator.videoEpisode.title'),
|
||||
elements: [
|
||||
...videoMovie.elements,
|
||||
{ type: 'input', label: 'Series', key: 'video:series', placeholder: 'Which series this episode belongs to...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.videoEpisode.series.label'), key: 'video:series', placeholder: t('tools.og-meta-generator.videoEpisode.series.placeholder') },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const videoMovie: OGSchemaType = {
|
||||
name: 'Movie details',
|
||||
name: t('tools.og-meta-generator.videoMovie.title'),
|
||||
elements: [
|
||||
{
|
||||
type: 'input-multiple',
|
||||
label: 'Actor',
|
||||
label: t('tools.og-meta-generator.videoMovie.actor.label'),
|
||||
key: 'video:actor',
|
||||
placeholder: 'Name of the actress/actor...',
|
||||
placeholder: t('tools.og-meta-generator.videoMovie.actor.placeholder'),
|
||||
},
|
||||
// { type: 'input', label: 'Actor role', key: 'video:actor:role', placeholder: 'The role they played...' },
|
||||
// { type: 'input', label: t('tools.og-meta-generator.videoMovie.actorRole.label'), key: 'video:actor:role', placeholder: t('tools.og-meta-generator.videoMovie.actorRole.placeholder') },
|
||||
{
|
||||
type: 'input-multiple',
|
||||
label: 'Director',
|
||||
label: t('tools.og-meta-generator.videoMovie.director.label'),
|
||||
key: 'video:director',
|
||||
placeholder: 'Name of the director...',
|
||||
placeholder: t('tools.og-meta-generator.videoMovie.director.placeholder'),
|
||||
},
|
||||
{ type: 'input-multiple', label: 'Writer', key: 'video:writer', placeholder: 'Writers of the movie...' },
|
||||
{ type: 'input', label: 'Duration', key: 'video:duration', placeholder: 'The movie\'s length in seconds...' },
|
||||
{ type: 'input-multiple', label: t('tools.og-meta-generator.videoMovie.writer.label'), key: 'video:writer', placeholder: t('tools.og-meta-generator.videoMovie.writer.placeholder') },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.videoMovie.duration.label'), key: 'video:duration', placeholder: t('tools.og-meta-generator.videoMovie.duration.placeholder') },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Release date',
|
||||
label: t('tools.og-meta-generator.videoMovie.releaseDate.label'),
|
||||
key: 'video:release_date',
|
||||
placeholder: 'The date the movie was released...',
|
||||
placeholder: t('tools.og-meta-generator.videoMovie.releaseDate.placeholder'),
|
||||
},
|
||||
{ type: 'input', label: 'Tag', key: 'video:tag', placeholder: 'Tag words associated with this movie...' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.videoMovie.tag.label'), key: 'video:tag', placeholder: t('tools.og-meta-generator.videoMovie.tag.placeholder') },
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { videoMovie } from './videoMovie';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const videoOther: OGSchemaType = {
|
||||
name: 'Other video details',
|
||||
name: t('tools.og-meta-generator.videoOther.title'),
|
||||
elements: [...videoMovie.elements],
|
||||
};
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { videoMovie } from './videoMovie';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const videoTVShow: OGSchemaType = {
|
||||
name: 'TV show details',
|
||||
name: t('tools.og-meta-generator.videoTVShow.title'),
|
||||
elements: [...videoMovie.elements],
|
||||
};
|
||||
|
|
|
@ -1,55 +1,56 @@
|
|||
import type { OGSchemaType } from '../OGSchemaType.type';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
const typeOptions = [
|
||||
{ label: 'Website', value: 'website' },
|
||||
{ label: 'Article', value: 'article' },
|
||||
{ label: 'Book', value: 'book' },
|
||||
{ label: 'Profile', value: 'profile' },
|
||||
{ label: t('tools.og-meta-generator.website.web'), value: 'website' },
|
||||
{ label: t('tools.og-meta-generator.website.article'), value: 'article' },
|
||||
{ label: t('tools.og-meta-generator.website.book'), value: 'book' },
|
||||
{ label: t('tools.og-meta-generator.website.profile'), value: 'profile' },
|
||||
{
|
||||
type: 'group',
|
||||
label: 'Music',
|
||||
label: t('tools.og-meta-generator.website.music.label'),
|
||||
key: 'Music',
|
||||
children: [
|
||||
{ label: 'Song', value: 'music.song' },
|
||||
{ label: 'Music album', value: 'music.album' },
|
||||
{ label: 'Playlist', value: 'music.playlist' },
|
||||
{ label: 'Radio station', value: 'music.radio_station' },
|
||||
{ label: t('tools.og-meta-generator.website.music.song'), value: 'music.song' },
|
||||
{ label: t('tools.og-meta-generator.website.music.musicAlbum'), value: 'music.album' },
|
||||
{ label: t('tools.og-meta-generator.website.music.playlist'), value: 'music.playlist' },
|
||||
{ label: t('tools.og-meta-generator.website.music.radioStation'), value: 'music.radio_station' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
label: 'Video',
|
||||
label: t('tools.og-meta-generator.website.video.label'),
|
||||
key: 'Video',
|
||||
children: [
|
||||
{ label: 'Movie', value: 'video.movie' },
|
||||
{ label: 'Episode', value: 'video.episode' },
|
||||
{ label: 'TV show', value: 'video.tv_show' },
|
||||
{ label: 'Other video', value: 'video.other' },
|
||||
{ label: t('tools.og-meta-generator.website.video.movie'), value: 'video.movie' },
|
||||
{ label: t('tools.og-meta-generator.website.video.episode'), value: 'video.episode' },
|
||||
{ label: t('tools.og-meta-generator.website.video.tvShow'), value: 'video.tv_show' },
|
||||
{ label: t('tools.og-meta-generator.website.video.otherVideo'), value: 'video.other' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const website: OGSchemaType = {
|
||||
name: 'General information',
|
||||
name: t('tools.og-meta-generator.website.title'),
|
||||
elements: [
|
||||
{
|
||||
type: 'select',
|
||||
label: 'Page type',
|
||||
placeholder: 'Select the type of your website...',
|
||||
label: t('tools.og-meta-generator.website.pageType.label'),
|
||||
placeholder: t('tools.og-meta-generator.website.pageType.placeholder'),
|
||||
key: 'type',
|
||||
options: typeOptions,
|
||||
},
|
||||
{ type: 'input', label: 'Title', placeholder: 'Enter the title of your website...', key: 'title' },
|
||||
{ type: 'input', label: t('tools.og-meta-generator.website.pageTitle.label'), placeholder: t('tools.og-meta-generator.website.pageTitle.placeholder'), key: 'title' },
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Description',
|
||||
placeholder: 'Enter the description of your website...',
|
||||
label: t('tools.og-meta-generator.website.description.label'),
|
||||
placeholder: t('tools.og-meta-generator.website.description.placeholder'),
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
label: 'Page URL',
|
||||
placeholder: 'Enter the url of your website...',
|
||||
label: t('tools.og-meta-generator.website.url.label'),
|
||||
placeholder: t('tools.og-meta-generator.website.url.placeholder'),
|
||||
key: 'url',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { World } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Mime types',
|
||||
name: t('tools.mime-types.title'),
|
||||
path: '/mime-types',
|
||||
description: 'Convert mime types to extensions and vice-versa.',
|
||||
description: t('tools.mime-types.description'),
|
||||
keywords: ['mime', 'types', 'extension', 'content', 'type'],
|
||||
component: () => import('./mime-types.vue'),
|
||||
icon: World,
|
||||
|
|
23
src/tools/mime-types/locales/en.yml
Normal file
23
src/tools/mime-types/locales/en.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
tools:
|
||||
mime-types:
|
||||
title: Mime types
|
||||
description: Convert mime types to extensions and vice-versa.
|
||||
|
||||
mimeType:
|
||||
title: Mime type to extension
|
||||
description: Know which file extensions are associated to a mime-type
|
||||
placeholder: 'Select your mimetype here... (ex: application/pdf)'
|
||||
extensionsFound:
|
||||
before: 'Extensions of files with the '
|
||||
after: ' mime-type:'
|
||||
extension:
|
||||
title: File extension to mime type
|
||||
description: Know which mime type is associated to a file extension
|
||||
placeholder: 'Select your mimetype here... (ex: application/pdf)'
|
||||
selectedExtension:
|
||||
before: 'Mime type associated to the extension '
|
||||
after: ' file'
|
||||
ext: 'extension:'
|
||||
table:
|
||||
mimeTypes: Mime types
|
||||
extensions: Extensions
|
23
src/tools/mime-types/locales/zh.yml
Normal file
23
src/tools/mime-types/locales/zh.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
tools:
|
||||
mime-types:
|
||||
title: MIME 类型
|
||||
description: 将 MIME 类型转换为扩展名,反之亦然。
|
||||
|
||||
mimeType:
|
||||
title: MIME 类型转扩展名
|
||||
description: 知道哪些文件扩展名与特定 MIME 类型相关联
|
||||
placeholder: '在此处选择您的 MIME 类型...(例如:application/pdf)'
|
||||
extensionsFound:
|
||||
before: '具有'
|
||||
after: ' MIME 类型的文件扩展名:'
|
||||
extension:
|
||||
title: 文件扩展名转 MIME 类型
|
||||
description: 知道哪种 MIME 类型与文件扩展名相关联
|
||||
placeholder: '在此处选择您的 MIME 类型...(例如:application/pdf)'
|
||||
selectedExtension:
|
||||
before: '与扩展名'
|
||||
after: '相关联的 MIME 类型:'
|
||||
ext: '扩展名:'
|
||||
table:
|
||||
mimeTypes: MIME 类型
|
||||
extensions: 扩展名
|
|
@ -1,6 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { types as extensionToMimeType, extensions as mimeTypeToExtension } from 'mime-types';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const mimeInfos = Object.entries(mimeTypeToExtension).map(([mimeType, extensions]) => ({ mimeType, extensions }));
|
||||
|
||||
const mimeToExtensionsOptions = Object.keys(mimeTypeToExtension).map(label => ({ label, value: label }));
|
||||
|
@ -21,23 +23,23 @@ const mimeTypeFound = computed(() => (selectedExtension.value ? extensionToMimeT
|
|||
<template>
|
||||
<c-card>
|
||||
<n-h2 style="margin-bottom: 0">
|
||||
Mime type to extension
|
||||
{{ t('tools.mime-types.mimeType.title') }}
|
||||
</n-h2>
|
||||
<div style="opacity: 0.8">
|
||||
Know which file extensions are associated to a mime-type
|
||||
{{ t('tools.mime-types.mimeType.description') }}
|
||||
</div>
|
||||
<c-select
|
||||
v-model:value="selectedMimeType"
|
||||
searchable
|
||||
my-4
|
||||
:options="mimeToExtensionsOptions"
|
||||
placeholder="Select your mimetype here... (ex: application/pdf)"
|
||||
:placeholder="t('tools.mime-types.mimeType.placeholder')"
|
||||
/>
|
||||
|
||||
<div v-if="extensionsFound.length > 0">
|
||||
Extensions of files with the <n-tag round :bordered="false">
|
||||
{{ t('tools.mime-types.mimeType.extensionsFound.before') }}<n-tag round :bordered="false">
|
||||
{{ selectedMimeType }}
|
||||
</n-tag> mime-type:
|
||||
</n-tag>{{ t('tools.mime-types.mimeType.extensionsFound.after') }}
|
||||
<div style="margin-top: 10px">
|
||||
<n-tag
|
||||
v-for="extension of extensionsFound"
|
||||
|
@ -55,24 +57,24 @@ const mimeTypeFound = computed(() => (selectedExtension.value ? extensionToMimeT
|
|||
|
||||
<c-card>
|
||||
<n-h2 style="margin-bottom: 0">
|
||||
File extension to mime type
|
||||
{{ t('tools.mime-types.extension.title') }}
|
||||
</n-h2>
|
||||
<div style="opacity: 0.8">
|
||||
Know which mime type is associated to a file extension
|
||||
{{ t('tools.mime-types.extension.description') }}
|
||||
</div>
|
||||
<c-select
|
||||
v-model:value="selectedExtension"
|
||||
searchable
|
||||
my-4
|
||||
:options="extensionToMimeTypeOptions"
|
||||
placeholder="Select your mimetype here... (ex: application/pdf)"
|
||||
:placeholder="t('tools.mime-types.extension.placeholder')"
|
||||
/>
|
||||
|
||||
<div v-if="selectedExtension">
|
||||
Mime type associated to the extension <n-tag round :bordered="false">
|
||||
{{ t('tools.mime-types.extension.selectedExtension.before') }}<n-tag round :bordered="false">
|
||||
{{ selectedExtension }}
|
||||
</n-tag> file
|
||||
extension:
|
||||
</n-tag>{{ t('tools.mime-types.extension.selectedExtension.after') }}
|
||||
{{ t('tools.mime-types.extension.selectedExtension.ext') }}
|
||||
<div style="margin-top: 10px">
|
||||
<n-tag round :bordered="false" type="primary" style="margin-right: 10px">
|
||||
{{ mimeTypeFound }}
|
||||
|
@ -85,8 +87,8 @@ const mimeTypeFound = computed(() => (selectedExtension.value ? extensionToMimeT
|
|||
<n-table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Mime types</th>
|
||||
<th>Extensions</th>
|
||||
<th>{{ t('tools.mime-types.table.mimeTypes') }}</th>
|
||||
<th>{{ t('tools.mime-types.table.extensions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { DeviceMobile } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'OTP code generator',
|
||||
name: t('tools.otp-generator.title'),
|
||||
path: '/otp-generator',
|
||||
description: 'Generate and validate time-based OTP (one time password) for multi-factor authentication.',
|
||||
description: t('tools.otp-generator.description'),
|
||||
keywords: [
|
||||
'otp',
|
||||
'code',
|
||||
|
|
30
src/tools/otp-code-generator-and-validator/locales/en.yml
Normal file
30
src/tools/otp-code-generator-and-validator/locales/en.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
tools:
|
||||
otp-generator:
|
||||
title: OTP code generator
|
||||
description: Generate and validate time-based OTP (one time password) for multi-factor authentication.
|
||||
|
||||
secretLabel: Secret
|
||||
secretPlaceholder: Paste your TOTP secret...
|
||||
generate: Generate a new random secret
|
||||
timeLeft: Next in {second}s
|
||||
keyUri: Open Key URI in new tab
|
||||
hexadecimalLabel: Secret in hexadecimal
|
||||
hexadecimalPlaceholder: Secret in hex will be displayed here
|
||||
epochLabel: Epoch
|
||||
epochPlaceholder: Epoch in sec will be displayed here
|
||||
iteration: Iteration
|
||||
countLabel: 'Count:'
|
||||
countPlaceholder: Iteration count will be displayed here
|
||||
paddedHexLabel: 'Padded hex:'
|
||||
paddedHexPlaceholder: Iteration count in hex will be displayed here
|
||||
|
||||
previous: Previous
|
||||
currentOTP: Current OTP
|
||||
next: Next
|
||||
copied: Copied !
|
||||
copyPreviousOTP: Copy previous OTP
|
||||
copyCurrentOTP: Copy current OTP
|
||||
copyNextOTP: Copy next OTP
|
||||
|
||||
typeErrorMessage: Secret should be a base32 string
|
||||
invalidMessage: Please set a secret
|
30
src/tools/otp-code-generator-and-validator/locales/zh.yml
Normal file
30
src/tools/otp-code-generator-and-validator/locales/zh.yml
Normal file
|
@ -0,0 +1,30 @@
|
|||
tools:
|
||||
otp-generator:
|
||||
title: OTP 验证码生成器
|
||||
description: 生成和验证基于时间的 OTP(一次性密码)以进行多因素身份验证。
|
||||
|
||||
secretLabel: 密钥
|
||||
secretPlaceholder: 粘贴您的 TOTP 密钥...
|
||||
generate: 生成一个新的随机密钥
|
||||
timeLeft: 还剩 {second} 秒
|
||||
keyUri: 在新标签页中打开 Key URI
|
||||
hexadecimalLabel: 十六进制密钥
|
||||
hexadecimalPlaceholder: 十六进制密钥将显示在此处
|
||||
epochLabel: 历元
|
||||
epochPlaceholder: 秒数将显示在此处
|
||||
iteration: 迭代
|
||||
countLabel: '计数:'
|
||||
countPlaceholder: 迭代计数将显示在此处
|
||||
paddedHexLabel: '填充的十六进制:'
|
||||
paddedHexPlaceholder: 十六进制迭代计数将显示在此处
|
||||
|
||||
previous: 上一个
|
||||
currentOTP: 当前 OTP
|
||||
next: 下一个
|
||||
copied: 已复制!
|
||||
copyPreviousOTP: 复制上一个 OTP
|
||||
copyCurrentOTP: 复制当前 OTP
|
||||
copyNextOTP: 复制下一个 OTP
|
||||
|
||||
typeErrorMessage: 密钥应为 base32 字符串
|
||||
invalidMessage: 请设置一个密钥
|
|
@ -8,6 +8,7 @@ import { useStyleStore } from '@/stores/style.store';
|
|||
import InputCopyable from '@/components/InputCopyable.vue';
|
||||
import { computedRefreshable } from '@/composable/computedRefreshable';
|
||||
|
||||
const { t } = useI18n();
|
||||
const now = useTimestamp();
|
||||
const interval = computed(() => (now.value / 1000) % 30);
|
||||
const theme = useThemeVars();
|
||||
|
@ -41,11 +42,11 @@ const { qrcode } = useQRCode({
|
|||
|
||||
const secretValidationRules = [
|
||||
{
|
||||
message: 'Secret should be a base32 string',
|
||||
message: t('tools.otp-generator.typeErrorMessage'),
|
||||
validator: (value: string) => value.toUpperCase().match(/^[A-Z234567]+$/),
|
||||
},
|
||||
{
|
||||
message: 'Please set a secret',
|
||||
message: t('tools.otp-generator.invalidMessage'),
|
||||
validator: (value: string) => value !== '',
|
||||
},
|
||||
];
|
||||
|
@ -55,13 +56,13 @@ const secretValidationRules = [
|
|||
<div style="max-width: 350px">
|
||||
<c-input-text
|
||||
v-model:value="secret"
|
||||
label="Secret"
|
||||
placeholder="Paste your TOTP secret..."
|
||||
:label="t('tools.otp-generator.secretLabel')"
|
||||
:placeholder="t('tools.otp-generator.secretPlaceholder')"
|
||||
mb-5
|
||||
:validation-rules="secretValidationRules"
|
||||
>
|
||||
<template #suffix>
|
||||
<c-tooltip tooltip="Generate a new random secret">
|
||||
<c-tooltip :tooltip="t('tools.otp-generator.generate')">
|
||||
<c-button circle variant="text" size="small" @click="refreshSecret">
|
||||
<icon-mdi-refresh />
|
||||
</c-button>
|
||||
|
@ -74,53 +75,49 @@ const secretValidationRules = [
|
|||
|
||||
<n-progress :percentage="(100 * interval) / 30" :color="theme.primaryColor" :show-indicator="false" />
|
||||
<div style="text-align: center">
|
||||
Next in {{ String(Math.floor(30 - interval)).padStart(2, '0') }}s
|
||||
{{ t('tools.otp-generator.timeLeft', { second: String(Math.floor(30 - interval)).padStart(2, '0') }) }}
|
||||
</div>
|
||||
</div>
|
||||
<div mt-4 flex flex-col items-center justify-center gap-3>
|
||||
<n-image :src="qrcode" />
|
||||
<c-button :href="keyUri" target="_blank">
|
||||
Open Key URI in new tab
|
||||
{{ t('tools.otp-generator.keyUri') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="max-width: 350px">
|
||||
<InputCopyable
|
||||
label="Secret in hexadecimal"
|
||||
:label="t('tools.otp-generator.hexadecimalLabel')"
|
||||
:value="base32toHex(secret)"
|
||||
readonly
|
||||
placeholder="Secret in hex will be displayed here"
|
||||
:placeholder="t('tools.otp-generator.hexadecimalPlaceholder')"
|
||||
mb-5
|
||||
/>
|
||||
|
||||
<InputCopyable
|
||||
label="Epoch"
|
||||
:label="t('tools.otp-generator.epochLabel')"
|
||||
:value="Math.floor(now / 1000).toString()"
|
||||
readonly
|
||||
mb-5
|
||||
placeholder="Epoch in sec will be displayed here"
|
||||
:placeholder="t('tools.otp-generator.epochPlaceholder')"
|
||||
/>
|
||||
|
||||
<p>Iteration</p>
|
||||
<p>{{ t('tools.otp-generator.iteration') }}</p>
|
||||
|
||||
<InputCopyable
|
||||
:value="String(getCounterFromTime({ now, timeStep: 30 }))"
|
||||
readonly
|
||||
label="Count:"
|
||||
label-position="left"
|
||||
label-width="90px"
|
||||
label-align="right"
|
||||
placeholder="Iteration count will be displayed here"
|
||||
:label="t('tools.otp-generator.countLabel')"
|
||||
:placeholder="t('tools.otp-generator.countPlaceholder')"
|
||||
mb-5
|
||||
/>
|
||||
|
||||
<InputCopyable
|
||||
:value="getCounterFromTime({ now, timeStep: 30 }).toString(16).padStart(16, '0')"
|
||||
readonly
|
||||
placeholder="Iteration count in hex will be displayed here"
|
||||
label-position="left"
|
||||
label-width="90px"
|
||||
label-align="right"
|
||||
label="Padded hex:"
|
||||
:placeholder="t('tools.otp-generator.paddedHexPlaceholder')"
|
||||
:label="t('tools.otp-generator.paddedHexLabel')"
|
||||
mb-5
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -6,6 +6,7 @@ const { copy: copyPrevious, isJustCopied: previousCopied } = useCopy({ createToa
|
|||
const { copy: copyCurrent, isJustCopied: currentCopied } = useCopy({ createToast: false });
|
||||
const { copy: copyNext, isJustCopied: nextCopied } = useCopy({ createToast: false });
|
||||
|
||||
const { t } = useI18n();
|
||||
const { tokens } = toRefs(props);
|
||||
</script>
|
||||
|
||||
|
@ -13,29 +14,29 @@ const { tokens } = toRefs(props);
|
|||
<div>
|
||||
<div mb-5px w-full flex items-center>
|
||||
<div flex-1 text-left>
|
||||
Previous
|
||||
{{ t('tools.otp-generator.previous') }}
|
||||
</div>
|
||||
<div flex-1 text-center>
|
||||
Current OTP
|
||||
{{ t('tools.otp-generator.currentOTP') }}
|
||||
</div>
|
||||
<div flex-1 text-right>
|
||||
Next
|
||||
</div>
|
||||
</div>
|
||||
<div flex items-center>
|
||||
<c-tooltip :tooltip="previousCopied ? 'Copied !' : 'Copy previous OTP'" position="bottom" flex-1>
|
||||
<c-tooltip :tooltip="previousCopied ? t('tools.otp-generator.copied') : t('tools.otp-generator.copyPreviousOTP')" position="bottom" flex-1>
|
||||
<c-button data-test-id="previous-otp" w-full important:h-12 important:rounded-r-none important:font-mono @click.prevent="copyPrevious(tokens.previous)">
|
||||
{{ tokens.previous }}
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
<c-tooltip :tooltip="currentCopied ? 'Copied !' : 'Copy current OTP'" position="bottom" flex-1 flex-basis-5xl>
|
||||
<c-tooltip :tooltip="currentCopied ? t('tools.otp-generator.copied') : t('tools.otp-generator.copyCurrentOTP')" position="bottom" flex-1 flex-basis-5xl>
|
||||
<c-button
|
||||
data-test-id="current-otp" w-full important:border-x="1px solid gray op-40" important:h-12 important:rounded-0 important:text-22px @click.prevent="copyCurrent(tokens.current)"
|
||||
>
|
||||
{{ tokens.current }}
|
||||
</c-button>
|
||||
</c-tooltip>
|
||||
<c-tooltip :tooltip="nextCopied ? 'Copied !' : 'Copy next OTP'" position="bottom" flex-1>
|
||||
<c-tooltip :tooltip="nextCopied ? t('tools.otp-generator.copied') : t('tools.otp-generator.copyNextOTP')" position="bottom" flex-1>
|
||||
<c-button data-test-id="next-otp" w-full important:h-12 important:rounded-l-none @click.prevent="copyNext(tokens.next)">
|
||||
{{ tokens.next }}
|
||||
</c-button>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { defineTool } from '../tool';
|
||||
import PasswordIcon from '~icons/mdi/form-textbox-password';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.password-strength-analyser.title'),
|
||||
name: t('tools.password-strength-analyser.title'),
|
||||
path: '/password-strength-analyser',
|
||||
description: translate('tools.password-strength-analyser.description'),
|
||||
description: t('tools.password-strength-analyser.description'),
|
||||
keywords: ['password', 'strength', 'analyser', 'and', 'crack', 'time', 'estimation', 'brute', 'force', 'attack', 'entropy', 'cracking', 'hash', 'hashing', 'algorithm', 'algorithms', 'md5', 'sha1', 'sha256', 'sha512', 'bcrypt', 'scrypt', 'argon2', 'argon2id', 'argon2i', 'argon2d'],
|
||||
component: () => import('./password-strength-analyser.vue'),
|
||||
icon: PasswordIcon,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import _ from 'lodash';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export { getPasswordCrackTimeEstimation, getCharsetLength };
|
||||
|
||||
|
@ -12,24 +12,24 @@ function prettifyExponentialNotation(exponentialNotation: number) {
|
|||
|
||||
function getHumanFriendlyDuration({ seconds }: { seconds: number }) {
|
||||
if (seconds <= 0.001) {
|
||||
return translate('tools.password-strength-analyser.instantly');
|
||||
return t('tools.password-strength-analyser.instantly');
|
||||
}
|
||||
|
||||
if (seconds <= 1) {
|
||||
return translate('tools.password-strength-analyser.lessThanASecond');
|
||||
return t('tools.password-strength-analyser.lessThanASecond');
|
||||
}
|
||||
|
||||
const timeUnits = [
|
||||
{ unit: translate('tools.password-strength-analyser.millenium'), secondsInUnit: 31536000000, format: prettifyExponentialNotation, plural: translate('tools.password-strength-analyser.millennia') },
|
||||
{ unit: translate('tools.password-strength-analyser.century'), secondsInUnit: 3153600000, plural: translate('tools.password-strength-analyser.centuries') },
|
||||
{ unit: translate('tools.password-strength-analyser.decade'), secondsInUnit: 315360000, plural: translate('tools.password-strength-analyser.decades') },
|
||||
{ unit: translate('tools.password-strength-analyser.year'), secondsInUnit: 31536000, plural: translate('tools.password-strength-analyser.years') },
|
||||
{ unit: translate('tools.password-strength-analyser.month'), secondsInUnit: 2592000, plural: translate('tools.password-strength-analyser.months') },
|
||||
{ unit: translate('tools.password-strength-analyser.week'), secondsInUnit: 604800, plural: translate('tools.password-strength-analyser.weeks') },
|
||||
{ unit: translate('tools.password-strength-analyser.day'), secondsInUnit: 86400, plural: translate('tools.password-strength-analyser.days') },
|
||||
{ unit: translate('tools.password-strength-analyser.hour'), secondsInUnit: 3600, plural: translate('tools.password-strength-analyser.hours') },
|
||||
{ unit: translate('tools.password-strength-analyser.minute'), secondsInUnit: 60, plural: translate('tools.password-strength-analyser.minutes') },
|
||||
{ unit: translate('tools.password-strength-analyser.second'), secondsInUnit: 1, plural: translate('tools.password-strength-analyser.seconds') },
|
||||
{ unit: t('tools.password-strength-analyser.millenium'), secondsInUnit: 31536000000, format: prettifyExponentialNotation, plural: t('tools.password-strength-analyser.millennia') },
|
||||
{ unit: t('tools.password-strength-analyser.century'), secondsInUnit: 3153600000, plural: t('tools.password-strength-analyser.centuries') },
|
||||
{ unit: t('tools.password-strength-analyser.decade'), secondsInUnit: 315360000, plural: t('tools.password-strength-analyser.decades') },
|
||||
{ unit: t('tools.password-strength-analyser.year'), secondsInUnit: 31536000, plural: t('tools.password-strength-analyser.years') },
|
||||
{ unit: t('tools.password-strength-analyser.month'), secondsInUnit: 2592000, plural: t('tools.password-strength-analyser.months') },
|
||||
{ unit: t('tools.password-strength-analyser.week'), secondsInUnit: 604800, plural: t('tools.password-strength-analyser.weeks') },
|
||||
{ unit: t('tools.password-strength-analyser.day'), secondsInUnit: 86400, plural: t('tools.password-strength-analyser.days') },
|
||||
{ unit: t('tools.password-strength-analyser.hour'), secondsInUnit: 3600, plural: t('tools.password-strength-analyser.hours') },
|
||||
{ unit: t('tools.password-strength-analyser.minute'), secondsInUnit: 60, plural: t('tools.password-strength-analyser.minutes') },
|
||||
{ unit: t('tools.password-strength-analyser.second'), secondsInUnit: 1, plural: t('tools.password-strength-analyser.seconds') },
|
||||
];
|
||||
|
||||
return _.chain(timeUnits)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { defineTool } from '../tool';
|
||||
import FileCertIcon from '~icons/mdi/file-certificate-outline';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.pdf-signature-checker.title'),
|
||||
name: t('tools.pdf-signature-checker.title'),
|
||||
path: '/pdf-signature-checker',
|
||||
description: translate('tools.pdf-signature-checker.description'),
|
||||
description: t('tools.pdf-signature-checker.description'),
|
||||
keywords: ['pdf', 'signature', 'checker', 'verify', 'validate', 'sign'],
|
||||
component: () => import('./pdf-signature-checker.vue'),
|
||||
icon: FileCertIcon,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { LetterX } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.roman-numeral-converter.title'),
|
||||
name: t('tools.roman-numeral-converter.title'),
|
||||
path: '/roman-numeral-converter',
|
||||
description: translate('tools.roman-numeral-converter.description'),
|
||||
description: t('tools.roman-numeral-converter.description'),
|
||||
keywords: ['roman', 'arabic', 'converter', 'X', 'I', 'V', 'L', 'C', 'D', 'M'],
|
||||
component: () => import('./roman-numeral-converter.vue'),
|
||||
icon: LetterX,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Certificate } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.rsa-key-pair-generator.title'),
|
||||
name: t('tools.rsa-key-pair-generator.title'),
|
||||
path: '/rsa-key-pair-generator',
|
||||
description: translate('tools.rsa-key-pair-generator.description'),
|
||||
description: t('tools.rsa-key-pair-generator.description'),
|
||||
keywords: ['rsa', 'key', 'pair', 'generator', 'public', 'private', 'secret', 'ssh', 'pem'],
|
||||
component: () => import('./rsa-key-pair-generator.vue'),
|
||||
icon: Certificate,
|
||||
|
|
4
src/tools/slugify-string/locales/en.yml
Normal file
4
src/tools/slugify-string/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
slugify-string:
|
||||
title: Slugify string
|
||||
description: Make a string url, filename and id safe.
|
|
@ -1,11 +1,11 @@
|
|||
import { Binary } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.text-to-binary.title'),
|
||||
name: t('tools.text-to-binary.title'),
|
||||
path: '/text-to-binary',
|
||||
description: translate('tools.text-to-binary.description'),
|
||||
description: t('tools.text-to-binary.description'),
|
||||
keywords: ['text', 'to', 'binary', 'converter', 'encode', 'decode', 'ascii'],
|
||||
component: () => import('./text-to-binary.vue'),
|
||||
icon: Binary,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export { convertTextToAsciiBinary, convertAsciiBinaryToText };
|
||||
|
||||
|
@ -13,7 +13,7 @@ function convertAsciiBinaryToText(binary: string): string {
|
|||
const cleanBinary = binary.replace(/[^01]/g, '');
|
||||
|
||||
if (cleanBinary.length % 8) {
|
||||
throw new Error(translate('tools.text-to-binary.invalidBinaryString'));
|
||||
throw new Error(t('tools.text-to-binary.invalidBinaryString'));
|
||||
}
|
||||
|
||||
return cleanBinary
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Speakerphone } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.text-to-nato-alphabet.title'),
|
||||
name: t('tools.text-to-nato-alphabet.title'),
|
||||
path: '/text-to-nato-alphabet',
|
||||
description: translate('tools.text-to-nato-alphabet.description'),
|
||||
description: t('tools.text-to-nato-alphabet.description'),
|
||||
keywords: ['string', 'nato', 'alphabet', 'phonetic', 'oral', 'transmission'],
|
||||
component: () => import('./text-to-nato-alphabet.vue'),
|
||||
icon: Speakerphone,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { ArrowsShuffle } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.token-generator.title'),
|
||||
name: t('tools.token-generator.title'),
|
||||
path: '/token-generator',
|
||||
description: translate('token-generator.description'),
|
||||
description: t('tools.token-generator.description'),
|
||||
keywords: [
|
||||
'token',
|
||||
'random',
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
import BracketIcon from '~icons/mdi/code-brackets';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.toml-to-json.title'),
|
||||
name: t('tools.toml-to-json.title'),
|
||||
path: '/toml-to-json',
|
||||
description: translate('tools.toml-to-json.description'),
|
||||
description: t('tools.toml-to-json.description'),
|
||||
keywords: ['toml', 'json', 'convert', 'online', 'transform', 'parser'],
|
||||
component: () => import('./toml-to-json.vue'),
|
||||
icon: BracketIcon,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
import BracketIcon from '~icons/mdi/code-brackets';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.toml-to-yaml.title'),
|
||||
name: t('tools.toml-to-yaml.title'),
|
||||
path: '/toml-to-yaml',
|
||||
description: translate('tools.toml-to-yaml.description'),
|
||||
description: t('tools.toml-to-yaml.description'),
|
||||
keywords: ['toml', 'yaml', 'convert', 'online', 'transform', 'parse'],
|
||||
component: () => import('./toml-to-yaml.vue'),
|
||||
icon: BracketIcon,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { SortDescendingNumbers } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.ulid-generator.title'),
|
||||
name: t('tools.ulid-generator.title'),
|
||||
path: '/ulid-generator',
|
||||
description: translate('tools.ulid-generator.description'),
|
||||
description: t('tools.ulid-generator.description'),
|
||||
keywords: ['ulid', 'generator', 'random', 'id', 'alphanumeric', 'identity', 'token', 'string', 'identifier', 'unique'],
|
||||
component: () => import('./ulid-generator.vue'),
|
||||
icon: SortDescendingNumbers,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Link } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Encode/decode url formatted strings',
|
||||
name: t('tools.url-encoder.title'),
|
||||
path: '/url-encoder',
|
||||
description: 'Encode to url-encoded format (also known as "percent-encoded") or decode from it.',
|
||||
description: t('tools.url-encoder.description'),
|
||||
keywords: ['url', 'encode', 'decode', 'percent', '%20', 'format'],
|
||||
component: () => import('./url-encoder.vue'),
|
||||
icon: Link,
|
||||
|
|
23
src/tools/url-encoder/locales/en.yml
Normal file
23
src/tools/url-encoder/locales/en.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
tools:
|
||||
url-encoder:
|
||||
title: Encode/decode url formatted strings
|
||||
description: Encode to url-encoded format (also known as "percent-encoded") or decode from it.
|
||||
|
||||
encode:
|
||||
title: Encode
|
||||
inputLabel: 'Your string :'
|
||||
inputPlaceholder: The string to encode
|
||||
outputLabel: 'Your string encoded :'
|
||||
outputPlaceholder: Your string encoded
|
||||
copied: Encoded string copied to the clipboard
|
||||
inValidMessage: Impossible to parse this string
|
||||
decode:
|
||||
title: Decode
|
||||
inputLabel: 'Your encoded string :'
|
||||
inputPlaceholder: The string to decode
|
||||
outputLabel: 'Your string decoded :'
|
||||
outputPlaceholder: Your string decoded
|
||||
copied: Decoded string copied to the clipboard
|
||||
inValidMessage: Impossible to parse this string
|
||||
|
||||
copy: Copy
|
23
src/tools/url-encoder/locales/zh.yml
Normal file
23
src/tools/url-encoder/locales/zh.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
tools:
|
||||
url-encoder:
|
||||
title: 编码/解码 URL 格式化字符串
|
||||
description: 编码为 URL 编码格式(也称为 "百分比编码")或从中解码。
|
||||
|
||||
encode:
|
||||
title: 编码
|
||||
inputLabel: '您的字符串:'
|
||||
inputPlaceholder: 要编码的字符串
|
||||
outputLabel: '您的字符串编码:'
|
||||
outputPlaceholder: 您的字符串编码
|
||||
copied: 编码字符串已复制到剪贴板
|
||||
inValidMessage: 无法解析此字符串
|
||||
decode:
|
||||
title: 解码
|
||||
inputLabel: '您的编码字符串:'
|
||||
inputPlaceholder: 要解码的字符串
|
||||
outputLabel: '您的字符串解码:'
|
||||
outputPlaceholder: 您的字符串解码
|
||||
copied: 解码字符串已复制到剪贴板
|
||||
inValidMessage: 无法解析此字符串
|
||||
|
||||
copy: 复制
|
|
@ -4,6 +4,8 @@ import { useValidation } from '@/composable/validation';
|
|||
import { isNotThrowing } from '@/utils/boolean';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const encodeInput = ref('Hello world :)');
|
||||
const encodeOutput = computed(() => withDefaultOnError(() => encodeURIComponent(encodeInput.value), ''));
|
||||
|
||||
|
@ -12,12 +14,12 @@ const encodedValidation = useValidation({
|
|||
rules: [
|
||||
{
|
||||
validator: value => isNotThrowing(() => encodeURIComponent(value)),
|
||||
message: 'Impossible to parse this string',
|
||||
message: t('tools.url-encoder.encode.inValidMessage'),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { copy: copyEncoded } = useCopy({ source: encodeOutput, text: 'Encoded string copied to the clipboard' });
|
||||
const { copy: copyEncoded } = useCopy({ source: encodeOutput, text: t('tools.url-encoder.encode.copied') });
|
||||
|
||||
const decodeInput = ref('Hello%20world%20%3A)');
|
||||
const decodeOutput = computed(() => withDefaultOnError(() => decodeURIComponent(decodeInput.value), ''));
|
||||
|
@ -27,70 +29,70 @@ const decodeValidation = useValidation({
|
|||
rules: [
|
||||
{
|
||||
validator: value => isNotThrowing(() => decodeURIComponent(value)),
|
||||
message: 'Impossible to parse this string',
|
||||
message: t('tools.url-encoder.decode.inValidMessage'),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { copy: copyDecoded } = useCopy({ source: decodeOutput, text: 'Decoded string copied to the clipboard' });
|
||||
const { copy: copyDecoded } = useCopy({ source: decodeOutput, text: t('tools.url-encoder.decode.copied') });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<c-card title="Encode">
|
||||
<c-card :title="t('tools.url-encoder.encode.title')">
|
||||
<c-input-text
|
||||
v-model:value="encodeInput"
|
||||
label="Your string :"
|
||||
:label="t('tools.url-encoder.encode.inputLabel')"
|
||||
:validation="encodedValidation"
|
||||
multiline
|
||||
autosize
|
||||
placeholder="The string to encode"
|
||||
:placeholder="t('tools.url-encoder.encode.inputPlaceholder')"
|
||||
rows="2"
|
||||
mb-3
|
||||
/>
|
||||
|
||||
<c-input-text
|
||||
label="Your string encoded :"
|
||||
:label="t('tools.url-encoder.encode.outputLabel')"
|
||||
:value="encodeOutput"
|
||||
multiline
|
||||
autosize
|
||||
readonly
|
||||
placeholder="Your string encoded"
|
||||
:placeholder="t('tools.url-encoder.encode.outputPlaceholder')"
|
||||
rows="2"
|
||||
mb-3
|
||||
/>
|
||||
|
||||
<div flex justify-center>
|
||||
<c-button @click="copyEncoded()">
|
||||
Copy
|
||||
{{ t('tools.url-encoder.copy') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
<c-card title="Decode">
|
||||
<c-card :title="t('tools.url-encoder.decode.title')">
|
||||
<c-input-text
|
||||
v-model:value="decodeInput"
|
||||
label="Your encoded string :"
|
||||
:label="t('tools.url-encoder.decode.inputLabel')"
|
||||
:validation="decodeValidation"
|
||||
multiline
|
||||
autosize
|
||||
placeholder="The string to decode"
|
||||
:placeholder="t('tools.url-encoder.decode.inputPlaceholder')"
|
||||
rows="2"
|
||||
mb-3
|
||||
/>
|
||||
|
||||
<c-input-text
|
||||
label="Your string decoded :"
|
||||
:label="t('tools.url-encoder.decode.outputLabel')"
|
||||
:value="decodeOutput"
|
||||
multiline
|
||||
autosize
|
||||
readonly
|
||||
placeholder="Your string decoded"
|
||||
:placeholder="t('tools.url-encoder.decode.outputPlaceholder')"
|
||||
rows="2"
|
||||
mb-3
|
||||
/>
|
||||
|
||||
<div flex justify-center>
|
||||
<c-button @click="copyDecoded()">
|
||||
Copy
|
||||
{{ t('tools.url-encoder.copy') }}
|
||||
</c-button>
|
||||
</div>
|
||||
</c-card>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Unlink } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'Url parser',
|
||||
name: t('tools.url-parser.title'),
|
||||
path: '/url-parser',
|
||||
description:
|
||||
'Parse an url string to get all the different parts (protocol, origin, params, port, username-password, ...)',
|
||||
description: t('tools.url-parser.description'),
|
||||
keywords: ['url', 'parser', 'protocol', 'origin', 'params', 'port', 'username', 'password', 'href'],
|
||||
component: () => import('./url-parser.vue'),
|
||||
icon: Unlink,
|
||||
|
|
17
src/tools/url-parser/locales/en.yml
Normal file
17
src/tools/url-parser/locales/en.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
tools:
|
||||
url-parser:
|
||||
title: Url parser
|
||||
description: Parse an url string to get all the different parts (protocol, origin, params, port, username-password, ...)
|
||||
|
||||
inputLabel: 'Your url to parse:'
|
||||
inputPlaceholder: Your url to parse...
|
||||
|
||||
protocol: Protocol
|
||||
username: Username
|
||||
password: Password
|
||||
hostname: Hostname
|
||||
port: Port
|
||||
path: Path
|
||||
params: Params
|
||||
|
||||
inValidMessage: Invalid url
|
17
src/tools/url-parser/locales/zh.yml
Normal file
17
src/tools/url-parser/locales/zh.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
tools:
|
||||
url-parser:
|
||||
title: Url 解析器
|
||||
description: '解析 URL 字符串以获取所有不同部分(协议,源,参数,端口,用户名-密码,...)'
|
||||
|
||||
inputLabel: '要解析的 URL:'
|
||||
inputPlaceholder: 要解析的 URL...
|
||||
|
||||
protocol: 协议
|
||||
username: 用户名
|
||||
password: 密码
|
||||
hostname: 主机名
|
||||
port: 端口
|
||||
path: 路径
|
||||
params: 参数
|
||||
|
||||
inValidMessage: 无效的 URL
|
|
@ -3,24 +3,25 @@ import InputCopyable from '../../components/InputCopyable.vue';
|
|||
import { isNotThrowing } from '@/utils/boolean';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
|
||||
const { t } = useI18n();
|
||||
const urlToParse = ref('https://me:pwd@it-tools.tech:3000/url-parser?key1=value&key2=value2#the-hash');
|
||||
|
||||
const urlParsed = computed(() => withDefaultOnError(() => new URL(urlToParse.value), undefined));
|
||||
const urlValidationRules = [
|
||||
{
|
||||
validator: (value: string) => isNotThrowing(() => new URL(value)),
|
||||
message: 'Invalid url',
|
||||
message: t('tools.url-parser.inValidMessage'),
|
||||
},
|
||||
];
|
||||
|
||||
const properties: { title: string; key: keyof URL }[] = [
|
||||
{ title: 'Protocol', key: 'protocol' },
|
||||
{ title: 'Username', key: 'username' },
|
||||
{ title: 'Password', key: 'password' },
|
||||
{ title: 'Hostname', key: 'hostname' },
|
||||
{ title: 'Port', key: 'port' },
|
||||
{ title: 'Path', key: 'pathname' },
|
||||
{ title: 'Params', key: 'search' },
|
||||
{ title: t('tools.url-parser.protocol'), key: 'protocol' },
|
||||
{ title: t('tools.url-parser.username'), key: 'username' },
|
||||
{ title: t('tools.url-parser.password'), key: 'password' },
|
||||
{ title: t('tools.url-parser.hostname'), key: 'hostname' },
|
||||
{ title: t('tools.url-parser.port'), key: 'port' },
|
||||
{ title: t('tools.url-parser.path'), key: 'pathname' },
|
||||
{ title: t('tools.url-parser.params'), key: 'search' },
|
||||
];
|
||||
</script>
|
||||
|
||||
|
@ -28,8 +29,8 @@ const properties: { title: string; key: keyof URL }[] = [
|
|||
<c-card>
|
||||
<c-input-text
|
||||
v-model:value="urlToParse"
|
||||
label="Your url to parse:"
|
||||
placeholder="Your url to parse..."
|
||||
:label="t('tools.url-parser.inputLabel')"
|
||||
:placeholder="t('tools.url-parser.inputPlaceholder')"
|
||||
raw-text
|
||||
:validation-rules="urlValidationRules"
|
||||
/>
|
||||
|
|
4
src/tools/user-agent-parser/locales/en.yml
Normal file
4
src/tools/user-agent-parser/locales/en.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
tools:
|
||||
user-agent-parser:
|
||||
title: User-agent parser
|
||||
description: Detect and parse Browser, Engine, OS, CPU, and Device type/model from an user-agent string.
|
|
@ -1,11 +1,11 @@
|
|||
import { Fingerprint } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.uuid-generator.title'),
|
||||
name: t('tools.uuid-generator.title'),
|
||||
path: '/uuid-generator',
|
||||
description: translate('tools.uuid-generator.description'),
|
||||
description: t('tools.uuid-generator.description'),
|
||||
keywords: ['uuid', 'v4', 'random', 'id', 'alphanumeric', 'identity', 'token', 'string', 'identifier', 'unique', 'v1', 'v3', 'v5', 'nil'],
|
||||
component: () => import('./uuid-generator.vue'),
|
||||
icon: Fingerprint,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { AlignJustified } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.yaml-to-json-converter.title'),
|
||||
name: t('tools.yaml-to-json-converter.title'),
|
||||
path: '/yaml-to-json-converter',
|
||||
description: translate('tools.yaml-to-json-converter.description'),
|
||||
description: t('tools.yaml-to-json-converter.description'),
|
||||
keywords: ['yaml', 'to', 'json'],
|
||||
component: () => import('./yaml-to-json.vue'),
|
||||
icon: AlignJustified,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { AlignJustified } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
import { translate } from '@/plugins/i18n.plugin';
|
||||
import { translate as t } from '@/plugins/i18n.plugin';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: translate('tools.yaml-to-toml.title'),
|
||||
name: t('tools.yaml-to-toml.title'),
|
||||
path: '/yaml-to-toml',
|
||||
description: translate('tools.yaml-to-toml.title'),
|
||||
description: t('tools.yaml-to-toml.title'),
|
||||
keywords: ['yaml', 'to', 'toml', 'convert', 'transform'],
|
||||
component: () => import('./yaml-to-toml.vue'),
|
||||
icon: AlignJustified,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue