iobroker.script-restore 0.1.1 → 0.1.3

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.
package/README.de.md CHANGED
@@ -77,7 +77,15 @@ Das Archiv wird vollständig im Browser geparst — beim Durchsuchen werden kein
77
77
  Placeholder for the next version (at the beginning of the line):
78
78
  ### **WORK IN PROGRESS**
79
79
  -->
80
- ### **WORK IN PROGRESS**
80
+ ### 0.1.3 (2026-05-24)
81
+ * (ipod86) Language-Flash behoben: Socket-Override wird übersprungen wenn Sprache bereits vom Admin-Frame erkannt wurde
82
+ * (ipod86) Alle hardcodierten Statusmeldungen durch übersetzte t()-Aufrufe ersetzt
83
+ * (ipod86) codeHint-Übersetzungsschlüssel in alle 11 Sprachen ergänzt
84
+
85
+ ### 0.1.2 (2026-05-24)
86
+ * (ipod86) Vollständige i18n im Admin-Tab: alle Strings in de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn übersetzt
87
+
88
+ ### 0.1.1 (2026-05-24)
81
89
  * (ipod86) Überschreiben bestehender Skripte beim Restore erlaubt (Bestätigungs-Dialog mit Pfadanzeige)
82
90
  * (ipod86) Leeres Suffix erlaubt, um Skript unter dem Originalnamen wiederherzustellen
83
91
  * (ipod86) Hinweis nach erfolgreichem Restore: Skript direkt starten?
package/README.md CHANGED
@@ -75,6 +75,14 @@ The archive is parsed entirely in the browser — no files are written to disk d
75
75
  Placeholder for the next version (at the beginning of the line):
76
76
  ### **WORK IN PROGRESS**
77
77
  -->
78
+ ### 0.1.3 (2026-05-24)
79
+ * (ipod86) fix language flash: skip socket override when language already detected from admin frame
80
+ * (ipod86) replace all hardcoded status strings with translated t() calls
81
+ * (ipod86) add codeHint translation key in all 11 languages
82
+
83
+ ### 0.1.2 (2026-05-24)
84
+ * (ipod86) add full i18n to tab UI: all strings translated into de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn
85
+
78
86
  ### 0.1.1 (2026-05-24)
79
87
  * (ipod86) allow overwriting existing scripts during restore (confirmation dialog with path display)
80
88
  * (ipod86) allow empty suffix to restore script under its original name
@@ -90,16 +98,6 @@ The archive is parsed entirely in the browser — no files are written to disk d
90
98
  * (ipod86) add common.singleton to prevent multiple instances
91
99
  * (ipod86) complete i18n translations for all supported languages (fr, es, it, nl, pl, pt, ru, uk, zh-cn)
92
100
 
93
- ### 0.0.11 (2026-04-13)
94
- * (ipod86) add type filter (JS/TS/Blockly/Rules) in script sidebar
95
- * (ipod86) add direct restore into ioBroker with suffix input and confirm modal
96
- * (ipod86) remove obsolete admin/words.js and .prettierignore
97
-
98
- ### 0.0.10 (2026-04-08)
99
- * (ipod86) fix jsonConfig responsive sizes lg/xl for backupPath (E5509)
100
- * (ipod86) trim news entries to 7 (W1032)
101
- * (ipod86) add Dependabot npm cooldown of 7 days (W8915)
102
-
103
101
  ## License
104
102
  MIT License
105
103
 
package/admin/tab_m.html CHANGED
@@ -393,39 +393,39 @@
393
393
  <div class="progress-inner"><span id="progressPercent">0%</span></div>
394
394
  </div>
395
395
  <div id="spinnerEl" class="spinner" style="display:none;"></div>
396
- <div id="loaderText">Lade Backup...</div>
396
+ <div id="loaderText" data-i18n="loaderLoading">Lade Backup...</div>
397
397
  </div>
398
398
 
399
399
  <!-- Restore Modal -->
400
400
  <div class="restore-modal-overlay" id="restoreModalOverlay" onclick="closeRestoreModal(event)">
401
401
  <div class="restore-modal" onclick="event.stopPropagation()">
402
- <h3>In ioBroker laden</h3>
402
+ <h3 data-i18n="modalTitle">In ioBroker laden</h3>
403
403
  <div class="restore-modal-meta">
404
- <div>Skript: <strong id="rmScriptName"></strong></div>
405
- <div>Pfad: <strong id="rmScriptPath"></strong></div>
406
- <div>Typ: <strong id="rmScriptType"></strong></div>
404
+ <div><span data-i18n="modalLabelScript">Skript:</span> <strong id="rmScriptName"></strong></div>
405
+ <div><span data-i18n="modalLabelPath">Pfad:</span> <strong id="rmScriptPath"></strong></div>
406
+ <div><span data-i18n="modalLabelType">Typ:</span> <strong id="rmScriptType"></strong></div>
407
407
  </div>
408
- <label for="rmSuffix">Suffix (wird an den Skriptnamen angehängt)</label>
408
+ <label for="rmSuffix" data-i18n="modalLabelSuffix">Suffix (wird an den Skriptnamen angehängt)</label>
409
409
  <input type="text" id="rmSuffix" value="_rcvr" oninput="updateRestorePreview();">
410
410
  <div class="restore-modal-preview" id="rmPreview"></div>
411
411
  <div class="restore-modal-warning" id="rmWarning">
412
- <p>⚠ Ein Skript unter <code id="rmWarningPath"></code> existiert bereits.<br>Soll es wirklich überschrieben werden?</p>
412
+ <p></p>
413
413
  <div class="rmw-actions">
414
- <button class="btn btn-outline" onclick="dismissWarning()">Anderen Suffix wählen</button>
415
- <button class="btn btn-danger" onclick="overwriteConfirmed()">Überschreiben</button>
414
+ <button class="btn btn-outline" onclick="dismissWarning()" data-i18n="modalDismiss">Anderen Suffix wählen</button>
415
+ <button class="btn btn-danger" onclick="overwriteConfirmed()" data-i18n="modalOverwrite">Überschreiben</button>
416
416
  </div>
417
417
  </div>
418
418
  <div class="restore-modal-success" id="rmSuccess">
419
- <p>✓ Erfolgreich wiederhergestellt.<br>Soll das Skript jetzt gestartet werden?</p>
419
+ <p data-i18n-html="modalSuccess">✓ Erfolgreich wiederhergestellt.<br>Soll das Skript jetzt gestartet werden?</p>
420
420
  <div class="rmw-actions">
421
- <button class="btn btn-outline" onclick="closeRestoreModal()">Nein danke</button>
422
- <button class="btn btn-outline-success" id="rmStartBtn" onclick="startRestoredScript()">Jetzt starten</button>
421
+ <button class="btn btn-outline" onclick="closeRestoreModal()" data-i18n="modalClose">Nein danke</button>
422
+ <button class="btn btn-outline-success" id="rmStartBtn" onclick="startRestoredScript()" data-i18n="modalStart">Jetzt starten</button>
423
423
  </div>
424
424
  </div>
425
425
  <div class="restore-modal-footer">
426
426
  <span id="rmMsg" style="flex:1;font-size:0.85rem;align-self:center;"></span>
427
- <button class="btn btn-outline" onclick="closeRestoreModal()">Schließen</button>
428
- <button class="btn btn-outline-success" id="rmConfirmBtn" onclick="confirmRestoreScript(false)">Laden</button>
427
+ <button class="btn btn-outline" onclick="closeRestoreModal()" data-i18n="modalCancel">Schließen</button>
428
+ <button class="btn btn-outline-success" id="rmConfirmBtn" onclick="confirmRestoreScript(false)" data-i18n="modalLoad">Laden</button>
429
429
  </div>
430
430
  </div>
431
431
  </div>
@@ -433,56 +433,56 @@
433
433
  <div class="toolbar">
434
434
  <div class="toolbar-left">
435
435
  <label class="file-input-label">
436
- 📂 Backup hochladen
436
+ <span data-i18n="uploadLabel">📂 Backup hochladen</span>
437
437
  <input type="file" id="fileInput" accept=".tar,.gz,.tar.gz,.json,.jsonl">
438
438
  </label>
439
439
  <div class="dropdown-wrapper" id="localDropdown">
440
- <button class="btn btn-outline" onclick="toggleDropdown('local')">
440
+ <button class="btn btn-outline" onclick="toggleDropdown('local')" data-i18n="localDropdown">
441
441
  🗂️ Lokale Backups ▾
442
442
  </button>
443
443
  <div class="dropdown-menu" id="localMenu"></div>
444
444
  </div>
445
445
  <div class="dropdown-wrapper" id="ftpDropdown" style="display:none;">
446
- <button class="btn btn-outline" onclick="toggleDropdown('ftp')">
446
+ <button class="btn btn-outline" onclick="toggleDropdown('ftp')" data-i18n="ftpDropdown">
447
447
  🌐 FTP Backups ▾
448
448
  </button>
449
449
  <div class="dropdown-menu" id="ftpMenu"></div>
450
450
  </div>
451
451
  <div class="dropdown-wrapper" id="smbDropdown" style="display:none;">
452
- <button class="btn btn-outline" onclick="toggleDropdown('smb')">
452
+ <button class="btn btn-outline" onclick="toggleDropdown('smb')" data-i18n="smbDropdown">
453
453
  🗄️ SMB Backups ▾
454
454
  </button>
455
455
  <div class="dropdown-menu" id="smbMenu"></div>
456
456
  </div>
457
457
  <div class="dropdown-wrapper" id="sftpDropdown" style="display:none;">
458
- <button class="btn btn-outline" onclick="toggleDropdown('sftp')">
458
+ <button class="btn btn-outline" onclick="toggleDropdown('sftp')" data-i18n="sftpDropdown">
459
459
  🔒 SFTP Backups ▾
460
460
  </button>
461
461
  <div class="dropdown-menu" id="sftpMenu"></div>
462
462
  </div>
463
463
  <div class="dropdown-wrapper" id="webdavDropdown" style="display:none;">
464
- <button class="btn btn-outline" onclick="toggleDropdown('webdav')">
464
+ <button class="btn btn-outline" onclick="toggleDropdown('webdav')" data-i18n="webdavDropdown">
465
465
  ☁️ WebDAV Backups ▾
