breaking: refactor topic events

for proper i18n
support both `user locked this topic 3 hours ago` & `user locked this topic on 19 Oct 2022, 11:42`
This commit is contained in:
Barış Soner Uşaklı
2022-11-30 22:02:06 -05:00
parent 17a6621cd8
commit b422c8ce52
3 changed files with 78 additions and 24 deletions

View File

@@ -100,8 +100,8 @@
"nodebb-plugin-spam-be-gone": "2.0.4",
"nodebb-rewards-essentials": "0.2.1",
"nodebb-theme-lavender": "7.0.2",
"nodebb-theme-peace": "2.0.8",
"nodebb-theme-persona": "13.0.28",
"nodebb-theme-peace": "2.0.9",
"nodebb-theme-persona": "13.0.30",
"nodebb-widget-essentials": "7.0.2",
"nodemailer": "6.8.0",
"nprogress": "0.2.0",

View File

@@ -43,16 +43,26 @@
"ban-ip": "Ban IP",
"view-history": "Edit History",
"locked-by": "Locked by",
"unlocked-by": "Unlocked by",
"pinned-by": "Pinned by",
"unpinned-by": "Unpinned by",
"deleted-by": "Deleted by",
"restored-by": "Restored by",
"moved-from-by": "Moved from %1 by",
"queued-by": "Post queued for approval →",
"backlink": "Referenced by",
"forked-by": "Forked by",
"user-locked-topic-ago": "%1 locked this topic %2",
"user-locked-topic-on": "%1 locked this topic on %2",
"user-unlocked-topic-ago": "%1 unlocked this topic %2",
"user-unlocked-topic-on": "%1 unlocked this topic on %2",
"user-pinned-topic-ago": "%1 pinned this topic %2",
"user-pinned-topic-on": "%1 pinned this topic on %2",
"user-unpinned-topic-ago": "%1 unpinned this topic %2",
"user-unpinned-topic-on": "%1 unpinned this topic on %2",
"user-deleted-topic-ago": "%1 deleted this topic %2",
"user-deleted-topic-on": "%1 deleted this topic on %2",
"user-restored-topic-ago": "%1 restored this topic %2",
"user-restored-topic-on": "%1 restored this topic on %2",
"user-moved-topic-from-ago": "%1 moved this topic from %2 %3",
"user-moved-topic-from-on": "%1 moved this topic from %2 on %3",
"user-queued-post-ago": "%1 <a href=\"%2\">queued</a> post for approval %3",
"user-queued-post-on": "%1 <a href=\"%2\">queued</a> post for approval on %3",
"user-referenced-topic-ago": "%1 <a href=\"%2\">referenced</a> this topic %3",
"user-referenced-topic-on": "%1 <a href=\"%2\">referenced</a> this topic on %3",
"user-forked-topic-ago": "%1 <a href=\"%2\">forked</a> this topic %3",
"user-forked-topic-on": "%1 <a href=\"%2\">forked</a> this topic on %3",
"bookmark_instructions" : "Click here to return to the last read post in this thread.",

View File

