From a7400dca4503961267cc5fd6a1c8efaa78668f77 Mon Sep 17 00:00:00 2001 From: Lauri Ojansivu Date: Mon, 22 Dec 2025 22:24:10 +0200 Subject: [PATCH] More translations. Added support page to Admin Panel / Settings / Layout. Thanks to xet7 ! --- client/components/boards/boardBody.jade | 2 +- client/components/cards/resultCard.jade | 6 +-- client/components/main/support.jade | 29 ++++++++++++ client/components/main/support.js | 41 ++++++++++++++++ client/components/migrationProgress.jade | 12 ++--- .../rules/triggers/boardTriggers.jade | 2 +- client/components/settings/settingBody.jade | 23 +++++++++ client/components/settings/settingBody.js | 42 +++++++++++++++++ client/components/users/userHeader.jade | 12 +++-- client/components/users/userHeader.js | 4 ++ config/router.js | 47 +++++++++++++++++++ imports/i18n/data/en.i18n.json | 8 ++++ imports/i18n/languages.js | 12 +++++ models/settings.js | 22 +++++++++ 14 files changed, 246 insertions(+), 16 deletions(-) create mode 100644 client/components/main/support.jade create mode 100644 client/components/main/support.js diff --git a/client/components/boards/boardBody.jade b/client/components/boards/boardBody.jade index 8357c857a..ce29541f6 100644 --- a/client/components/boards/boardBody.jade +++ b/client/components/boards/boardBody.jade @@ -24,7 +24,7 @@ template(name="boardBody") // Debug information (remove in production) if debugBoardState .debug-info(style="position: fixed; top: 0; left: 0; background: rgba(0,0,0,0.8); color: white; padding: 10px; z-index: 9999; font-size: 12px;") - | Board: {{currentBoard.title}} | View: {{boardView}} | HasSwimlanes: {{hasSwimlanes}} | Swimlanes: {{currentBoard.swimlanes.length}} + | {{_ 'board'}}: {{currentBoard.title}} | {{_ 'view'}}: {{boardView}} | {{_ 'has-swimlanes'}}: {{hasSwimlanes}} | {{_ 'swimlanes'}}: {{currentBoard.swimlanes.length}} .board-wrapper(class=currentBoard.colorClass class="{{#if isMiniScreen}}mobile-view{{/if}}") .board-canvas.js-swimlanes( class="{{#if hasSwimlanes}}dragscroll{{/if}}" diff --git a/client/components/cards/resultCard.jade b/client/components/cards/resultCard.jade index f2bd16657..5259f8ecc 100644 --- a/client/components/cards/resultCard.jade +++ b/client/components/cards/resultCard.jade @@ -11,7 +11,7 @@ template(name="resultCard") = getBoard.title else .broken-cards-null - | NULL + | {{_ 'no-name'}} if getBoard.archived | πŸ“¦ li.result-card-context.result-card-context-separator @@ -25,7 +25,7 @@ template(name="resultCard") = getSwimlane.title else .broken-cards-null - | NULL + | {{_ 'no-name'}} if getSwimlane.archived | πŸ“¦ li.result-card-context.result-card-context-separator @@ -39,6 +39,6 @@ template(name="resultCard") = getList.title else .broken-cards-null - | NULL + | {{_ 'no-name'}} if getList.archived | πŸ“¦ diff --git a/client/components/main/support.jade b/client/components/main/support.jade new file mode 100644 index 000000000..97529476b --- /dev/null +++ b/client/components/main/support.jade @@ -0,0 +1,29 @@ +template(name="supportHeaderBar") + h1 + if isSupportEnabled + = supportTitle + else + | {{_ 'support'}} + +template(name="support") + .support-page + if isSupportPublic + if isSupportEnabled + .support-page-content + +viewer + | {{supportContent}} + else + .support-page-content + | {{_ 'support-info-not-added-yet'}} + else + if currentUser + if isSupportEnabled + .support-page-content + +viewer + | {{supportContent}} + else + .support-page-content + | {{_ 'support-info-not-added-yet'}} + else + .support-page-content + | {{_ 'support-info-only-for-logged-in-users'}} diff --git a/client/components/main/support.js b/client/components/main/support.js new file mode 100644 index 000000000..0aaa9dcb1 --- /dev/null +++ b/client/components/main/support.js @@ -0,0 +1,41 @@ +import { ReactiveCache } from '/imports/reactiveCache'; +import { TAPi18n } from '/imports/i18n'; + +// Shared helpers for both support templates +const supportHelpers = { + supportTitle() { + const setting = ReactiveCache.getCurrentSetting(); + return setting && setting.supportTitle ? setting.supportTitle : TAPi18n.__('support'); + }, + supportContent() { + const setting = ReactiveCache.getCurrentSetting(); + return setting && setting.supportPageText ? setting.supportPageText : TAPi18n.__('support-info-not-added-yet'); + }, + isSupportEnabled() { + const setting = ReactiveCache.getCurrentSetting(); + return setting && setting.supportPageEnabled; + }, + isSupportPublic() { + const setting = ReactiveCache.getCurrentSetting(); + return setting && setting.supportPagePublic; + } +}; + +// Main support page component +BlazeComponent.extendComponent({ + onCreated() { + this.error = new ReactiveVar(''); + this.loading = new ReactiveVar(false); + + Meteor.subscribe('setting'); + }, + ...supportHelpers +}).register('support'); + +// Header bar component +BlazeComponent.extendComponent({ + onCreated() { + Meteor.subscribe('setting'); + }, + ...supportHelpers +}).register('supportHeaderBar'); diff --git a/client/components/migrationProgress.jade b/client/components/migrationProgress.jade index 250e20920..c68a3836a 100644 --- a/client/components/migrationProgress.jade +++ b/client/components/migrationProgress.jade @@ -4,14 +4,14 @@ template(name="migrationProgress") .migration-progress-modal .migration-progress-header h3.migration-progress-title - | πŸ”„ Board Migration in Progress + | πŸ”„ {{_ 'migration-progress-title'}} .migration-progress-close.js-close-migration-progress | ❌ .migration-progress-content .migration-progress-overall .migration-progress-overall-label - | Overall Progress: {{currentStep}} of {{totalSteps}} steps + | {{_ 'migration-progress-overall'}}: {{currentStep}} {{_ 'of'}} {{totalSteps}} {{_ 'steps'}} .migration-progress-overall-bar .migration-progress-overall-fill(style="{{progressBarStyle}}") .migration-progress-overall-percentage @@ -19,7 +19,7 @@ template(name="migrationProgress") .migration-progress-current-step .migration-progress-step-label - | Current Step: {{stepNameFormatted}} + | {{_ 'migration-progress-current-step'}}: {{stepNameFormatted}} .migration-progress-step-bar .migration-progress-step-fill(style="{{stepProgressBarStyle}}") .migration-progress-step-percentage @@ -27,17 +27,17 @@ template(name="migrationProgress") .migration-progress-status .migration-progress-status-label - | Status: + | {{_ 'migration-progress-status'}}: .migration-progress-status-text | {{stepStatus}} if stepDetailsFormatted .migration-progress-details .migration-progress-details-label - | Details: + | {{_ 'migration-progress-details'}}: .migration-progress-details-text | {{stepDetailsFormatted}} .migration-progress-footer .migration-progress-note - | Please wait while we migrate your board to the latest structure... \ No newline at end of file + | {{_ 'migration-progress-note'}} \ No newline at end of file diff --git a/client/components/rules/triggers/boardTriggers.jade b/client/components/rules/triggers/boardTriggers.jade index d9d2c4e17..419c5faaf 100644 --- a/client/components/rules/triggers/boardTriggers.jade +++ b/client/components/rules/triggers/boardTriggers.jade @@ -105,7 +105,7 @@ template(name="boardTriggers") template(name="boardCardTitlePopup") form label - | Card Title Filter + | {{_ 'boardCardTitlePopup-title'}} input.js-card-filter-name(type="text" value=title autofocus) input.js-card-filter-button.primary.wide(type="submit" value="{{_ 'set-filter'}}") diff --git a/client/components/settings/settingBody.jade b/client/components/settings/settingBody.jade index 9101e18f7..1df865f38 100644 --- a/client/components/settings/settingBody.jade +++ b/client/components/settings/settingBody.jade @@ -375,6 +375,29 @@ template(name='layoutSettings') ul#layout-setting.setting-detail li button.js-all-boards-hide-activities.primary {{_ 'hide-activities-of-all-boards'}} + li + a(href="/support" style="text-decoration: underline; color: blue;") {{_ 'support'}} + li + a.flex.js-toggle-support + .materialCheckBox(class="{{#if currentSetting.supportPageEnabled}}is-checked{{/if}}") + + span {{_ 'support-page-enabled'}} + li + .support-content(class="{{#if currentSetting.supportPageEnabled}}{{else}}hide{{/if}}") + ul + li + a.flex.js-toggle-support-public + .materialCheckBox(class="{{#if currentSetting.supportPagePublic}}is-checked{{/if}}") + + span {{_ 'public'}} + li + .title {{_ 'support-title'}} + textarea#support-title.wekan-form-control= currentSetting.supportTitle + li + .title {{_ 'support-content'}} + textarea#support-page-text.wekan-form-control= currentSetting.supportPageText + li + button.js-support-save.primary {{_ 'save'}} li.layout-form .title {{_ 'oidc-button-text'}} .form-group diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js index 682479c92..d40b2aab2 100644 --- a/client/components/settings/settingBody.js +++ b/client/components/settings/settingBody.js @@ -518,6 +518,45 @@ BlazeComponent.extendComponent({ DocHead.setTitle(productName); }, + toggleSupportPage() { + this.setLoading(true); + const supportPageEnabled = !$('.js-toggle-support .materialCheckBox').hasClass('is-checked'); + $('.js-toggle-support .materialCheckBox').toggleClass('is-checked'); + $('.support-content').toggleClass('hide'); + Settings.update(Settings.findOne()._id, { + $set: { supportPageEnabled }, + }); + this.setLoading(false); + }, + + toggleSupportPublic() { + this.setLoading(true); + const supportPagePublic = !$('.js-toggle-support-public .materialCheckBox').hasClass('is-checked'); + $('.js-toggle-support-public .materialCheckBox').toggleClass('is-checked'); + Settings.update(Settings.findOne()._id, { + $set: { supportPagePublic }, + }); + this.setLoading(false); + }, + + saveSupportSettings() { + this.setLoading(true); + const supportTitle = ($('#support-title').val() || '').trim(); + const supportPageText = ($('#support-page-text').val() || '').trim(); + try { + Settings.update(Settings.findOne()._id, { + $set: { + supportTitle, + supportPageText, + }, + }); + } catch (e) { + return; + } finally { + this.setLoading(false); + } + }, + sendSMTPTestEmail() { Meteor.call('sendSMTPTestEmail', (err, ret) => { if (!err && ret) { @@ -546,6 +585,9 @@ BlazeComponent.extendComponent({ 'click a.js-toggle-hide-card-counter-list': this.toggleHideCardCounterList, 'click a.js-toggle-hide-board-member-list': this.toggleHideBoardMemberList, 'click button.js-save-layout': this.saveLayout, + 'click a.js-toggle-support': this.toggleSupportPage, + 'click a.js-toggle-support-public': this.toggleSupportPublic, + 'click button.js-support-save': this.saveSupportSettings, 'click a.js-toggle-display-authentication-method': this .toggleDisplayAuthenticationMethod, }, diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade index 7ee64d138..9c36bc2f7 100644 --- a/client/components/users/userHeader.jade +++ b/client/components/users/userHeader.jade @@ -87,10 +87,11 @@ template(name="memberMenuPopup") a.js-change-language | 🏁 | {{_ 'changeLanguagePopup-title'}} - //li - // a.js-support - // ❓-circle - // | {{_ 'support'}} + if isSupportPageEnabled + li + a(href="{{pathFor 'support'}}") + | ❓ + | {{_ 'support'}} unless isSandstorm hr ul.pop-over-list @@ -157,7 +158,8 @@ template(name="editProfilePopup") template(name="supportPopup") ul.pop-over-list li - | Support popup text will be editable later. + +viewer + = currentSetting.supportPopupText template(name="changePasswordPopup") +atForm(state='changePwd') diff --git a/client/components/users/userHeader.js b/client/components/users/userHeader.js index 5514a1127..b9cffe2fa 100644 --- a/client/components/users/userHeader.js +++ b/client/components/users/userHeader.js @@ -31,6 +31,10 @@ Template.memberMenuPopup.helpers({ return false; } }, + isSupportPageEnabled() { + const setting = ReactiveCache.getCurrentSetting(); + return setting && setting.supportPageEnabled; + }, isSameDomainNameSettingValue(){ const currSett = ReactiveCache.getCurrentSetting(); if(currSett && currSett != undefined && currSett.disableRegistration && currSett.mailDomainName !== undefined && currSett.mailDomainName != ""){ diff --git a/config/router.js b/config/router.js index 1ab853dbd..20c9ebf8a 100644 --- a/config/router.js +++ b/config/router.js @@ -79,6 +79,53 @@ FlowRouter.route('/accessibility', { }, }); +FlowRouter.route('/support', { + name: 'support', + triggersEnter: [AccountsTemplates.ensureSignedIn], + action() { + Session.set('currentBoard', null); + Session.set('currentList', null); + Session.set('currentCard', null); + Session.set('popupCardId', null); + Session.set('popupCardBoardId', null); + + Filter.reset(); + Session.set('sortBy', ''); + EscapeActions.executeAll(); + + Utils.manageCustomUI(); + Utils.manageMatomo(); + + BlazeLayout.render('defaultLayout', { + headerBar: 'supportHeaderBar', + content: 'support', + }); + }, +}); + +FlowRouter.route('/public', { + name: 'public', + action() { + Session.set('currentBoard', null); + Session.set('currentList', null); + Session.set('currentCard', null); + Session.set('popupCardId', null); + Session.set('popupCardBoardId', null); + + Filter.reset(); + Session.set('sortBy', ''); + EscapeActions.executeAll(); + + Utils.manageCustomUI(); + Utils.manageMatomo(); + + BlazeLayout.render('defaultLayout', { + headerBar: 'supportHeaderBar', + content: 'support', + }); + }, +}); + FlowRouter.route('/b/:id/:slug', { name: 'board', action(params) { diff --git a/imports/i18n/data/en.i18n.json b/imports/i18n/data/en.i18n.json index 625325786..e4eb3c786 100644 --- a/imports/i18n/data/en.i18n.json +++ b/imports/i18n/data/en.i18n.json @@ -1311,6 +1311,11 @@ "hideAllChecklistItems": "Hide all checklist items", "support": "Support", "supportPopup-title": "Support", + "support-page-enabled": "Support page enabled", + "support-info-not-added-yet": "Support info has not been added yet", + "support-info-only-for-logged-in-users": "Support info is only for logged in users.", + "support-title": "Support title", + "support-content": "Support content", "accessibility": "Accessibility", "accessibility-page-enabled": "Accessibility page enabled", "accessibility-info-not-added-yet": "Accessibility info has not been added yet", @@ -1468,6 +1473,9 @@ "migration-progress-status": "Status", "migration-progress-details": "Details", "migration-progress-note": "Please wait while we migrate your board to the latest structure...", + "steps": "steps", + "view": "View", + "has-swimlanes": "Has Swimlanes", "step-analyze-board-structure": "Analyze Board Structure", "step-fix-orphaned-cards": "Fix Orphaned Cards", diff --git a/imports/i18n/languages.js b/imports/i18n/languages.js index 3291df95f..3a653f6a2 100644 --- a/imports/i18n/languages.js +++ b/imports/i18n/languages.js @@ -449,6 +449,12 @@ export default { name: "αž—αžΆαžŸαžΆαžαŸ’αž˜αŸ‚αžš", load: () => import('./data/km.i18n.json'), }, + "km-KH": { + code: "km", + tag: "km_KH", + name: "αžαŸ’αž˜αŸ‚αžš (αž€αž˜αŸ’αž–αž»αž‡αžΆ)", + load: () => import('./data/km-KH.i18n.json'), + }, "ko-KR": { code: "ko", tag: "ko-KR", @@ -581,6 +587,12 @@ export default { name: "Русский", load: () => import('./data/ru.i18n.json'), }, + "ru-RU": { + code: "ru", + tag: "ru_RU", + name: "Русский язык (Россия)", + load: () => import('./data/ru-RU.i18n.json'), + }, "sk": { code: "sk", tag: "sk", diff --git a/models/settings.js b/models/settings.js index 00349c762..3a85e5013 100644 --- a/models/settings.js +++ b/models/settings.js @@ -130,6 +130,28 @@ Settings.attachSchema( type: String, optional: true, }, + supportPopupText: { + type: String, + optional: true, + }, + supportPageEnabled: { + type: Boolean, + optional: true, + defaultValue: false, + }, + supportPagePublic: { + type: Boolean, + optional: true, + defaultValue: false, + }, + supportTitle: { + type: String, + optional: true, + }, + supportPageText: { + type: String, + optional: true, + }, createdAt: { type: Date, denyUpdate: true,