466
466
  </button>
467
467
  <div class="dropdown-menu" id="webdavMenu"></div>
468
468
  </div>
469
469
  <div id="httpInputWrapper" style="display:none; align-items:center; gap:6px;">
470
470
  <input type="text" id="httpUrlInput" placeholder="https://..." style="padding:0.35rem 0.6rem; border:1px solid #ced4da; border-radius:4px; font-size:0.875rem; min-width:260px; font-family:inherit;">
471
- <button type="button" class="btn btn-outline" onclick="loadHttpUrl()">🌐 URL laden</button>
471
+ <button type="button" class="btn btn-outline" onclick="loadHttpUrl()" data-i18n="httpLoadBtn">🌐 URL laden</button>
472
472
  </div>
473
- <button id="zipBtn" class="btn btn-outline" onclick="downloadZip()" style="display:none;">📦 ZIP</button>
474
- <span class="status-msg" id="statusMsg">Backup laden oder Quelle wählen</span>
473
+ <button id="zipBtn" class="btn btn-outline" onclick="downloadZip()" style="display:none;" data-i18n="zipBtn">📦 ZIP</button>
474
+ <span class="status-msg" id="statusMsg" data-i18n="statusDefault">Backup laden oder Quelle wählen</span>
475
475
  </div>
476
476
  </div>
477
477
 
478
478
  <div class="main-container">
479
479
  <div class="sidebar" id="sidebar">
480
480
  <div class="sidebar-header">
481
- <input type="text" id="q" placeholder="Suche in Namen, Ordner &amp; Code...">
482
- <button class="btn-icon" id="expandToggleBtn" onclick="toggleExpandAll()" title="Alle Ordner aufklappen">📂</button>
481
+ <input type="text" id="q" data-i18n-placeholder="searchPlaceholder" placeholder="Suche in Namen, Ordner &amp; Code...">
482
+ <button class="btn-icon" id="expandToggleBtn" onclick="toggleExpandAll()" data-i18n-title="expandAll" title="Alle Ordner aufklappen">📂</button>
483
483
  </div>
484
484
  <div class="type-filter-bar">
485
- <button class="btn-type active" onclick="setTypeFilter(this, '')">Alle</button>
485
+ <button class="btn-type active" onclick="setTypeFilter(this, '')" data-i18n="typeAll">Alle</button>
486
486
  <button class="btn-type" onclick="setTypeFilter(this, 'JS')"><span class="type-badge badge-JS">JS</span></button>
487
487
  <button class="btn-type" onclick="setTypeFilter(this, 'TypeScript')"><span class="type-badge badge-TypeScript">TS</span></button>
488
488
  <button class="btn-type" onclick="setTypeFilter(this, 'Blockly')"><span class="type-badge badge-Blockly">Blockly</span></button>
@@ -498,17 +498,16 @@
498
498
  <div class="action-bar-inner">
499
499
  <div class="btn-group" id="viewSwitcher"></div>
500
500
  <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
501
- <button onclick="openRestoreModal()" class="btn btn-outline-success" id="restoreBtn">In ioBroker laden</button>
502
- <button onclick="copyCode(this)" class="btn btn-outline-light">Code Kopieren</button>
503
- <button onclick="downloadActive()" class="btn btn-primary" id="dlBtn">Download</button>
501
+ <button onclick="openRestoreModal()" class="btn btn-outline-success" id="restoreBtn" data-i18n="restoreBtn">In ioBroker laden</button>
502
+ <button onclick="copyCode(this)" class="btn btn-outline-light" data-i18n="copyBtnAction">Code Kopieren</button>
503
+ <button onclick="downloadActive()" class="btn btn-primary" id="dlBtn" data-i18n="downloadBtn">Download</button>
504
504
  </div>
505
505
  </div>
506
506
  </div>
507
507
  <div id="codeContainer" class="code-empty">
508
508
  <div>
509
509
  <strong>ioBroker Script Restore</strong><br><br>
510
- Lade ein Backup hoch oder wähle eine lokale Datei,<br>
511
- um Skripte anzuzeigen und wiederherzustellen.
510
+ <span data-i18n-html="welcomeText">Lade ein Backup hoch oder wähle eine lokale Datei,<br>um Skripte anzuzeigen und wiederherzustellen.</span>
512
511
  </div>
513
512
  </div>
514
513
  </div>
@@ -520,6 +519,720 @@
520
519
  const instance = urlParams.get('instance') || '0';
521
520
  const adapterInst = 'script-restore.' + instance;
522
521
 
