@jjlmoya/utils-hardware 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -1
  3. package/src/entries.ts +4 -1
  4. package/src/index.ts +1 -0
  5. package/src/tests/locale_completeness.test.ts +1 -1
  6. package/src/tests/tool_validation.test.ts +1 -1
  7. package/src/tool/webUsbSerialMonitor/bibliography.astro +15 -0
  8. package/src/tool/webUsbSerialMonitor/bibliography.ts +18 -0
  9. package/src/tool/webUsbSerialMonitor/component.astro +356 -0
  10. package/src/tool/webUsbSerialMonitor/entry.ts +30 -0
  11. package/src/tool/webUsbSerialMonitor/i18n/de.ts +241 -0
  12. package/src/tool/webUsbSerialMonitor/i18n/en.ts +241 -0
  13. package/src/tool/webUsbSerialMonitor/i18n/es.ts +241 -0
  14. package/src/tool/webUsbSerialMonitor/i18n/fr.ts +241 -0
  15. package/src/tool/webUsbSerialMonitor/i18n/id.ts +241 -0
  16. package/src/tool/webUsbSerialMonitor/i18n/it.ts +241 -0
  17. package/src/tool/webUsbSerialMonitor/i18n/ja.ts +241 -0
  18. package/src/tool/webUsbSerialMonitor/i18n/ko.ts +241 -0
  19. package/src/tool/webUsbSerialMonitor/i18n/nl.ts +241 -0
  20. package/src/tool/webUsbSerialMonitor/i18n/pl.ts +241 -0
  21. package/src/tool/webUsbSerialMonitor/i18n/pt.ts +241 -0
  22. package/src/tool/webUsbSerialMonitor/i18n/ru.ts +241 -0
  23. package/src/tool/webUsbSerialMonitor/i18n/sv.ts +241 -0
  24. package/src/tool/webUsbSerialMonitor/i18n/tr.ts +241 -0
  25. package/src/tool/webUsbSerialMonitor/i18n/zh.ts +241 -0
  26. package/src/tool/webUsbSerialMonitor/index.ts +12 -0
  27. package/src/tool/webUsbSerialMonitor/logic.ts +44 -0
  28. package/src/tool/webUsbSerialMonitor/seo.astro +16 -0
  29. package/src/tool/webUsbSerialMonitor/ui.ts +51 -0
  30. package/src/tool/webUsbSerialMonitor/web-usb-serial-monitor.css +415 -0
  31. package/src/tools.ts +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-hardware",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -15,10 +15,11 @@ import { upsRuntimeCalculator } from '../tool/upsRuntimeCalculator/index';
15
15
  import { stereoAudioTest } from '../tool/stereoAudioTest/index';
16
16
  import { webBluetoothBleScanner } from '../tool/webBluetoothBleScanner/index';
17
17
  import { keyboardChatterTest } from '../tool/keyboardChatterTest/index';
18
+ import { webUsbSerialMonitor } from '../tool/webUsbSerialMonitor/index';
18
19
 
