iobroker.staticsfilefolder 0.0.10 → 0.0.11

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/io-package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "staticsfilefolder",
4
- "version": "0.0.10",
4
+ "version": "0.0.11",
5
5
  "news": {
6
+ "0.0.11": {
7
+ "en": "Added multi-language support (English and Azerbaijani) with English as the default."
8
+ },
6
9
  "0.0.10": {
7
10
  "en": "Updated README.md with detailed instructions for instance configuration settings."
8
11
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.staticsfilefolder",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "description": "Static Files Folder",
5
5
  "author": {
6
6
  "name": "gokturk413",
package/www/app.js CHANGED
@@ -16,6 +16,7 @@ const btnBack = document.getElementById('btn-back');
16
16
  const btnForward = document.getElementById('btn-forward');
17
17
  const btnHome = document.getElementById('btn-home');
18
18
  const btnTheme = document.getElementById('btn-theme');
19
+ const btnLang = document.getElementById('btn-lang');
19
20
  const searchBox = document.getElementById('search-box');
20
21
  const typeFilter = document.getElementById('type-filter');
21
22
  const sortSelect = document.getElementById('sort-select');
@@ -33,11 +34,105 @@ const modalBtnDownload = document.getElementById('modal-btn-download');
33
34
  let currentOpenItem = null;
34
35
  let currentFilesList = [];
35
36
 
37
+ // Localization Settings
38
+ const translations = {
39
+ en: {
40
+ back: "← Back",
41
+ forward: "Forward →",
42
+ home: "Home",
43
+ searchPlaceholder: "Search...",
44
+ allTypes: "All Types",
45
+ sortAz: "Sort A-Z",
46
+ sortZa: "Sort Z-A",
47
+ sortNewest: "Newest First",
48
+ sortOldest: "Oldest First",
49
+ title: "Omni Reports",
50
+ loadingPdf: "Loading PDF...",
51
+ loadingExcel: "Loading Excel...",
52
+ loadingWord: "Loading Word...",
53
+ emptyFolder: "This folder is empty.",
54
+ root: "Root",
55
+ themeTooltip: "Toggle Dark/Light Mode",
56
+ langTooltip: "Change Language / Dili Dəyiş",
57
+ modalTitle: "File Viewer",
58
+ modalBack: "← Back",
59
+ modalForward: "Next →",
60
+ modalPrint: "🖨️ Print / PDF",
61
+ modalDownload: "📥 Download",
62
+ todayBadge: "Today",
63
+ errorLoading: "An error occurred: "
64
+ },
65
+ az: {
66
+ back: "← Geri",
67
+ forward: "İrəli →",
68
+ home: "Ev (Home)",
69
+ searchPlaceholder: "Axtarış...",
70
+ allTypes: "Bütün Tiplər",
71
+ sortAz: "A-Z Sırala",
72
+ sortZa: "Z-A Sırala",
73
+ sortNewest: "Ən Yeni",
74
+ sortOldest: "Ən Köhnə",
75
+ title: "Omni Hesabatlar",
76
+ loadingPdf: "PDF Yüklənir...",
77
+ loadingExcel: "Excel Yüklənir...",
78
+ loadingWord: "Word Yüklənir...",
79
+ emptyFolder: "Bu qovluq boşdur.",
80
+ root: "Kök",
81
+ themeTooltip: "Gecə/Gündüz Rejimi",
82
+ langTooltip: "Change Language / Dili Dəyiş",
83
+ modalTitle: "Fayl Baxışı",
84
+ modalBack: "← Geri",
85
+ modalForward: "İrəli →",
86
+ modalPrint: "🖨️ Çap / PDF",
87
+ modalDownload: "📥 Yüklə",
88
+ todayBadge: "Bu gün",
89
+ errorLoading: "Xəta baş verdi: "
90
+ }
91
+ };
92
+
93
+ let currentLang = 'en'; // default English
94
+
36
95
  // Setup PDF.js worker
37
96
  if (window.pdfjsLib) {
38
97
  window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'libs/pdfjs/pdf.worker.min.mjs';
39
98
  }
40
99
 
100
+ // Language Initialization
101
+ function initLang() {
102
+ currentLang = localStorage.getItem('staticsfilefolder_lang') || 'en';
103
+ applyTranslations();
104
+ }
105
+
106
+ function toggleLang() {
107
+ currentLang = currentLang === 'en' ? 'az' : 'en';
108
+ localStorage.setItem('staticsfilefolder_lang', currentLang);
109
+ applyTranslations();
110
+ }
111
+
112
+ function applyTranslations() {
113
+ const t = translations[currentLang];
114
+
115
+ // Update elements with data-i18n attribute
116
+ document.querySelectorAll('[data-i18n]').forEach(el => {
117
+ const key = el.getAttribute('data-i18n');
118
+ if (t[key]) {
119
+ if (el.tagName === 'INPUT') {
120
+ el.placeholder = t[key];
121
+ } else {
122
+ el.textContent = t[key];
123
+ }
124
+ }
125
+ });
126
+
127
+ // Update search placeholder and other specific inputs
128
+ searchBox.placeholder = t.searchPlaceholder;
129
+ btnLang.textContent = currentLang === 'en' ? '🌐 AZ' : '🌐 EN';
130
+
131
+ // Refresh UI to update dynamic content like dates/breadcrumbs
132
+ updateBreadcrumb();
133
+ renderItems();
134
+ }
135
+
41
136
  // Theme Initialization
42
137
  function initTheme() {
43
138
  const savedTheme = localStorage.getItem('staticsfilefolder_theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
@@ -56,6 +151,7 @@ function toggleTheme() {
56
151
  // Initialize
57
152
  document.addEventListener('DOMContentLoaded', () => {
58
153
  initTheme();
154
+ initLang();
59
155
  loadPath('');
60
156
 
61
157
  // Event Listeners
@@ -63,6 +159,7 @@ document.addEventListener('DOMContentLoaded', () => {
63
159
  btnForward.addEventListener('click', goForward);
64
160
  btnHome.addEventListener('click', () => navigateTo(''));
65
161
  btnTheme.addEventListener('click', toggleTheme);
162
+ btnLang.addEventListener('click', toggleLang);
66
163
 
67
164
  searchBox.addEventListener('input', renderItems);
68
165
  typeFilter.addEventListener('change', renderItems);
@@ -132,13 +229,14 @@ function updateNavButtons() {
132
229
  }
133
230
 
134
231
  function updateBreadcrumb() {
232
+ const rootName = translations[currentLang]?.root || 'Root';
135
233
  if (!currentPath) {
136
- breadcrumbEl.innerHTML = '<span><i class="icon">🏠</i> Kök Qovluq</span>';
234
+ breadcrumbEl.innerHTML = `<span><i class="icon">🏠</i> ${rootName}</span>`;
137
235
  return;
138
236
  }
139
237
 
140
238
  const parts = currentPath.split('/');
141
- let html = '<span data-path="">🏠 Kök</span>';
239
+ let html = `<span data-path="">🏠 ${rootName}</span>`;
142
240
  let buildPath = '';
143
241
 
144
242
  parts.forEach((part, index) => {
@@ -216,7 +314,8 @@ function renderItems() {
216
314
  const isToday = itemDate.setHours(0,0,0,0) === today;
217
315
  if (isToday) div.classList.add('is-today');
218
316
 
219
- const dateStr = new Date(item.mtime).toLocaleString('az-AZ');
317
+ const locale = currentLang === 'en' ? 'en-US' : 'az-AZ';
318
+ const dateStr = new Date(item.mtime).toLocaleString(locale);
220
319
 
221
320
  let sizeStr = '';
222
321
  if (!item.isDirectory) {
@@ -224,11 +323,13 @@ function renderItems() {
224
323
  else sizeStr = (item.size / 1024).toFixed(2) + ' KB';
225
324
  }
226
325
 
326
+ const todayText = translations[currentLang]?.todayBadge || 'Today';
327
+
227
328
  div.innerHTML = `
228
329
  <div class="file-icon">${icon}</div>
229
330
  <div class="file-name" title="${item.name}">${item.name}</div>
230
331
  <div class="file-meta">${dateStr}<br>${sizeStr}</div>
231
- ${isToday ? '<div class="today-badge">Bu gün</div>' : ''}
332
+ ${isToday ? `<div class="today-badge">${todayText}</div>` : ''}
232
333
  `;
233
334
 
234
335
  div.addEventListener('click', () => handleItemClick(item));
@@ -352,7 +453,7 @@ function downloadCurrentFile() {
352
453
 
353
454
  async function openPdf(url) {
354
455
  viewerModal.style.display = 'block';
355
- viewerBody.innerHTML = '<h2>PDF Yüklənir...</h2>';
456
+ viewerBody.innerHTML = `<h2>${translations[currentLang]?.loadingPdf || 'Loading PDF...'}</h2>`;
356
457
 
357
458
  try {
358
459
  const loadingTask = window.pdfjsLib.getDocument({ url: url });
@@ -379,13 +480,14 @@ async function openPdf(url) {
379
480
  await page.render(renderContext).promise;
380
481
  }
381
482
  } catch (e) {
382
- viewerBody.innerHTML = `<h2 style="color:red">Xəta baş verdi: ${e.message}</h2>`;
483
+ const errorText = translations[currentLang]?.errorLoading || 'An error occurred: ';
484
+ viewerBody.innerHTML = `<h2 style="color:red">${errorText}${e.message}</h2>`;
383
485
  }
384
486
  }
385
487
 
386
488
  async function openExcel(url) {
387
489
  viewerModal.style.display = 'block';
388
- viewerBody.innerHTML = '<h2>Excel Yüklənir...</h2>';
490
+ viewerBody.innerHTML = `<h2>${translations[currentLang]?.loadingExcel || 'Loading Excel...'}</h2>`;
389
491
 
390
492
  try {
391
493
  const res = await fetch(url);
@@ -407,13 +509,14 @@ async function openExcel(url) {
407
509
  if(table) table.className = 'sheetjs-table';
408
510
 
409
511
  } catch (e) {
410
- viewerBody.innerHTML = `<h2 style="color:red">Xəta baş verdi: ${e.message}</h2>`;
512
+ const errorText = translations[currentLang]?.errorLoading || 'An error occurred: ';
513
+ viewerBody.innerHTML = `<h2 style="color:red">${errorText}${e.message}</h2>`;
411
514
  }
412
515
  }
413
516
 
414
517
  async function openWord(url) {
415
518
  viewerModal.style.display = 'block';
416
- viewerBody.innerHTML = '<h2>Word Sənədi Yüklənir...</h2>';
519
+ viewerBody.innerHTML = `<h2>${translations[currentLang]?.loadingWord || 'Loading Word...'}</h2>`;
417
520
 
418
521
  try {
419
522
  const res = await fetch(url);
@@ -425,6 +528,7 @@ async function openWord(url) {
425
528
  ${result.value}
426
529
  </div>`;
427
530
  } catch (e) {
428
- viewerBody.innerHTML = `<h2 style="color:red">Xəta baş verdi: ${e.message}</h2>`;
531
+ const errorText = translations[currentLang]?.errorLoading || 'An error occurred: ';
532
+ viewerBody.innerHTML = `<h2 style="color:red">${errorText}${e.message}</h2>`;
429
533
  }
430
534
  }
package/www/index.html CHANGED
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="az">
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -16,31 +16,32 @@
16
16
  <div class="app-container">
17
17
  <!-- Header & Toolbar -->
18
18
  <header class="app-header">
19
- <div class="header-title">Omni Reports</div>
19
+ <div class="header-title" id="app-title" data-i18n="title">Omni Reports</div>
20
20
 
21
21
  <div class="toolbar">
22
- <button id="btn-back" class="nav-btn" disabled>&larr; Geri</button>
23
- <button id="btn-forward" class="nav-btn" disabled>İrəli &rarr;</button>
24
- <button id="btn-home" class="nav-btn">Evə (Home)</button>
22
+ <button id="btn-back" class="nav-btn" data-i18n="back" disabled>&larr; Back</button>
23
+ <button id="btn-forward" class="nav-btn" data-i18n="forward" disabled>Forward &rarr;</button>
24
+ <button id="btn-home" class="nav-btn" data-i18n="home">Home</button>
25
25
 
26
26
  <div class="breadcrumb" id="breadcrumb">
27
27
  <!-- Path will be injected here -->
28
28
  </div>
29
29
 
30
30
  <div class="filters">
31
- <button id="btn-theme" class="nav-btn" title="Gecə/Gündüz Rejimi">🌙</button>
32
- <input type="text" id="search-box" placeholder="Axtarış...">
31
+ <button id="btn-lang" class="nav-btn" title="Change Language / Dili Dəyiş">🌐 AZ</button>
32
+ <button id="btn-theme" class="nav-btn" title="Toggle Dark/Light Mode">🌙</button>
33
+ <input type="text" id="search-box" placeholder="Search...">
33
34
  <select id="type-filter">
34
- <option value="all">Bütün Tiplər</option>
35
+ <option value="all" data-i18n="allTypes">All Types</option>
35
36
  <option value=".pdf">PDF</option>
36
37
  <option value=".xlsx">Excel</option>
37
38
  <option value=".docx">Word</option>
38
39
  </select>
39
40
  <select id="sort-select">
40
- <option value="name-asc">A-Z Sırala</option>
41
- <option value="name-desc">Z-A Sırala</option>
42
- <option value="date-desc">Ən Yeni</option>
43
- <option value="date-asc">Ən Köhnə</option>
41
+ <option value="name-asc" data-i18n="sortAz">Sort A-Z</option>
42
+ <option value="name-desc" data-i18n="sortZa">Sort Z-A</option>
43
+ <option value="date-desc" data-i18n="sortNewest">Newest First</option>
44
+ <option value="date-asc" data-i18n="sortOldest">Oldest First</option>
44
45
  </select>
45
46
  </div>
46
47
  </div>
@@ -51,8 +52,8 @@
51
52
  <div id="file-list" class="file-list">
52
53
  <!-- File items will be injected here -->
53
54
  </div>
54
- <div id="empty-state" class="empty-state" style="display: none;">
55
- Fayl tapılmadı
55
+ <div id="empty-state" class="empty-state" data-i18n="emptyFolder" style="display: none;">
56
+ This folder is empty.
56
57
  </div>
57
58
  </main>
58
59
  </div>
@@ -61,12 +62,12 @@
61
62
  <div id="viewer-modal" class="modal">
62
63
  <div class="modal-content">
63
64
  <header class="modal-header">
64
- <div class="modal-title" id="modal-title">Fayl Baxışı</div>
65
+ <div class="modal-title" id="modal-title" data-i18n="modalTitle">File Viewer</div>
65
66
  <div class="modal-toolbar">
66
- <button id="modal-btn-prev" class="nav-btn" title="Əvvəlki">&larr; Geri</button>
67
- <button id="modal-btn-next" class="nav-btn" title="Növbəti">İrəli &rarr;</button>
68
- <button id="modal-btn-print" class="nav-btn" title="Çap et / PDF olaraq saxla">🖨️ Çap / PDF</button>
69
- <button id="modal-btn-download" class="nav-btn" title="Faylı Yüklə / Export">📥 Yüklə</button>
67
+ <button id="modal-btn-prev" class="nav-btn" data-i18n="modalBack" title="Previous">&larr; Back</button>
68
+ <button id="modal-btn-next" class="nav-btn" data-i18n="modalForward" title="Next">Next &rarr;</button>
69
+ <button id="modal-btn-print" class="nav-btn" data-i18n="modalPrint" title="Print / Save as PDF">🖨️ Print / PDF</button>
70
+ <button id="modal-btn-download" class="nav-btn" data-i18n="modalDownload" title="Download File">📥 Download</button>
70
71
  <span id="close-modal" class="close-button">&times;</span>
71
72
  </div>
72
73
  </header>