Skip to content

Commit 3326e73

Browse files
committed
FIX: 'Show original' button only shows in topics where there are translated content
1 parent 142902a commit 3326e73

File tree

7 files changed

+160
-20
lines changed

7 files changed

+160
-20
lines changed

app/models/concerns/discourse_translator/translatable.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ def set_translation(locale, text)
3030

3131
def translation_for(locale)
3232
locale = locale.to_s.gsub("_", "-")
33-
translations.find_by(locale: locale)&.translation
33+
# this is a tricky perf balancing act when loading translations for a topic with many posts.
34+
# the topic_view_serializer includes(:translations) for posts in the topic,
35+
# the alternative is to do a find_by(locale: locale) which would result in a query per post.
36+
translations.to_a.find { |t| t.locale == locale }&.translation
3437
end
3538

3639
def detected_locale

assets/javascripts/discourse/components/show-original-content.gjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import DButton from "discourse/components/d-button";
66
import concatClass from "discourse/helpers/concat-class";
77

88
export default class ShowOriginalContent extends Component {
9+
static shouldRender(args) {
10+
return args.topic.is_translated;
11+
}
12+
913
@service router;
1014
@tracked isTranslated = true;
1115

lib/discourse_translator/inline_translation.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ def inject(plugin)
3737
&.then { |t| Topic.fancy_title(t) }
3838
end
3939
end
40+
41+
plugin.add_to_serializer(
42+
:basic_post,
43+
:is_translated,
44+
include_condition: -> { SiteSetting.experimental_inline_translation },
45+
) { object.translation_for(I18n.locale).present? }
46+
47+
plugin.add_to_serializer(
48+
:topic_view,
49+
:is_translated,
50+
include_condition: -> { SiteSetting.experimental_inline_translation },
51+
) { object.topic.translations.present? || object.posts.any? { |p| p.translations.present? } }
4052
end
4153
end
4254
end

lib/discourse_translator/topic_view_serializer_extension.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ module DiscourseTranslator
44
module TopicViewSerializerExtension
55
def posts
66
if SiteSetting.translator_enabled?
7-
object.instance_variable_set(:@posts, object.posts.includes(:content_locale))
7+
posts_query = object.posts.includes(:content_locale)
8+
posts_query =
9+
posts_query.includes(:translations) if SiteSetting.experimental_inline_translation
10+
object.instance_variable_set(:@posts, posts_query)
811
end
912
super
1013
end

spec/serializers/post_serializer_spec.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,45 @@
5656
end
5757
end
5858

59+
describe "#is_translated" do
60+
fab!(:post)
61+
62+
it "returns false when translator disabled" do
63+
SiteSetting.translator_enabled = false
64+
serializer = PostSerializer.new(post, scope: Guardian.new)
65+
66+
expect(serializer.is_translated).to eq(false)
67+
end
68+
69+
it "returns false when experimental inline translation disabled" do
70+
SiteSetting.translator_enabled = true
71+
SiteSetting.experimental_inline_translation = false
72+
serializer = PostSerializer.new(post, scope: Guardian.new)
73+
74+
expect(serializer.is_translated).to eq(false)
75+
end
76+
77+
it "returns true when there is a translation for the current locale" do
78+
SiteSetting.translator_enabled = true
79+
SiteSetting.experimental_inline_translation = true
80+
I18n.locale = "ja"
81+
post.set_translation("ja", "こんにちは")
82+
serializer = PostSerializer.new(post, scope: Guardian.new)
83+
84+
expect(serializer.is_translated).to eq(true)
85+
end
86+
87+
it "returns false when there is no translation for the current locale" do
88+
SiteSetting.translator_enabled = true
89+
SiteSetting.experimental_inline_translation = true
90+
I18n.locale = "ja"
91+
post.set_translation("es", "Hola")
92+
serializer = PostSerializer.new(post, scope: Guardian.new)
93+
94+
expect(serializer.is_translated).to eq(false)
95+
end
96+
end
97+
5998
describe "#cooked" do
6099
def serialize_post(guardian_user: user, params: {})
61100
env = { "action_dispatch.request.parameters" => params, "REQUEST_METHOD" => "GET" }

spec/serializers/topic_view_serializer_spec.rb

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,75 @@
33
require "rails_helper"
44

55
describe TopicViewSerializer do
6-
fab!(:user)
76
fab!(:topic)
8-
fab!(:post1) { Fabricate(:post, topic: topic).set_detected_locale("en") }
9-
fab!(:post2) { Fabricate(:post, topic: topic).set_detected_locale("es") }
10-
fab!(:post3) { Fabricate(:post, topic: topic).set_detected_locale("ja") }
117

128
before do
139
SiteSetting.translator_enabled = true
1410
SiteSetting.restrict_translation_by_group = "#{Group::AUTO_GROUPS[:everyone]}"
1511
SiteSetting.restrict_translation_by_poster_group = "#{Group::AUTO_GROUPS[:everyone]}"
1612
end
1713

18-
it "preloads translations without N+1 queries" do
19-
topic_view = TopicView.new(topic)
20-
serializer = TopicViewSerializer.new(topic_view, scope: Guardian.new(user), root: false)
14+
describe "preloading" do
15+
fab!(:user)
16+
fab!(:en_post) do
17+
post = Fabricate(:post, topic: topic)
18+
post.set_detected_locale("en")
19+
post
20+
end
21+
fab!(:es_post) do
22+
post = Fabricate(:post, topic: topic)
23+
post.set_detected_locale("es")
24+
post
25+
end
26+
fab!(:ja_post) do
27+
post = Fabricate(:post, topic: topic)
28+
post.set_detected_locale("ja")
29+
post
30+
end
31+
32+
it "preloads locale without N+1 queries" do
33+
topic_view = TopicView.new(topic)
34+
serializer = TopicViewSerializer.new(topic_view, scope: Guardian.new(user), root: false)
35+
36+
# ensure translation data is included in the JSON
37+
json = {}
38+
queries = track_sql_queries { json = serializer.as_json }
39+
posts_json = json[:post_stream][:posts]
40+
expect(posts_json.map { |p| p[:can_translate] }).to eq([false, true, true])
41+
42+
translation_queries = queries.count { |q| q.include?("discourse_translator_post_locales") }
43+
expect(translation_queries).to eq(1) # would be 3 (posts) if not preloaded
44+
45+
expect(topic_view.posts.first.association(:content_locale)).to be_loaded
46+
end
2147

22-
# ensure translation data is included in the JSON
23-
json = {}
24-
queries = track_sql_queries { json = serializer.as_json }
25-
posts_json = json[:post_stream][:posts]
26-
expect(posts_json.map { |p| p[:can_translate] }).to eq([false, true, true])
48+
it "preloads translations when experimental_inline_translation is enabled" do
49+
SiteSetting.experimental_inline_translation = true
50+
51+
en_post.set_translation("es", "Hola")
52+
es_post.set_translation("en", "Hello")
53+
54+
topic_view = TopicView.new(topic)
55+
serializer = TopicViewSerializer.new(topic_view, scope: Guardian.new(user), root: false)
56+
57+
topic_view.posts.reload
2758

28-
translation_queries = queries.count { |q| q.include?("discourse_translator_post_locales") }
29-
expect(translation_queries).to eq(1) # would be 3 (posts) if not preloaded
59+
queries =
60+
track_sql_queries do
61+
json = serializer.as_json
62+
json[:post_stream][:posts].each { |p| p[:translations] }
63+
end
3064

31-
expect(topic_view.posts.first.association(:content_locale)).to be_loaded
65+
translation_queries =
66+
queries.count { |q| q.include?("discourse_translator_post_translations") }
67+
expect(translation_queries).to eq(1)
68+
expect(topic_view.posts.first.association(:translations)).to be_loaded
69+
end
3270
end
3371

3472
describe "#fancy_title" do
3573
fab!(:user) { Fabricate(:user, locale: "ja") }
36-
fab!(:topic)
3774

38-
let!(:guardian) { Guardian.new(user) }
3975
let!(:original_title) { "<h1>FUS ROH DAAHHH</h1>" }
4076
let!(:jap_title) { "<h1>フス・ロ・ダ・ア</h1>" }
4177

@@ -81,4 +117,39 @@ def serialize_topic(guardian_user: user, params: {})
81117
expect(serialize_topic.fancy_title).to eq("&lt;h1&gt;フス・ロ・ダ・ア&lt;/h1&gt;")
82118
end
83119
end
120+
121+
describe "#is_translated" do
122+
fab!(:user)
123+
124+
def serialize_topic(guardian_user: user)
125+
TopicViewSerializer.new(TopicView.new(topic), scope: Guardian.new(guardian_user))
126+
end
127+
128+
it "returns false when translator is disabled or experimental inline translation is disabled" do
129+
SiteSetting.translator_enabled = true
130+
SiteSetting.experimental_inline_translation = true
131+
I18n.locale = "ja"
132+
Fabricate(:post, topic: topic)
133+
134+
expect(serialize_topic.is_translated).to eq(false)
135+
end
136+
137+
it "returns true when there is translation for the topic" do
138+
SiteSetting.translator_enabled = true
139+
SiteSetting.experimental_inline_translation = true
140+
I18n.locale = "ja"
141+
topic.set_translation("ja", "こんにちは")
142+
143+
expect(serialize_topic.is_translated).to eq(true)
144+
end
145+
146+
it "returns true when there is translation for a post in the topic" do
147+
SiteSetting.translator_enabled = true
148+
SiteSetting.experimental_inline_translation = true
149+
I18n.locale = "ja"
150+
Fabricate(:post, topic: topic).set_translation("ja", "こんにちは")
151+
152+
expect(serialize_topic.is_translated).to eq(true)
153+
end
154+
end
84155
end

spec/system/full_page_translation_spec.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
RSpec.describe "Full page translation", type: :system do
3+
RSpec.describe "Inline translation", type: :system do
44
fab!(:japanese_user) { Fabricate(:user, locale: "ja") }
55
fab!(:site_local_user) { Fabricate(:user, locale: "en") }
66
fab!(:author) { Fabricate(:user) }
@@ -51,6 +51,14 @@
5151
visit("/")
5252
visit("/t/#{topic.id}")
5353
expect(topic_page.has_topic_title?("孫子兵法からの人生戦略")).to eq(true)
54+
55+
page.find(".discourse-translator_toggle-original button").click
56+
expect(page).to have_current_path(/.*show=original.*/)
57+
58+
expect(topic_page.has_topic_title?("Life strategies from The Art of War")).to eq(true)
59+
expect(find(topic_page.post_by_number_selector(1))).to have_content(
60+
"The masterpiece isn’t just about military strategy",
61+
)
5462
end
5563
end
5664
end

0 commit comments

Comments
 (0)