Merge d20c027957 into 07eea0f484
				
					
				
			This commit is contained in:
		
						commit
						0d85581ef3
					
				
							
								
								
									
										130
									
								
								locales/de.yml
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								locales/de.yml
									
									
									
									
									
								
							| @ -1,16 +1,9 @@ | ||||
| '404': | ||||
|   notFound: 404 Nicht gefunden | ||||
|   sorry: Entschuldigung, diese Seite scheint nicht zu existieren | ||||
|   maybe: >- | ||||
|     Vielleicht macht der Cache etwas Seltsames. Mit einem erzwungenen Neuladen | ||||
|     versuchen? | ||||
|   backHome: Zurück zur Startseite | ||||
| home: | ||||
|   categories: | ||||
|     newestTools: Neueste Tools | ||||
|     favoriteTools: Deine Lieblingstools | ||||
|     allTools: Alle Tools | ||||
|     favoritesDndToolTip: 'Ziehen und Ablegen, um Favoriten neu zu ordnen' | ||||
|     favoritesDndToolTip: Drag and Drop, um Favoriten neu zu ordnen | ||||
|   subtitle: Praktische Tools für Entwickler | ||||
|   toggleMenu: Menü umschalten | ||||
|   home: Startseite | ||||
| @ -72,6 +65,13 @@ about: | ||||
|     funktioniert, melde bitte einen Fehler im | ||||
|     [Issues-Bereich](https://github.com/CorentinTh/it-tools/issues/new/choose) | ||||
|     im GitHub-Repository. | ||||
| 404: | ||||
|   notFound: 404 Nicht gefunden | ||||
|   sorry: Entschuldigung, diese Seite scheint nicht zu existieren | ||||
|   maybe: >- | ||||
|     Vielleicht macht der Cache etwas Seltsames. Mit einem erzwungenen Neuladen | ||||
|     versuchen? | ||||
|   backHome: Zurück zur Startseite | ||||
| favoriteButton: | ||||
|   remove: Aus Favoriten entfernen | ||||
|   add: Zu Favoriten hinzufügen | ||||
| @ -79,6 +79,20 @@ toolCard: | ||||
|   new: Neu | ||||
| search: | ||||
|   label: Suche | ||||
|   placeholder: Tippe, um ein Tool oder einen Befehl zu suchen... | ||||
| textareaCopyable: | ||||
|   copy: In die Zwischenablage kopieren | ||||
|   copied: Kopiert! | ||||
| spanCopyable: | ||||
|   copy: In die Zwischenablage kopieren | ||||
|   copied: Kopiert! | ||||
| inputCopyable: | ||||
|   copy: In die Zwischenablage kopieren | ||||
|   copied: Kopiert! | ||||
| formatTransformer: | ||||
|   input: Eingabe | ||||
|   input-placeholder: Eingabe... | ||||
|   output: Ausgabe | ||||
| tools: | ||||
|   categories: | ||||
|     favorite-tools: Deine Lieblingstools | ||||
| @ -102,6 +116,10 @@ tools: | ||||
|     description: >- | ||||
|       Überwache die Dauer einer Sache. Im Grunde ein Chronometer mit einfachen | ||||
|       Chronometerfunktionen. | ||||
|     button: | ||||
|       start: Start | ||||
|       stop: Stopp | ||||
|       reset: Zurücksetzen | ||||
|   token-generator: | ||||
|     title: Token-Generator | ||||
|     description: >- | ||||
| @ -296,6 +314,13 @@ tools: | ||||
|     description: >- | ||||
|       Generiere und downloade QR-Codes für eine URL oder einfach einen Text und | ||||
|       passe die Hintergrund- und Vordergrundfarben an. | ||||
|     text: 'Text:' | ||||
|     placeholder: Dein Link oder Text... | ||||
|     foreground-color: 'Vordergrundfarbe:' | ||||
|     background-color: 'Hintergrundfarbe:' | ||||
|     error-resistance: 'Fehlerresistenz:' | ||||
|     button: | ||||
|       download: QR-Code herunterladen | ||||
|   wifi-qrcode-generator: | ||||
|     title: WLAN-QR-Code-Generator | ||||
|     description: >- | ||||
| @ -420,6 +445,11 @@ tools: | ||||
|     description: >- | ||||
|       Informationen zu einem Text erhalten, wie die Anzahl der Zeichen, die | ||||
|       Anzahl der Wörter, die Größe usw. | ||||
|     characters: Anzahl Zeichen | ||||
|     words: Anzahl Wörter | ||||
|     lines: Anzahl Zeilen | ||||
|     bytes: Bytegröße | ||||
|     placeholder: Dein Text... | ||||
|   text-to-nato-alphabet: | ||||
|     title: Text zu NATO-Alphabet | ||||
|     description: >- | ||||
| @ -430,6 +460,13 @@ tools: | ||||
|     description: >- | ||||
|       Generiere einen Base64-Basic-Auth-Header aus einem Benutzernamen und einem | ||||
|       Passwort. | ||||
|     button: | ||||
|       copy: Header kopieren | ||||
|     copied: Header in die Zwischenablage kopiert | ||||
|     password: Passwort | ||||
|     username: Benutzername | ||||
|     yourpassword: Dein Passwort... | ||||
|     yourusername: Dein Benutzername... | ||||
|   text-to-unicode: | ||||
|     title: Text zu Unicode | ||||
|     description: Parse und konvertiere Text in Unicode und umgekehrt. | ||||
| @ -454,3 +491,80 @@ tools: | ||||
|   text-to-binary: | ||||
|     title: Text zu ASCII-Binär | ||||
|     description: Konvertiere Text in seine ASCII-Binärrepräsentation und umgekehrt. | ||||
|   safelink-decoder: | ||||
|     title: Outlook Safelink-Decoder | ||||
|     description: Outlook Safelinks decodieren | ||||
|     input: 'Eingabe einer Outlook Safelink-URL:' | ||||
|     input-placeholder: Deine eingegebene Outlook Safelink-URL... | ||||
|     output: 'Ausgabe der decodierten URL:' | ||||
|   ascii-text-drawer: | ||||
|     title: ASCII-Art-Text-Generator | ||||
|     description: ASCII-Art-Text mit vielen Schriftarten und Stilen erstellen. | ||||
|     text: 'Dein Text:' | ||||
|     placeholder: Dein zu zeichnender Text | ||||
|     font: 'Schriftart:' | ||||
|     width: 'Breite:' | ||||
|     loading: Schriftart wird geladen... | ||||
|     error: Die aktuellen Einstellungen führten zu einem Fehler. | ||||
|     output: 'ASCII-Art-Text:' | ||||
|   json-to-xml: | ||||
|     title: JSON zu XML | ||||
|     description: JSON in XML konvertieren | ||||
|     input: Dein JSON-Inhalt | ||||
|     input-placeholder: Füge hier deinen JSON-Inhalt ein... | ||||
|     output: Konvertiertes XML | ||||
|     error: Bereitgestelltes JSON ist ungültig. | ||||
|   xml-to-json: | ||||
|     title: XML zu JSON | ||||
|     description: XML in JSON konvertieren | ||||
|     input: Dein XML-Inhalt | ||||
|     input-placeholder: Füge hier deinen XML-Inhalt ein... | ||||
|     output: Konvertiertes JSON | ||||
|     error: Bereitgestelltes XML ist ungültig. | ||||
|   email-normalizer: | ||||
|     title: E-Mail-Normalisierung | ||||
|     description: >- | ||||
|       Vereinheitlichen von E-Mail-Adressen auf ein Standardformat für einen | ||||
|       einfacheren Vergleich. Nützlich für Deduplizierung und Datenbereinigung. | ||||
|     input: 'Unbearbeitete E-Mails zur Normalisierung:' | ||||
|     input-placeholder: Gib hier deine E-Mails ein (eine pro Zeile)... | ||||
|     output: 'Normalisierte E-Mails:' | ||||
|     output-placeholder: Hier werden normalisierte E-Mails angezeigt... | ||||
|     button: | ||||
|       clear: E-Mails leeren | ||||
|       copy: Kopiere normalisierte E-Mails | ||||
|     copied: Normalisierte E-Mails in die Zwischenablage kopiert | ||||
|   markdown-to-html: | ||||
|     title: Markdown zu HTML | ||||
|     description: Markdown in HTML konvertieren und (als PDF) ausdrucken | ||||
|     markdown: 'Dein zu konvertierender Markdown-Inhalt:' | ||||
|     markdownInput: Dein Markdown-Inhalt... | ||||
|     html: 'HTML-Ausgabe:' | ||||
|     button: | ||||
|       print: Als PDF drucken | ||||
|   regex-memo: | ||||
|     title: Regex-Spickzettel | ||||
|     description: Spickzettel für Javascript Regex/Regulärer Ausdruck | ||||
|   regex-tester: | ||||
|     title: Regex-Tester | ||||
|     description: Teste deine regulären Ausdrücke mit Beispieltext. | ||||
|     regex: Regex | ||||
|     regex-input: 'Regex zum Testen:' | ||||
|     regex-input-placeholder: Eingabe des zu testenden regulären Ausdrucks | ||||
|     link: Siehe Spickzettel für reguläre Ausdrücke | ||||
|     text-input: 'Zu prüfender Text:' | ||||
|     text-input-placeholder: Eingabe des zu prüfenden Texts | ||||
|     matches: Treffer | ||||
|     text-index: Index im Text | ||||
|     value: Wert | ||||
|     captures: Erfassungen | ||||
|     groups: Gruppen | ||||
|     sample: Beispiel für passenden Text | ||||
|     diagram: Regex-Diagramm | ||||
|     global: Globale Suche. | ||||
|     ignoreCase: Suche ohne Berücksichtigung der Groß-/Kleinschreibung. | ||||
|     multiline: Ermöglicht die Übereinstimmung von ^ und $ neben Zeilenumbruchzeichen. | ||||
|     dotAll: Lässt . als Treffer für Zeilenumbruchzeichen zu. | ||||
|     unicode: Unicode; behandelt ein Muster als eine Folge von Unicode-Codepunkten. | ||||
|     unicodeSets: Ein Upgrade zum u-Modus mit mehr Unicode-Funktionen. | ||||
|     no-match: Kein Treffer | ||||
|  | ||||
							
								
								
									
										124
									
								
								locales/en.yml
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								locales/en.yml
									
									
									
									
									
								
							| @ -57,6 +57,20 @@ toolCard: | ||||
|   new: New | ||||
| search: | ||||
|   label: Search | ||||
|   placeholder: Type to search a tool or a command... | ||||
| textareaCopyable: | ||||
|   copy: Copy to clipboard | ||||
|   copied: Copied! | ||||
| spanCopyable: | ||||
|   copy: Copy to clipboard | ||||
|   copied: Copied! | ||||
| inputCopyable: | ||||
|   copy: Copy to clipboard | ||||
|   copied: Copied! | ||||
| formatTransformer: | ||||
|   input: Input | ||||
|   input-placeholder: Input... | ||||
|   output: Output | ||||
| tools: | ||||
|   categories: | ||||
|     favorite-tools: 'Your favorite tools' | ||||
| @ -78,7 +92,11 @@ tools: | ||||
|   chronometer: | ||||
|     title: Chronometer | ||||
|     description: Monitor the duration of a thing. Basically a chronometer with simple chronometer features. | ||||
| 
 | ||||
|     button: | ||||
|       start: Start | ||||
|       stop: Stop | ||||
|       reset: Reset | ||||
|        | ||||
|   token-generator: | ||||
|     title: Token generator | ||||
|     description: Generate random string with the chars you want, uppercase or lowercase letters, numbers and/or symbols. | ||||
| @ -252,6 +270,13 @@ tools: | ||||
|   qrcode-generator: | ||||
|     title: QR Code generator | ||||
|     description: Generate and download a QR code for a URL (or just plain text), and customize the background and foreground colors. | ||||
|     error-resistance: 'Error resistance:' | ||||
|     background-color: 'Background color:' | ||||
|     foreground-color: 'Foreground color:' | ||||
|     text: 'Text:' | ||||
|     placeholder: Your link or text... | ||||
|     button: | ||||
|       download: Download QR code | ||||
| 
 | ||||
|   wifi-qrcode-generator: | ||||
|     title: WiFi QR Code generator | ||||
| @ -360,6 +385,11 @@ tools: | ||||
|   text-statistics: | ||||
|     title: Text statistics | ||||
|     description: Get information about a text, the number of characters, the number of words, its size in bytes, ... | ||||
|     characters: Character count | ||||
|     words: Word count | ||||
|     lines: Line count | ||||
|     bytes: Byte size | ||||
|     placeholder: Your text... | ||||
| 
 | ||||
|   text-to-nato-alphabet: | ||||
|     title: Text to NATO alphabet | ||||
| @ -368,6 +398,13 @@ tools: | ||||
|   basic-auth-generator: | ||||
|     title: Basic auth generator | ||||
|     description: Generate a base64 basic auth header from a username and password. | ||||
|     button: | ||||
|       copy: Copy header | ||||
|     username: Username | ||||
|     yourusername: Your username... | ||||
|     password: Password | ||||
|     yourpassword: Your password... | ||||
|     copied: Header copied to the clipboard | ||||
| 
 | ||||
|   text-to-unicode: | ||||
|     title: Text to Unicode | ||||
| @ -392,3 +429,88 @@ tools: | ||||
|   text-to-binary: | ||||
|     title: Text to ASCII binary | ||||
|     description: Convert text to its ASCII binary representation and vice-versa. | ||||
| 
 | ||||
|   safelink-decoder: | ||||
|     title: Outlook Safelink decoder | ||||
|     description: Decode Outlook SafeLink links | ||||
|     input: 'Your input Outlook SafeLink Url:' | ||||
|     input-placeholder: Your input Outlook SafeLink Url... | ||||
|     output: 'Output decoded URL:' | ||||
| 
 | ||||
|   ascii-text-drawer: | ||||
|     title: ASCII Art Text Generator | ||||
|     description: Create ASCII art text with many fonts and styles. | ||||
|     text: 'Your text:' | ||||
|     placeholder: Your text to draw | ||||
|     output: 'Ascii Art text:' | ||||
|     font: 'Font:' | ||||
|     width: 'Width:' | ||||
|     loading: Loading font... | ||||
|     error: Current settings resulted in error. | ||||
| 
 | ||||
|   json-to-xml: | ||||
|     title: JSON to XML | ||||
|     description: Convert JSON to XML | ||||
|     input: Your JSON content | ||||
|     input-placeholder: Paste your JSON content here... | ||||
|     output: Converted XML | ||||
|     error: Provided JSON is not valid. | ||||
| 
 | ||||
|   xml-to-json: | ||||
|     title: XML to JSON | ||||
|     description: Convert XML to JSON | ||||
|     input: Your XML content | ||||
|     input-placeholder: Paste your XML content here... | ||||
|     output: Converted JSON | ||||
|     error: Provided XML is not valid. | ||||
| 
 | ||||
|   email-normalizer: | ||||
|     title: Email normalizer | ||||
|     description: >- | ||||
|       Normalize email addresses to a standard format for easier comparison. | ||||
|       Useful for deduplication and data cleaning. | ||||
|     input: 'Raw emails to normalize:' | ||||
|     output: 'Normalized emails:' | ||||
|     input-placeholder: Put your emails here (one per line)... | ||||
|     output-placeholder: Normalized emails will appear here... | ||||
|     button: | ||||
|       clear: Clear emails | ||||
|       copy: Copy normalized emails | ||||
|     copied: Normalized emails copied to the clipboard | ||||
| 
 | ||||
|   markdown-to-html: | ||||
|     title: Markdown to HTML | ||||
|     description: Convert Markdown to HTML and allow to print (as PDF) | ||||
|     markdown: 'Your Markdown to convert:' | ||||
|     markdownInput: Your Markdown content... | ||||
|     html: 'Output HTML:' | ||||
|     button: | ||||
|       print: Print as PDF | ||||
| 
 | ||||
|   regex-memo: | ||||
|     title: Regex cheatsheet | ||||
|     description: Javascript Regex/Regular Expression cheatsheet | ||||
| 
 | ||||
|   regex-tester: | ||||
|     title: Regex Tester | ||||
|     description: Test your regular expressions with sample text. | ||||
|     regex-input: 'Regex to test:' | ||||
|     regex-input-placeholder: Put the regex to test | ||||
|     link: See Regular Expression Cheatsheet | ||||
|     text-input: 'Text to match:' | ||||
|     text-input-placeholder: Put the text to match | ||||
|     matches: Matches | ||||
|     text-index: Index in text | ||||
|     value: Value | ||||
|     captures: Captures | ||||
|     groups: Groups | ||||
|     sample: Sample matching text | ||||
|     diagram: Regex Diagram | ||||
|     global: Global search | ||||
|     ignoreCase: Case-insensitive search | ||||
|     multiline: Allows ^ and $ to match next to newline characters. | ||||
|     dotAll: Allows . to match newline characters. | ||||
|     unicode: Unicode; treat a pattern as a sequence of Unicode code points. | ||||
|     unicodeSets: An upgrade to the u mode with more Unicode features. | ||||
|     regex: Regex | ||||
|     no-match: No match | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| import _ from 'lodash'; | ||||
| import type { UseValidationRule } from '@/composable/validation'; | ||||
| import CInputText from '@/ui/c-input-text/c-input-text.vue'; | ||||
| import { translate as t } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| const props = withDefaults( | ||||
|   defineProps<{ | ||||
| @ -16,10 +17,10 @@ const props = withDefaults( | ||||
|   { | ||||
|     transformer: _.identity, | ||||
|     inputValidationRules: () => [], | ||||
|     inputLabel: 'Input', | ||||
|     inputLabel: t('formatTransformer.input'), | ||||
|     inputDefault: '', | ||||
|     inputPlaceholder: 'Input...', | ||||
|     outputLabel: 'Output', | ||||
|     inputPlaceholder: t('formatTransformer.input-placeholder'), | ||||
|     outputLabel: t('formatTransformer.output'), | ||||
|     outputLanguage: '', | ||||
|   }, | ||||
| ); | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| <script setup lang="ts"> | ||||
| import { useVModel } from '@vueuse/core'; | ||||
| import { useCopy } from '@/composable/copy'; | ||||
| import { translate as t } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| const props = defineProps<{ value: string }>(); | ||||
| const emit = defineEmits(['update:value']); | ||||
| 
 | ||||
| const value = useVModel(props, 'value', emit); | ||||
| const { copy, isJustCopied } = useCopy({ source: value, createToast: false }); | ||||
| const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : 'Copy to clipboard'); | ||||
| const tooltipText = computed(() => isJustCopied.value ? t('inputCopyable.copied') : t('inputCopyable.copy')); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| <script setup lang="ts"> | ||||
| import { useCopy } from '@/composable/copy'; | ||||
| import { translate as t } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ value?: string }>(), { value: '' }); | ||||
| const { value } = toRefs(props); | ||||
| 
 | ||||