@@ -1,6 +1,7 @@
'use strict';
const _ = require('lodash');
const nconf = require('nconf');
const db = require('../database');
const meta = require('../meta');
const user = require('../user');
@@ -9,6 +10,10 @@ const categories = require('../categories');
const plugins = require('../plugins');
const translator = require('../translator');
const privileges = require('../privileges');
const utils = require('../utils');
const helpers = require('../helpers');
const relative_path = nconf.get('relative_path');
const Events = module.exports;
@@ -20,49 +25,49 @@ const Events = module.exports;
* You can then log a custom topic event by calling `topics.events.log(tid, { type, uid });`
* `uid` is optional; if you pass in a valid uid in the payload,
* the user avatar/username will be rendered as part of the event text
*
* see https://github.com/NodeBB/nodebb-plugin-question-and-answer/blob/master/library.js#L288-L306
*/
Events._types = {
pin: {
icon: 'fa-thumb-tack',
text: '[[topic:pinned-by]]',
translation: async event => translateSimple(event, 'topic:user-pinned-topic'),
},
unpin: {
icon: 'fa-thumb-tack fa-rotate-90',
text: '[[topic:unpinned-by]]',
translation: async event => translateSimple(event, 'topic:user-unpinned-topic'),
},
lock: {
icon: 'fa-lock',
text: '[[topic:locked-by]]',
translation: async event => translateSimple(event, 'topic:user-locked-topic'),
},
unlock: {
icon: 'fa-unlock',
text: '[[topic:unlocked-by]]',
translation: async event => translateSimple(event, 'topic:user-unlocked-topic'),
},
delete: {
icon: 'fa-trash',
text: '[[topic:deleted-by]]',
translation: async event => translateSimple(event, 'topic:user-deleted-topic'),
},
restore: {
icon: 'fa-trash-o',
text: '[[topic:restored-by]]',
translation: async event => translateSimple(event, 'topic:user-restored-topic'),
},
move: {
icon: 'fa-arrow-circle-right',
// text: '[[topic:moved-from-by]]',
translation: async event => translateEventArgs(event, 'topic:user-moved-topic-from', renderUser(event), `${event.fromCategory.name}`, renderTimeago(event)),
},
'post-queue': {
icon: 'fa-history',
text: '[[topic:queued-by]]',
href: '/post-queue',
translation: async event => translateEventArgs(event, 'topic:user-queued-post', renderUser(event), `/post-queue`, renderTimeago(event)),
},
backlink: {
icon: 'fa-link',
text: '[[topic:backlink]]',
translation: async event => translateEventArgs(event, 'topic:user-referenced-topic', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
},
fork: {
icon: 'fa-code-fork',
text: '[[topic:forked-by]]',
translation: async event => translateEventArgs(event, 'topic:user-forked-topic', renderUser(event), `${relative_path}${event.href}`, renderTimeago(event)),
},
};
@@ -72,6 +77,40 @@ Events.init = async () => {
Events._types = types;
};
async function translateEventArgs(event, prefix, ...args) {
const key = getTranslationKey(event, prefix);
const compiled = translator.compile.apply(null, [key, ...args]);
return utils.decodeHTMLEntities(await translator.translate(compiled));
}
async function translateSimple(event, prefix) {
return await translateEventArgs(event, prefix, renderUser(event), renderTimeago(event));
}
Events.translateSimple = translateSimple; // so plugins can perform translate
Events.translateEventArgs = translateEventArgs; // so plugins can perform translate
// generate `user-locked-topic-ago` or `user-locked-topic-on` based on timeago cutoff setting
function getTranslationKey(event, prefix) {
const cutoffMs = 1000 * 60 * 60 * 24 * Math.max(0, parseInt(meta.config.timeagoCutoff, 10));
let translationSuffix = 'ago';
if (cutoffMs > 0 && Date.now() - event.timestamp > cutoffMs) {
translationSuffix = 'on';
}
return `${prefix}-${translationSuffix}`;
}
function renderUser(event) {
if (!event.user || event.user.system) {
return '[[global:system-user]]';
}
return `<a href="${relative_path}/user/${event.user.userslug}">${helpers.buildAvatar(event.user, '16px', true)} ${event.user.username}</a>`;
}
function renderTimeago(event) {
return `<span class="timeago timeline-text" title="${event.timestampISO}"></span>`;
}
Events.get = async (tid, uid, reverse = false) => {
const topics = require('.');
@@ -154,12 +193,17 @@ async function modifyEvent({ tid, uid, eventIds, timestamps, events }) {
}
if (event.hasOwnProperty('fromCid')) {
event.fromCategory = fromCategories[event.fromCid];
event.text = translator.compile('topic:moved-from-by', event.fromCategory.name);
}
Object.assign(event, Events._types[event.type]);
});
await Promise.all(events.map(async (event) => {
if (Events._types[event.type].translation) {
event.text = await Events._types[event.type].translation(event);
}
}));
// Sort events
events.sort((a, b) => a.timestamp - b.timestamp);