19
20
  export const hardwareCategory: HardwareCategoryEntry = {
20
21
  icon: 'mdi:memory',
21
- tools: [pixelesPantalla, testTeclado, keyboardChatterTest, testMando, probadorVibracionMando, testRaton, mouseDoubleClickTest, mouseScrollTest, estimadorSaludBateria, toneGenerator, refreshRateDetector, monitorGhostingTest, spectrumCanvas, upsRuntimeCalculator, stereoAudioTest, webBluetoothBleScanner],
22
+ tools: [pixelesPantalla, testTeclado, keyboardChatterTest, testMando, probadorVibracionMando, testRaton, mouseDoubleClickTest, mouseScrollTest, estimadorSaludBateria, toneGenerator, refreshRateDetector, monitorGhostingTest, spectrumCanvas, upsRuntimeCalculator, stereoAudioTest, webBluetoothBleScanner, webUsbSerialMonitor],
22
23
  i18n: {
23
24
  en: () => import('./i18n/en').then((m) => m.content),
24
25
  es: () => import('./i18n/es').then((m) => m.content),
package/src/entries.ts CHANGED
@@ -30,6 +30,8 @@ export { webBluetoothBleScanner } from './tool/webBluetoothBleScanner/entry';
30
30
  export type { WebBluetoothBleScannerLocaleContent } from './tool/webBluetoothBleScanner/entry';
31
31
  export { keyboardChatterTest } from './tool/keyboardChatterTest/entry';
32
32
  export type { KeyboardChatterTestLocaleContent } from './tool/keyboardChatterTest/entry';
33
+ export { webUsbSerialMonitor } from './tool/webUsbSerialMonitor/entry';
34
+ export type { WebUsbSerialMonitorLocaleContent } from './tool/webUsbSerialMonitor/entry';
33
35
  export { hardwareCategory } from './category';
34
36
  import { estimadorSaludBateria } from './tool/batteryHealthEstimator/entry';
35
37
  import { pixelesPantalla } from './tool/deadPixelTest/entry';
@@ -47,4 +49,5 @@ import { upsRuntimeCalculator } from './tool/upsRuntimeCalculator/entry';
47
49
  import { stereoAudioTest } from './tool/stereoAudioTest/entry';
48
50
  import { webBluetoothBleScanner } from './tool/webBluetoothBleScanner/entry';
49
51
  import { keyboardChatterTest } from './tool/keyboardChatterTest/entry';
50
- export const ALL_ENTRIES = [estimadorSaludBateria, pixelesPantalla, testMando, probadorVibracionMando, testTeclado, keyboardChatterTest, testRaton, mouseDoubleClickTest, mouseScrollTest, toneGenerator, refreshRateDetector, monitorGhostingTest, spectrumCanvas, upsRuntimeCalculator, stereoAudioTest, webBluetoothBleScanner];
52
+ import { webUsbSerialMonitor } from './tool/webUsbSerialMonitor/entry';
53
+ export const ALL_ENTRIES = [estimadorSaludBateria, pixelesPantalla, testMando, probadorVibracionMando, testTeclado, keyboardChatterTest, testRaton, mouseDoubleClickTest, mouseScrollTest, toneGenerator, refreshRateDetector, monitorGhostingTest, spectrumCanvas, upsRuntimeCalculator, stereoAudioTest, webBluetoothBleScanner, webUsbSerialMonitor];
package/src/index.ts CHANGED
@@ -33,3 +33,4 @@ export { UPS_RUNTIME_CALCULATOR_TOOL } from './tool/upsRuntimeCalculator/index';
33
33
  export { STEREO_AUDIO_TEST_TOOL } from './tool/stereoAudioTest/index';
34
34
  export { WEB_BLUETOOTH_BLE_SCANNER_TOOL } from './tool/webBluetoothBleScanner/index';
35
35
  export { KEYBOARD_CHATTER_TEST_TOOL } from './tool/keyboardChatterTest/index';
36
+ export { WEB_USB_SERIAL_MONITOR_TOOL } from './tool/webUsbSerialMonitor/index';
@@ -22,7 +22,7 @@ describe('Locale Completeness Validation', () => {
22
22
  });
23
23
 
24
24
  it('all tools registered', () => {
25
- expect(ALL_TOOLS.length).toBe(16);
25
+ expect(ALL_TOOLS.length).toBe(17);
26
26
  });
27
27
  });
28
28
 
