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: | home: | ||||||
|   categories: |   categories: | ||||||
|     newestTools: Neueste Tools |     newestTools: Neueste Tools | ||||||
|     favoriteTools: Deine Lieblingstools |     favoriteTools: Deine Lieblingstools | ||||||
|     allTools: Alle Tools |     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 |   subtitle: Praktische Tools für Entwickler | ||||||
|   toggleMenu: Menü umschalten |   toggleMenu: Menü umschalten | ||||||
|   home: Startseite |   home: Startseite | ||||||
| @ -72,6 +65,13 @@ about: | |||||||
|     funktioniert, melde bitte einen Fehler im |     funktioniert, melde bitte einen Fehler im | ||||||
|     [Issues-Bereich](https://github.com/CorentinTh/it-tools/issues/new/choose) |     [Issues-Bereich](https://github.com/CorentinTh/it-tools/issues/new/choose) | ||||||
|     im GitHub-Repository. |     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: | favoriteButton: | ||||||
|   remove: Aus Favoriten entfernen |   remove: Aus Favoriten entfernen | ||||||
|   add: Zu Favoriten hinzufügen |   add: Zu Favoriten hinzufügen | ||||||
| @ -79,6 +79,20 @@ toolCard: | |||||||
|   new: Neu |   new: Neu | ||||||
| search: | search: | ||||||
|   label: Suche |   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: | tools: | ||||||
|   categories: |   categories: | ||||||
|     favorite-tools: Deine Lieblingstools |     favorite-tools: Deine Lieblingstools | ||||||
| @ -102,6 +116,10 @@ tools: | |||||||
|     description: >- |     description: >- | ||||||
|       Überwache die Dauer einer Sache. Im Grunde ein Chronometer mit einfachen |       Überwache die Dauer einer Sache. Im Grunde ein Chronometer mit einfachen | ||||||
|       Chronometerfunktionen. |       Chronometerfunktionen. | ||||||
|  |     button: | ||||||
|  |       start: Start | ||||||
|  |       stop: Stopp | ||||||
|  |       reset: Zurücksetzen | ||||||
|   token-generator: |   token-generator: | ||||||
|     title: Token-Generator |     title: Token-Generator | ||||||
|     description: >- |     description: >- | ||||||
| @ -296,6 +314,13 @@ tools: | |||||||
|     description: >- |     description: >- | ||||||
|       Generiere und downloade QR-Codes für eine URL oder einfach einen Text und |       Generiere und downloade QR-Codes für eine URL oder einfach einen Text und | ||||||
|       passe die Hintergrund- und Vordergrundfarben an. |       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: |   wifi-qrcode-generator: | ||||||
|     title: WLAN-QR-Code-Generator |     title: WLAN-QR-Code-Generator | ||||||
|     description: >- |     description: >- | ||||||
| @ -420,6 +445,11 @@ tools: | |||||||
|     description: >- |     description: >- | ||||||
|       Informationen zu einem Text erhalten, wie die Anzahl der Zeichen, die |       Informationen zu einem Text erhalten, wie die Anzahl der Zeichen, die | ||||||
|       Anzahl der Wörter, die Größe usw. |       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: |   text-to-nato-alphabet: | ||||||
|     title: Text zu NATO-Alphabet |     title: Text zu NATO-Alphabet | ||||||
|     description: >- |     description: >- | ||||||
| @ -430,6 +460,13 @@ tools: | |||||||
|     description: >- |     description: >- | ||||||
|       Generiere einen Base64-Basic-Auth-Header aus einem Benutzernamen und einem |       Generiere einen Base64-Basic-Auth-Header aus einem Benutzernamen und einem | ||||||
|       Passwort. |       Passwort. | ||||||
|  |     button: | ||||||
|  |       copy: Header kopieren | ||||||
|  |     copied: Header in die Zwischenablage kopiert | ||||||
|  |     password: Passwort | ||||||
|  |     username: Benutzername | ||||||
|  |     yourpassword: Dein Passwort... | ||||||
|  |     yourusername: Dein Benutzername... | ||||||
|   text-to-unicode: |   text-to-unicode: | ||||||
|     title: Text zu Unicode |     title: Text zu Unicode | ||||||
|     description: Parse und konvertiere Text in Unicode und umgekehrt. |     description: Parse und konvertiere Text in Unicode und umgekehrt. | ||||||
| @ -454,3 +491,80 @@ tools: | |||||||
|   text-to-binary: |   text-to-binary: | ||||||
|     title: Text zu ASCII-Binär |     title: Text zu ASCII-Binär | ||||||
|     description: Konvertiere Text in seine ASCII-Binärrepräsentation und umgekehrt. |     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 | ||||||
|  | |||||||
							
								
								
									
										122
									
								
								locales/en.yml
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								locales/en.yml
									
									
									
									
									
								
							| @ -57,6 +57,20 @@ toolCard: | |||||||
|   new: New |   new: New | ||||||
| search: | search: | ||||||
|   label: 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: | tools: | ||||||
|   categories: |   categories: | ||||||
|     favorite-tools: 'Your favorite tools' |     favorite-tools: 'Your favorite tools' | ||||||
| @ -78,6 +92,10 @@ tools: | |||||||
|   chronometer: |   chronometer: | ||||||
|     title: Chronometer |     title: Chronometer | ||||||
|     description: Monitor the duration of a thing. Basically a chronometer with simple chronometer features. |     description: Monitor the duration of a thing. Basically a chronometer with simple chronometer features. | ||||||
|  |     button: | ||||||
|  |       start: Start | ||||||
|  |       stop: Stop | ||||||
|  |       reset: Reset | ||||||
|        |        | ||||||
|   token-generator: |   token-generator: | ||||||
|     title: Token generator |     title: Token generator | ||||||
| @ -252,6 +270,13 @@ tools: | |||||||
|   qrcode-generator: |   qrcode-generator: | ||||||
|     title: QR Code 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. |     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: |   wifi-qrcode-generator: | ||||||
|     title: WiFi QR Code generator |     title: WiFi QR Code generator | ||||||
| @ -360,6 +385,11 @@ tools: | |||||||
|   text-statistics: |   text-statistics: | ||||||
|     title: Text statistics |     title: Text statistics | ||||||
|     description: Get information about a text, the number of characters, the number of words, its size in bytes, ... |     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: |   text-to-nato-alphabet: | ||||||
|     title: Text to NATO alphabet |     title: Text to NATO alphabet | ||||||
| @ -368,6 +398,13 @@ tools: | |||||||
|   basic-auth-generator: |   basic-auth-generator: | ||||||
|     title: Basic auth generator |     title: Basic auth generator | ||||||
|     description: Generate a base64 basic auth header from a username and password. |     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: |   text-to-unicode: | ||||||
|     title: Text to Unicode |     title: Text to Unicode | ||||||
| @ -392,3 +429,88 @@ tools: | |||||||
|   text-to-binary: |   text-to-binary: | ||||||
|     title: Text to ASCII binary |     title: Text to ASCII binary | ||||||
|     description: Convert text to its ASCII binary representation and vice-versa. |     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 _ from 'lodash'; | ||||||
| import type { UseValidationRule } from '@/composable/validation'; | import type { UseValidationRule } from '@/composable/validation'; | ||||||
| import CInputText from '@/ui/c-input-text/c-input-text.vue'; | import CInputText from '@/ui/c-input-text/c-input-text.vue'; | ||||||
|  | import { translate as t } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| const props = withDefaults( | const props = withDefaults( | ||||||
|   defineProps<{ |   defineProps<{ | ||||||
| @ -16,10 +17,10 @@ const props = withDefaults( | |||||||
|   { |   { | ||||||
|     transformer: _.identity, |     transformer: _.identity, | ||||||
|     inputValidationRules: () => [], |     inputValidationRules: () => [], | ||||||
|     inputLabel: 'Input', |     inputLabel: t('formatTransformer.input'), | ||||||
|     inputDefault: '', |     inputDefault: '', | ||||||
|     inputPlaceholder: 'Input...', |     inputPlaceholder: t('formatTransformer.input-placeholder'), | ||||||
|     outputLabel: 'Output', |     outputLabel: t('formatTransformer.output'), | ||||||
|     outputLanguage: '', |     outputLanguage: '', | ||||||
|   }, |   }, | ||||||
| ); | ); | ||||||
|  | |||||||
| @ -1,13 +1,14 @@ | |||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { useVModel } from '@vueuse/core'; | import { useVModel } from '@vueuse/core'; | ||||||
| import { useCopy } from '@/composable/copy'; | import { useCopy } from '@/composable/copy'; | ||||||
|  | import { translate as t } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ value: string }>(); | const props = defineProps<{ value: string }>(); | ||||||
| const emit = defineEmits(['update:value']); | const emit = defineEmits(['update:value']); | ||||||
| 
 | 
 | ||||||
| const value = useVModel(props, 'value', emit); | const value = useVModel(props, 'value', emit); | ||||||
| const { copy, isJustCopied } = useCopy({ source: value, createToast: false }); | 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> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|  | |||||||
| @ -1,13 +1,14 @@ | |||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { useCopy } from '@/composable/copy'; | import { useCopy } from '@/composable/copy'; | ||||||
|  | import { translate as t } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| const props = withDefaults(defineProps<{ value?: string }>(), { value: '' }); | const props = withDefaults(defineProps<{ value?: string }>(), { value: '' }); | ||||||
| const { value } = toRefs(props); | const { value } = toRefs(props); | ||||||
| 
 | 
 | ||||||
| const initialText = 'Copy to clipboard'; | const initialText = t('spanCopyable.copy'); | ||||||
| 
 | 
 | ||||||
| const { copy, isJustCopied } = useCopy({ source: value, createToast: false }); | 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> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ import yamlHljs from 'highlight.js/lib/languages/yaml'; | |||||||
| import iniHljs from 'highlight.js/lib/languages/ini'; | import iniHljs from 'highlight.js/lib/languages/ini'; | ||||||
| import markdownHljs from 'highlight.js/lib/languages/markdown'; | import markdownHljs from 'highlight.js/lib/languages/markdown'; | ||||||
| import { useCopy } from '@/composable/copy'; | import { useCopy } from '@/composable/copy'; | ||||||
|  | import { translate as t } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| const props = withDefaults( | const props = withDefaults( | ||||||
|   defineProps<{ |   defineProps<{ | ||||||
| @ -22,7 +23,7 @@ const props = withDefaults( | |||||||
|     followHeightOf: null, |     followHeightOf: null, | ||||||
|     language: 'txt', |     language: 'txt', | ||||||
|     copyPlacement: 'top-right', |     copyPlacement: 'top-right', | ||||||
|     copyMessage: 'Copy to clipboard', |     copyMessage: t('textareaCopyable.copy'), | ||||||
|   }, |   }, | ||||||
| ); | ); | ||||||
| hljs.registerLanguage('sql', sqlHljs); | 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 { height } = followHeightOf.value ? useElementSize(followHeightOf) : { height: ref(null) }; | ||||||
| 
 | 
 | ||||||
| const { copy, isJustCopied } = useCopy({ source: value, createToast: false }); | 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> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|  | |||||||
| @ -125,7 +125,7 @@ function activateOption(option: PaletteOption) { | |||||||
|     </c-button> |     </c-button> | ||||||
| 
 | 
 | ||||||
|     <c-modal v-model:open="isModalOpen" class="palette-modal" shadow-xl important:max-w-650px important:pa-12px @keydown="handleKeydown"> |     <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 v-for="(options, category) in filteredSearchResult" :key="category"> | ||||||
|         <div ml-3 mt-3 text-sm font-bold text-primary op-60> |         <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 output = ref(''); | ||||||
| const errored = ref(false); | const errored = ref(false); | ||||||
| const processing = ref(false); | const processing = ref(false); | ||||||
|  | const { t } = useI18n(); | ||||||
| 
 | 
 | ||||||
| figlet.defaults({ fontPath: '//unpkg.com/figlet@1.6.0/fonts/' }); | 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-card style="max-width: 600px;"> | ||||||
|     <c-input-text |     <c-input-text | ||||||
|       v-model:value="input" |       v-model:value="input" | ||||||
|       label="Your text:" |       :label="t('tools.ascii-text-drawer.text')" | ||||||
|       placeholder="Your text to draw" |       :placeholder="t('tools.ascii-text-drawer.placeholder')" | ||||||
|       raw-text |       raw-text | ||||||
|       multiline |       multiline | ||||||
|       rows="4" |       rows="4" | ||||||
| @ -58,14 +59,14 @@ const fonts = ['1Row', '3-D', '3D Diagonal', '3D-ASCII', '3x5', '4Max', '5 Line | |||||||
|         <c-select |         <c-select | ||||||
|           v-model:value="font" |           v-model:value="font" | ||||||
|           label-position="top" |           label-position="top" | ||||||
|           label="Font:" |           :label="t('tools.ascii-text-drawer.font')" | ||||||
|           :options="fonts" |           :options="fonts" | ||||||
|           searchable="true" |           searchable="true" | ||||||
|           placeholder="Select font to use" |           placeholder="Select font to use" | ||||||
|         /> |         /> | ||||||
|       </n-gi> |       </n-gi> | ||||||
|       <n-gi span="2"> |       <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-input-number v-model:value="width" min="0" max="10000" w-full placeholder="Width of the text" /> | ||||||
|         </n-form-item> |         </n-form-item> | ||||||
|       </n-gi> |       </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> |     <div v-if="processing" flex items-center justify-center> | ||||||
|       <n-spin size="medium" /> |       <n-spin size="medium" /> | ||||||
|       <span class="ml-2">Loading font...</span> |       <span class="ml-2">{{ t('tools.ascii-text-drawer.loading') }}</span> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     <c-alert v-if="errored" mt-1 text-center type="error"> |     <c-alert v-if="errored" mt-1 text-center type="error"> | ||||||
|       Current settings resulted in error. |       {{ t('tools.ascii-text-drawer.error') }} | ||||||
|     </c-alert> |     </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 |       <TextareaCopyable | ||||||
|         :value="output" |         :value="output" | ||||||
|         mb-1 mt-1 |         mb-1 mt-1 | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { Artboard } from '@vicons/tabler'; | import { Artboard } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'ASCII Art Text Generator', |   name: translate('tools.ascii-text-drawer.title'), | ||||||
|   path: '/ascii-text-drawer', |   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'], |   keywords: ['ascii', 'asciiart', 'text', 'drawer'], | ||||||
|   component: () => import('./ascii-text-drawer.vue'), |   component: () => import('./ascii-text-drawer.vue'), | ||||||
|   icon: Artboard, |   icon: Artboard, | ||||||
|  | |||||||
| @ -5,17 +5,25 @@ import { textToBase64 } from '@/utils/base64'; | |||||||
| const username = ref(''); | const username = ref(''); | ||||||
| const password = ref(''); | const password = ref(''); | ||||||
| const header = computed(() => `Authorization: Basic ${textToBase64(`${username.value}:${password.value}`)}`); | 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> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <div> |   <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 |     <c-input-text | ||||||
|       v-model:value="password" |       v-model:value="password" | ||||||
|       label="Password" |       :label="t('tools.basic-auth-generator.password')" | ||||||
|       placeholder="Your password..." |       :placeholder="t('tools.basic-auth-generator.yourpassword')" | ||||||
|       clearable |       clearable | ||||||
|       raw-text |       raw-text | ||||||
|       mb-2 |       mb-2 | ||||||
| @ -31,7 +39,7 @@ const { copy } = useCopy({ source: header, text: 'Header copied to the clipboard | |||||||
|     </c-card> |     </c-card> | ||||||
|     <div mt-5 flex justify-center> |     <div mt-5 flex justify-center> | ||||||
|       <c-button @click="copy()"> |       <c-button @click="copy()"> | ||||||
|         Copy header |         {{ t('tools.basic-auth-generator.button.copy') }} | ||||||
|       </c-button> |       </c-button> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ import { formatMs } from './chronometer.service'; | |||||||
| 
 | 
 | ||||||
| const isRunning = ref(false); | const isRunning = ref(false); | ||||||
| const counter = ref(0); | const counter = ref(0); | ||||||
|  | const { t } = useI18n(); | ||||||
| 
 | 
 | ||||||
| let previousRafDate = Date.now(); | let previousRafDate = Date.now(); | ||||||
| const { pause: pauseRaf, resume: resumeRaf } = useRafFn( | const { pause: pauseRaf, resume: resumeRaf } = useRafFn( | ||||||
| @ -37,14 +38,14 @@ function pause() { | |||||||
|     </c-card> |     </c-card> | ||||||
|     <div mt-5 flex justify-center gap-3> |     <div mt-5 flex justify-center gap-3> | ||||||
|       <c-button v-if="!isRunning" type="primary" @click="resume"> |       <c-button v-if="!isRunning" type="primary" @click="resume"> | ||||||
|         Start |         {{ t('tools.chronometer.button.start') }} | ||||||
|       </c-button> |       </c-button> | ||||||
|       <c-button v-else type="warning" @click="pause"> |       <c-button v-else type="warning" @click="pause"> | ||||||
|         Stop |         {{ t('tools.chronometer.button.stop') }} | ||||||
|       </c-button> |       </c-button> | ||||||
| 
 | 
 | ||||||
|       <c-button @click="counter = 0"> |       <c-button @click="counter = 0"> | ||||||
|         Reset |         {{ t('tools.chronometer.button.reset') }} | ||||||
|       </c-button> |       </c-button> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ import { normalizeEmail } from 'email-normalizer'; | |||||||
| import { withDefaultOnError } from '@/utils/defaults'; | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
| import { useCopy } from '@/composable/copy'; | import { useCopy } from '@/composable/copy'; | ||||||
| 
 | 
 | ||||||
|  | const { t } = useI18n(); | ||||||
| const emails = ref(''); | const emails = ref(''); | ||||||
| const normalizedEmails = computed(() => { | const normalizedEmails = computed(() => { | ||||||
|   if (!emails.value) { |   if (!emails.value) { | ||||||
| @ -17,17 +18,17 @@ const normalizedEmails = computed(() => { | |||||||
|     .join('\n'); |     .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> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <div> |   <div> | ||||||
|     <div class="mb-2"> |     <div class="mb-2"> | ||||||
|       Raw emails to normalize: |       {{ t('tools.email-normalizer.input') }} | ||||||
|     </div> |     </div> | ||||||
|     <c-input-text |     <c-input-text | ||||||
|       v-model:value="emails" |       v-model:value="emails" | ||||||
|       placeholder="Put your emails here (one per line)..." |       :placeholder="t('tools.email-normalizer.input-placeholder')" | ||||||
|       rows="3" |       rows="3" | ||||||
|       multiline |       multiline | ||||||
|       autocomplete="off" |       autocomplete="off" | ||||||
| @ -39,11 +40,11 @@ const { copy } = useCopy({ source: normalizedEmails, text: 'Normalized emails co | |||||||
|     /> |     /> | ||||||
| 
 | 
 | ||||||
|     <div class="mb-2 mt-4"> |     <div class="mb-2 mt-4"> | ||||||
|       Normalized emails: |       {{ t('tools.email-normalizer.output') }} | ||||||
|     </div> |     </div> | ||||||
|     <c-input-text |     <c-input-text | ||||||
|       :value="normalizedEmails" |       :value="normalizedEmails" | ||||||
|       placeholder="Normalized emails will appear here..." |       :placeholder="t('tools.email-normalizer.output-placeholder')" | ||||||
|       rows="3" |       rows="3" | ||||||
|       autocomplete="off" |       autocomplete="off" | ||||||
|       autocorrect="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"> |     <div class="mt-4 flex justify-center gap-2"> | ||||||
|       <c-button @click="emails = ''"> |       <c-button @click="emails = ''"> | ||||||
|         Clear emails |         {{ t('tools.email-normalizer.button.clear') }} | ||||||
|       </c-button> |       </c-button> | ||||||
|       <c-button :disabled="!normalizedEmails" @click="copy()"> |       <c-button :disabled="!normalizedEmails" @click="copy()"> | ||||||
|         Copy normalized emails |         {{ t('tools.email-normalizer.button.copy') }} | ||||||
|       </c-button> |       </c-button> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { Mail } from '@vicons/tabler'; | import { Mail } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'Email normalizer', |   name: translate('tools.email-normalizer.title'), | ||||||
|   path: '/email-normalizer', |   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'], |   keywords: ['email', 'normalizer'], | ||||||
|   component: () => import('./email-normalizer.vue'), |   component: () => import('./email-normalizer.vue'), | ||||||
|   icon: Mail, |   icon: Mail, | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { Braces } from '@vicons/tabler'; | import { Braces } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'JSON to XML', |   name: translate('tools.json-to-xml.title'), | ||||||
|   path: '/json-to-xml', |   path: '/json-to-xml', | ||||||
|   description: 'Convert JSON to XML', |   description: translate('tools.json-to-xml.description'), | ||||||
|   keywords: ['json', 'xml'], |   keywords: ['json', 'xml'], | ||||||
|   component: () => import('./json-to-xml.vue'), |   component: () => import('./json-to-xml.vue'), | ||||||
|   icon: Braces, |   icon: Braces, | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ import JSON5 from 'json5'; | |||||||
| import { withDefaultOnError } from '@/utils/defaults'; | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
| import type { UseValidationRule } from '@/composable/validation'; | import type { UseValidationRule } from '@/composable/validation'; | ||||||
| 
 | 
 | ||||||
|  | const { t } = useI18n(); | ||||||
| const defaultValue = '{"a":{"_attributes":{"x":"1.234","y":"It\'s"}}}'; | const defaultValue = '{"a":{"_attributes":{"x":"1.234","y":"It\'s"}}}'; | ||||||
| function transformer(value: string) { | function transformer(value: string) { | ||||||
|   return withDefaultOnError(() => { |   return withDefaultOnError(() => { | ||||||
| @ -14,17 +15,17 @@ function transformer(value: string) { | |||||||
| const rules: UseValidationRule<string>[] = [ | const rules: UseValidationRule<string>[] = [ | ||||||
|   { |   { | ||||||
|     validator: (v: string) => v === '' || JSON5.parse(v), |     validator: (v: string) => v === '' || JSON5.parse(v), | ||||||
|     message: 'Provided JSON is not valid.', |     message: t('tools.json-to-xml.error'), | ||||||
|   }, |   }, | ||||||
| ]; | ]; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <format-transformer |   <format-transformer | ||||||
|     input-label="Your JSON content" |     :input-label="t('tools.json-to-xml.input')" | ||||||
|     :input-default="defaultValue" |     :input-default="defaultValue" | ||||||
|     input-placeholder="Paste your JSON content here..." |     :input-placeholder="t('tools.json-to-xml.input-placeholder')" | ||||||
|     output-label="Converted XML" |     :output-label="t('tools.json-to-xml.output')" | ||||||
|     output-language="xml" |     output-language="xml" | ||||||
|     :transformer="transformer" |     :transformer="transformer" | ||||||
|     :input-validation-rules="rules" |     :input-validation-rules="rules" | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { Markdown } from '@vicons/tabler'; | import { Markdown } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'Markdown to HTML', |   name: translate('tools.markdown-to-html.title'), | ||||||
|   path: '/markdown-to-html', |   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'], |   keywords: ['markdown', 'html', 'converter', 'pdf'], | ||||||
|   component: () => import('./markdown-to-html.vue'), |   component: () => import('./markdown-to-html.vue'), | ||||||
|   icon: Markdown, |   icon: Markdown, | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ const outputHtml = computed(() => { | |||||||
|   const md = markdownit(); |   const md = markdownit(); | ||||||
|   return md.render(inputMarkdown.value); |   return md.render(inputMarkdown.value); | ||||||
| }); | }); | ||||||
|  | const { t } = useI18n(); | ||||||
| 
 | 
 | ||||||
| function printHtml() { | function printHtml() { | ||||||
|   const w = window.open(); |   const w = window.open(); | ||||||
| @ -23,21 +24,21 @@ function printHtml() { | |||||||
|     <c-input-text |     <c-input-text | ||||||
|       v-model:value="inputMarkdown" |       v-model:value="inputMarkdown" | ||||||
|       multiline raw-text |       multiline raw-text | ||||||
|       placeholder="Your Markdown content..." |       :placeholder="t('tools.markdown-to-html.markdownInput')" | ||||||
|       rows="8" |       rows="8" | ||||||
|       autofocus |       autofocus | ||||||
|       label="Your Markdown to convert:" |       :label="t('tools.markdown-to-html.markdown')" | ||||||
|     /> |     /> | ||||||
| 
 | 
 | ||||||
|     <n-divider /> |     <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" /> |       <TextareaCopyable :value="outputHtml" :word-wrap="true" language="html" /> | ||||||
|     </n-form-item> |     </n-form-item> | ||||||
| 
 | 
 | ||||||
|     <div flex justify-center> |     <div flex justify-center> | ||||||
|       <n-button @click="printHtml"> |       <n-button @click="printHtml"> | ||||||
|         Print as PDF |         {{ t('tools.markdown-to-html.button.print') }} | ||||||
|       </n-button> |       </n-button> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ import type { QRCodeErrorCorrectionLevel } from 'qrcode'; | |||||||
| import { useQRCode } from './useQRCode'; | import { useQRCode } from './useQRCode'; | ||||||
| import { useDownloadFileFromBase64 } from '@/composable/downloadBase64'; | import { useDownloadFileFromBase64 } from '@/composable/downloadBase64'; | ||||||
| 
 | 
 | ||||||
|  | const { t } = useI18n(); | ||||||
| const foreground = ref('#000000ff'); | const foreground = ref('#000000ff'); | ||||||
| const background = ref('#ffffffff'); | const background = ref('#ffffffff'); | ||||||
| const errorCorrectionLevel = ref<QRCodeErrorCorrectionLevel>('medium'); | const errorCorrectionLevel = ref<QRCodeErrorCorrectionLevel>('medium'); | ||||||
| @ -32,23 +33,23 @@ const { download } = useDownloadFileFromBase64({ source: qrcode, filename: 'qr-c | |||||||
|           label-position="left" |           label-position="left" | ||||||
|           label-width="130px" |           label-width="130px" | ||||||
|           label-align="right" |           label-align="right" | ||||||
|           label="Text:" |           :label="t('tools.qrcode-generator.text')" | ||||||
|           multiline |           multiline | ||||||
|           rows="1" |           rows="1" | ||||||
|           autosize |           autosize | ||||||
|           placeholder="Your link or text..." |           :placeholder="t('tools.qrcode-generator.placeholder')" | ||||||
|           mb-6 |           mb-6 | ||||||
|         /> |         /> | ||||||
|         <n-form label-width="130" label-placement="left"> |         <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-color-picker v-model:value="foreground" :modes="['hex']" /> | ||||||
|           </n-form-item> |           </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-color-picker v-model:value="background" :modes="['hex']" /> | ||||||
|           </n-form-item> |           </n-form-item> | ||||||
|           <c-select |           <c-select | ||||||
|             v-model:value="errorCorrectionLevel" |             v-model:value="errorCorrectionLevel" | ||||||
|             label="Error resistance:" |             :label="t('tools.qrcode-generator.error-resistance')" | ||||||
|             label-position="left" |             label-position="left" | ||||||
|             label-width="130px" |             label-width="130px" | ||||||
|             label-align="right" |             label-align="right" | ||||||
| @ -60,7 +61,7 @@ const { download } = useDownloadFileFromBase64({ source: qrcode, filename: 'qr-c | |||||||
|         <div flex flex-col items-center gap-3> |         <div flex flex-col items-center gap-3> | ||||||
|           <n-image :src="qrcode" width="200" /> |           <n-image :src="qrcode" width="200" /> | ||||||
|           <c-button @click="download"> |           <c-button @click="download"> | ||||||
|             Download qr-code |             {{ t('tools.qrcode-generator.button.download') }} | ||||||
|           </c-button> |           </c-button> | ||||||
|         </div> |         </div> | ||||||
|       </n-gi> |       </n-gi> | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { BrandJavascript } from '@vicons/tabler'; | import { BrandJavascript } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'Regex cheatsheet', |   name: translate('tools.regex-memo.title'), | ||||||
|   path: '/regex-memo', |   path: '/regex-memo', | ||||||
|   description: 'Javascript Regex/Regular Expression cheatsheet', |   description: translate('tools.regex-memo.description'), | ||||||
|   keywords: ['regex', 'regular', 'expression', 'javascript', 'memo', 'cheatsheet'], |   keywords: ['regex', 'regular', 'expression', 'javascript', 'memo', 'cheatsheet'], | ||||||
|   component: () => import('./regex-memo.vue'), |   component: () => import('./regex-memo.vue'), | ||||||
|   icon: BrandJavascript, |   icon: BrandJavascript, | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { Language } from '@vicons/tabler'; | import { Language } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'Regex Tester', |   name: translate('tools.regex-tester.title'), | ||||||
|   path: '/regex-tester', |   path: '/regex-tester', | ||||||
|   description: 'Test your regular expressions with sample text.', |   description: translate('tools.regex-tester.description'), | ||||||
|   keywords: ['regex', 'tester', 'sample', 'expression'], |   keywords: ['regex', 'tester', 'sample', 'expression'], | ||||||
|   component: () => import('./regex-tester.vue'), |   component: () => import('./regex-tester.vue'), | ||||||
|   icon: Language, |   icon: Language, | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ const dotAll = ref(true); | |||||||
| const unicode = ref(true); | const unicode = ref(true); | ||||||
| const unicodeSets = ref(false); | const unicodeSets = ref(false); | ||||||
| const visualizerSVG = ref<ShadowRootExpose>(); | const visualizerSVG = ref<ShadowRootExpose>(); | ||||||
|  | const { t } = useI18n(); | ||||||
| 
 | 
 | ||||||
| const regexValidation = useValidation({ | const regexValidation = useValidation({ | ||||||
|   source: regex, |   source: regex, | ||||||
| @ -92,36 +93,36 @@ watchEffect( | |||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <div max-w-600px> |   <div max-w-600px> | ||||||
|     <c-card title="Regex" mb-1> |     <c-card :title="t('tools.regex-tester.regex')" mb-1> | ||||||
|       <c-input-text |       <c-input-text | ||||||
|         v-model:value="regex" |         v-model:value="regex" | ||||||
|         label="Regex to test:" |         :label="t('tools.regex-tester.regex-input')" | ||||||
|         placeholder="Put the regex to test" |         :placeholder="t('tools.regex-tester.regex-input-placeholder')" | ||||||
|         multiline |         multiline | ||||||
|         rows="3" |         rows="3" | ||||||
|         :validation="regexValidation" |         :validation="regexValidation" | ||||||
|       /> |       /> | ||||||
|       <router-link target="_blank" to="/regex-memo" mb-1 mt-1> |       <router-link target="_blank" to="/regex-memo" mb-1 mt-1> | ||||||
|         See Regular Expression Cheatsheet |         {{ t('tools.regex-tester.link') }} | ||||||
|       </router-link> |       </router-link> | ||||||
|       <n-space> |       <n-space> | ||||||
|         <n-checkbox v-model:checked="global"> |         <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> | ||||||
|         <n-checkbox v-model:checked="ignoreCase"> |         <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> | ||||||
|         <n-checkbox v-model:checked="multiline"> |         <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> | ||||||
|         <n-checkbox v-model:checked="dotAll"> |         <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> | ||||||
|         <n-checkbox v-model:checked="unicode"> |         <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> | ||||||
|         <n-checkbox v-model:checked="unicodeSets"> |         <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-checkbox> | ||||||
|       </n-space> |       </n-space> | ||||||
| 
 | 
 | ||||||
| @ -129,28 +130,28 @@ watchEffect( | |||||||
| 
 | 
 | ||||||
|       <c-input-text |       <c-input-text | ||||||
|         v-model:value="text" |         v-model:value="text" | ||||||
|         label="Text to match:" |         :label="t('tools.regex-tester.text-input')" | ||||||
|         placeholder="Put the text to match" |         :placeholder="t('tools.regex-tester.text-input-placeholder')" | ||||||
|         multiline |         multiline | ||||||
|         rows="5" |         rows="5" | ||||||
|       /> |       /> | ||||||
|     </c-card> |     </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"> |       <n-table v-if="results?.length > 0"> | ||||||
|         <thead> |         <thead> | ||||||
|           <tr> |           <tr> | ||||||
|             <th scope="col"> |             <th scope="col"> | ||||||
|               Index in text |               {{ t('tools.regex-tester.text-index') }} | ||||||
|             </th> |             </th> | ||||||
|             <th scope="col"> |             <th scope="col"> | ||||||
|               Value |               {{ t('tools.regex-tester.value') }} | ||||||
|             </th> |             </th> | ||||||
|             <th scope="col"> |             <th scope="col"> | ||||||
|               Captures |               {{ t('tools.regex-tester.captures') }} | ||||||
|             </th> |             </th> | ||||||
|             <th scope="col"> |             <th scope="col"> | ||||||
|               Groups |               {{ t('tools.regex-tester.groups') }} | ||||||
|             </th> |             </th> | ||||||
|           </tr> |           </tr> | ||||||
|         </thead> |         </thead> | ||||||
| @ -176,15 +177,15 @@ watchEffect( | |||||||
|         </tbody> |         </tbody> | ||||||
|       </n-table> |       </n-table> | ||||||
|       <c-alert v-else> |       <c-alert v-else> | ||||||
|         No match |         {{ t('tools.regex-tester.no-match') }} | ||||||
|       </c-alert> |       </c-alert> | ||||||
|     </c-card> |     </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> |       <pre style="white-space: pre-wrap; word-break: break-all;">{{ sample }}</pre> | ||||||
|     </c-card> |     </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 ref="visualizerSVG"> | ||||||
|   |   | ||||||
|       </shadow-root> |       </shadow-root> | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { Mailbox } from '@vicons/tabler'; | import { Mailbox } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'Outlook Safelink decoder', |   name: translate('tools.safelink-decoder.title'), | ||||||
|   path: '/safelink-decoder', |   path: '/safelink-decoder', | ||||||
|   description: 'Decode Outlook SafeLink links', |   description: translate('tools.safelink-decoder.description'), | ||||||
|   keywords: ['outlook', 'safelink', 'decoder'], |   keywords: ['outlook', 'safelink', 'decoder'], | ||||||
|   component: () => import('./safelink-decoder.vue'), |   component: () => import('./safelink-decoder.vue'), | ||||||
|   icon: Mailbox, |   icon: Mailbox, | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| import { decodeSafeLinksURL } from './safelink-decoder.service'; | import { decodeSafeLinksURL } from './safelink-decoder.service'; | ||||||
| import TextareaCopyable from '@/components/TextareaCopyable.vue'; | import TextareaCopyable from '@/components/TextareaCopyable.vue'; | ||||||
| 
 | 
 | ||||||
|  | const { t } = useI18n(); | ||||||
| const inputSafeLinkUrl = ref(''); | const inputSafeLinkUrl = ref(''); | ||||||
| const outputDecodedUrl = computed(() => { | const outputDecodedUrl = computed(() => { | ||||||
|   try { |   try { | ||||||
| @ -18,14 +19,14 @@ const outputDecodedUrl = computed(() => { | |||||||
|     <c-input-text |     <c-input-text | ||||||
|       v-model:value="inputSafeLinkUrl" |       v-model:value="inputSafeLinkUrl" | ||||||
|       raw-text |       raw-text | ||||||
|       placeholder="Your input Outlook SafeLink Url..." |       :placeholder="t('tools.safelink-decoder.input-placeholder')" | ||||||
|       autofocus |       autofocus | ||||||
|       label="Your input Outlook SafeLink Url:" |       :label="t('tools.safelink-decoder.input')" | ||||||
|     /> |     /> | ||||||
| 
 | 
 | ||||||
|     <n-divider /> |     <n-divider /> | ||||||
| 
 | 
 | ||||||
|     <n-form-item label="Output decoded URL:"> |     <n-form-item :label="t('tools.safelink-decoder.output')"> | ||||||
|       <TextareaCopyable :value="outputDecodedUrl" :word-wrap="true" /> |       <TextareaCopyable :value="outputDecodedUrl" :word-wrap="true" /> | ||||||
|     </n-form-item> |     </n-form-item> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -3,17 +3,18 @@ import { getStringSizeInBytes } from './text-statistics.service'; | |||||||
| import { formatBytes } from '@/utils/convert'; | import { formatBytes } from '@/utils/convert'; | ||||||
| 
 | 
 | ||||||
| const text = ref(''); | const text = ref(''); | ||||||
|  | const { t } = useI18n(); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <c-card> |   <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> |     <div mt-5 flex> | ||||||
|       <n-statistic label="Character count" :value="text.length" flex-1 /> |       <n-statistic :label="t('tools.text-statistics.characters')" :value="text.length" flex-1 /> | ||||||
|       <n-statistic label="Word count" :value="text === '' ? 0 : text.split(/\s+/).length" flex-1 /> |       <n-statistic :label="t('tools.text-statistics.words')" :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="t('tools.text-statistics.lines')" :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.bytes')" :value="formatBytes(getStringSizeInBytes(text))" flex-1 /> | ||||||
|     </div> |     </div> | ||||||
|   </c-card> |   </c-card> | ||||||
| </template> | </template> | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import { Braces } from '@vicons/tabler'; | import { Braces } from '@vicons/tabler'; | ||||||
| import { defineTool } from '../tool'; | import { defineTool } from '../tool'; | ||||||
|  | import { translate } from '@/plugins/i18n.plugin'; | ||||||
| 
 | 
 | ||||||
| export const tool = defineTool({ | export const tool = defineTool({ | ||||||
|   name: 'XML to JSON', |   name: translate('tools.xml-to-json.title'), | ||||||
|   path: '/xml-to-json', |   path: '/xml-to-json', | ||||||
|   description: 'Convert XML to JSON', |   description: translate('tools.xml-to-json.description'), | ||||||
|   keywords: ['xml', 'json'], |   keywords: ['xml', 'json'], | ||||||
|   component: () => import('./xml-to-json.vue'), |   component: () => import('./xml-to-json.vue'), | ||||||
|   icon: Braces, |   icon: Braces, | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ import { isValidXML } from '../xml-formatter/xml-formatter.service'; | |||||||
| import { withDefaultOnError } from '@/utils/defaults'; | import { withDefaultOnError } from '@/utils/defaults'; | ||||||
| import type { UseValidationRule } from '@/composable/validation'; | import type { UseValidationRule } from '@/composable/validation'; | ||||||
| 
 | 
 | ||||||
|  | const { t } = useI18n(); | ||||||
| const defaultValue = '<a x="1.234" y="It\'s"/>'; | const defaultValue = '<a x="1.234" y="It\'s"/>'; | ||||||
| function transformer(value: string) { | function transformer(value: string) { | ||||||
|   return withDefaultOnError(() => { |   return withDefaultOnError(() => { | ||||||
| @ -14,17 +15,17 @@ function transformer(value: string) { | |||||||
| const rules: UseValidationRule<string>[] = [ | const rules: UseValidationRule<string>[] = [ | ||||||
|   { |   { | ||||||
|     validator: isValidXML, |     validator: isValidXML, | ||||||
|     message: 'Provided XML is not valid.', |     message: t('tools.xml-to-json.error'), | ||||||
|   }, |   }, | ||||||
| ]; | ]; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <format-transformer |   <format-transformer | ||||||
|     input-label="Your XML content" |     :input-label="t('tools.xml-to-json.input')" | ||||||
|     :input-default="defaultValue" |     :input-default="defaultValue" | ||||||
|     input-placeholder="Paste your XML content here..." |     :input-placeholder="t('tools.xml-to-json.input-placeholder')" | ||||||
|     output-label="Converted JSON" |     :output-label="t('tools.xml-to-json.output')" | ||||||
|     output-language="json" |     output-language="json" | ||||||
|     :transformer="transformer" |     :transformer="transformer" | ||||||
|     :input-validation-rules="rules" |     :input-validation-rules="rules" | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user