522
+ // === i18n ===
523
+ const TRANSLATIONS = {
524
+ de: {
525
+ loaderLoading: 'Lade Backup...',
526
+ loaderProcessing: 'Verarbeite...',
527
+ modalTitle: 'In ioBroker laden',
528
+ modalLabelScript: 'Skript:',
529
+ modalLabelPath: 'Pfad:',
530
+ modalLabelType: 'Typ:',
531
+ modalLabelSuffix: 'Suffix (wird an den Skriptnamen angehängt)',
532
+ modalWarning: '⚠ Ein Skript unter {path} existiert bereits.<br>Soll es wirklich überschrieben werden?',
533
+ modalDismiss: 'Anderen Suffix wählen',
534
+ modalOverwrite: 'Überschreiben',
535
+ modalSuccess: '✓ Erfolgreich wiederhergestellt.<br>Soll das Skript jetzt gestartet werden?',
536
+ modalClose: 'Nein danke',
537
+ modalStart: 'Jetzt starten',
538
+ modalLoad: 'Laden',
539
+ modalLoading: '⏳ Laden...',
540
+ modalStarting: '⏳ Starte...',
541
+ modalStarted: '✓ Gestartet',
542
+ modalLoaded: '✓ Geladen!',
543
+ modalUnknownError: '✗ Unbekannter Fehler',
544
+ modalErrorPrefix: '✗ Fehler: ',
545
+ copyBtn: 'Code Kopieren',
546
+ copyBtnAction: 'Code Kopieren',
547
+ copied: '✓ Kopiert!',
548
+ uploadLabel: '📂 Backup hochladen',
549
+ localDropdown: '🗂️ Lokale Backups ▾',
550
+ ftpDropdown: '🌐 FTP Backups ▾',
551
+ smbDropdown: '🗄️ SMB Backups ▾',
552
+ sftpDropdown: '🔒 SFTP Backups ▾',
553
+ webdavDropdown: '☁️ WebDAV Backups ▾',
554
+ httpLoadBtn: '🌐 URL laden',
555
+ zipBtn: '📦 ZIP',
556
+ statusDefault: 'Backup laden oder Quelle wählen',
557
+ searchPlaceholder: 'Suche in Namen, Ordner & Code...',
558
+ expandAll: 'Alle aufklappen',
559
+ collapseAll: 'Alle einklappen',
560
+ typeAll: 'Alle',
561
+ restoreBtn: 'In ioBroker laden',
562
+ downloadBtn: 'Download',
563
+ welcomeText: 'Lade ein Backup hoch oder wähle eine lokale Datei,<br>um Skripte anzuzeigen und wiederherzustellen.',
564
+ noSocket: 'Kein Socket. Bitte prüfen ob script-restore.{i} läuft.',
565
+ timeout: 'Timeout: Adapter antwortet nicht. Läuft script-restore.{i}?',
566
+
567
+ modalCancel: 'Schließen',
568
+ loadingFiles: '⏳ Lade Dateiliste...',
569
+ scriptsLoaded: '{n} Skripte geladen aus: {f}',
570
+ scriptsLoadedUrl: '{n} Skripte geladen von URL',
571
+ noScripts: 'Keine Skripte gefunden.',
572
+ noScriptsBackup: 'Keine Skripte in diesem Backup gefunden.',
573
+ noArchiveFile: 'Keine passende Datei im Archiv gefunden.',
574
+ errorParsing: 'Fehler beim Parsen: ',
575
+ errorReading: 'Fehler beim Lesen der Datei.',
576
+ errorPrefix: 'Fehler: ',
577
+ adapterTimeout: 'Fehler: Keine Antwort vom Adapter. Läuft script-restore.{i}?',
578
+ codeHint: '// Skript im Baum links auswählen… oder mehrere mit Strg+Klick für ZIP',
579
+ },
580
+ en: {
581
+ loaderLoading: 'Loading backup...',
582
+ loaderProcessing: 'Processing...',
583
+ modalTitle: 'Load into ioBroker',
584
+ modalLabelScript: 'Script:',
585
+ modalLabelPath: 'Path:',
586
+ modalLabelType: 'Type:',
587
+ modalLabelSuffix: 'Suffix (appended to the script name)',
588
+ modalWarning: '⚠ A script at {path} already exists.<br>Do you really want to overwrite it?',
589
+ modalDismiss: 'Choose different suffix',
590
+ modalOverwrite: 'Overwrite',
591
+ modalSuccess: '✓ Successfully restored.<br>Do you want to start the script now?',
592
+ modalClose: 'No thanks',
593
+ modalStart: 'Start now',
594
+ modalLoad: 'Load',
595
+ modalLoading: '⏳ Loading...',
596
+ modalStarting: '⏳ Starting...',
597
+ modalStarted: '✓ Started',
598
+ modalLoaded: '✓ Loaded!',
599
+ modalUnknownError: '✗ Unknown error',
600
+ modalErrorPrefix: '✗ Error: ',
601
+ copyBtn: 'Copy Code',
602
+ copyBtnAction: 'Copy Code',
603
+ copied: '✓ Copied!',
604
+ uploadLabel: '📂 Upload backup',
605
+ localDropdown: '🗂️ Local Backups ▾',
606
+ ftpDropdown: '🌐 FTP Backups ▾',
607
+ smbDropdown: '🗄️ SMB Backups ▾',
608
+ sftpDropdown: '🔒 SFTP Backups ▾',
609
+ webdavDropdown: '☁️ WebDAV Backups ▾',
610
+ httpLoadBtn: '🌐 Load URL',
611
+ zipBtn: '📦 ZIP',
612
+ statusDefault: 'Load a backup or select a source',
613
+ searchPlaceholder: 'Search in names, folders & code...',
614
+ expandAll: 'Expand all',
615
+ collapseAll: 'Collapse all',
616
+ typeAll: 'All',
617
+ restoreBtn: 'Load into ioBroker',
618
+ downloadBtn: 'Download',
619
+ welcomeText: 'Upload a backup or select a local file,<br>to view and restore scripts.',
620
+ noSocket: 'No socket. Please check if script-restore.{i} is running.',
621
+ timeout: 'Timeout: Adapter not responding. Is script-restore.{i} running?',
622
+
623
+ modalCancel: 'Close',
624
+ loadingFiles: '⏳ Loading file list...',
625
+ scriptsLoaded: '{n} scripts loaded from: {f}',
626
+ scriptsLoadedUrl: '{n} scripts loaded from URL',
627
+ noScripts: 'No scripts found.',
628
+ noScriptsBackup: 'No scripts found in this backup.',
629
+ noArchiveFile: 'No matching file found in archive.',
630
+ errorParsing: 'Error parsing: ',
631
+ errorReading: 'Error reading file.',
632
+ errorPrefix: 'Error: ',
633
+ adapterTimeout: 'Error: No response from adapter. Is script-restore.{i} running?',
634
+ codeHint: '// Select a script in the tree… or Ctrl+click multiple for ZIP',
635
+ },
636
+ fr: {
637
+ loaderLoading: 'Chargement de la sauvegarde...',
638
+ loaderProcessing: 'Traitement en cours...',
639
+ modalTitle: 'Charger dans ioBroker',
640
+ modalLabelScript: 'Script :',
641
+ modalLabelPath: 'Chemin :',
642
+ modalLabelType: 'Type :',
643
+ modalLabelSuffix: 'Suffixe (ajouté au nom du script)',
644
+ modalWarning: '⚠ Un script à {path} existe déjà.<br>Voulez-vous vraiment l\'écraser ?',
645
+ modalDismiss: 'Choisir un autre suffixe',
646
+ modalOverwrite: 'Écraser',
647
+ modalSuccess: '✓ Restauré avec succès.<br>Voulez-vous démarrer le script maintenant ?',
648
+ modalClose: 'Non merci',
649
+ modalStart: 'Démarrer maintenant',
650
+ modalLoad: 'Charger',
651
+ modalLoading: '⏳ Chargement...',
652
+ modalStarting: '⏳ Démarrage...',
653
+ modalStarted: '✓ Démarré',
654
+ modalLoaded: '✓ Chargé !',
655
+ modalUnknownError: '✗ Erreur inconnue',
656
+ modalErrorPrefix: '✗ Erreur : ',
657
+ copyBtn: 'Copier le code',
658
+ copyBtnAction: 'Copier le code',
659
+ copied: '✓ Copié !',
660
+ uploadLabel: '📂 Téléverser une sauvegarde',
661
+ localDropdown: '🗂️ Sauvegardes locales ▾',
662
+ ftpDropdown: '🌐 Sauvegardes FTP ▾',
663
+ smbDropdown: '🗄️ Sauvegardes SMB ▾',
664
+ sftpDropdown: '🔒 Sauvegardes SFTP ▾',
665
+ webdavDropdown: '☁️ Sauvegardes WebDAV ▾',
666
+ httpLoadBtn: '🌐 Charger URL',
667
+ zipBtn: '📦 ZIP',
668
+ statusDefault: 'Charger une sauvegarde ou choisir une source',
669
+ searchPlaceholder: 'Rechercher dans les noms, dossiers et code...',
670
+ expandAll: 'Tout développer',
671
+ collapseAll: 'Tout réduire',
672
+ typeAll: 'Tous',
673
+ restoreBtn: 'Charger dans ioBroker',
674
+ downloadBtn: 'Télécharger',
675
+ welcomeText: 'Téléversez une sauvegarde ou sélectionnez un fichier local,<br>pour afficher et restaurer des scripts.',
676
+ noSocket: 'Pas de socket. Vérifiez si script-restore.{i} est en cours d\'exécution.',
677
+ timeout: 'Délai d\'attente : l\'adaptateur ne répond pas. script-restore.{i} est-il en cours d\'exécution ?',
678
+
679
+ modalCancel: 'Fermer',
680
+ loadingFiles: '⏳ Chargement de la liste...',
681
+ scriptsLoaded: '{n} scripts chargés depuis : {f}',
682
+ scriptsLoadedUrl: '{n} scripts chargés depuis URL',
683
+ noScripts: 'Aucun script trouvé.',
684
+ noScriptsBackup: 'Aucun script trouvé dans cette sauvegarde.',
685
+ noArchiveFile: 'Aucun fichier correspondant trouvé dans l\'archive.',
686
+ errorParsing: 'Erreur d\'analyse : ',
687
+ errorReading: 'Erreur de lecture du fichier.',
688
+ errorPrefix: 'Erreur : ',
689
+ adapterTimeout: 'Erreur : pas de réponse de l\'adaptateur. script-restore.{i} est-il actif ?',
690
+ codeHint: '// Sélectionnez un script dans l\'arborescence… ou Ctrl+clic pour plusieurs en ZIP',
691
+ },
692
+ es: {
693
+ loaderLoading: 'Cargando copia de seguridad...',
694
+ loaderProcessing: 'Procesando...',
695
+ modalTitle: 'Cargar en ioBroker',
696
+ modalLabelScript: 'Script:',
697
+ modalLabelPath: 'Ruta:',
698
+ modalLabelType: 'Tipo:',
699
+ modalLabelSuffix: 'Sufijo (se añade al nombre del script)',
700
+ modalWarning: '⚠ Ya existe un script en {path}.<br>¿Realmente desea sobrescribirlo?',
701
+ modalDismiss: 'Elegir otro sufijo',
702
+ modalOverwrite: 'Sobrescribir',
703
+ modalSuccess: '✓ Restaurado con éxito.<br>¿Desea iniciar el script ahora?',
704
+ modalClose: 'No gracias',
705
+ modalStart: 'Iniciar ahora',
706
+ modalLoad: 'Cargar',
707
+ modalLoading: '⏳ Cargando...',
708
+ modalStarting: '⏳ Iniciando...',
709
+ modalStarted: '✓ Iniciado',
710
+ modalLoaded: '✓ ¡Cargado!',
711
+ modalUnknownError: '✗ Error desconocido',
712
+ modalErrorPrefix: '✗ Error: ',
713
+ copyBtn: 'Copiar código',
714
+ copyBtnAction: 'Copiar código',
715
+ copied: '✓ ¡Copiado!',
716
+ uploadLabel: '📂 Subir copia de seguridad',
717
+ localDropdown: '🗂️ Copias locales ▾',
718
+ ftpDropdown: '🌐 Copias FTP ▾',
719
+ smbDropdown: '🗄️ Copias SMB ▾',
720
+ sftpDropdown: '🔒 Copias SFTP ▾',
721
+ webdavDropdown: '☁️ Copias WebDAV ▾',
722
+ httpLoadBtn: '🌐 Cargar URL',
723
+ zipBtn: '📦 ZIP',
724
+ statusDefault: 'Cargar una copia de seguridad o seleccionar una fuente',
725
+ searchPlaceholder: 'Buscar en nombres, carpetas y código...',
726
+ expandAll: 'Expandir todo',
727
+ collapseAll: 'Contraer todo',
728
+ typeAll: 'Todos',
729
+ restoreBtn: 'Cargar en ioBroker',
730
+ downloadBtn: 'Descargar',
731
+ welcomeText: 'Sube una copia de seguridad o selecciona un archivo local,<br>para ver y restaurar scripts.',
732
+ noSocket: 'Sin socket. Compruebe si script-restore.{i} está en ejecución.',
733
+ timeout: 'Tiempo de espera agotado: el adaptador no responde. ¿Está script-restore.{i} en ejecución?',
734
+
735
+ modalCancel: 'Cerrar',
736
+ loadingFiles: '⏳ Cargando lista de archivos...',
737
+ scriptsLoaded: '{n} scripts cargados desde: {f}',
738
+ scriptsLoadedUrl: '{n} scripts cargados desde URL',
739
+ noScripts: 'No se encontraron scripts.',
740
+ noScriptsBackup: 'No se encontraron scripts en este backup.',
741
+ noArchiveFile: 'No se encontró archivo compatible en el archivo.',
742
+ errorParsing: 'Error al analizar: ',
743
+ errorReading: 'Error al leer el archivo.',
744
+ errorPrefix: 'Error: ',
745
+ adapterTimeout: 'Error: sin respuesta del adaptador. ¿Está en ejecución script-restore.{i}?',
746
+ codeHint: '// Selecciona un script en el árbol… o Ctrl+clic para varios en ZIP',
747
+ },
748
+ it: {
749
+ loaderLoading: 'Caricamento backup...',
750
+ loaderProcessing: 'Elaborazione...',
751
+ modalTitle: 'Carica in ioBroker',
752
+ modalLabelScript: 'Script:',
753
+ modalLabelPath: 'Percorso:',
754
+ modalLabelType: 'Tipo:',
755
+ modalLabelSuffix: 'Suffisso (aggiunto al nome dello script)',
756
+ modalWarning: '⚠ Esiste già uno script in {path}.<br>Vuoi davvero sovrascriverlo?',
757
+ modalDismiss: 'Scegli un suffisso diverso',
758
+ modalOverwrite: 'Sovrascrivi',
759
+ modalSuccess: '✓ Ripristinato con successo.<br>Vuoi avviare lo script adesso?',
760
+ modalClose: 'No grazie',
761
+ modalStart: 'Avvia ora',
762
+ modalLoad: 'Carica',
763
+ modalLoading: '⏳ Caricamento...',
764
+ modalStarting: '⏳ Avvio...',
765
+ modalStarted: '✓ Avviato',
766
+ modalLoaded: '✓ Caricato!',
767
+ modalUnknownError: '✗ Errore sconosciuto',
768
+ modalErrorPrefix: '✗ Errore: ',
769
+ copyBtn: 'Copia codice',
770
+ copyBtnAction: 'Copia codice',
771
+ copied: '✓ Copiato!',
772
+ uploadLabel: '📂 Carica backup',
773
+ localDropdown: '🗂️ Backup locali ▾',
774
+ ftpDropdown: '🌐 Backup FTP ▾',
775
+ smbDropdown: '🗄️ Backup SMB ▾',
776
+ sftpDropdown: '🔒 Backup SFTP ▾',
777
+ webdavDropdown: '☁️ Backup WebDAV ▾',
778
+ httpLoadBtn: '🌐 Carica URL',
779
+ zipBtn: '📦 ZIP',
780
+ statusDefault: 'Carica un backup o seleziona una sorgente',
781
+ searchPlaceholder: 'Cerca in nomi, cartelle e codice...',
782
+ expandAll: 'Espandi tutto',
783
+ collapseAll: 'Comprimi tutto',
784
+ typeAll: 'Tutti',
785
+ restoreBtn: 'Carica in ioBroker',
786
+ downloadBtn: 'Scarica',
787
+ welcomeText: 'Carica un backup o seleziona un file locale,<br>per visualizzare e ripristinare gli script.',
788
+ noSocket: 'Nessun socket. Verificare se script-restore.{i} è in esecuzione.',
789
+ timeout: 'Timeout: l\'adattatore non risponde. script-restore.{i} è in esecuzione?',
790
+
791
+ modalCancel: 'Chiudi',
792
+ loadingFiles: '⏳ Caricamento lista file...',
793
+ scriptsLoaded: '{n} script caricati da: {f}',
794
+ scriptsLoadedUrl: '{n} script caricati da URL',
795
+ noScripts: 'Nessuno script trovato.',
796
+ noScriptsBackup: 'Nessuno script trovato in questo backup.',
797
+ noArchiveFile: 'Nessun file corrispondente trovato nell\'archivio.',
798
+ errorParsing: 'Errore di analisi: ',
799
+ errorReading: 'Errore nella lettura del file.',
800
+ errorPrefix: 'Errore: ',
801
+ adapterTimeout: 'Errore: nessuna risposta dall\'adattatore. script-restore.{i} è in esecuzione?',
802
+ codeHint: '// Seleziona uno script nell\'albero… o Ctrl+clic per più script in ZIP',
803
+ },
804
+ nl: {
805
+ loaderLoading: 'Back-up laden...',
806
+ loaderProcessing: 'Verwerken...',
807
+ modalTitle: 'Laden in ioBroker',
808
+ modalLabelScript: 'Script:',
809
+ modalLabelPath: 'Pad:',
810
+ modalLabelType: 'Type:',
811
+ modalLabelSuffix: 'Achtervoegsel (toegevoegd aan de scriptnaam)',
812
+ modalWarning: '⚠ Er bestaat al een script op {path}.<br>Wilt u het echt overschrijven?',
813
+ modalDismiss: 'Ander achtervoegsel kiezen',
814
+ modalOverwrite: 'Overschrijven',
815
+ modalSuccess: '✓ Succesvol hersteld.<br>Wilt u het script nu starten?',
816
+ modalClose: 'Nee bedankt',
817
+ modalStart: 'Nu starten',
818
+ modalLoad: 'Laden',
819
+ modalLoading: '⏳ Laden...',
820
+ modalStarting: '⏳ Starten...',
821
+ modalStarted: '✓ Gestart',
822
+ modalLoaded: '✓ Geladen!',
823
+ modalUnknownError: '✗ Onbekende fout',
824
+ modalErrorPrefix: '✗ Fout: ',
825
+ copyBtn: 'Code kopiëren',
826
+ copyBtnAction: 'Code kopiëren',
827
+ copied: '✓ Gekopieerd!',
828
+ uploadLabel: '📂 Back-up uploaden',
829
+ localDropdown: '🗂️ Lokale back-ups ▾',
830
+ ftpDropdown: '🌐 FTP back-ups ▾',
831
+ smbDropdown: '🗄️ SMB back-ups ▾',
832
+ sftpDropdown: '🔒 SFTP back-ups ▾',
833
+ webdavDropdown: '☁️ WebDAV back-ups ▾',
834
+ httpLoadBtn: '🌐 URL laden',
835
+ zipBtn: '📦 ZIP',
836
+ statusDefault: 'Laad een back-up of kies een bron',
837
+ searchPlaceholder: 'Zoeken in namen, mappen en code...',
838
+ expandAll: 'Alles uitklappen',
839
+ collapseAll: 'Alles inklappen',
840
+ typeAll: 'Alle',
841
+ restoreBtn: 'Laden in ioBroker',
842
+ downloadBtn: 'Downloaden',
843
+ welcomeText: 'Upload een back-up of selecteer een lokaal bestand,<br>om scripts te bekijken en te herstellen.',
844
+ noSocket: 'Geen socket. Controleer of script-restore.{i} actief is.',
845
+ timeout: 'Time-out: adapter reageert niet. Is script-restore.{i} actief?',
846
+
847
+ modalCancel: 'Sluiten',
848
+ loadingFiles: '⏳ Bestandslijst laden...',
849
+ scriptsLoaded: '{n} scripts geladen uit: {f}',
850
+ scriptsLoadedUrl: '{n} scripts geladen van URL',
851
+ noScripts: 'Geen scripts gevonden.',
852
+ noScriptsBackup: 'Geen scripts gevonden in deze backup.',
853
+ noArchiveFile: 'Geen overeenkomend bestand gevonden in het archief.',
854
+ errorParsing: 'Fout bij verwerken: ',
855
+ errorReading: 'Fout bij lezen van bestand.',
856
+ errorPrefix: 'Fout: ',
857
+ adapterTimeout: 'Fout: geen reactie van adapter. Is script-restore.{i} actief?',
858
+ codeHint: '// Selecteer een script in de boom… of Ctrl+klik voor meerdere als ZIP',
859
+ },
860
+ pl: {
861
+ loaderLoading: 'Wczytywanie kopii zapasowej...',
862
+ loaderProcessing: 'Przetwarzanie...',
863
+ modalTitle: 'Wczytaj do ioBroker',
864
+ modalLabelScript: 'Skrypt:',
865
+ modalLabelPath: 'Ścieżka:',
866
+ modalLabelType: 'Typ:',
867
+ modalLabelSuffix: 'Sufiks (dodawany do nazwy skryptu)',
868
+ modalWarning: '⚠ Skrypt w {path} już istnieje.<br>Czy na pewno chcesz go nadpisać?',
869
+ modalDismiss: 'Wybierz inny sufiks',
870
+ modalOverwrite: 'Nadpisz',
871
+ modalSuccess: '✓ Przywrócono pomyślnie.<br>Czy chcesz teraz uruchomić skrypt?',
872
+ modalClose: 'Nie, dziękuję',
873
+ modalStart: 'Uruchom teraz',
874
+ modalLoad: 'Wczytaj',
875
+ modalLoading: '⏳ Wczytywanie...',
876
+ modalStarting: '⏳ Uruchamianie...',
877
+ modalStarted: '✓ Uruchomiono',
878
+ modalLoaded: '✓ Wczytano!',
879
+ modalUnknownError: '✗ Nieznany błąd',
880
+ modalErrorPrefix: '✗ Błąd: ',
881
+ copyBtn: 'Kopiuj kod',
882
+ copyBtnAction: 'Kopiuj kod',
883
+ copied: '✓ Skopiowano!',
884
+ uploadLabel: '📂 Prześlij kopię zapasową',
885
+ localDropdown: '🗂️ Lokalne kopie ▾',
886
+ ftpDropdown: '🌐 Kopie FTP ▾',
887
+ smbDropdown: '🗄️ Kopie SMB ▾',
888
+ sftpDropdown: '🔒 Kopie SFTP ▾',
889
+ webdavDropdown: '☁️ Kopie WebDAV ▾',
890
+ httpLoadBtn: '🌐 Wczytaj URL',
891
+ zipBtn: '📦 ZIP',
892
+ statusDefault: 'Wczytaj kopię zapasową lub wybierz źródło',
893
+ searchPlaceholder: 'Szukaj w nazwach, folderach i kodzie...',
894
+ expandAll: 'Rozwiń wszystko',
895
+ collapseAll: 'Zwiń wszystko',
896
+ typeAll: 'Wszystkie',
897
+ restoreBtn: 'Wczytaj do ioBroker',
898
+ downloadBtn: 'Pobierz',
899
+ welcomeText: 'Prześlij kopię zapasową lub wybierz plik lokalny,<br>aby wyświetlić i przywrócić skrypty.',
900
+ noSocket: 'Brak gniazda. Sprawdź, czy script-restore.{i} działa.',
901
+ timeout: 'Przekroczono czas: adapter nie odpowiada. Czy script-restore.{i} działa?',
902
+
903
+ modalCancel: 'Zamknij',
904
+ loadingFiles: '⏳ Ładowanie listy plików...',
905
+ scriptsLoaded: '{n} skryptów załadowanych z: {f}',
906
+ scriptsLoadedUrl: '{n} skryptów załadowanych z URL',
907
+ noScripts: 'Nie znaleziono skryptów.',
908
+ noScriptsBackup: 'Nie znaleziono skryptów w tej kopii zapasowej.',
909
+ noArchiveFile: 'Nie znaleziono pasującego pliku w archiwum.',
910
+ errorParsing: 'Błąd analizy: ',
911
+ errorReading: 'Błąd odczytu pliku.',
912
+ errorPrefix: 'Błąd: ',
913
+ adapterTimeout: 'Błąd: brak odpowiedzi adaptera. Czy script-restore.{i} działa?',
914
+ codeHint: '// Wybierz skrypt w drzewie… lub Ctrl+klik dla wielu jako ZIP',
915
+ },
916
+ pt: {
917
+ loaderLoading: 'A carregar cópia de segurança...',
918
+ loaderProcessing: 'A processar...',
919
+ modalTitle: 'Carregar no ioBroker',
920
+ modalLabelScript: 'Script:',
921
+ modalLabelPath: 'Caminho:',
922
+ modalLabelType: 'Tipo:',
923
+ modalLabelSuffix: 'Sufixo (adicionado ao nome do script)',
924
+ modalWarning: '⚠ Já existe um script em {path}.<br>Tem a certeza que deseja substituí-lo?',
925
+ modalDismiss: 'Escolher outro sufixo',
926
+ modalOverwrite: 'Substituir',
927
+ modalSuccess: '✓ Restaurado com sucesso.<br>Deseja iniciar o script agora?',
928
+ modalClose: 'Não, obrigado',
929
+ modalStart: 'Iniciar agora',
930
+ modalLoad: 'Carregar',
931
+ modalLoading: '⏳ A carregar...',
932
+ modalStarting: '⏳ A iniciar...',
933
+ modalStarted: '✓ Iniciado',
934
+ modalLoaded: '✓ Carregado!',
935
+ modalUnknownError: '✗ Erro desconhecido',
936
+ modalErrorPrefix: '✗ Erro: ',
937
+ copyBtn: 'Copiar código',
938
+ copyBtnAction: 'Copiar código',
939
+ copied: '✓ Copiado!',
940
+ uploadLabel: '📂 Carregar cópia de segurança',
941
+ localDropdown: '🗂️ Cópias locais ▾',
942
+ ftpDropdown: '🌐 Cópias FTP ▾',
943
+ smbDropdown: '🗄️ Cópias SMB ▾',
944
+ sftpDropdown: '🔒 Cópias SFTP ▾',
945
+ webdavDropdown: '☁️ Cópias WebDAV ▾',
946
+ httpLoadBtn: '🌐 Carregar URL',
947
+ zipBtn: '📦 ZIP',
948
+ statusDefault: 'Carregar uma cópia de segurança ou selecionar uma fonte',
949
+ searchPlaceholder: 'Pesquisar em nomes, pastas e código...',
950
+ expandAll: 'Expandir tudo',
951
+ collapseAll: 'Recolher tudo',
952
+ typeAll: 'Todos',
953
+ restoreBtn: 'Carregar no ioBroker',
954
+ downloadBtn: 'Transferir',
955
+ welcomeText: 'Carregue uma cópia de segurança ou selecione um ficheiro local,<br>para ver e restaurar scripts.',
956
+ noSocket: 'Sem socket. Verifique se script-restore.{i} está em execução.',
957
+ timeout: 'Tempo esgotado: o adaptador não responde. O script-restore.{i} está em execução?',
958
+
959
+ modalCancel: 'Fechar',
960
+ loadingFiles: '⏳ A carregar lista de ficheiros...',
961
+ scriptsLoaded: '{n} scripts carregados de: {f}',
962
+ scriptsLoadedUrl: '{n} scripts carregados de URL',
963
+ noScripts: 'Nenhum script encontrado.',
964
+ noScriptsBackup: 'Nenhum script encontrado neste backup.',
965
+ noArchiveFile: 'Nenhum ficheiro correspondente encontrado no arquivo.',
966
+ errorParsing: 'Erro ao analisar: ',
967
+ errorReading: 'Erro ao ler ficheiro.',
968
+ errorPrefix: 'Erro: ',
969
+ adapterTimeout: 'Erro: sem resposta do adaptador. O script-restore.{i} está em execução?',
970
+ codeHint: '// Selecione um script na árvore… ou Ctrl+clique para vários em ZIP',
971
+ },
972
+ ru: {
973
+ loaderLoading: 'Загрузка резервной копии...',
974
+ loaderProcessing: 'Обработка...',
975
+ modalTitle: 'Загрузить в ioBroker',
976
+ modalLabelScript: 'Скрипт:',
977
+ modalLabelPath: 'Путь:',
978
+ modalLabelType: 'Тип:',
979
+ modalLabelSuffix: 'Суффикс (добавляется к имени скрипта)',
980
+ modalWarning: '⚠ Скрипт по пути {path} уже существует.<br>Вы действительно хотите перезаписать его?',
981
+ modalDismiss: 'Выбрать другой суффикс',
982
+ modalOverwrite: 'Перезаписать',
983
+ modalSuccess: '✓ Успешно восстановлено.<br>Хотите запустить скрипт сейчас?',
984
+ modalClose: 'Нет, спасибо',
985
+ modalStart: 'Запустить сейчас',
986
+ modalLoad: 'Загрузить',
987
+ modalLoading: '⏳ Загрузка...',
988
+ modalStarting: '⏳ Запуск...',
989
+ modalStarted: '✓ Запущен',
990
+ modalLoaded: '✓ Загружен!',
991
+ modalUnknownError: '✗ Неизвестная ошибка',
992
+ modalErrorPrefix: '✗ Ошибка: ',
993
+ copyBtn: 'Копировать код',
994
+ copyBtnAction: 'Копировать код',
995
+ copied: '✓ Скопировано!',
996
+ uploadLabel: '📂 Загрузить резервную копию',
997
+ localDropdown: '🗂️ Локальные резервные копии ▾',
998
+ ftpDropdown: '🌐 Резервные копии FTP ▾',
999
+ smbDropdown: '🗄️ Резервные копии SMB ▾',
1000
+ sftpDropdown: '🔒 Резервные копии SFTP ▾',
1001
+ webdavDropdown: '☁️ Резервные копии WebDAV ▾',
1002
+ httpLoadBtn: '🌐 Загрузить URL',
1003
+ zipBtn: '📦 ZIP',
1004
+ statusDefault: 'Загрузите резервную копию или выберите источник',
1005
+ searchPlaceholder: 'Поиск по именам, папкам и коду...',
1006
+ expandAll: 'Развернуть всё',
1007
+ collapseAll: 'Свернуть всё',
1008
+ typeAll: 'Все',
1009
+ restoreBtn: 'Загрузить в ioBroker',
1010
+ downloadBtn: 'Скачать',
1011
+ welcomeText: 'Загрузите резервную копию или выберите локальный файл,<br>чтобы просмотреть и восстановить скрипты.',
1012
+ noSocket: 'Нет сокета. Проверьте, запущен ли script-restore.{i}.',
1013
+ timeout: 'Таймаут: адаптер не отвечает. Запущен ли script-restore.{i}?',
1014
+
1015
+ modalCancel: 'Закрыть',
1016
+ loadingFiles: '⏳ Загрузка списка файлов...',
1017
+ scriptsLoaded: '{n} скриптов загружено из: {f}',
1018
+ scriptsLoadedUrl: '{n} скриптов загружено по URL',
1019
+ noScripts: 'Скрипты не найдены.',
1020
+ noScriptsBackup: 'Скрипты в этой резервной копии не найдены.',
1021
+ noArchiveFile: 'Подходящий файл в архиве не найден.',
1022
+ errorParsing: 'Ошибка разбора: ',
1023
+ errorReading: 'Ошибка чтения файла.',
1024
+ errorPrefix: 'Ошибка: ',
1025
+ adapterTimeout: 'Ошибка: адаптер не отвечает. Запущен ли script-restore.{i}?',
1026
+ codeHint: '// Выберите скрипт в дереве… или Ctrl+клик для нескольких в ZIP',
1027
+ },
1028
+ uk: {
1029
+ loaderLoading: 'Завантаження резервної копії...',
1030
+ loaderProcessing: 'Обробка...',
1031
+ modalTitle: 'Завантажити в ioBroker',
1032
+ modalLabelScript: 'Скрипт:',
1033
+ modalLabelPath: 'Шлях:',
1034
+ modalLabelType: 'Тип:',
1035
+ modalLabelSuffix: 'Суфікс (додається до назви скрипта)',
1036
+ modalWarning: '⚠ Скрипт за шляхом {path} вже існує.<br>Ви дійсно хочете його перезаписати?',
1037
+ modalDismiss: 'Вибрати інший суфікс',
1038
+ modalOverwrite: 'Перезаписати',
1039
+ modalSuccess: '✓ Успішно відновлено.<br>Хочете запустити скрипт зараз?',
1040
+ modalClose: 'Ні, дякую',
1041
+ modalStart: 'Запустити зараз',
1042
+ modalLoad: 'Завантажити',
1043
+ modalLoading: '⏳ Завантаження...',
1044
+ modalStarting: '⏳ Запуск...',
1045
+ modalStarted: '✓ Запущено',
1046
+ modalLoaded: '✓ Завантажено!',
1047
+ modalUnknownError: '✗ Невідома помилка',
1048
+ modalErrorPrefix: '✗ Помилка: ',
1049
+ copyBtn: 'Копіювати код',
1050
+ copyBtnAction: 'Копіювати код',
1051
+ copied: '✓ Скопійовано!',
1052
+ uploadLabel: '📂 Завантажити резервну копію',
1053
+ localDropdown: '🗂️ Локальні резервні копії ▾',
1054
+ ftpDropdown: '🌐 Резервні копії FTP ▾',
1055
+ smbDropdown: '🗄️ Резервні копії SMB ▾',
1056
+ sftpDropdown: '🔒 Резервні копії SFTP ▾',
1057
+ webdavDropdown: '☁️ Резервні копії WebDAV ▾',
1058
+ httpLoadBtn: '🌐 Завантажити URL',
1059
+ zipBtn: '📦 ZIP',
1060
+ statusDefault: 'Завантажте резервну копію або оберіть джерело',
1061
+ searchPlaceholder: 'Пошук за іменами, папками та кодом...',
1062
+ expandAll: 'Розгорнути все',
1063
+ collapseAll: 'Згорнути все',
1064
+ typeAll: 'Усі',
1065
+ restoreBtn: 'Завантажити в ioBroker',
1066
+ downloadBtn: 'Завантажити',
1067
+ welcomeText: 'Завантажте резервну копію або оберіть локальний файл,<br>щоб переглянути та відновити скрипти.',
1068
+ noSocket: 'Немає сокета. Перевірте, чи запущено script-restore.{i}.',
1069
+ timeout: 'Час очікування вичерпано: адаптер не відповідає. Чи запущено script-restore.{i}?',
1070
+
1071
+ modalCancel: 'Закрити',
1072
+ loadingFiles: '⏳ Завантаження списку файлів...',
1073
+ scriptsLoaded: '{n} скриптів завантажено з: {f}',
1074
+ scriptsLoadedUrl: '{n} скриптів завантажено за URL',
1075
+ noScripts: 'Скрипти не знайдено.',
1076
+ noScriptsBackup: 'Скрипти у цій резервній копії не знайдено.',
1077
+ noArchiveFile: 'Відповідний файл в архіві не знайдено.',
1078
+ errorParsing: 'Помилка розбору: ',
1079
+ errorReading: 'Помилка читання файлу.',
1080
+ errorPrefix: 'Помилка: ',
1081
+ adapterTimeout: 'Помилка: адаптер не відповідає. Чи запущено script-restore.{i}?',
1082
+ codeHint: '// Оберіть скрипт у дереві… або Ctrl+клік для кількох у ZIP',
1083
+ },
1084
+ 'zh-cn': {
1085
+ loaderLoading: '正在加载备份...',
1086
+ loaderProcessing: '处理中...',
1087
+ modalTitle: '加载到 ioBroker',
1088
+ modalLabelScript: '脚本:',
1089
+ modalLabelPath: '路径:',
1090
+ modalLabelType: '类型:',
1091
+ modalLabelSuffix: '后缀(附加到脚本名称)',
1092
+ modalWarning: '⚠ {path} 下已存在一个脚本。<br>您真的要覆盖它吗?',
1093
+ modalDismiss: '选择其他后缀',
1094
+ modalOverwrite: '覆盖',
1095
+ modalSuccess: '✓ 恢复成功。<br>是否立即启动该脚本?',
1096
+ modalClose: '不,谢谢',
1097
+ modalStart: '立即启动',
1098
+ modalLoad: '加载',
1099
+ modalLoading: '⏳ 加载中...',
1100
+ modalStarting: '⏳ 启动中...',
1101
+ modalStarted: '✓ 已启动',
1102
+ modalLoaded: '✓ 已加载!',
1103
+ modalUnknownError: '✗ 未知错误',
1104
+ modalErrorPrefix: '✗ 错误:',
1105
+ copyBtn: '复制代码',
1106
+ copyBtnAction: '复制代码',
1107
+ copied: '✓ 已复制!',
1108
+ uploadLabel: '📂 上传备份',
1109
+ localDropdown: '🗂️ 本地备份 ▾',
1110
+ ftpDropdown: '🌐 FTP 备份 ▾',
1111
+ smbDropdown: '🗄️ SMB 备份 ▾',
1112
+ sftpDropdown: '🔒 SFTP 备份 ▾',
1113
+ webdavDropdown: '☁️ WebDAV 备份 ▾',
1114
+ httpLoadBtn: '🌐 加载 URL',
1115
+ zipBtn: '📦 ZIP',
1116
+ statusDefault: '加载备份或选择来源',
1117
+ searchPlaceholder: '在名称、文件夹和代码中搜索...',
1118
+ expandAll: '全部展开',
1119
+ collapseAll: '全部折叠',
1120
+ typeAll: '全部',
1121
+ restoreBtn: '加载到 ioBroker',
1122
+ downloadBtn: '下载',
1123
+ welcomeText: '上传备份或选择本地文件,<br>以查看和恢复脚本。',
1124
+ noSocket: '无套接字。请检查 script-restore.{i} 是否正在运行。',
1125
+ timeout: '超时:适配器无响应。script-restore.{i} 是否正在运行?',
1126
+
1127
+ modalCancel: '关闭',
1128
+ loadingFiles: '⏳ 正在加载文件列表...',
1129
+ scriptsLoaded: '已从 {f} 加载 {n} 个脚本',
1130
+ scriptsLoadedUrl: '已从URL加载 {n} 个脚本',
1131
+ noScripts: '未找到脚本。',
1132
+ noScriptsBackup: '此备份中未找到脚本。',
1133
+ noArchiveFile: '在存档中未找到匹配的文件。',
1134
+ errorParsing: '解析错误:',
1135
+ errorReading: '读取文件时出错。',
1136
+ errorPrefix: '错误:',
1137
+ adapterTimeout: '错误:适配器无响应。script-restore.{i} 是否正在运行?',
1138
+ codeHint: '// 在左侧树中选择脚本…或按住 Ctrl 点击多个以下载 ZIP',
1139
+ },
1140
+ };
1141
+
1142
+ function detectLang() {
1143
+ // 1. URL parameter
1144
+ const lp = urlParams.get('lang') || urlParams.get('language');
1145
+ if (lp) return { lang: normLang(lp), confident: true };
1146
+ // 2. <html lang="de"> des Parent-Frames (ioBroker Admin setzt das zuverlässig)
1147
+ try {
1148
+ const hl = window.parent.document.documentElement.lang;
1149
+ if (hl && hl.length >= 2) return { lang: normLang(hl), confident: true };
1150
+ } catch(e) {}
1151
+ // 3. localStorage (verschiedene Admin-Versionen)
1152
+ try {
1153
+ for (const k of ['App.language', 'ioBroker.locale', 'lang', 'language']) {
1154
+ const v = localStorage.getItem(k);
1155
+ if (v && v.length >= 2) return { lang: normLang(v), confident: true };
1156
+ }
1157
+ } catch(e) {}
1158
+ // 4. Parent frame Variablen (Admin v5/v6/v7)
1159
+ try {
1160
+ const p = window.parent;
1161
+ if (p.sysLang) return { lang: normLang(p.sysLang), confident: true };
1162
+ if (p.systemLang) return { lang: normLang(p.systemLang), confident: true };
1163
+ if (p.main && p.main.language) return { lang: normLang(p.main.language), confident: true };
1164
+ if (p.app && p.app.language) return { lang: normLang(p.app.language), confident: true };
1165
+ } catch(e) {}
1166
+ // 5. Browser-Sprache (least reliable — socket may override)
1167
+ return { lang: normLang(navigator.language || 'en'), confident: false };
1168
+ }
1169
+
1170
+ function normLang(l) {
1171
+ if (!l) return 'en';
1172
+ const ll = l.toLowerCase().replace('_', '-');
1173
+ if (ll === 'zh-cn' || ll === 'zh') return 'zh-cn';
1174
+ return ll.slice(0, 2);
1175
+ }
1176
+
1177
+ let LANG_CONFIDENT = false;
1178
+ let LANG = (function() {
1179
+ const { lang, confident } = detectLang();
1180
+ const resolved = TRANSLATIONS[lang] ? lang : 'en';
1181
+ LANG_CONFIDENT = confident && !!TRANSLATIONS[lang];
1182
+ return resolved;
1183
+ })();
1184
+
1185
+ function t(key) {
1186
+ return (TRANSLATIONS[LANG] && TRANSLATIONS[LANG][key]) || (TRANSLATIONS.en && TRANSLATIONS.en[key]) || key;
1187
+ }
1188
+
1189
+ function applyLangFromSocket() {
1190
+ // Skip: a reliable sync source (parent html, localStorage, URL) already resolved the language.
1191
+ // Applying the socket result on top would cause a visible flash.
1192
+ if (LANG_CONFIDENT) return;
1193
+ if (!socket) return;
1194
+ const apply = function(lang) {
1195
+ if (!lang) return;
1196
+ const l = normLang(lang);
1197
+ if (TRANSLATIONS[l] && l !== LANG) {
1198
+ LANG = l;
1199
+ applyTranslations();
1200
+ }
1201
+ };
1202
+ try {
1203
+ if (typeof socket.getSystemConfig === 'function') {
1204
+ Promise.resolve(socket.getSystemConfig()).then(function(cfg) {
1205
+ if (cfg && cfg.common) apply(cfg.common.language);
1206
+ }).catch(function() {});
1207
+ } else if (typeof socket.getObject === 'function') {
1208
+ Promise.resolve(socket.getObject('system.config')).then(function(obj) {
1209
+ if (obj && obj.common) apply(obj.common.language);
1210
+ }).catch(function() {});
1211
+ } else if (typeof socket.emit === 'function') {
1212
+ socket.emit('getObject', 'system.config', function(err, obj) {
1213
+ if (!err && obj && obj.common) apply(obj.common.language);
1214
+ });
1215
+ }
1216
+ } catch(e) {}
1217
+ }
1218
+
1219
+ function applyTranslations() {
1220
+ document.querySelectorAll('[data-i18n]').forEach(function(el) {
1221
+ el.textContent = t(el.getAttribute('data-i18n'));
1222
+ });
1223
+ document.querySelectorAll('[data-i18n-html]').forEach(function(el) {
1224
+ el.innerHTML = t(el.getAttribute('data-i18n-html'));
1225
+ });
1226
+ document.querySelectorAll('[data-i18n-placeholder]').forEach(function(el) {
1227
+ el.placeholder = t(el.getAttribute('data-i18n-placeholder'));
1228
+ });
1229
+ document.querySelectorAll('[data-i18n-title]').forEach(function(el) {
1230
+ el.title = t(el.getAttribute('data-i18n-title'));
1231
+ });
1232
+ }
1233
+
1234
+ applyTranslations();
1235
+
523
1236
  // === Dark Theme Detection ===