| const initialText = 'Copy to clipboard'; | ||||
| const initialText = t('spanCopyable.copy'); | ||||
| 
 | ||||
| const { copy, isJustCopied } = useCopy({ source: value, createToast: false }); | ||||
| const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : initialText); | ||||
| const tooltipText = computed(() => isJustCopied.value ? t('spanCopyable.copied') : initialText); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  | ||||
| @ -9,6 +9,7 @@ import yamlHljs from 'highlight.js/lib/languages/yaml'; | ||||
| import iniHljs from 'highlight.js/lib/languages/ini'; | ||||
| import markdownHljs from 'highlight.js/lib/languages/markdown'; | ||||
| import { useCopy } from '@/composable/copy'; | ||||
| import { translate as t } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| const props = withDefaults( | ||||
|   defineProps<{ | ||||
| @ -22,7 +23,7 @@ const props = withDefaults( | ||||
|     followHeightOf: null, | ||||
|     language: 'txt', | ||||
|     copyPlacement: 'top-right', | ||||
|     copyMessage: 'Copy to clipboard', | ||||
|     copyMessage: t('textareaCopyable.copy'), | ||||
|   }, | ||||
| ); | ||||
| hljs.registerLanguage('sql', sqlHljs); | ||||
| @ -37,7 +38,7 @@ const { value, language, followHeightOf, copyPlacement, copyMessage } = toRefs(p | ||||
| const { height } = followHeightOf.value ? useElementSize(followHeightOf) : { height: ref(null) }; | ||||
| 
 | ||||
| const { copy, isJustCopied } = useCopy({ source: value, createToast: false }); | ||||
| const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.value); | ||||
| const tooltipText = computed(() => isJustCopied.value ? t('textareaCopyable.copied') : copyMessage.value); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  | ||||
| @ -125,7 +125,7 @@ function activateOption(option: PaletteOption) { | ||||
|     </c-button> | ||||
| 
 | ||||
|     <c-modal v-model:open="isModalOpen" class="palette-modal" shadow-xl important:max-w-650px important:pa-12px @keydown="handleKeydown"> | ||||
|       <c-input-text ref="inputRef" v-model:value="searchPrompt" raw-text placeholder="Type to search a tool or a command..." autofocus clearable /> | ||||
|       <c-input-text ref="inputRef" v-model:value="searchPrompt" raw-text :placeholder="$t('search.placeholder')" autofocus clearable /> | ||||
| 
 | ||||
|       <div v-for="(options, category) in filteredSearchResult" :key="category"> | ||||
|         <div ml-3 mt-3 text-sm font-bold text-primary op-60> | ||||
|  | ||||
| @ -8,6 +8,7 @@ const width = useStorage('ascii-text-drawer:width', 80); | ||||
| const output = ref(''); | ||||
| const errored = ref(false); | ||||
| const processing = ref(false); | ||||
| const { t } = useI18n(); | ||||
| 
 | ||||
| figlet.defaults({ fontPath: '//unpkg.com/figlet@1.6.0/fonts/' }); | ||||
| 
 | ||||
| @ -44,8 +45,8 @@ const fonts = ['1Row', '3-D', '3D Diagonal', '3D-ASCII', '3x5', '4Max', '5 Line | ||||
|   <c-card style="max-width: 600px;"> | ||||
|     <c-input-text | ||||
|       v-model:value="input" | ||||
|       label="Your text:" | ||||
|       placeholder="Your text to draw" | ||||
|       :label="t('tools.ascii-text-drawer.text')" | ||||
|       :placeholder="t('tools.ascii-text-drawer.placeholder')" | ||||
|       raw-text | ||||
|       multiline | ||||
|       rows="4" | ||||
| @ -58,14 +59,14 @@ const fonts = ['1Row', '3-D', '3D Diagonal', '3D-ASCII', '3x5', '4Max', '5 Line | ||||
|         <c-select | ||||
|           v-model:value="font" | ||||
|           label-position="top" | ||||
|           label="Font:" | ||||
|           :label="t('tools.ascii-text-drawer.font')" | ||||
|           :options="fonts" | ||||
|           searchable="true" | ||||
|           placeholder="Select font to use" | ||||
|         /> | ||||
|       </n-gi> | ||||
|       <n-gi span="2"> | ||||
|         <n-form-item label="Width:" label-placement="top" label-width="100" :show-feedback="false"> | ||||
|         <n-form-item :label="t('tools.ascii-text-drawer.width')" label-placement="top" label-width="100" :show-feedback="false"> | ||||
|           <n-input-number v-model:value="width" min="0" max="10000" w-full placeholder="Width of the text" /> | ||||
|         </n-form-item> | ||||
|       </n-gi> | ||||
| @ -75,14 +76,14 @@ const fonts = ['1Row', '3-D', '3D Diagonal', '3D-ASCII', '3x5', '4Max', '5 Line | ||||
| 
 | ||||
|     <div v-if="processing" flex items-center justify-center> | ||||
|       <n-spin size="medium" /> | ||||
|       <span class="ml-2">Loading font...</span> | ||||
|       <span class="ml-2">{{ t('tools.ascii-text-drawer.loading') }}</span> | ||||
|     </div> | ||||
| 
 | ||||
|     <c-alert v-if="errored" mt-1 text-center type="error"> | ||||
|       Current settings resulted in error. | ||||
|       {{ t('tools.ascii-text-drawer.error') }} | ||||
|     </c-alert> | ||||
| 
 | ||||
|     <n-form-item v-if="!processing && !errored" label="Ascii Art text:"> | ||||
|     <n-form-item v-if="!processing && !errored" :label="t('tools.ascii-text-drawer.output')"> | ||||
|       <TextareaCopyable | ||||
|         :value="output" | ||||
|         mb-1 mt-1 | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Artboard } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'ASCII Art Text Generator', | ||||
|   name: translate('tools.ascii-text-drawer.title'), | ||||
|   path: '/ascii-text-drawer', | ||||
|   description: 'Create ASCII art text with many fonts and styles.', | ||||
|   description: translate('tools.ascii-text-drawer.description'), | ||||
|   keywords: ['ascii', 'asciiart', 'text', 'drawer'], | ||||
|   component: () => import('./ascii-text-drawer.vue'), | ||||
|   icon: Artboard, | ||||
|  | ||||
| @ -5,17 +5,25 @@ import { textToBase64 } from '@/utils/base64'; | ||||
| const username = ref(''); | ||||
| const password = ref(''); | ||||
| const header = computed(() => `Authorization: Basic ${textToBase64(`${username.value}:${password.value}`)}`); | ||||
| const { t } = useI18n(); | ||||
| 
 | ||||
| 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')" | ||||
|       :placeholder="t('tools.basic-auth-generator.yourusername')" | ||||
|       clearable | ||||
|       raw-text | ||||
|       mb-5 | ||||
|     /> | ||||
|     <c-input-text | ||||
|       v-model:value="password" | ||||
|       label="Password" | ||||
|       placeholder="Your password..." | ||||
|       :label="t('tools.basic-auth-generator.password')" | ||||
|       :placeholder="t('tools.basic-auth-generator.yourpassword')" | ||||
|       clearable | ||||
|       raw-text | ||||
|       mb-2 | ||||
| @ -31,7 +39,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.button.copy') }} | ||||
|       </c-button> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
| @ -5,6 +5,7 @@ import { formatMs } from './chronometer.service'; | ||||
| 
 | ||||
| const isRunning = ref(false); | ||||
| const counter = ref(0); | ||||
| const { t } = useI18n(); | ||||
| 
 | ||||
| let previousRafDate = Date.now(); | ||||
| const { pause: pauseRaf, resume: resumeRaf } = useRafFn( | ||||
| @ -37,14 +38,14 @@ function pause() { | ||||
|     </c-card> | ||||
|     <div mt-5 flex justify-center gap-3> | ||||
|       <c-button v-if="!isRunning" type="primary" @click="resume"> | ||||
|         Start | ||||
|         {{ t('tools.chronometer.button.start') }} | ||||
|       </c-button> | ||||
|       <c-button v-else type="warning" @click="pause"> | ||||
|         Stop | ||||
|         {{ t('tools.chronometer.button.stop') }} | ||||
|       </c-button> | ||||
| 
 | ||||
|       <c-button @click="counter = 0"> | ||||
|         Reset | ||||
|         {{ t('tools.chronometer.button.reset') }} | ||||
|       </c-button> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
| @ -3,6 +3,7 @@ import { normalizeEmail } from 'email-normalizer'; | ||||
| import { withDefaultOnError } from '@/utils/defaults'; | ||||
| import { useCopy } from '@/composable/copy'; | ||||
| 
 | ||||
| const { t } = useI18n(); | ||||
| const emails = ref(''); | ||||
| const normalizedEmails = computed(() => { | ||||
|   if (!emails.value) { | ||||
| @ -17,17 +18,17 @@ const normalizedEmails = computed(() => { | ||||
|     .join('\n'); | ||||
| }); | ||||
| 
 | ||||
| const { copy } = useCopy({ source: normalizedEmails, text: 'Normalized emails copied to the clipboard', createToast: true }); | ||||
| const { copy } = useCopy({ source: normalizedEmails, text: t('tools.email-normalizer.copied'), createToast: true }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div> | ||||
|     <div class="mb-2"> | ||||
|       Raw emails to normalize: | ||||
|       {{ t('tools.email-normalizer.input') }} | ||||
|     </div> | ||||
|     <c-input-text | ||||
|       v-model:value="emails" | ||||
|       placeholder="Put your emails here (one per line)..." | ||||
|       :placeholder="t('tools.email-normalizer.input-placeholder')" | ||||
|       rows="3" | ||||
|       multiline | ||||
|       autocomplete="off" | ||||
| @ -39,11 +40,11 @@ const { copy } = useCopy({ source: normalizedEmails, text: 'Normalized emails co | ||||
|     /> | ||||
| 
 | ||||
|     <div class="mb-2 mt-4"> | ||||
|       Normalized emails: | ||||
|       {{ t('tools.email-normalizer.output') }} | ||||
|     </div> | ||||
|     <c-input-text | ||||
|       :value="normalizedEmails" | ||||
|       placeholder="Normalized emails will appear here..." | ||||
|       :placeholder="t('tools.email-normalizer.output-placeholder')" | ||||
|       rows="3" | ||||
|       autocomplete="off" | ||||
|       autocorrect="off" | ||||
| @ -55,10 +56,10 @@ const { copy } = useCopy({ source: normalizedEmails, text: 'Normalized emails co | ||||
|     /> | ||||
|     <div class="mt-4 flex justify-center gap-2"> | ||||
|       <c-button @click="emails = ''"> | ||||
|         Clear emails | ||||
|         {{ t('tools.email-normalizer.button.clear') }} | ||||
|       </c-button> | ||||
|       <c-button :disabled="!normalizedEmails" @click="copy()"> | ||||
|         Copy normalized emails | ||||
|         {{ t('tools.email-normalizer.button.copy') }} | ||||
|       </c-button> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Mail } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Email normalizer', | ||||
|   name: translate('tools.email-normalizer.title'), | ||||
|   path: '/email-normalizer', | ||||
|   description: 'Normalize email addresses to a standard format for easier comparison. Useful for deduplication and data cleaning.', | ||||
|   description: translate('tools.email-normalizer.description'), | ||||
|   keywords: ['email', 'normalizer'], | ||||
|   component: () => import('./email-normalizer.vue'), | ||||
|   icon: Mail, | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Braces } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'JSON to XML', | ||||
|   name: translate('tools.json-to-xml.title'), | ||||
|   path: '/json-to-xml', | ||||
|   description: 'Convert JSON to XML', | ||||
|   description: translate('tools.json-to-xml.description'), | ||||
|   keywords: ['json', 'xml'], | ||||
|   component: () => import('./json-to-xml.vue'), | ||||
|   icon: Braces, | ||||
|  | ||||
| @ -4,6 +4,7 @@ import JSON5 from 'json5'; | ||||
| import { withDefaultOnError } from '@/utils/defaults'; | ||||
| import type { UseValidationRule } from '@/composable/validation'; | ||||
| 
 | ||||
| const { t } = useI18n(); | ||||
| const defaultValue = '{"a":{"_attributes":{"x":"1.234","y":"It\'s"}}}'; | ||||
| function transformer(value: string) { | ||||
|   return withDefaultOnError(() => { | ||||
| @ -14,17 +15,17 @@ function transformer(value: string) { | ||||
| const rules: UseValidationRule<string>[] = [ | ||||
|   { | ||||
|     validator: (v: string) => v === '' || JSON5.parse(v), | ||||
|     message: 'Provided JSON is not valid.', | ||||
|     message: t('tools.json-to-xml.error'), | ||||
|   }, | ||||
| ]; | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <format-transformer | ||||
|     input-label="Your JSON content" | ||||
|     :input-label="t('tools.json-to-xml.input')" | ||||
|     :input-default="defaultValue" | ||||
|     input-placeholder="Paste your JSON content here..." | ||||
|     output-label="Converted XML" | ||||
|     :input-placeholder="t('tools.json-to-xml.input-placeholder')" | ||||
|     :output-label="t('tools.json-to-xml.output')" | ||||
|     output-language="xml" | ||||
|     :transformer="transformer" | ||||
|     :input-validation-rules="rules" | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Markdown } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Markdown to HTML', | ||||
|   name: translate('tools.markdown-to-html.title'), | ||||
|   path: '/markdown-to-html', | ||||
|   description: 'Convert Markdown to Html and allow to print (as PDF)', | ||||
|   description: translate('tools.markdown-to-html.description'), | ||||
|   keywords: ['markdown', 'html', 'converter', 'pdf'], | ||||
|   component: () => import('./markdown-to-html.vue'), | ||||
|   icon: Markdown, | ||||
|  | ||||
| @ -7,6 +7,7 @@ const outputHtml = computed(() => { | ||||
|   const md = markdownit(); | ||||
|   return md.render(inputMarkdown.value); | ||||
| }); | ||||
| const { t } = useI18n(); | ||||
| 
 | ||||
| function printHtml() { | ||||
|   const w = window.open(); | ||||
| @ -23,21 +24,21 @@ function printHtml() { | ||||
|     <c-input-text | ||||
|       v-model:value="inputMarkdown" | ||||
|       multiline raw-text | ||||
|       placeholder="Your Markdown content..." | ||||
|       :placeholder="t('tools.markdown-to-html.markdownInput')" | ||||
|       rows="8" | ||||
|       autofocus | ||||
|       label="Your Markdown to convert:" | ||||
|       :label="t('tools.markdown-to-html.markdown')" | ||||
|     /> | ||||
| 
 | ||||
|     <n-divider /> | ||||
| 
 | ||||
|     <n-form-item label="Output HTML:"> | ||||
|     <n-form-item :label="t('tools.markdown-to-html.html')"> | ||||
|       <TextareaCopyable :value="outputHtml" :word-wrap="true" language="html" /> | ||||
|     </n-form-item> | ||||
| 
 | ||||
|     <div flex justify-center> | ||||
|       <n-button @click="printHtml"> | ||||
|         Print as PDF | ||||
|         {{ t('tools.markdown-to-html.button.print') }} | ||||
|       </n-button> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
| @ -3,6 +3,7 @@ import type { QRCodeErrorCorrectionLevel } from 'qrcode'; | ||||
| import { useQRCode } from './useQRCode'; | ||||
| import { useDownloadFileFromBase64 } from '@/composable/downloadBase64'; | ||||
| 
 | ||||
| const { t } = useI18n(); | ||||
| const foreground = ref('#000000ff'); | ||||
| const background = ref('#ffffffff'); | ||||
| const errorCorrectionLevel = ref<QRCodeErrorCorrectionLevel>('medium'); | ||||
| @ -32,23 +33,23 @@ const { download } = useDownloadFileFromBase64({ source: qrcode, filename: 'qr-c | ||||
|           label-position="left" | ||||
|           label-width="130px" | ||||
|           label-align="right" | ||||
|           label="Text:" | ||||
|           :label="t('tools.qrcode-generator.text')" | ||||
|           multiline | ||||
|           rows="1" | ||||
|           autosize | ||||
|           placeholder="Your link or text..." | ||||
|           :placeholder="t('tools.qrcode-generator.placeholder')" | ||||
|           mb-6 | ||||
|         /> | ||||
|         <n-form label-width="130" label-placement="left"> | ||||
|           <n-form-item label="Foreground color:"> | ||||
|           <n-form-item :label="t('tools.qrcode-generator.foreground-color')"> | ||||
|             <n-color-picker v-model:value="foreground" :modes="['hex']" /> | ||||
|           </n-form-item> | ||||
|           <n-form-item label="Background color:"> | ||||
|           <n-form-item :label="t('tools.qrcode-generator.background-color')"> | ||||
|             <n-color-picker v-model:value="background" :modes="['hex']" /> | ||||
|           </n-form-item> | ||||
|           <c-select | ||||
|             v-model:value="errorCorrectionLevel" | ||||
|             label="Error resistance:" | ||||
|             :label="t('tools.qrcode-generator.error-resistance')" | ||||
|             label-position="left" | ||||
|             label-width="130px" | ||||
|             label-align="right" | ||||
| @ -60,7 +61,7 @@ const { download } = useDownloadFileFromBase64({ source: qrcode, filename: 'qr-c | ||||
|         <div flex flex-col items-center gap-3> | ||||
|           <n-image :src="qrcode" width="200" /> | ||||
|           <c-button @click="download"> | ||||
|             Download qr-code | ||||
|             {{ t('tools.qrcode-generator.button.download') }} | ||||
|           </c-button> | ||||
|         </div> | ||||
|       </n-gi> | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { BrandJavascript } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Regex cheatsheet', | ||||
|   name: translate('tools.regex-memo.title'), | ||||
|   path: '/regex-memo', | ||||
|   description: 'Javascript Regex/Regular Expression cheatsheet', | ||||
|   description: translate('tools.regex-memo.description'), | ||||
|   keywords: ['regex', 'regular', 'expression', 'javascript', 'memo', 'cheatsheet'], | ||||
|   component: () => import('./regex-memo.vue'), | ||||
|   icon: BrandJavascript, | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Language } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Regex Tester', | ||||
|   name: translate('tools.regex-tester.title'), | ||||
|   path: '/regex-tester', | ||||
|   description: 'Test your regular expressions with sample text.', | ||||
|   description: translate('tools.regex-tester.description'), | ||||
|   keywords: ['regex', 'tester', 'sample', 'expression'], | ||||
|   component: () => import('./regex-tester.vue'), | ||||
|   icon: Language, | ||||
|  | ||||
| @ -15,6 +15,7 @@ const dotAll = ref(true); | ||||
| const unicode = ref(true); | ||||
| const unicodeSets = ref(false); | ||||
| const visualizerSVG = ref<ShadowRootExpose>(); | ||||
| const { t } = useI18n(); | ||||
| 
 | ||||
| const regexValidation = useValidation({ | ||||
|   source: regex, | ||||
| @ -92,36 +93,36 @@ watchEffect( | ||||
| 
 | ||||
| <template> | ||||
|   <div max-w-600px> | ||||
|     <c-card title="Regex" mb-1> | ||||
|     <c-card :title="t('tools.regex-tester.regex')" mb-1> | ||||
|       <c-input-text | ||||
|         v-model:value="regex" | ||||
|         label="Regex to test:" | ||||
|         placeholder="Put the regex to test" | ||||
|         :label="t('tools.regex-tester.regex-input')" | ||||
|         :placeholder="t('tools.regex-tester.regex-input-placeholder')" | ||||
|         multiline | ||||
|         rows="3" | ||||
|         :validation="regexValidation" | ||||
|       /> | ||||
|       <router-link target="_blank" to="/regex-memo" mb-1 mt-1> | ||||
|         See Regular Expression Cheatsheet | ||||
|         {{ t('tools.regex-tester.link') }} | ||||
|       </router-link> | ||||
|       <n-space> | ||||
|         <n-checkbox v-model:checked="global"> | ||||
|           <span title="Global search">Global search. (<code>g</code>)</span> | ||||
|           <span :title="t('tools.regex-tester.global')">Global search (<code>g</code>)</span> | ||||
|         </n-checkbox> | ||||
|         <n-checkbox v-model:checked="ignoreCase"> | ||||
|           <span title="Case-insensitive search">Case-insensitive search. (<code>i</code>)</span> | ||||
|           <span :title="t('tools.regex-tester.ignoreCase')">Case-insensitive search (<code>i</code>)</span> | ||||
|         </n-checkbox> | ||||
|         <n-checkbox v-model:checked="multiline"> | ||||
|           <span title="Allows ^ and $ to match next to newline characters.">Multiline(<code>m</code>)</span> | ||||
|           <span :title="t('tools.regex-tester.multiline')">Multiline (<code>m</code>)</span> | ||||
|         </n-checkbox> | ||||
|         <n-checkbox v-model:checked="dotAll"> | ||||
|           <span title="Allows . to match newline characters.">Singleline(<code>s</code>)</span> | ||||
|           <span :title="t('tools.regex-tester.dotAll')">Singleline (<code>s</code>)</span> | ||||
|         </n-checkbox> | ||||
|         <n-checkbox v-model:checked="unicode"> | ||||
|           <span title="Unicode; treat a pattern as a sequence of Unicode code points.">Unicode(<code>u</code>)</span> | ||||
|           <span :title="t('tools.regex-tester.unicode')">Unicode (<code>u</code>)</span> | ||||
|         </n-checkbox> | ||||
|         <n-checkbox v-model:checked="unicodeSets"> | ||||
|           <span title="An upgrade to the u mode with more Unicode features.">Unicode Sets (<code>v</code>)</span> | ||||
|           <span :title="t('tools.regex-tester.unicodeSets')">Unicode Sets (<code>v</code>)</span> | ||||
|         </n-checkbox> | ||||
|       </n-space> | ||||
| 
 | ||||
| @ -129,28 +130,28 @@ watchEffect( | ||||
| 
 | ||||
|       <c-input-text | ||||
|         v-model:value="text" | ||||
|         label="Text to match:" | ||||
|         placeholder="Put the text to match" | ||||
|         :label="t('tools.regex-tester.text-input')" | ||||
|         :placeholder="t('tools.regex-tester.text-input-placeholder')" | ||||
|         multiline | ||||
|         rows="5" | ||||
|       /> | ||||
|     </c-card> | ||||
| 
 | ||||
|     <c-card title="Matches" mb-1 mt-3> | ||||
|     <c-card :title="t('tools.regex-tester.matches')" mb-1 mt-3> | ||||
|       <n-table v-if="results?.length > 0"> | ||||
|         <thead> | ||||
|           <tr> | ||||
|             <th scope="col"> | ||||
|               Index in text | ||||
|               {{ t('tools.regex-tester.text-index') }} | ||||
|             </th> | ||||
|             <th scope="col"> | ||||
|               Value | ||||
|               {{ t('tools.regex-tester.value') }} | ||||
|             </th> | ||||
|             <th scope="col"> | ||||
|               Captures | ||||
|               {{ t('tools.regex-tester.captures') }} | ||||
|             </th> | ||||
|             <th scope="col"> | ||||
|               Groups | ||||
|               {{ t('tools.regex-tester.groups') }} | ||||
|             </th> | ||||
|           </tr> | ||||
|         </thead> | ||||
| @ -176,15 +177,15 @@ watchEffect( | ||||
|         </tbody> | ||||
|       </n-table> | ||||
|       <c-alert v-else> | ||||
|         No match | ||||
|         {{ t('tools.regex-tester.no-match') }} | ||||
|       </c-alert> | ||||
|     </c-card> | ||||
| 
 | ||||
|     <c-card title="Sample matching text" mt-3> | ||||
|     <c-card :title="t('tools.regex-tester.sample')" mt-3> | ||||
|       <pre style="white-space: pre-wrap; word-break: break-all;">{{ sample }}</pre> | ||||
|     </c-card> | ||||
| 
 | ||||
|     <c-card title="Regex Diagram" style="overflow-x: scroll;" mt-3> | ||||
|     <c-card :title="t('tools.regex-tester.diagram')" style="overflow-x: scroll;" mt-3> | ||||
|       <shadow-root ref="visualizerSVG"> | ||||
|   | ||||
|       </shadow-root> | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Mailbox } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Outlook Safelink decoder', | ||||
|   name: translate('tools.safelink-decoder.title'), | ||||
|   path: '/safelink-decoder', | ||||
|   description: 'Decode Outlook SafeLink links', | ||||
|   description: translate('tools.safelink-decoder.description'), | ||||
|   keywords: ['outlook', 'safelink', 'decoder'], | ||||
|   component: () => import('./safelink-decoder.vue'), | ||||
|   icon: Mailbox, | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| import { decodeSafeLinksURL } from './safelink-decoder.service'; | ||||
| import TextareaCopyable from '@/components/TextareaCopyable.vue'; | ||||
| 
 | ||||
| const { t } = useI18n(); | ||||
| const inputSafeLinkUrl = ref(''); | ||||
| const outputDecodedUrl = computed(() => { | ||||
|   try { | ||||
| @ -18,14 +19,14 @@ const outputDecodedUrl = computed(() => { | ||||
|     <c-input-text | ||||
|       v-model:value="inputSafeLinkUrl" | ||||
|       raw-text | ||||
|       placeholder="Your input Outlook SafeLink Url..." | ||||
|       :placeholder="t('tools.safelink-decoder.input-placeholder')" | ||||
|       autofocus | ||||
|       label="Your input Outlook SafeLink Url:" | ||||
|       :label="t('tools.safelink-decoder.input')" | ||||
|     /> | ||||
| 
 | ||||
|     <n-divider /> | ||||
| 
 | ||||
|     <n-form-item label="Output decoded URL:"> | ||||
|     <n-form-item :label="t('tools.safelink-decoder.output')"> | ||||
|       <TextareaCopyable :value="outputDecodedUrl" :word-wrap="true" /> | ||||
|     </n-form-item> | ||||
|   </div> | ||||
|  | ||||
| @ -3,17 +3,18 @@ import { getStringSizeInBytes } from './text-statistics.service'; | ||||
| import { formatBytes } from '@/utils/convert'; | ||||
| 
 | ||||
| const text = ref(''); | ||||
| const { t } = useI18n(); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <c-card> | ||||
|     <c-input-text v-model:value="text" multiline placeholder="Your text..." rows="5" /> | ||||
|     <c-input-text v-model:value="text" multiline :placeholder="t('tools.text-statistics.placeholder')" rows="5" /> | ||||
| 
 | ||||
|     <div mt-5 flex> | ||||
|       <n-statistic label="Character count" :value="text.length" flex-1 /> | ||||
|       <n-statistic label="Word count" :value="text === '' ? 0 : text.split(/\s+/).length" flex-1 /> | ||||
|       <n-statistic label="Line count" :value="text === '' ? 0 : text.split(/\r\n|\r|\n/).length" flex-1 /> | ||||
|       <n-statistic label="Byte size" :value="formatBytes(getStringSizeInBytes(text))" flex-1 /> | ||||
|       <n-statistic :label="t('tools.text-statistics.characters')" :value="text.length" flex-1 /> | ||||
|       <n-statistic :label="t('tools.text-statistics.words')" :value="text === '' ? 0 : text.split(/\s+/).length" flex-1 /> | ||||
|       <n-statistic :label="t('tools.text-statistics.lines')" :value="text === '' ? 0 : text.split(/\r\n|\r|\n/).length" flex-1 /> | ||||
|       <n-statistic :label="t('tools.text-statistics.bytes')" :value="formatBytes(getStringSizeInBytes(text))" flex-1 /> | ||||
|     </div> | ||||
|   </c-card> | ||||
| </template> | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| import { Braces } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| import { translate } from '@/plugins/i18n.plugin'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'XML to JSON', | ||||
|   name: translate('tools.xml-to-json.title'), | ||||
|   path: '/xml-to-json', | ||||
|   description: 'Convert XML to JSON', | ||||
|   description: translate('tools.xml-to-json.description'), | ||||
|   keywords: ['xml', 'json'], | ||||
|   component: () => import('./xml-to-json.vue'), | ||||
|   icon: Braces, | ||||
|  | ||||
| @ -4,6 +4,7 @@ import { isValidXML } from '../xml-formatter/xml-formatter.service'; | ||||
| import { withDefaultOnError } from '@/utils/defaults'; | ||||
| import type { UseValidationRule } from '@/composable/validation'; | ||||
| 
 | ||||
| const { t } = useI18n(); | ||||
| const defaultValue = '<a x="1.234" y="It\'s"/>'; | ||||
| function transformer(value: string) { | ||||
|   return withDefaultOnError(() => { | ||||
| @ -14,17 +15,17 @@ function transformer(value: string) { | ||||
| const rules: UseValidationRule<string>[] = [ | ||||
|   { | ||||
|     validator: isValidXML, | ||||
|     message: 'Provided XML is not valid.', | ||||
|     message: t('tools.xml-to-json.error'), | ||||
|   }, | ||||
| ]; | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <format-transformer | ||||
|     input-label="Your XML content" | ||||
|     :input-label="t('tools.xml-to-json.input')" | ||||
|     :input-default="defaultValue" | ||||
|     input-placeholder="Paste your XML content here..." | ||||
|     output-label="Converted JSON" | ||||
|     :input-placeholder="t('tools.xml-to-json.input-placeholder')" | ||||
|     :output-label="t('tools.xml-to-json.output')" | ||||
|     output-language="json" | ||||
|     :transformer="transformer" | ||||
|     :input-validation-rules="rules" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user