From 554135d26c9be8e8cde67f99e62b700b2c28919e Mon Sep 17 00:00:00 2001 From: AMAARETS Date: Thu, 8 Jan 2026 00:04:33 +0200 Subject: [PATCH 1/3] feat(glossary): expand language support and admin interface - Add Hebrew (he) language translation file with complete glossary strings - Expand German (de) language file with widgets and admin interface translations - Expand English (en-GB, en-US) language files with widgets and admin interface translations - Expand Turkish (tr) language file with widgets and admin interface translations - Update controllers to use translator for dynamic admin page title - Enhance admin templates with improved form layouts and item management UI - Add client-side functionality for CSV upload and keyword management - Update .gitignore to exclude local git configuration files - Update package.json with new dependencies and version bump - Improve admin interface with better widget positioning and form validation --- .gitignore | 1 + languages/de/glossary.json | 32 +++++++++++++++++-- languages/en-GB/glossary.json | 32 +++++++++++++++++-- languages/en-US/glossary.json | 32 +++++++++++++++++-- languages/he/glossary.json | 31 ++++++++++++++++++ languages/tr/glossary.json | 32 +++++++++++++++++-- lib/controllers.js | 6 ++-- library.js | 14 ++++---- package.json | 4 +-- static/lib/admin.js | 25 +++++++++------ static/lib/main.js | 16 ++++++++-- templates/admin/plugins/glossary.tpl | 18 +++++------ .../glossary/partials/sorted-list/form.tpl | 10 +++--- .../glossary/partials/sorted-list/item.tpl | 4 +-- 14 files changed, 209 insertions(+), 48 deletions(-) create mode 100644 languages/he/glossary.json diff --git a/.gitignore b/.gitignore index d77e539..5826bf4 100644 --- a/.gitignore +++ b/.gitignore @@ -216,3 +216,4 @@ pip-log.txt sftp-config.json node_modules/ +.gitconfig_local diff --git a/languages/de/glossary.json b/languages/de/glossary.json index 7f762c0..2e4a9a3 100644 --- a/languages/de/glossary.json +++ b/languages/de/glossary.json @@ -1,3 +1,31 @@ { - "title": "Wörterbuch" -} + "title": "Wörterbuch", + "widgets": { + "header": "Wörterbuch-Seite (Kopfzeile)", + "left": "Wörterbuch-Seite (Links)", + "right": "Wörterbuch-Seite (Rechts)", + "footer": "Wörterbuch-Seite (Fußzeile)" + }, + "admin": { + "general": "Allgemein", + "enabled": "Aktiviert", + "singleMatch": "Einzelne Übereinstimmung", + "caseSensitive": "Groß-/Kleinschreibung beachten", + "iconLabel": "Symbol neben Schlüsselwort anzeigen, leer lassen zum Deaktivieren", + "keywords": "Schlüsselwörter", + "uploadCsv": "CSV hochladen", + "deleteAll": "Alle löschen", + "addItem": "Element hinzufügen", + "edit": "Bearbeiten", + "delete": "Löschen", + "add": "Hinzufügen", + "confirmDeleteAll": "Sind Sie sicher, dass Sie alle Schlüsselwörter löschen möchten?", + "settingsSaved": "Einstellungen gespeichert", + "reloadMessage": "Bitte laden Sie NodeBB neu, um diese Einstellungen anzuwenden", + "form": { + "name": "Name", + "description": "Beschreibung", + "infoLabel": "Info (optional). Wird auf der /glossary Seite angezeigt" + } + } +} diff --git a/languages/en-GB/glossary.json b/languages/en-GB/glossary.json index 984c96f..f370ce5 100644 --- a/languages/en-GB/glossary.json +++ b/languages/en-GB/glossary.json @@ -1,3 +1,31 @@ { - "title": "Glossary" -} \ No newline at end of file + "title": "Glossary", + "widgets": { + "header": "Glossary Page (Header)", + "left": "Glossary Page (Left)", + "right": "Glossary Page (Right)", + "footer": "Glossary Page (Footer)" + }, + "admin": { + "general": "General", + "enabled": "Enabled", + "singleMatch": "Single Match", + "caseSensitive": "Case Sensitive", + "iconLabel": "Icon to show next to keyword, leave empty to disable", + "keywords": "Keywords", + "uploadCsv": "Upload CSV", + "deleteAll": "Delete All", + "addItem": "Add Item", + "edit": "Edit", + "delete": "Delete", + "add": "Add", + "confirmDeleteAll": "Are you sure you want to delete all keywords?", + "settingsSaved": "Settings Saved", + "reloadMessage": "Please reload your NodeBB to apply these settings", + "form": { + "name": "Name", + "description": "Description", + "infoLabel": "Info (optional). Displayed on the /glossary page" + } + } +} diff --git a/languages/en-US/glossary.json b/languages/en-US/glossary.json index 984c96f..f370ce5 100644 --- a/languages/en-US/glossary.json +++ b/languages/en-US/glossary.json @@ -1,3 +1,31 @@ { - "title": "Glossary" -} \ No newline at end of file + "title": "Glossary", + "widgets": { + "header": "Glossary Page (Header)", + "left": "Glossary Page (Left)", + "right": "Glossary Page (Right)", + "footer": "Glossary Page (Footer)" + }, + "admin": { + "general": "General", + "enabled": "Enabled", + "singleMatch": "Single Match", + "caseSensitive": "Case Sensitive", + "iconLabel": "Icon to show next to keyword, leave empty to disable", + "keywords": "Keywords", + "uploadCsv": "Upload CSV", + "deleteAll": "Delete All", + "addItem": "Add Item", + "edit": "Edit", + "delete": "Delete", + "add": "Add", + "confirmDeleteAll": "Are you sure you want to delete all keywords?", + "settingsSaved": "Settings Saved", + "reloadMessage": "Please reload your NodeBB to apply these settings", + "form": { + "name": "Name", + "description": "Description", + "infoLabel": "Info (optional). Displayed on the /glossary page" + } + } +} diff --git a/languages/he/glossary.json b/languages/he/glossary.json new file mode 100644 index 0000000..5673630 --- /dev/null +++ b/languages/he/glossary.json @@ -0,0 +1,31 @@ +{ + "title": "מילון מונחים", + "widgets": { + "header": "דף מילון מונחים (כותרת)", + "left": "דף מילון מונחים (שמאל)", + "right": "דף מילון מונחים (ימין)", + "footer": "דף מילון מונחים (תחתית)" + }, + "admin": { + "general": "כללי", + "enabled": "מופעל", + "singleMatch": "התאמה בודדת", + "caseSensitive": "תלוי רישיות", + "iconLabel": "אייקון להצגה ליד מילת מפתח, השאר ריק לביטול", + "keywords": "מילות מפתח", + "uploadCsv": "העלאת CSV", + "deleteAll": "מחק הכל", + "addItem": "הוסף פריט", + "edit": "עריכה", + "delete": "מחיקה", + "add": "הוסף", + "confirmDeleteAll": "האם אתה בטוח שברצונך למחוק את כל מילות המפתח?", + "settingsSaved": "ההגדרות נשמרו", + "reloadMessage": "אנא טען מחדש את NodeBB כדי להחיל הגדרות אלו", + "form": { + "name": "שם", + "description": "תיאור", + "infoLabel": "מידע (אופציונלי). מוצג בדף /glossary" + } + } +} diff --git a/languages/tr/glossary.json b/languages/tr/glossary.json index 4702ee3..1e98afb 100644 --- a/languages/tr/glossary.json +++ b/languages/tr/glossary.json @@ -1,3 +1,31 @@ { - "title": "Sözlük" -} + "title": "Sözlük", + "widgets": { + "header": "Sözlük Sayfası (Üst)", + "left": "Sözlük Sayfası (Sol)", + "right": "Sözlük Sayfası (Sağ)", + "footer": "Sözlük Sayfası (Alt)" + }, + "admin": { + "general": "Genel", + "enabled": "Etkin", + "singleMatch": "Tek Eşleşme", + "caseSensitive": "Büyük/Küçük Harf Duyarlı", + "iconLabel": "Anahtar kelimenin yanında gösterilecek simge, devre dışı bırakmak için boş bırakın", + "keywords": "Anahtar Kelimeler", + "uploadCsv": "CSV Yükle", + "deleteAll": "Tümünü Sil", + "addItem": "Öğe Ekle", + "edit": "Düzenle", + "delete": "Sil", + "add": "Ekle", + "confirmDeleteAll": "Tüm anahtar kelimeleri silmek istediğinizden emin misiniz?", + "settingsSaved": "Ayarlar Kaydedildi", + "reloadMessage": "Bu ayarları uygulamak için lütfen NodeBB'yi yeniden yükleyin", + "form": { + "name": "Ad", + "description": "Açıklama", + "infoLabel": "Bilgi (isteğe bağlı). /glossary sayfasında görüntülenir" + } + } +} diff --git a/lib/controllers.js b/lib/controllers.js index 0a6c25a..f34eb14 100644 --- a/lib/controllers.js +++ b/lib/controllers.js @@ -40,9 +40,11 @@ Controllers.renderGlossary = async function (req, res) { }); }; -Controllers.renderAdminPage = function (req, res/* , next */) { +Controllers.renderAdminPage = async function (req, res/* , next */) { + const translator = require.main.require('./src/translator'); + const title = await translator.translate('[[glossary:title]]'); res.render('admin/plugins/glossary', { - title: 'Glossary', + title: title, }); }; diff --git a/library.js b/library.js index 157ae28..17af0fd 100644 --- a/library.js +++ b/library.js @@ -30,8 +30,8 @@ plugin.init = async (params) => { await loadSettings(); }; - routeHelpers.setupPageRoute(router, '/glossary', controllers.renderGlossary); - routeHelpers.setupAdminPageRoute(router, '/admin/plugins/glossary', controllers.renderAdminPage); + routeHelpers.setupPageRoute(router, '/glossary', [], controllers.renderGlossary); + routeHelpers.setupAdminPageRoute(router, '/admin/plugins/glossary', [], controllers.renderAdminPage); }; async function loadSettings() { @@ -91,22 +91,22 @@ plugin.filterTeasersConfigureStripTags = function (hookData) { plugin.defineWidgetAreas = async function (areas) { areas = areas.concat([ { - name: 'Glossary Page (Header)', + name: '[[glossary:widgets.header]]', template: 'glossary.tpl', location: 'header', }, { - name: 'Glossary Page (Left)', + name: '[[glossary:widgets.left]]', template: 'glossary.tpl', location: 'left', }, { - name: 'Glossary Page (Right)', + name: '[[glossary:widgets.right]]', template: 'glossary.tpl', location: 'right', }, { - name: 'Glossary Page (Footer)', + name: '[[glossary:widgets.footer]]', template: 'glossary.tpl', location: 'footer', }, @@ -118,7 +118,7 @@ plugin.addAdminNavigation = (header) => { header.plugins.push({ route: '/plugins/glossary', icon: 'fa-info', - name: 'Glossary', + name: '[[glossary:title]]', }); return header; diff --git a/package.json b/package.json index 5b93059..da9df99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodebb-plugin-glossary", - "version": "1.1.0", + "version": "2.0.0", "description": "A glossary plugin", "main": "library.js", "repository": { @@ -34,7 +34,7 @@ }, "readmeFilename": "README.md", "nbbpm": { - "compatibility": "^3.2.0" + "compatibility": "^4.0.0" }, "dependencies": { "csvtojson": "^2.0.10", diff --git a/static/lib/admin.js b/static/lib/admin.js index e3569c8..38b77f2 100644 --- a/static/lib/admin.js +++ b/static/lib/admin.js @@ -3,21 +3,23 @@ /* globals csv */ define('admin/plugins/glossary', [ - 'settings', 'settings/sorted-list', 'bootbox', 'benchpress', 'alerts', -], function (settings, sortedList, bootbox, benchpress, alerts) { + 'settings', 'settings/sorted-list', 'bootbox', 'benchpress', 'alerts', 'translator', +], function (settings, sortedList, bootbox, benchpress, alerts, translator) { var ACP = {}; ACP.init = function () { settings.load('glossary', $('.glossary-settings')); $('#save').on('click', saveSettings); - $('#upload-csv').on('click', function () { + $('#upload-csv').on('click', async function () { + const title = await translator.translate('[[glossary:admin.uploadCsv]]'); + const addLabel = await translator.translate('[[glossary:admin.add]]'); const modal = bootbox.dialog({ - title: 'Upload CSV', + title: title, message: '', buttons: { submit: { - label: 'Add', + label: addLabel, className: 'btn-primary', callback: async function () { const text = modal.find('#csv-input').val(); @@ -42,8 +44,9 @@ define('admin/plugins/glossary', [ return false; }); - $('#empty-glossary').on('click', function () { - bootbox.confirm('Are you sure you want to delete all keywords?', function (ok) { + $('#empty-glossary').on('click', async function () { + const confirmMsg = await translator.translate('[[glossary:admin.confirmDeleteAll]]'); + bootbox.confirm(confirmMsg, function (ok) { if (!ok) { return; } @@ -59,13 +62,15 @@ define('admin/plugins/glossary', [ }); }; - function saveSettings() { + async function saveSettings() { + const savedTitle = await translator.translate('[[glossary:admin.settingsSaved]]'); + const savedMessage = await translator.translate('[[glossary:admin.reloadMessage]]'); settings.save('glossary', $('.glossary-settings'), function () { alerts.alert({ type: 'success', alert_id: 'glossary-saved', - title: 'Settings Saved', - message: 'Please reload your NodeBB to apply these settings', + title: savedTitle, + message: savedMessage, clickfn: function () { socket.emit('admin.reload'); }, diff --git a/static/lib/main.js b/static/lib/main.js index 364a88e..c7c02bf 100644 --- a/static/lib/main.js +++ b/static/lib/main.js @@ -1,8 +1,18 @@ 'use strict'; $(document).ready(function () { - $('#content').tooltip({ - selector: '.glossary-wrapper', - container: '#content', + function initTooltips() { + const tooltipTriggerList = document.querySelectorAll('#content .glossary-wrapper'); + tooltipTriggerList.forEach(function (el) { + if (!bootstrap.Tooltip.getInstance(el)) { + new bootstrap.Tooltip(el); + } + }); + } + + initTooltips(); + + $(window).on('action:posts.loaded action:ajaxify.end', function () { + initTooltips(); }); }); diff --git a/templates/admin/plugins/glossary.tpl b/templates/admin/plugins/glossary.tpl index 1c5d5da..849b317 100644 --- a/templates/admin/plugins/glossary.tpl +++ b/templates/admin/plugins/glossary.tpl @@ -5,26 +5,26 @@
-
General
+
[[glossary:admin.general]]
- +
- +
- +
@@ -34,15 +34,15 @@
-
Keywords
+
[[glossary:admin.keywords]]
- - + +
    - +
    diff --git a/templates/admin/plugins/glossary/partials/sorted-list/form.tpl b/templates/admin/plugins/glossary/partials/sorted-list/form.tpl index 7f1b5c5..64eef9a 100644 --- a/templates/admin/plugins/glossary/partials/sorted-list/form.tpl +++ b/templates/admin/plugins/glossary/partials/sorted-list/form.tpl @@ -1,14 +1,14 @@
    - - + +
    - - + +
    - +
    \ No newline at end of file diff --git a/templates/admin/plugins/glossary/partials/sorted-list/item.tpl b/templates/admin/plugins/glossary/partials/sorted-list/item.tpl index e26565f..90f3b5a 100644 --- a/templates/admin/plugins/glossary/partials/sorted-list/item.tpl +++ b/templates/admin/plugins/glossary/partials/sorted-list/item.tpl @@ -6,8 +6,8 @@ {info}
    - - + +
    \ No newline at end of file From bdc09b8300f0e274047cabb896b59167263f0a84 Mon Sep 17 00:00:00 2001 From: ClickAndGoScript Date: Thu, 8 Jan 2026 00:07:20 +0200 Subject: [PATCH 2/3] feat(glossary): expand language support and admin interface - Add Hebrew (he) language translation file with complete glossary strings - Expand German (de) language file with widgets and admin interface translations - Expand English (en-GB, en-US) language files with widgets and admin interface translations - Expand Turkish (tr) language file with widgets and admin interface translations - Update controllers to use translator for dynamic admin page title - Enhance admin templates with improved form layouts and item management UI - Add client-side functionality for CSV upload and keyword management - Update .gitignore to exclude local git configuration files - Update package.json with new dependencies and version bump - Improve admin interface with better widget positioning and form validation --- .gitignore | 1 + languages/de/glossary.json | 32 +++++++++++++++++-- languages/en-GB/glossary.json | 32 +++++++++++++++++-- languages/en-US/glossary.json | 32 +++++++++++++++++-- languages/he/glossary.json | 31 ++++++++++++++++++ languages/tr/glossary.json | 32 +++++++++++++++++-- lib/controllers.js | 6 ++-- library.js | 14 ++++---- package.json | 4 +-- static/lib/admin.js | 25 +++++++++------ static/lib/main.js | 16 ++++++++-- templates/admin/plugins/glossary.tpl | 18 +++++------ .../glossary/partials/sorted-list/form.tpl | 10 +++--- .../glossary/partials/sorted-list/item.tpl | 4 +-- 14 files changed, 209 insertions(+), 48 deletions(-) create mode 100644 languages/he/glossary.json diff --git a/.gitignore b/.gitignore index d77e539..5826bf4 100644 --- a/.gitignore +++ b/.gitignore @@ -216,3 +216,4 @@ pip-log.txt sftp-config.json node_modules/ +.gitconfig_local diff --git a/languages/de/glossary.json b/languages/de/glossary.json index 7f762c0..2e4a9a3 100644 --- a/languages/de/glossary.json +++ b/languages/de/glossary.json @@ -1,3 +1,31 @@ { - "title": "Wörterbuch" -} + "title": "Wörterbuch", + "widgets": { + "header": "Wörterbuch-Seite (Kopfzeile)", + "left": "Wörterbuch-Seite (Links)", + "right": "Wörterbuch-Seite (Rechts)", + "footer": "Wörterbuch-Seite (Fußzeile)" + }, + "admin": { + "general": "Allgemein", + "enabled": "Aktiviert", + "singleMatch": "Einzelne Übereinstimmung", + "caseSensitive": "Groß-/Kleinschreibung beachten", + "iconLabel": "Symbol neben Schlüsselwort anzeigen, leer lassen zum Deaktivieren", + "keywords": "Schlüsselwörter", + "uploadCsv": "CSV hochladen", + "deleteAll": "Alle löschen", + "addItem": "Element hinzufügen", + "edit": "Bearbeiten", + "delete": "Löschen", + "add": "Hinzufügen", + "confirmDeleteAll": "Sind Sie sicher, dass Sie alle Schlüsselwörter löschen möchten?", + "settingsSaved": "Einstellungen gespeichert", + "reloadMessage": "Bitte laden Sie NodeBB neu, um diese Einstellungen anzuwenden", + "form": { + "name": "Name", + "description": "Beschreibung", + "infoLabel": "Info (optional). Wird auf der /glossary Seite angezeigt" + } + } +} diff --git a/languages/en-GB/glossary.json b/languages/en-GB/glossary.json index 984c96f..f370ce5 100644 --- a/languages/en-GB/glossary.json +++ b/languages/en-GB/glossary.json @@ -1,3 +1,31 @@ { - "title": "Glossary" -} \ No newline at end of file + "title": "Glossary", + "widgets": { + "header": "Glossary Page (Header)", + "left": "Glossary Page (Left)", + "right": "Glossary Page (Right)", + "footer": "Glossary Page (Footer)" + }, + "admin": { + "general": "General", + "enabled": "Enabled", + "singleMatch": "Single Match", + "caseSensitive": "Case Sensitive", + "iconLabel": "Icon to show next to keyword, leave empty to disable", + "keywords": "Keywords", + "uploadCsv": "Upload CSV", + "deleteAll": "Delete All", + "addItem": "Add Item", + "edit": "Edit", + "delete": "Delete", + "add": "Add", + "confirmDeleteAll": "Are you sure you want to delete all keywords?", + "settingsSaved": "Settings Saved", + "reloadMessage": "Please reload your NodeBB to apply these settings", + "form": { + "name": "Name", + "description": "Description", + "infoLabel": "Info (optional). Displayed on the /glossary page" + } + } +} diff --git a/languages/en-US/glossary.json b/languages/en-US/glossary.json index 984c96f..f370ce5 100644 --- a/languages/en-US/glossary.json +++ b/languages/en-US/glossary.json @@ -1,3 +1,31 @@ { - "title": "Glossary" -} \ No newline at end of file + "title": "Glossary", + "widgets": { + "header": "Glossary Page (Header)", + "left": "Glossary Page (Left)", + "right": "Glossary Page (Right)", + "footer": "Glossary Page (Footer)" + }, + "admin": { + "general": "General", + "enabled": "Enabled", + "singleMatch": "Single Match", + "caseSensitive": "Case Sensitive", + "iconLabel": "Icon to show next to keyword, leave empty to disable", + "keywords": "Keywords", + "uploadCsv": "Upload CSV", + "deleteAll": "Delete All", + "addItem": "Add Item", + "edit": "Edit", + "delete": "Delete", + "add": "Add", + "confirmDeleteAll": "Are you sure you want to delete all keywords?", + "settingsSaved": "Settings Saved", + "reloadMessage": "Please reload your NodeBB to apply these settings", + "form": { + "name": "Name", + "description": "Description", + "infoLabel": "Info (optional). Displayed on the /glossary page" + } + } +} diff --git a/languages/he/glossary.json b/languages/he/glossary.json new file mode 100644 index 0000000..5673630 --- /dev/null +++ b/languages/he/glossary.json @@ -0,0 +1,31 @@ +{ + "title": "מילון מונחים", + "widgets": { + "header": "דף מילון מונחים (כותרת)", + "left": "דף מילון מונחים (שמאל)", + "right": "דף מילון מונחים (ימין)", + "footer": "דף מילון מונחים (תחתית)" + }, + "admin": { + "general": "כללי", + "enabled": "מופעל", + "singleMatch": "התאמה בודדת", + "caseSensitive": "תלוי רישיות", + "iconLabel": "אייקון להצגה ליד מילת מפתח, השאר ריק לביטול", + "keywords": "מילות מפתח", + "uploadCsv": "העלאת CSV", + "deleteAll": "מחק הכל", + "addItem": "הוסף פריט", + "edit": "עריכה", + "delete": "מחיקה", + "add": "הוסף", + "confirmDeleteAll": "האם אתה בטוח שברצונך למחוק את כל מילות המפתח?", + "settingsSaved": "ההגדרות נשמרו", + "reloadMessage": "אנא טען מחדש את NodeBB כדי להחיל הגדרות אלו", + "form": { + "name": "שם", + "description": "תיאור", + "infoLabel": "מידע (אופציונלי). מוצג בדף /glossary" + } + } +} diff --git a/languages/tr/glossary.json b/languages/tr/glossary.json index 4702ee3..1e98afb 100644 --- a/languages/tr/glossary.json +++ b/languages/tr/glossary.json @@ -1,3 +1,31 @@ { - "title": "Sözlük" -} + "title": "Sözlük", + "widgets": { + "header": "Sözlük Sayfası (Üst)", + "left": "Sözlük Sayfası (Sol)", + "right": "Sözlük Sayfası (Sağ)", + "footer": "Sözlük Sayfası (Alt)" + }, + "admin": { + "general": "Genel", + "enabled": "Etkin", + "singleMatch": "Tek Eşleşme", + "caseSensitive": "Büyük/Küçük Harf Duyarlı", + "iconLabel": "Anahtar kelimenin yanında gösterilecek simge, devre dışı bırakmak için boş bırakın", + "keywords": "Anahtar Kelimeler", + "uploadCsv": "CSV Yükle", + "deleteAll": "Tümünü Sil", + "addItem": "Öğe Ekle", + "edit": "Düzenle", + "delete": "Sil", + "add": "Ekle", + "confirmDeleteAll": "Tüm anahtar kelimeleri silmek istediğinizden emin misiniz?", + "settingsSaved": "Ayarlar Kaydedildi", + "reloadMessage": "Bu ayarları uygulamak için lütfen NodeBB'yi yeniden yükleyin", + "form": { + "name": "Ad", + "description": "Açıklama", + "infoLabel": "Bilgi (isteğe bağlı). /glossary sayfasında görüntülenir" + } + } +} diff --git a/lib/controllers.js b/lib/controllers.js index 0a6c25a..f34eb14 100644 --- a/lib/controllers.js +++ b/lib/controllers.js @@ -40,9 +40,11 @@ Controllers.renderGlossary = async function (req, res) { }); }; -Controllers.renderAdminPage = function (req, res/* , next */) { +Controllers.renderAdminPage = async function (req, res/* , next */) { + const translator = require.main.require('./src/translator'); + const title = await translator.translate('[[glossary:title]]'); res.render('admin/plugins/glossary', { - title: 'Glossary', + title: title, }); }; diff --git a/library.js b/library.js index 157ae28..17af0fd 100644 --- a/library.js +++ b/library.js @@ -30,8 +30,8 @@ plugin.init = async (params) => { await loadSettings(); }; - routeHelpers.setupPageRoute(router, '/glossary', controllers.renderGlossary); - routeHelpers.setupAdminPageRoute(router, '/admin/plugins/glossary', controllers.renderAdminPage); + routeHelpers.setupPageRoute(router, '/glossary', [], controllers.renderGlossary); + routeHelpers.setupAdminPageRoute(router, '/admin/plugins/glossary', [], controllers.renderAdminPage); }; async function loadSettings() { @@ -91,22 +91,22 @@ plugin.filterTeasersConfigureStripTags = function (hookData) { plugin.defineWidgetAreas = async function (areas) { areas = areas.concat([ { - name: 'Glossary Page (Header)', + name: '[[glossary:widgets.header]]', template: 'glossary.tpl', location: 'header', }, { - name: 'Glossary Page (Left)', + name: '[[glossary:widgets.left]]', template: 'glossary.tpl', location: 'left', }, { - name: 'Glossary Page (Right)', + name: '[[glossary:widgets.right]]', template: 'glossary.tpl', location: 'right', }, { - name: 'Glossary Page (Footer)', + name: '[[glossary:widgets.footer]]', template: 'glossary.tpl', location: 'footer', }, @@ -118,7 +118,7 @@ plugin.addAdminNavigation = (header) => { header.plugins.push({ route: '/plugins/glossary', icon: 'fa-info', - name: 'Glossary', + name: '[[glossary:title]]', }); return header; diff --git a/package.json b/package.json index 5b93059..da9df99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nodebb-plugin-glossary", - "version": "1.1.0", + "version": "2.0.0", "description": "A glossary plugin", "main": "library.js", "repository": { @@ -34,7 +34,7 @@ }, "readmeFilename": "README.md", "nbbpm": { - "compatibility": "^3.2.0" + "compatibility": "^4.0.0" }, "dependencies": { "csvtojson": "^2.0.10", diff --git a/static/lib/admin.js b/static/lib/admin.js index e3569c8..38b77f2 100644 --- a/static/lib/admin.js +++ b/static/lib/admin.js @@ -3,21 +3,23 @@ /* globals csv */ define('admin/plugins/glossary', [ - 'settings', 'settings/sorted-list', 'bootbox', 'benchpress', 'alerts', -], function (settings, sortedList, bootbox, benchpress, alerts) { + 'settings', 'settings/sorted-list', 'bootbox', 'benchpress', 'alerts', 'translator', +], function (settings, sortedList, bootbox, benchpress, alerts, translator) { var ACP = {}; ACP.init = function () { settings.load('glossary', $('.glossary-settings')); $('#save').on('click', saveSettings); - $('#upload-csv').on('click', function () { + $('#upload-csv').on('click', async function () { + const title = await translator.translate('[[glossary:admin.uploadCsv]]'); + const addLabel = await translator.translate('[[glossary:admin.add]]'); const modal = bootbox.dialog({ - title: 'Upload CSV', + title: title, message: '', buttons: { submit: { - label: 'Add', + label: addLabel, className: 'btn-primary', callback: async function () { const text = modal.find('#csv-input').val(); @@ -42,8 +44,9 @@ define('admin/plugins/glossary', [ return false; }); - $('#empty-glossary').on('click', function () { - bootbox.confirm('Are you sure you want to delete all keywords?', function (ok) { + $('#empty-glossary').on('click', async function () { + const confirmMsg = await translator.translate('[[glossary:admin.confirmDeleteAll]]'); + bootbox.confirm(confirmMsg, function (ok) { if (!ok) { return; } @@ -59,13 +62,15 @@ define('admin/plugins/glossary', [ }); }; - function saveSettings() { + async function saveSettings() { + const savedTitle = await translator.translate('[[glossary:admin.settingsSaved]]'); + const savedMessage = await translator.translate('[[glossary:admin.reloadMessage]]'); settings.save('glossary', $('.glossary-settings'), function () { alerts.alert({ type: 'success', alert_id: 'glossary-saved', - title: 'Settings Saved', - message: 'Please reload your NodeBB to apply these settings', + title: savedTitle, + message: savedMessage, clickfn: function () { socket.emit('admin.reload'); }, diff --git a/static/lib/main.js b/static/lib/main.js index 364a88e..c7c02bf 100644 --- a/static/lib/main.js +++ b/static/lib/main.js @@ -1,8 +1,18 @@ 'use strict'; $(document).ready(function () { - $('#content').tooltip({ - selector: '.glossary-wrapper', - container: '#content', + function initTooltips() { + const tooltipTriggerList = document.querySelectorAll('#content .glossary-wrapper'); + tooltipTriggerList.forEach(function (el) { + if (!bootstrap.Tooltip.getInstance(el)) { + new bootstrap.Tooltip(el); + } + }); + } + + initTooltips(); + + $(window).on('action:posts.loaded action:ajaxify.end', function () { + initTooltips(); }); }); diff --git a/templates/admin/plugins/glossary.tpl b/templates/admin/plugins/glossary.tpl index 1c5d5da..849b317 100644 --- a/templates/admin/plugins/glossary.tpl +++ b/templates/admin/plugins/glossary.tpl @@ -5,26 +5,26 @@
    -
    General
    +
    [[glossary:admin.general]]
    - +
    - +
    - +
    @@ -34,15 +34,15 @@
    -
    Keywords
    +
    [[glossary:admin.keywords]]
    - - + +
      - +
      diff --git a/templates/admin/plugins/glossary/partials/sorted-list/form.tpl b/templates/admin/plugins/glossary/partials/sorted-list/form.tpl index 7f1b5c5..64eef9a 100644 --- a/templates/admin/plugins/glossary/partials/sorted-list/form.tpl +++ b/templates/admin/plugins/glossary/partials/sorted-list/form.tpl @@ -1,14 +1,14 @@
      - - + +
      - - + +
      - +
      \ No newline at end of file diff --git a/templates/admin/plugins/glossary/partials/sorted-list/item.tpl b/templates/admin/plugins/glossary/partials/sorted-list/item.tpl index e26565f..90f3b5a 100644 --- a/templates/admin/plugins/glossary/partials/sorted-list/item.tpl +++ b/templates/admin/plugins/glossary/partials/sorted-list/item.tpl @@ -6,8 +6,8 @@ {info}
      - - + +
      \ No newline at end of file From bafa7a2562004b627d4d138f2aeb5a3fa446e6a9 Mon Sep 17 00:00:00 2001 From: ClickAndGoScript Date: Fri, 16 Jan 2026 10:42:44 +0200 Subject: [PATCH 3/3] fix(tooltips): add bootstrap existence check to prevent initialization errors - Wrap tooltip initialization in a typeof bootstrap check to avoid errors when the library is not loaded. - Ensures tooltips only initialize if bootstrap is available, improving robustness in edge cases. --- static/lib/main.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/static/lib/main.js b/static/lib/main.js index c7c02bf..27e831c 100644 --- a/static/lib/main.js +++ b/static/lib/main.js @@ -4,8 +4,10 @@ $(document).ready(function () { function initTooltips() { const tooltipTriggerList = document.querySelectorAll('#content .glossary-wrapper'); tooltipTriggerList.forEach(function (el) { - if (!bootstrap.Tooltip.getInstance(el)) { - new bootstrap.Tooltip(el); + if (typeof bootstrap !== 'undefined') { + if (!bootstrap.Tooltip.getInstance(el)) { + new bootstrap.Tooltip(el); + } } }); }