524
1237
  function applyTheme(isDark) {
525
1238
  document.body.classList.toggle('dark', !!isDark);
@@ -625,14 +1338,14 @@
625
1338
 
626
1339
  function sendTo(command, message, callback) {
627
1340
  if (!socket) {
628
- callback({ error: 'Kein Socket. Bitte prüfen ob script-restore.' + instance + ' läuft.' });
1341
+ callback({ error: t('noSocket').replace('{i}', instance) });
629
1342
  return;
630
1343
  }
631
1344
  let done = false;
632
1345
  const timer = setTimeout(() => {
633
1346
  if (done) return;
634
1347
  done = true;
635
- callback({ error: 'Timeout: Adapter antwortet nicht. Läuft script-restore.' + instance + '?' });
1348
+ callback({ error: t('timeout').replace('{i}', instance) });
636
1349
  }, 30000);
637
1350
  const wrapped = (result) => {
638
1351
  if (done) return;
@@ -651,6 +1364,8 @@
651
1364
  }
652
1365
 
653
1366
  initSocket();
1367
+ applyLangFromSocket();
1368
+ setTimeout(applyLangFromSocket, 800);
654
1369
 
655
1370
  // === Resizer ===
656
1371
  const resizerEl = document.getElementById('resizer');
@@ -807,7 +1522,7 @@
807
1522
  const entry = entries.find(e => e.name === target || e.name.endsWith('/' + target));
808
1523
  if (entry) return parseJsonContent(dec.decode(entry.content), target);
809
1524
  }
810
- throw new Error('Keine passende Datei im Archiv gefunden (objects.json, objects.jsonl, scripts.json)');
1525
+ throw new Error(t('noArchiveFile'));
811
1526
  }