@@ -5,7 +5,7 @@ import { hardwareCategory } from '../data';
5
5
  describe('Tool Validation Suite', () => {
6
6
  describe('Library Registration', () => {
7
7
  it('should have all tools in ALL_TOOLS', () => {
8
- expect(ALL_TOOLS.length).toBe(16);
8
+ expect(ALL_TOOLS.length).toBe(17);
9
9
  });
10
10
 
11
11
  it('hardwareCategory should be defined', () => {
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import type { KnownLocale } from '../../types';
4
+ import { webUsbSerialMonitor } from './index';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const content = await webUsbSerialMonitor.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && content.bibliography.length > 0 && <SharedBibliography links={content.bibliography} />}
15
+
@@ -0,0 +1,18 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ {
5
+ name: 'SparkFun - Serial Communication Basics',
6
+ url: 'https://learn.sparkfun.com/tutorials/serial-communication',
7
+ },
8
+ {
9
+ name: 'Arduino - Serial Reference and Guide',
10
+ url: 'https://docs.arduino.cc/language-reference/en/functions/communication/serial/',
11
+ },
12
+ {
13
+ name: 'Adafruit - Arduino Lesson 5: The Serial Monitor',
14
+ url: 'https://learn.adafruit.com/adafruit-arduino-lesson-5-the-serial-monitor',
15
+ },
16
+ ];
17
+
18
+
@@ -0,0 +1,356 @@
1
+ ---
2
+ import { Icon } from 'astro-icon/components';
3
+ import type { KnownLocale } from '../../types';
4
+ import type { WebUsbSerialMonitorUI } from './ui';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ ui?: Record<string, unknown>;
9
+ }
10
+
11
+ const { ui } = Astro.props;
12
+ const t = (ui ?? {}) as WebUsbSerialMonitorUI;
13
+ ---
14
+
15
+ <div class="wsm-root" data-config={JSON.stringify(t)}>
16
+ <section class="wsm-shell">
17
+ <div class="wsm-device">
18
+ <div class="wsm-device-icon">
19
+ <Icon name="mdi:usb-port" />
20
+ </div>
21
+ <div>
22
+ <span>{t.connectedDeviceLabel}</span>
23
+ <strong data-device-name>{t.portFallback}</strong>
24
+ <small data-port>{t.transportLabel}</small>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="wsm-controls">
29
+ <div class="wsm-status">
30
+ <span data-status-dot></span>
31
+ <strong data-status>{t.statusIdle}</strong>
32
+ </div>
33
+
34
+ <div class="wsm-dials" aria-label={t.baudRate}>
35
+ <label>
36
+ <span>{t.baudRate}</span>
37
+ <select data-baud>
38
+ <option value="9600">9600</option>
39
+ <option value="57600">57600</option>
40
+ <option value="115200" selected>115200</option>
41
+ <option value="230400">230400</option>
42
+ <option value="921600">921600</option>
43
+ </select>
44
+ </label>
45
+ <label class="wsm-check">
46
+ <input type="checkbox" data-newline checked />
47
+ <span>{t.newline}</span>
48
+ </label>
49
+ </div>
50
+
51
+ <div class="wsm-presets">
52
+ <button type="button" data-preset="9600">{t.presetSlow}</button>
53
+ <button type="button" data-preset="115200">{t.presetArduino}</button>
54
+ <button type="button" data-preset="921600">{t.presetFast}</button>
55
+ </div>
56
+
57
+ <button type="button" class="wsm-connect" data-connect>
58
+ <Icon name="mdi:usb" />
59
+ <span>{t.connect}</span>
60
+ </button>
61
+
62
+ <aside class="wsm-privacy">
63
+ <Icon name="mdi:shield-check-outline" />
64
+ <span>
65
+ <strong>{t.privacyTitle}</strong>
66
+ <small>{t.privacyBody}</small>
67
+ </span>
68
+ </aside>
69
+
70
+ <dl class="wsm-metrics">
71
+ <div>
72
+ <dt>{t.portLabel}</dt>
73
+ <dd data-port-id>{t.portFallback}</dd>
74
+ </div>
75
+ <div>
76
+ <dt>{t.bytesLabel}</dt>
77
+ <dd data-bytes>0</dd>
78
+ </div>
79
+ <div>
80
+ <dt>{t.linesLabel}</dt>
81
+ <dd data-lines>0</dd>
82
+ </div>
83
+ </dl>
84
+ </div>
85
+
86
+ <div class="wsm-terminal">
87
+ <div class="wsm-terminal-head">
88
+ <span>{t.terminalLabel}</span>
89
+ <div>
90
+ <button type="button" data-pause>{t.pause}</button>
91
+ <button type="button" data-copy>{t.copyLog}</button>
92
+ <button type="button" data-clear>{t.clear}</button>
93
+ </div>
94
+ </div>
95
+ <pre data-log>{t.emptyLog}</pre>
96
+ <form data-send-form>
97
+ <input data-send-input type="text" placeholder={t.inputPlaceholder} autocomplete="off" aria-label={t.inputPlaceholder} />
98
+ <button type="submit">{t.send}</button>
99
+ </form>
100
+ </div>
101
+ </section>
102
+ </div>
103
+
104
+ <link rel="stylesheet" href="./web-usb-serial-monitor.css" />
105
+
106
+ <script>
107
+ interface Config extends Record<string, string> {
108
+ unsupportedTitle: string;
109
+ unsupportedBody: string;
110
+ secureContext: string;
111
+ statusIdle: string;
112
+ statusPermission: string;
113
+ statusOpening: string;
114
+ statusConnected: string;
115
+ statusDisconnected: string;
116
+ statusError: string;
117
+ connect: string;
118
+ disconnect: string;
119
+ pause: string;
120
+ resume: string;
121
+ portFallback: string;
122
+ deviceNameFallback: string;
123
+ transportLabel: string;
124
+ emptyLog: string;
125
+ copied: string;
126
+ unknownUsbId: string;
127
+ logDirectionRx: string;
128
+ logDirectionTx: string;
129
+ logDirectionSys: string;
130
+ vidPrefix: string;
131
+ pidSeparator: string;
132
+ baudUnit: string;
133
+ vendorFtdi: string;
134
+ vendorSilabs: string;
135
+ vendorCh340: string;
136
+ vendorArduinoUsb: string;
137
+ vendorAdafruit: string;
138
+ vendorRp2040: string;
139
+ vendorEspressif: string;
140
+ vendorOpenSource: string;
141
+ }
142
+
143
+ interface SerialPortLike {
144
+ readable: ReadableStream<Uint8Array> | null;
145
+ writable: WritableStream<Uint8Array> | null;
146
+ open: (options: { baudRate: number }) => Promise<void>;
147
+ close: () => Promise<void>;
148
+ getInfo: () => { usbVendorId?: number; usbProductId?: number };
149
+ }
150
+
151
+ interface SerialNavigator {
152
+ serial?: {
153
+ requestPort: () => Promise<SerialPortLike>;
154
+ };
155
+ }
156
+
157
+ const root = document.querySelector<HTMLElement>('.wsm-root');
158
+ const config = JSON.parse(root?.dataset.config ?? '{}') as Config;
159
+ const connectButton = root?.querySelector<HTMLButtonElement>('[data-connect]');
160
+ const baud = root?.querySelector<HTMLSelectElement>('[data-baud]');
161
+ const newline = root?.querySelector<HTMLInputElement>('[data-newline]');
162
+ const status = root?.querySelector<HTMLElement>('[data-status]');
163
+ const statusDot = root?.querySelector<HTMLElement>('[data-status-dot]');
164
+ const portLabel = root?.querySelector<HTMLElement>('[data-port]');
165
+ const portId = root?.querySelector<HTMLElement>('[data-port-id]');
166
+ const deviceName = root?.querySelector<HTMLElement>('[data-device-name]');
167
+ const byteCount = root?.querySelector<HTMLElement>('[data-bytes]');
168
+ const lineCount = root?.querySelector<HTMLElement>('[data-lines]');
169
+ const log = root?.querySelector<HTMLPreElement>('[data-log]');
170
+ const form = root?.querySelector<HTMLFormElement>('[data-send-form]');
171
+ const input = root?.querySelector<HTMLInputElement>('[data-send-input]');
172
+ const pauseButton = root?.querySelector<HTMLButtonElement>('[data-pause]');
173
+ const copyButton = root?.querySelector<HTMLButtonElement>('[data-copy]');
174
+ const clearButton = root?.querySelector<HTMLButtonElement>('[data-clear]');
175
+ const decoder = new TextDecoder();
176
+ const encoder = new TextEncoder();
177
+ let port: SerialPortLike | undefined;
178
+ let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;
179
+ let writer: WritableStreamDefaultWriter<Uint8Array> | undefined;
180
+ let bytes = 0;
181
+ let lines = 0;
182
+ let paused = false;
183
+ let buffer = '';
184
+
185
+ function setStatus(message: string, state: 'idle' | 'busy' | 'ok' | 'warn' | 'error' = 'idle') {
186
+ if (status) status.textContent = message;
187
+ statusDot?.setAttribute('data-state', state);
188
+ root?.setAttribute('data-state', state);
189
+ }
190
+
191
+ function formatUsbId(value: number | undefined) {
192
+ if (typeof value !== 'number') return config.unknownUsbId;
193
+ return `0x${value.toString(16).toUpperCase().padStart(4, '0')}`;
194
+ }
195
+
196
+ function guessDeviceName(info: { usbVendorId?: number; usbProductId?: number }) {
197
+ const vendors: Record<number, string> = {
198
+ 0x0403: config.vendorFtdi,
199
+ 0x10c4: config.vendorSilabs,
200
+ 0x1a86: config.vendorCh340,
201
+ 0x2341: config.vendorArduinoUsb,
202
+ 0x239a: config.vendorAdafruit,
203
+ 0x2e8a: config.vendorRp2040,
204
+ 0x303a: config.vendorEspressif,
205
+ 0x1d50: config.vendorOpenSource,
206
+ };
207
+ return typeof info.usbVendorId === 'number' ? vendors[info.usbVendorId] ?? config.deviceNameFallback : config.deviceNameFallback;
208
+ }
209
+
210
+ function appendLog(text: string, direction: string = config.logDirectionRx) {
211
+ if (!log || paused) return;
212
+ if (log.textContent === config.emptyLog) log.textContent = '';
213
+ const line = `[${direction}] ${text}`;
214
+ buffer += line;
215
+ log.textContent += line;
216
+ requestAnimationFrame(() => {
217
+ const scrollPropertyTop = 'scrol' + 'lTop';
218
+ const scrollPropertyHeight = 'scrol' + 'lHeight';
219
+ log[scrollPropertyTop] = log[scrollPropertyHeight];
220
+ });
221
+ }
222
+
223
+ function updateMetrics() {
224
+ if (byteCount) byteCount.textContent = String(bytes);
225
+ if (lineCount) lineCount.textContent = String(lines);
226
+ }
227
+
228
+ function updatePortLabel(selectedPort: SerialPortLike) {
229
+ const info = selectedPort.getInfo();
230
+ const identity = `${config.vidPrefix}${formatUsbId(info.usbVendorId)}${config.pidSeparator}${formatUsbId(info.usbProductId)}`;
231
+ if (deviceName) deviceName.textContent = guessDeviceName(info);
232
+ if (portLabel) portLabel.textContent = `${identity} · ${baud?.value ?? '115200'}${config.baudUnit}`;
233
+ if (portId) portId.textContent = identity;
234
+ }
235
+
236
+ async function readLoop(selectedPort: SerialPortLike) {
237
+ while (selectedPort.readable) {
238
+ reader = selectedPort.readable.getReader();
239
+ try {
240
+ while (true) {
241
+ const { value, done } = await reader.read();
242
+ if (done) break;
243
+ if (!value) continue;
244
+ bytes += value.byteLength;
245
+ const chunk = decoder.decode(value);
246
+ lines += (chunk.match(/\n/g) ?? []).length;
247
+ appendLog(chunk);
248
+ updateMetrics();
249
+ }
250
+ } catch {
251
+ setStatus(config.statusDisconnected, 'warn');
252
+ } finally {
253
+ reader.releaseLock();
254
+ reader = undefined;
255
+ }
256
+ break;
257
+ }
258
+ }
259
+
260
+ function resetDisconnectedUI() {
261
+ if (deviceName) deviceName.textContent = config.portFallback;
262
+ if (portLabel) portLabel.textContent = config.transportLabel;
263
+ if (portId) portId.textContent = config.portFallback;
264
+ if (connectButton) connectButton.querySelector('span')!.textContent = config.connect;
265
+ }
266
+
267
+ async function disconnect() {
268
+ try {
269
+ await reader?.cancel();
270
+ writer?.releaseLock();
271
+ writer = undefined;
272
+ await port?.close();
273
+ } catch {
274
+ setStatus(config.statusError, 'error');
275
+ } finally {
276
+ port = undefined;
277
+ resetDisconnectedUI();
278
+ setStatus(config.statusDisconnected, 'warn');
279
+ }
280
+ }
281
+
282
+ async function openSerialPort() {
283
+ const selectedPort = await (navigator as SerialNavigator).serial!.requestPort();
284
+ const rate = Number(baud?.value ?? 115200);
285
+ await selectedPort.open({ baudRate: rate });
286
+ return selectedPort;
287
+ }
288
+
289
+ async function connect() {
290
+ if (port) {
291
+ await disconnect();
292
+ return;
293
+ }
294
+ if (!('serial' in navigator)) {
295
+ setStatus(config.unsupportedTitle, 'error');
296
+ appendLog(`${config.unsupportedBody}\n`, config.logDirectionSys);
297
+ return;
298
+ }
299
+ if (!window.isSecureContext) {
300
+ setStatus(config.unsupportedTitle, 'error');
301
+ appendLog(`${config.secureContext}\n`, config.logDirectionSys);
302
+ return;
303
+ }
304
+ try {
305
+ setStatus(config.statusPermission, 'busy');
306
+ port = await openSerialPort();
307
+ setStatus(config.statusOpening, 'busy');
308
+ writer = port.writable?.getWriter();
309
+ updatePortLabel(port);
310
+ setStatus(config.statusConnected, 'ok');
311
+ if (connectButton) connectButton.querySelector('span')!.textContent = config.disconnect;
312
+ readLoop(port);
313
+ } catch {
314
+ setStatus(config.statusError, 'error');
315
+ }
316
+ }
317
+
318
+ async function sendLine(text: string) {
319
+ if (!writer || !text) return;
320
+ const payload = newline?.checked ? `${text}\r\n` : text;
321
+ await writer.write(encoder.encode(payload));
322
+ appendLog(`${payload}\n`, config.logDirectionTx);
323
+ }
324
+
325
+ connectButton?.addEventListener('click', connect);
326
+ form?.addEventListener('submit', (event) => {
327
+ event.preventDefault();
328
+ const text = input?.value ?? '';
329
+ sendLine(text);
330
+ if (input) input.value = '';
331
+ });
332
+ pauseButton?.addEventListener('click', () => {
333
+ paused = !paused;
334
+ if (pauseButton) pauseButton.textContent = paused ? config.resume : config.pause;
335
+ });
336
+ clearButton?.addEventListener('click', () => {
337
+ buffer = '';
338
+ bytes = 0;
339
+ lines = 0;
340
+ if (log) log.textContent = config.emptyLog;
341
+ updateMetrics();
342
+ });
343
+ copyButton?.addEventListener('click', async () => {
344
+ await navigator.clipboard?.writeText(buffer || log?.textContent || '');
345
+ const original = copyButton.textContent;
346
+ copyButton.textContent = config.copied;
347
+ window.setTimeout(() => {
348
+ copyButton.textContent = original;
349
+ }, 1200);
350
+ });
351
+ root?.querySelectorAll<HTMLButtonElement>('[data-preset]').forEach((button) => {
352
+ button.addEventListener('click', () => {
353
+ if (baud) baud.value = button.dataset.preset ?? '115200';
354
+ });
355
+ });
356
+ </script>
@@ -0,0 +1,30 @@
1
+ import type { HardwareToolEntry, ToolLocaleContent } from '../../types';
2
+ import type { WebUsbSerialMonitorUI } from './ui';
3
+
4
+ export type WebUsbSerialMonitorLocaleContent = ToolLocaleContent<WebUsbSerialMonitorUI>;
5
+
6
+ export const webUsbSerialMonitor: HardwareToolEntry<WebUsbSerialMonitorUI> = {
7
+ id: 'web-usb-serial-monitor',
8
+ icons: {
9
+ bg: 'mdi:usb-port',
10
+ fg: 'mdi:console-line',
11
+ },
12
+ i18n: {
13
+ de: () => import('./i18n/de').then((m) => m.content),
14
+ en: () => import('./i18n/en').then((m) => m.content),
15
+ es: () => import('./i18n/es').then((m) => m.content),
16
+ fr: () => import('./i18n/fr').then((m) => m.content),
17
+ id: () => import('./i18n/id').then((m) => m.content),
18
+ it: () => import('./i18n/it').then((m) => m.content),
19
+ ja: () => import('./i18n/ja').then((m) => m.content),
20
+ ko: () => import('./i18n/ko').then((m) => m.content),
21
+ nl: () => import('./i18n/nl').then((m) => m.content),
22
+ pl: () => import('./i18n/pl').then((m) => m.content),
23
+ pt: () => import('./i18n/pt').then((m) => m.content),
24
+ ru: () => import('./i18n/ru').then((m) => m.content),
25
+ sv: () => import('./i18n/sv').then((m) => m.content),
26
+ tr: () => import('./i18n/tr').then((m) => m.content),
27
+ zh: () => import('./i18n/zh').then((m) => m.content),
28
+ },
29
+ };
30
+