diff --git a/public/openapi/components/schemas/PostObject.yaml b/public/openapi/components/schemas/PostObject.yaml index bcb2f79e53..530aedc204 100644 --- a/public/openapi/components/schemas/PostObject.yaml +++ b/public/openapi/components/schemas/PostObject.yaml @@ -18,6 +18,10 @@ PostObject: For posts received via ActivityPub, it is the url of the original piece of content. content: type: string + isEnglish: + type: boolean + translatedContent: + type: string sourceContent: type: string nullable: true @@ -170,6 +174,10 @@ PostDataObject: description: A topic identifier content: type: string + isEnglish: + type: boolean + translatedContent: + type: string timestamp: type: number votes: diff --git a/public/openapi/read/categories.yaml b/public/openapi/read/categories.yaml index 76d2375ebb..7f832e914c 100644 --- a/public/openapi/read/categories.yaml +++ b/public/openapi/read/categories.yaml @@ -82,6 +82,10 @@ get: type: number content: type: string + isEnglish: + type: boolean + translatedContent: + type: string timestampISO: type: string description: An ISO 8601 formatted date string (complementing `timestamp`) @@ -142,6 +146,10 @@ get: type: number content: type: string + isEnglish: + type: boolean + translatedContent: + type: string sourceContent: type: string nullable: true diff --git a/public/openapi/read/index.yaml b/public/openapi/read/index.yaml index 4c45da4360..bf5f16c7b2 100644 --- a/public/openapi/read/index.yaml +++ b/public/openapi/read/index.yaml @@ -77,6 +77,10 @@ get: type: number content: type: string + isEnglish: + type: boolean + translatedContent: + type: string timestampISO: type: string description: An ISO 8601 formatted date string (complementing `timestamp`) @@ -144,6 +148,10 @@ get: type: number content: type: string + isEnglish: + type: boolean + translatedContent: + type: string sourceContent: type: string nullable: true diff --git a/public/openapi/write/posts/pid.yaml b/public/openapi/write/posts/pid.yaml index 2203992b52..c1c572e340 100644 --- a/public/openapi/write/posts/pid.yaml +++ b/public/openapi/write/posts/pid.yaml @@ -35,6 +35,10 @@ get: description: A topic identifier content: type: string + isEnglish: + type: boolean + translatedContent: + type: string timestamp: type: number flagId: diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 43a64a9fa3..1807a94bf7 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -71,12 +71,28 @@ define('forum/topic', [ handleThumbs(); $(window).on('scroll', utils.debounce(updateTopicTitle, 250)); + configurePostToggle(); handleTopicSearch(); hooks.fire('action:topic.loaded', ajaxify.data); }; + function configurePostToggle() { + $('.topic').on('click', '.view-translated-btn', function () { + // Toggle the visibility of the next .translated-content div + $(this).closest('.sensitive-content-message').next('.translated-content').toggle(); + // Optionally, change the button text based on visibility + var isVisible = $(this).closest('.sensitive-content-message').next('.translated-content').is(':visible'); + if (isVisible) { + $(this).text('Hide the translated message.'); + } else { + $(this).text('Click here to view the translated message.'); + } + }); + } + + function handleTopicSearch() { require(['mousetrap'], (mousetrap) => { if (config.topicSearchEnabled) { diff --git a/src/posts/create.js b/src/posts/create.js index 656ae68ab0..59bd71f933 100644 --- a/src/posts/create.js +++ b/src/posts/create.js @@ -10,6 +10,7 @@ const groups = require('../groups'); const privileges = require('../privileges'); const activitypub = require('../activitypub'); const utils = require('../utils'); +const translate = require('../translate'); module.exports = function (Posts) { Posts.create = async function (data) { @@ -18,6 +19,7 @@ module.exports = function (Posts) { const content = data.content.toString(); const timestamp = data.timestamp || Date.now(); const isMain = data.isMain || false; + const [isEnglish, translatedContent] = await translate.translate(data); if (!uid && parseInt(uid, 10) !== 0) { throw new Error('[[error:invalid-uid]]'); @@ -28,7 +30,7 @@ module.exports = function (Posts) { } const pid = data.pid || await db.incrObjectField('global', 'nextPid'); - let postData = { pid, uid, tid, content, sourceContent, timestamp }; + let postData = { pid, uid, tid, content, sourceContent, timestamp, isEnglish, translatedContent }; if (data.toPid) { postData.toPid = data.toPid; diff --git a/src/posts/data.js b/src/posts/data.js index d74a22e69d..3e4cbbbbbf 100644 --- a/src/posts/data.js +++ b/src/posts/data.js @@ -70,5 +70,11 @@ function modifyPost(post, fields) { if (!fields.length || fields.includes('attachments')) { post.attachments = (post.attachments || '').split(',').filter(Boolean); } + // Mark post as "English" if decided by translator service or if it has no info + post.isEnglish = post.isEnglish == 'true' || post.isEnglish === undefined; + // If translatedContent is undefined, default to empty string (no translation needed for English posts) + if (post.translatedContent === undefined) { + post.translatedContent = ''; + } } } diff --git a/src/posts/summary.js b/src/posts/summary.js index 5995514eb6..9264c42327 100644 --- a/src/posts/summary.js +++ b/src/posts/summary.js @@ -22,7 +22,7 @@ module.exports = function (Posts) { options.escape = options.hasOwnProperty('escape') ? options.escape : false; options.extraFields = options.hasOwnProperty('extraFields') ? options.extraFields : []; - const fields = ['pid', 'tid', 'toPid', 'url', 'content', 'sourceContent', 'uid', 'timestamp', 'deleted', 'upvotes', 'downvotes', 'replies', 'handle'].concat(options.extraFields); + const fields = ['pid', 'tid', 'toPid', 'url', 'content', 'sourceContent', 'uid', 'timestamp', 'deleted', 'upvotes', 'downvotes', 'replies', 'handle', 'isEnglish', 'translatedContent'].concat(options.extraFields); let posts = await Posts.getPostsFields(pids, fields); posts = posts.filter(Boolean); diff --git a/src/translate/index.js b/src/translate/index.js new file mode 100644 index 0000000000..979949ec28 --- /dev/null +++ b/src/translate/index.js @@ -0,0 +1,17 @@ + +/* eslint-disable strict */ +//var request = require('request'); + +const translatorApi = module.exports; + +translatorApi.translate = function (postData) { + return ['is_english',postData]; +}; + +// translatorApi.translate = async function (postData) { +// Edit the translator URL below +// const TRANSLATOR_API = "TODO" +// const response = await fetch(TRANSLATOR_API+'/?content='+postData.content); +// const data = await response.json(); +// return ['is_english','translated_content']; +// }; diff --git a/vendor/nodebb-theme-harmony-2.1.23/library.js b/vendor/nodebb-theme-harmony-2.1.23/library.js index f41b426fa3..45f8bd2707 100644 --- a/vendor/nodebb-theme-harmony-2.1.23/library.js +++ b/vendor/nodebb-theme-harmony-2.1.23/library.js @@ -45,7 +45,6 @@ async function buildSkins() { const plugins = require.main.require('./src/plugins'); await plugins.prepareForBuild(['client side styles']); for (const skin of meta.css.supportedSkins) { - await meta.css.buildBundle(`client-${skin}`, true); } require.main.require('./src/meta/minifier').killAll(); diff --git a/vendor/nodebb-theme-harmony-2.1.23/templates/partials/topic/post.tpl b/vendor/nodebb-theme-harmony-2.1.23/templates/partials/topic/post.tpl index 0ba7023ae7..d72b58ef40 100644 --- a/vendor/nodebb-theme-harmony-2.1.23/templates/partials/topic/post.tpl +++ b/vendor/nodebb-theme-harmony-2.1.23/templates/partials/topic/post.tpl @@ -81,7 +81,15 @@