812
1527
 
813
1528
  // === File Upload ===
@@ -828,13 +1543,13 @@
828
1543
  const scripts = parseJsonContent(reader.result, file.name);
829
1544
  hideLoader();
830
1545
  loadScripts(scripts);
831
- setStatus(scripts.length + ' Skripte geladen aus: ' + file.name, 'success');
1546
+ setStatus(t('scriptsLoaded').replace('{n}', scripts.length).replace('{f}', file.name), 'success');
832
1547
  } catch(e) {
833
1548
  hideLoader();
834
- setStatus('Fehler beim Parsen: ' + e.message, 'error');
1549
+ setStatus(t('errorParsing') + e.message, 'error');
835
1550
  }
836
1551
  };
837
- reader.onerror = () => { hideLoader(); setStatus('Fehler beim Lesen der Datei.', 'error'); };
1552
+ reader.onerror = () => { hideLoader(); setStatus(t('errorReading'), 'error'); };
838
1553
  reader.readAsText(file, 'utf-8');
839
1554
  this.value = '';
840
1555
  return;
@@ -851,15 +1566,15 @@
851
1566
  const scripts = await parseArchiveInBrowser(archiveReader.result, file.name); // result is ArrayBuffer
852
1567
  hideLoader();
853
1568
  loadScripts(scripts);
