Skip to content

Commit e82061a

Browse files
authored
DEV: Added compatibility with the Glimmer Post Menu (#173)
1 parent f10d55c commit e82061a

File tree

8 files changed

+216
-45
lines changed

8 files changed

+216
-45
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import Component from "@glimmer/component";
2+
import { action } from "@ember/object";
3+
import { inject as service } from "@ember/service";
4+
import DButton from "discourse/components/d-button";
5+
import concatClass from "discourse/helpers/concat-class";
6+
import { popupAjaxError } from "discourse/lib/ajax-error";
7+
8+
export default class ToggleTranslationButton extends Component {
9+
static shouldRender(args) {
10+
return args.post.can_translate;
11+
}
12+
13+
@service modal;
14+
@service translator;
15+
16+
get isTranslating() {
17+
return this.args.post.isTranslating;
18+
}
19+
20+
get isTranslated() {
21+
return this.args.post.isTranslated;
22+
}
23+
24+
get title() {
25+
if (this.isTranslating) {
26+
return "translator.translating";
27+
}
28+
29+
return this.isTranslated
30+
? "translator.hide_translation"
31+
: "translator.view_translation";
32+
}
33+
34+
@action
35+
hideTranslation() {
36+
this.args.post.isTranslated = false;
37+
this.args.post.isTranslating = false;
38+
this.translator.clearPostTranslation(this.args.post);
39+
}
40+
41+
@action
42+
toggleTranslation() {
43+
return this.args.post.isTranslated
44+
? this.hideTranslation()
45+
: this.translate();
46+
}
47+
48+
@action
49+
async translate() {
50+
const post = this.args.post;
51+
post.isTranslating = true;
52+
53+
try {
54+
await this.translator.translatePost(post);
55+
post.isTranslated = true;
56+
} catch (error) {
57+
this.translator.clearPostTranslation(this.args.post);
58+
post.isTranslated = false;
59+
popupAjaxError(error);
60+
} finally {
61+
post.isTranslating = false;
62+
}
63+
}
64+
65+
<template>
66+
<DButton
67+
class={{concatClass
68+
"post-action-menu__translate"
69+
(if this.isTranslated "translated")
70+
}}
71+
...attributes
72+
@action={{this.toggleTranslation}}
73+
@disabled={{this.isTranslating}}
74+
@icon="globe"
75+
@label={{if @showLabel this.title}}
76+
@title={{this.title}}
77+
/>
78+
</template>
79+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import Component from "@glimmer/component";
2+
import { inject as service } from "@ember/service";
3+
import { htmlSafe } from "@ember/template";
4+
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
5+
import i18n from "discourse-common/helpers/i18n";
6+
7+
export default class TranslatedPost extends Component {
8+
static shouldRender(args) {
9+
return args.post.isTranslated || args.post.isTranslating;
10+
}
11+
12+
@service siteSettings;
13+
14+
get loading() {
15+
return this.post.isTranslating;
16+
}
17+
18+
get isTranslated() {
19+
return this.post.isTranslated;
20+
}
21+
22+
get post() {
23+
return this.args.outletArgs.post;
24+
}
25+
26+
get translatedText() {
27+
return this.post.translatedText;
28+
}
29+
30+
get translatedTitle() {
31+
return this.post.translatedTitle;
32+
}
33+
34+
<template>
35+
<div class="post-translation">
36+
<ConditionalLoadingSpinner
37+
class="post-translation"
38+
@condition={{this.loading}}
39+
@size="small"
40+
>
41+
<hr />
42+
{{#if this.translatedTitle}}
43+
<div class="topic-attribution">
44+
{{this.translatedTitle}}
45+
</div>
46+
{{/if}}
47+
<div class="post-attribution">
48+
{{i18n
49+
"translator.translated_from"
50+
language=this.post.detectedLang
51+
translator=this.siteSettings.translator
52+
}}
53+
</div>
54+
<div class="cooked">
55+
{{htmlSafe this.post.translatedText}}
56+
</div>
57+
</ConditionalLoadingSpinner>
58+
</div>
59+
</template>
60+
}

assets/javascripts/discourse/components/translated-post.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

assets/javascripts/discourse/initializers/extend-for-translate-button.js

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,66 @@
1+
import { tracked } from "@glimmer/tracking";
12
import { ajax } from "discourse/lib/ajax";
23
import { popupAjaxError } from "discourse/lib/ajax-error";
34
import { withPluginApi } from "discourse/lib/plugin-api";
5+
import { withSilencedDeprecations } from "discourse-common/lib/deprecated";
46
import I18n from "I18n";
5-
6-
function translatePost(post) {
7-
return ajax("/translator/translate", {
8-
type: "POST",
9-
data: { post_id: post.get("id") },
10-
}).then(function (res) {
11-
post.setProperties({
12-
translated_text: res.translation,
13-
detected_lang: res.detected_lang,
14-
translated_title: res.title_translation,
15-
});
16-
});
17-
}
7+
import ToggleTranslationButton from "../components/post-menu/toggle-translation-button";
8+
import TranslatedPost from "../components/translated-post";
189

1910
function initializeTranslation(api) {
2011
const siteSettings = api.container.lookup("service:site-settings");
2112
const currentUser = api.getCurrentUser();
2213

23-
if (!currentUser) {
14+
if (!currentUser || !siteSettings.translator_enabled) {
2415
return;
2516
}
26-
if (!siteSettings.translator_enabled) {
27-
return;
17+
18+
customizePostMenu(api);
19+
}
20+
21+
function customizePostMenu(api, container) {
22+
const transformerRegistered = api.registerValueTransformer(
23+
"post-menu-buttons",
24+
({ value: dag, context: { firstButtonKey } }) => {
25+
dag.add("translate", ToggleTranslationButton, { before: firstButtonKey });
26+
}
27+
);
28+
29+
if (transformerRegistered) {
30+
// the plugin outlet is not updated when the post instance is modified unless we extend it to add the tracking to
31+
// the new properties
32+
api.modifyClass(
33+
"model:post",
34+
(Superclass) =>
35+
class extends Superclass {
36+
@tracked detectedLang;
37+
@tracked isTranslating;
38+
@tracked isTranslated;
39+
@tracked translatedText;
40+
@tracked translatedTitle;
41+
}
42+
);
43+
44+
api.renderBeforeWrapperOutlet("post-menu", TranslatedPost);
2845
}
2946

47+
const silencedKey =
48+
transformerRegistered && "discourse.post-menu-widget-overrides";
49+
50+
withSilencedDeprecations(silencedKey, () =>
51+
customizeWidgetPostMenu(api, container)
52+
);
53+
}
54+
55+
function customizeWidgetPostMenu(api) {
3056
api.includePostAttributes(
3157
"can_translate",
3258
"translated_text",
3359
"detected_lang",
3460
"translated_title"
3561
);
3662

63+
const siteSettings = api.container.lookup("service:site-settings");
3764
api.decorateWidget("post-menu:before", (dec) => {
3865
if (!dec.state.isTranslated) {
3966
return;
@@ -74,7 +101,17 @@ function initializeTranslation(api) {
74101
const post = this.findAncestorModel();
75102

76103
if (post) {
77-
return translatePost(post)
104+
return ajax("/translator/translate", {
105+
type: "POST",
106+
data: { post_id: post.get("id") },
107+
})
108+
.then(function (res) {
109+
post.setProperties({
110+
translated_text: res.translation,
111+
detected_lang: res.detected_lang,
112+
translated_title: res.title_translation,
113+
});
114+
})
78115
.catch((error) => {
79116
popupAjaxError(error);
80117
state.isTranslating = false;
@@ -114,6 +151,6 @@ function initializeTranslation(api) {
114151
export default {
115152
name: "extend-for-translate-button",
116153
initialize() {
117-
withPluginApi("0.1", (api) => initializeTranslation(api));
154+
withPluginApi("1.34.0", (api) => initializeTranslation(api));
118155
},
119156
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Service from "@ember/service";
2+
import { ajax } from "discourse/lib/ajax";
3+
4+
export default class TranslatorService extends Service {
5+
async translatePost(post) {
6+
const response = await ajax("/translator/translate", {
7+
type: "POST",
8+
data: { post_id: post.id },
9+
});
10+
11+
post.detectedLang = response.detected_lang;
12+
post.translatedText = response.translation;
13+
post.translatedTitle = response.title_translation;
14+
}
15+
16+
clearPostTranslation(post) {
17+
post.detectedLang = null;
18+
post.translatedText = null;
19+
post.translatedTitle = null;
20+
}
21+
}

assets/javascripts/discourse/templates/components/translated-post.hbs

Lines changed: 0 additions & 17 deletions
This file was deleted.

assets/javascripts/discourse/templates/connectors/post-after-cooked/translate.hbs

Lines changed: 0 additions & 1 deletion
This file was deleted.

config/locales/client.en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ en:
99
view_translation: "View translation"
1010
hide_translation: "Hide translation"
1111
translated_from: "Translated from %{language} by %{translator}"
12+
translating: "Translating"

0 commit comments

Comments
 (0)