diff --git a/assets/javascripts/discourse/components/post-menu/toggle-translation-button.gjs b/assets/javascripts/discourse/components/post-menu/toggle-translation-button.gjs index b9541ccf..4edb5669 100644 --- a/assets/javascripts/discourse/components/post-menu/toggle-translation-button.gjs +++ b/assets/javascripts/discourse/components/post-menu/toggle-translation-button.gjs @@ -21,6 +21,10 @@ export default class ToggleTranslationButton extends Component { return this.args.post.isTranslated; } + get showButton() { + return this.args.post.can_translate; + } + get title() { if (this.isTranslating) { return "translator.translating"; @@ -63,17 +67,19 @@ export default class ToggleTranslationButton extends Component { } } diff --git a/assets/javascripts/discourse/components/translated-post.gjs b/assets/javascripts/discourse/components/translated-post.gjs index 5039ae6b..75e23c8e 100644 --- a/assets/javascripts/discourse/components/translated-post.gjs +++ b/assets/javascripts/discourse/components/translated-post.gjs @@ -31,6 +31,10 @@ export default class TranslatedPost extends Component { return this.post.translatedTitle; } + get showTranslation() { + return !this.siteSettings.experimental_topic_translation; + } + diff --git a/assets/javascripts/discourse/initializers/extend-for-translate-button.js b/assets/javascripts/discourse/initializers/extend-for-translate-button.js index 182c9c21..c8208a1f 100644 --- a/assets/javascripts/discourse/initializers/extend-for-translate-button.js +++ b/assets/javascripts/discourse/initializers/extend-for-translate-button.js @@ -31,9 +31,7 @@ function initializeTranslation(api) { api.renderInOutlet("topic-navigation", ShowOriginalContent); } - if (!siteSettings.experimental_topic_translation) { - customizePostMenu(api); - } + customizePostMenu(api); } function customizePostMenu(api, container) { diff --git a/assets/javascripts/discourse/services/translator.js b/assets/javascripts/discourse/services/translator.js index bcb5ca16..238db2ae 100644 --- a/assets/javascripts/discourse/services/translator.js +++ b/assets/javascripts/discourse/services/translator.js @@ -1,7 +1,11 @@ -import Service from "@ember/service"; +import Service, { service } from "@ember/service"; import { ajax } from "discourse/lib/ajax"; export default class TranslatorService extends Service { + @service siteSettings; + @service appEvents; + @service documentTitle; + async translatePost(post) { const response = await ajax("/translator/translate", { type: "POST", @@ -11,6 +15,16 @@ export default class TranslatorService extends Service { post.detectedLang = response.detected_lang; post.translatedText = response.translation; post.translatedTitle = response.title_translation; + if (this.siteSettings.experimental_topic_translation) { + if (post.post_number === 1) { + post.topic.set("fancy_title", response.title_translation); + this.appEvents.trigger("header:update-topic", post.topic); + this.documentTitle.setTitle(response.title_translation); + } + post.set("cooked", response.translation); + post.set("can_translate", false); + this.appEvents.trigger("post-stream:refresh", { id: post.id }); + } } clearPostTranslation(post) { diff --git a/test/javascripts/integration/toggle-translation-button-test.js b/test/javascripts/integration/toggle-translation-button-test.js new file mode 100644 index 00000000..02073835 --- /dev/null +++ b/test/javascripts/integration/toggle-translation-button-test.js @@ -0,0 +1,51 @@ +import { render } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; + +module("Integration | Component | toggle-translation-button", function (hooks) { + setupRenderingTest(hooks); + + test("doesn't render when post cannot be translated", async function (assert) { + this.set("post", { can_translate: false }); + + await render(hbs` + + `); + + assert.dom("button").doesNotExist(); + }); + + test("renders translation button with correct states", async function (assert) { + const post = { + can_translate: true, + isTranslated: false, + isTranslating: false, + }; + + this.set("post", post); + + await render(hbs` + + `); + + assert.dom("button").exists(); + assert.dom("button").hasText("View translation"); + assert.dom("button").doesNotHaveClass("translated"); + + post.isTranslating = true; + await render(hbs` + + `); + assert.dom("button").hasAttribute("disabled"); + assert.dom("button").hasText("Translating"); + + post.isTranslating = false; + post.isTranslated = true; + await render(hbs` + + `); + assert.dom("button").hasClass("translated"); + assert.dom("button").hasText("Hide translation"); + }); +}); diff --git a/test/javascripts/integration/translated-post-test.js b/test/javascripts/integration/translated-post-test.js new file mode 100644 index 00000000..57376737 --- /dev/null +++ b/test/javascripts/integration/translated-post-test.js @@ -0,0 +1,51 @@ +import { render } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; + +module("Integration | Component | translated-post", function (hooks) { + setupRenderingTest(hooks); + + test("renders translation when post is translated", async function (assert) { + this.set("outletArgs", { + post: { + isTranslated: true, + isTranslating: false, + translatedText: "こんにちは", + translatedTitle: "良い一日", + detectedLang: "ja", + }, + }); + + this.siteSettings.experimental_topic_translation = false; + this.siteSettings.translator = "Google"; + + await render(hbs` + + `); + + assert.dom(".post-translation").exists(); + assert.dom(".topic-attribution").hasText("良い一日"); + assert.dom(".post-attribution").hasText("Translated from ja by Google"); + assert.dom(".cooked").hasText("こんにちは"); + }); + + test("hides translation when experimental_topic_translation is enabled", async function (assert) { + this.set("outletArgs", { + post: { + isTranslated: true, + isTranslating: false, + translatedText: "Bonjour monde", + }, + }); + + this.siteSettings.experimental_topic_translation = true; + + await render(hbs` + + `); + + assert.dom(".topic-attribution").doesNotExist(); + assert.dom(".post-attribution").doesNotExist(); + }); +}); diff --git a/test/javascripts/service/translator-test.js b/test/javascripts/service/translator-test.js new file mode 100644 index 00000000..d486f14f --- /dev/null +++ b/test/javascripts/service/translator-test.js @@ -0,0 +1,97 @@ +import { setupTest } from "ember-qunit"; +import { module, test } from "qunit"; +import pretender, { response } from "discourse/tests/helpers/create-pretender"; + +module("Unit | Service | translator", function (hooks) { + setupTest(hooks); + + test("translatePost - standard translation", async function (assert) { + const service = this.owner.lookup("service:translator"); + + pretender.post("/translator/translate", () => { + return response({ + detected_lang: "ja", + translation: "I am a cat", + title_translation: "Surprise!", + }); + }); + + const post = { + id: 1, + post_number: 2, + }; + + await service.translatePost(post); + + assert.strictEqual(post.detectedLang, "ja"); + assert.strictEqual(post.translatedText, "I am a cat"); + assert.strictEqual(post.translatedTitle, "Surprise!"); + }); + + test("translatePost - with experimental translation for first post", async function (assert) { + const service = this.owner.lookup("service:translator"); + + service.siteSettings.experimental_topic_translation = true; + + let headerUpdateCalled = false; + let postStreamRefreshCalled = false; + let titleSet = null; + + service.appEvents.on( + "header:update-topic", + () => (headerUpdateCalled = true) + ); + service.appEvents.on( + "post-stream:refresh", + () => (postStreamRefreshCalled = true) + ); + service.documentTitle.setTitle = (title) => (titleSet = title); + + pretender.post("/translator/translate", () => { + return response({ + detected_lang: "ja", + translation: "I am a cat", + title_translation: "Surprise!", + }); + }); + + const topic = { + set: function (key, value) { + this[key] = value; + }, + }; + const post = { + id: 1, + post_number: 1, + topic, + set: function (key, value) { + this[key] = value; + }, + }; + + await service.translatePost(post); + + assert.true(headerUpdateCalled); + assert.true(postStreamRefreshCalled); + assert.strictEqual(titleSet, "Surprise!"); + assert.strictEqual(post.cooked, "I am a cat"); + assert.false(post.can_translate); + assert.strictEqual(topic.fancy_title, "Surprise!"); + }); + + test("clearPostTranslation", function (assert) { + const service = this.owner.lookup("service:translator"); + + const post = { + detectedLang: "ja", + translatedText: "Hello", + translatedTitle: "Title", + }; + + service.clearPostTranslation(post); + + assert.strictEqual(post.detectedLang, null); + assert.strictEqual(post.translatedText, null); + assert.strictEqual(post.translatedTitle, null); + }); +});