854
- setStatus(scripts.length + ' Skripte geladen aus: ' + file.name, 'success');
1569
+ setStatus(t('scriptsLoaded').replace('{n}', scripts.length).replace('{f}', file.name), 'success');
855
1570
  } catch(e) {
856
1571
  hideLoader();
857
- setStatus('Fehler: ' + e.message, 'error');
1572
+ setStatus(t('errorPrefix') + e.message, 'error');
858
1573
  }
859
1574
  };
860
1575
  archiveReader.onerror = function() {
861
1576
  hideLoader();
862
- setStatus('Fehler beim Lesen der Datei.', 'error');
1577
+ setStatus(t('errorReading'), 'error');
863
1578
  };
864
1579
  archiveReader.readAsArrayBuffer(file);
865
1580
  this.value = '';
@@ -910,7 +1625,7 @@
910
1625
  dropdownState[src] = !isOpen;
911
1626
  if (dropdownState[src]) {
912
1627
  menu.classList.add('open');
913
- menu.innerHTML = '<div class="dropdown-loading">⏳ Lade Dateiliste...</div>';
1628
+ menu.innerHTML = '<div class="dropdown-loading">' + t('loadingFiles') + '</div>';
914
1629
  sendTo(cfg.listCmd, {}, function(result) {
915
1630
  if (result && result.error) {
916
1631
  menu.innerHTML = '<div class="dropdown-empty">⚠️ ' + escapeHTML(result.error) + '</div>';
@@ -954,12 +1669,12 @@
954
1669
  sendTo(cfg.parseCmd, { filename: filename }, function(result) {
955
1670
  hideLoader();
956
1671
  if (result && result.error) {
957
- setStatus('Fehler: ' + result.error, 'error');
1672
+ setStatus(t('errorPrefix') + result.error, 'error');
958
1673
  } else if (result && result.scripts) {
959
1674
  loadScripts(result.scripts);
960
- setStatus(result.scripts.length + ' Skripte geladen aus: ' + filename, 'success');
1675
+ setStatus(t('scriptsLoaded').replace('{n}', result.scripts.length).replace('{f}', filename), 'success');
961
1676
  } else {
962
- setStatus('Keine Skripte gefunden.', 'error');
1677
+ setStatus(t('noScripts'), 'error');
963
1678
  }
964
1679
  });
965
1680
  }
@@ -973,15 +1688,15 @@
973
1688
  sendTo('parseHttpUrl', { url }, function(result) {
974
1689
  hideLoader();
975
1690
  if (!result) {
976
- setStatus('Fehler: Keine Antwort vom Adapter. Läuft script-restore.' + instance + '?', 'error');
1691
+ setStatus(t('adapterTimeout').replace('{i}', instance), 'error');
977
1692
  } else if (result.error) {
978
- setStatus('Fehler: ' + result.error, 'error');
979
- alert('Fehler beim Laden: ' + result.error);
1693
+ setStatus(t('errorPrefix') + result.error, 'error');
1694
+ alert(t('errorPrefix') + result.error);
980
1695
  } else if (result.scripts) {
981
1696
  loadScripts(result.scripts);
982
- setStatus(result.scripts.length + ' Skripte geladen von URL', 'success');
1697
+ setStatus(t('scriptsLoadedUrl').replace('{n}', result.scripts.length), 'success');
983
1698
  } else {
984
- setStatus('Keine Skripte gefunden.', 'error');
1699
+ setStatus(t('noScripts'), 'error');
985
1700
  }
986
1701
  });
987
1702
  }
@@ -1028,8 +1743,8 @@
1028
1743
  document.getElementById('actionBar').style.display = 'none';
1029
1744
  document.getElementById('codeContainer').className = 'code-empty';
1030
1745
  document.getElementById('codeContainer').innerHTML = scripts.length > 0
1031
- ? '// Skript im Baum links auswählen… oder mehrere mit Strg+Klick für ZIP'
1032
- : '<span style="color:#dc3545">Keine Skripte in diesem Backup gefunden.</span>';
1746
+ ? t('codeHint')
1747
+ : '<span style="color:#dc3545">' + t('noScriptsBackup') + '</span>';
1033
1748
  }
1034
1749
 
1035
1750
  // === Loader ===
@@ -1038,13 +1753,13 @@
1038
1753
  document.getElementById('spinnerEl').style.display = 'none';
1039
1754
  document.getElementById('progressCircle').style.background = 'conic-gradient(var(--primary) 0%, #e9ecef 0%)';
1040
1755
  document.getElementById('progressPercent').textContent = '0%';
1041
- document.getElementById('loaderText').textContent = text || 'Laden...';
1756
+ document.getElementById('loaderText').textContent = text || t('loaderLoading');
1042
1757
  document.getElementById('loader').style.display = 'flex';
1043
1758
  }
1044
1759
  function showLoaderSpinner(text) {
1045
1760
  document.getElementById('progressContainer').style.display = 'none';
1046
1761
  document.getElementById('spinnerEl').style.display = 'block';
1047
- document.getElementById('loaderText').textContent = text || 'Verarbeite...';
1762
+ document.getElementById('loaderText').textContent = text || t('loaderProcessing');
1048
1763
  document.getElementById('loader').style.display = 'flex';
1049
1764
  }
1050
1765
  function updateProgress(pct) {
@@ -1061,7 +1776,7 @@
1061
1776
  isAllExpanded = !isAllExpanded;
1062
1777
  const btn = document.getElementById('expandToggleBtn');
1063
1778
  btn.innerHTML = isAllExpanded ? '📁' : '📂';
1064
- btn.title = isAllExpanded ? 'Alle einklappen' : 'Alle aufklappen';
1779
+ btn.title = isAllExpanded ? t('collapseAll') : t('expandAll');
1065
1780
  document.querySelectorAll('.tree-folder').forEach(el => {
1066
1781
  const p = el.dataset.path;
1067
1782
  const icon = el.querySelector('.folder-icon');
@@ -1248,12 +1963,12 @@
1248
1963
  ta.value = txt; document.body.appendChild(ta); ta.select();
1249
1964
  try {
1250
1965
  document.execCommand('copy');
1251
- btn.textContent = '✓ Kopiert!';
1966
+ btn.textContent = t('copied');
1252
1967
  btn.classList.replace('btn-outline-light', 'btn-outline-success');
1253
1968
  } finally {
1254
1969
  document.body.removeChild(ta);
1255
1970
  setTimeout(() => {
1256
- btn.textContent = 'Code Kopieren';
1971
+ btn.textContent = t('copyBtnAction');
1257
1972
  btn.classList.replace('btn-outline-success', 'btn-outline-light');
1258
1973
  }, 1500);
1259
1974
  }
@@ -1325,18 +2040,18 @@
1325
2040
  const msgEl = document.getElementById('rmMsg');
1326
2041
  const confirmBtn = document.getElementById('rmConfirmBtn');
1327
2042
  msgEl.style.color = '#aaa';
1328
- msgEl.textContent = '⏳ Laden...';
2043
+ msgEl.textContent = t('modalLoading');
1329
2044
  confirmBtn.disabled = true;
1330
2045
  sendTo('restoreScript', { path: s.path, name: s.name, type: s.type, source: s.source, suffix, overwrite: !!overwrite }, function(result) {
1331
2046
  if (result && result.exists) {
1332
- document.getElementById('rmWarningPath').textContent = result.id.replace(/^script\.js\./, '');
2047
+ document.querySelector('#rmWarning p').innerHTML = t('modalWarning').replace('{path}', '<code>' + escapeHTML(result.id.replace(/^script\.js\./, '')) + '</code>');
1333
2048
  document.getElementById('rmWarning').style.display = 'block';
1334
2049
  document.getElementById('rmSuffix').disabled = true;
1335
2050
  msgEl.textContent = '';
1336
2051
  } else if (result && result.error) {
1337
2052
  confirmBtn.disabled = false;
1338
2053
  msgEl.style.color = '#dc3545';
1339
- msgEl.textContent = '' + result.error;
2054
+ msgEl.textContent = t('modalErrorPrefix') + result.error;
1340
2055
  } else if (result && result.success) {
1341
2056
  _restoredScriptId = result.id;
1342
2057
  msgEl.textContent = '';
@@ -1345,7 +2060,7 @@
1345
2060
  } else {
1346
2061
  confirmBtn.disabled = false;
1347
2062
  msgEl.style.color = '#dc3545';
1348
- msgEl.textContent = '✗ Unbekannter Fehler';
2063
+ msgEl.textContent = t('modalUnknownError');
1349
2064
  }
1350
2065
  });
1351
2066
  }
@@ -1367,16 +2082,16 @@
1367
2082
  if (!_restoredScriptId) return;
1368
2083
  const startBtn = document.getElementById('rmStartBtn');
1369
2084
  startBtn.disabled = true;
1370
- startBtn.textContent = '⏳ Starte...';
2085
+ startBtn.textContent = t('modalStarting');
1371
2086
  sendTo('enableScript', { id: _restoredScriptId }, function(result) {
1372
2087
  if (result && result.success) {
1373
- startBtn.textContent = '✓ Gestartet';
2088
+ startBtn.textContent = t('modalStarted');
1374
2089
  setTimeout(() => closeRestoreModal(), 1000);
1375
2090
  } else {
1376
2091
  startBtn.disabled = false;
1377
- startBtn.textContent = 'Jetzt starten';
2092
+ startBtn.textContent = t('modalStart');
1378
2093
  const p = document.querySelector('#rmSuccess p');
1379
- p.innerHTML = '✗ Fehler: ' + ((result && result.error) || 'Unbekannt');
2094
+ p.innerHTML = t('modalErrorPrefix') + escapeHTML((result && result.error) || 'Unbekannt');
1380
2095
  p.style.color = '#dc3545';
1381
2096
  }
1382
2097
  });
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "script-restore",
4
- "version": "0.1.1",
4
+ "version": "0.1.3",
5
5
  "news": {
6
+ "0.1.3": {
7
+ "en": "fix language flash: skip socket override when language already detected from admin frame\nreplace all hardcoded status strings with translated t() calls\nadd codeHint translation key in all 11 languages",
8
+ "de": "fixer sprachblitz: überschreiben der sprachfassung, wenn die sprache bereits von admin-rahmen erkannt wurde\nalle hardcoded status strings durch übersetzte t()-anrufe ersetzen\ncode hinzufügenHint Übersetzungsschlüssel in allen 11 Sprachen",
9
+ "ru": "исправьте языковую вспышку: пропустите переопределение сокетов, когда язык уже обнаружен в рамке администратора\nзаменить все жестко закодированные строки состояния переводными вызовами t()\nдобавить ключ перевода codeHint на все 11 языков",
10
+ "pt": "flash da linguagem de correção: sobreposição do socket pule quando a linguagem já detectada do frame do administrador\nsubstituir todas as cadeias de estado codificadas por chamadas traduzidas em t()\nadicionar códigoHint chave de tradução em todos os 11 idiomas",
11
+ "nl": "fix taalflits: sla socket over wanneer taal al gedetecteerd vanuit admin frame\nvervangen alle hardcoded status strings door vertaalde t() calls\ncodeHint vertaalsleutel toevoegen in alle 11 talen",
12
+ "fr": "résoudre le flash de langue: sauter la préséance socket lorsque la langue déjà détectée à partir du cadre admin\nremplacer toutes les chaînes d'état codées en dur par des appels traduit t()\najouter codeHint clé de traduction dans les 11 langues",
13
+ "it": "fix lingua flash: saltare socket override quando la lingua già rilevata dalla cornice di amministrazione\nsostituire tutte le stringhe di stato codificate con le chiamate t() tradotte\naggiungere codice Chiave di traduzione in tutte le 11 lingue",
14
+ "es": "solucionar el flash del lenguaje: saltar la anulación de la toma cuando el lenguaje ya detectado desde el marco de administración\nreemplazar todas las cadenas de estado codificadas con llamadas t( traducido)\nañadir codeHint traducción clave en los 11 idiomas",
15
+ "pl": "fix flash język: skip derogator gniazda, gdy język już wykryty z ramki admin\nzastąp wszystkie zaszyfrowane łańcuchy stanu translated t () calls\ndodaj klucz tłumaczeniowy CodeHint we wszystkich 11 językach",
16
+ "uk": "фіксувати мовне спалах: пропустити розетку перенапругою, коли мова вже виявлена з адмін кадру\nзамінити всі жорсткікодовані рядки стану з перекладеними t() дзвінки\nadd codeПеревірити ключ у всіх 11 мовах",
17
+ "zh-cn": "修补语言闪存: 当语言已经从管理员框架中检测到时跳过套接字覆盖\n将所有硬码状态字符串替换为已翻译的 t() 调用\n在所有11种语言中添加代码Hint翻译密钥"
18
+ },
19
+ "0.1.2": {
20
+ "en": "add full i18n to tab UI: all strings translated into de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
21
+ "de": "fügen Sie volle i18n zu Tab UI: alle Strings übersetzt in de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
22
+ "ru": "добавить полный i18n в вкладку UI: все строки переведены в de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
23
+ "pt": "adicionar i18n completo à guia UI: todas as strings traduzidas para de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
24
+ "nl": "volledige i18n toevoegen aan tab UI: alle tekenreeksen vertaald in de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
25
+ "fr": "ajouter i18n complet à l'onglet UI: toutes les chaînes traduites en de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
26
+ "it": "aggiungere i18n completo alla scheda UI: tutte le stringhe tradotte in de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
27
+ "es": "añadir i18n completo a la pestaña UI: todas las cadenas traducidas a de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn",
28
+ "pl": "dodaj pełny i18n do zakładki Interfejs: wszystkie struny przetłumaczone na de / en / fr / es / it / nl / pl / pt / ru / uk / zh- cn",
29
+ "uk": "додати повну i18n в закладку UI: всі рядки, перекладені в de/en/fr/es/nl/pl/pt/ru/uk/zh-cn",
30
+ "zh-cn": "将完整 i18n 添加到 Tab UI 中: 所有字符串翻译为 de/en/fr/es/it/nl/pl/pt/ru/uk/zh-cn"
31
+ },
6
32
  "0.1.1": {
7
33
  "en": "allow overwriting existing scripts during restore (confirmation dialog with path display)\nallow empty suffix to restore script under its original name\nprompt to start script immediately after successful restore",
8
34
  "de": "das überschreiben bestehender skripte während der wiederherstellung (bestätigungsdialog mit pfadanzeige)\nleere suffix erlauben, skript unter seinem ursprünglichen namen wiederherzustellen\nscript sofort nach erfolgreicher wiederherstellung starten",
@@ -67,32 +93,6 @@
67
93
  "pl": "Poprawiono rozmiary responsywne jsonConfig; aktualności ograniczone do 7; dodano cooldown Dependabot",
68
94
  "uk": "Виправлено розміри jsonConfig; новини скорочено до 7; додано cooldown Dependabot",
69
95
  "zh-cn": "修复 jsonConfig 响应式尺寸;新闻条目减少至 7 条;添加 Dependabot 冷却时间"
70
- },
71
- "0.0.9": {
72
- "en": "Fix jsonConfig: add responsive size attributes, i18n support, remove outdated admin files",
73
- "de": "jsonConfig: Responsive Size-Attribute ergänzt, i18n-Unterstützung, veraltete Admin-Dateien entfernt",
74
- "ru": "jsonConfig: добавлены атрибуты размера, поддержка i18n, удалены устаревшие файлы admin",
75
- "pt": "jsonConfig: atributos de tamanho responsivos, suporte i18n, remoção de ficheiros admin obsoletos",
76
- "nl": "jsonConfig: responsieve grootteattributen, i18n-ondersteuning, verouderde adminbestanden verwijderd",
77
- "fr": "jsonConfig: attributs de taille responsifs, support i18n, suppression fichiers admin obsolètes",
78
- "it": "jsonConfig: attributi dimensione responsivi, supporto i18n, rimozione file admin obsoleti",
79
- "es": "jsonConfig: atributos de tamaño responsivos, soporte i18n, eliminación de archivos admin obsoletos",
80
- "pl": "jsonConfig: atrybuty rozmiaru responsywnego, wsparcie i18n, usunięcie przestarzałych plików admin",
81
- "uk": "jsonConfig: атрибути розміру, підтримка i18n, видалення застарілих файлів admin",
82
- "zh-cn": "jsonConfig:添加响应式尺寸属性、i18n 支持,删除过时的 admin 文件"
83
- },
84
- "0.0.8": {
85
- "en": "Migrate settings UI to jsonConfig (admin 5+); fix node:fs import; update Dependabot schedule; migrate automerge workflow",
86
- "de": "Einstellungen auf jsonConfig (Admin 5+) migriert; node:fs-Import korrigiert; Dependabot-Schedule aktualisiert; Automerge-Workflow migriert",
87
- "ru": "Миграция UI настроек на jsonConfig (admin 5+); исправлен импорт node:fs; обновлён Dependabot; миграция automerge workflow",
88
- "pt": "Migrar UI de configurações para jsonConfig (admin 5+); corrigir importação node:fs; atualizar Dependabot; migrar workflow automerge",
89
- "nl": "Instellingen UI migreren naar jsonConfig (admin 5+); node:fs import gecorrigeerd; Dependabot schedule bijgewerkt; automerge workflow gemigreerd",
90
- "fr": "Migration de l'UI des paramètres vers jsonConfig (admin 5+); correction de l'import node:fs; mise à jour Dependabot; migration du workflow automerge",
91
- "it": "Migrazione UI impostazioni a jsonConfig (admin 5+); corretto import node:fs; aggiornato Dependabot; migrato workflow automerge",
92
- "es": "Migrar UI de configuración a jsonConfig (admin 5+); corregir importación node:fs; actualizar Dependabot; migrar workflow automerge",
93
- "pl": "Migracja UI ustawień do jsonConfig (admin 5+); poprawka importu node:fs; aktualizacja Dependabot; migracja workflow automerge",
94
- "uk": "Міграція UI налаштувань на jsonConfig (admin 5+); виправлено імпорт node:fs; оновлено Dependabot; міграція automerge workflow",
95
- "zh-cn": "将设置 UI 迁移至 jsonConfig(admin 5+);修复 node:fs 导入;更新 Dependabot 计划;迁移 automerge 工作流"
96
96
  }
97
97
  },
98
98
  "titleLang": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.script-restore",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Restore ioBroker scripts from backup archives",
5
5
  "author": {
6
6
  "name": "ipod86",