Skip to content

Commit dbd9af6

Browse files
authored
FIX: Skip locale region for Google Translate API (#263)
There is some peculiar behaviour with Google Translate API (translation provider) right now that requires this change. ### Extra context: For each translation provider, we can make an API call to get the language code (locale) of a piece of text. This can be things like "en", "pt", "zh", "pt-PT", "zh-CN". We use the result here to determine if the user is able to translate the post or not. If the user is in the same locale as the post, we do not allow them to translate since it is already in a readable language. For some translation providers, we take this language code and tell the API "please translate this content from pt-PT to en". For some other providers, we can just do "please translate this content to en". ### This fix Google Translate API is returning "bn-Latn" for some texts. However, 1. they do not support translation from "bn-Latn" to "en", 2. they do support translation from "bn" to "en", 3. same piece of text can be directly translated to "en" without supplying the source locale ("bn-Latn") 🤯 This fix does two things specific to the Google provider: - Re-check if an unsupported language is supported, by removing the region part of the locale - Send content for translation without indicating the source language
1 parent bf3ae87 commit dbd9af6

File tree

2 files changed

+48
-43
lines changed

2 files changed

+48
-43
lines changed

app/services/discourse_translator/google.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class Google < Base
6464
nb_NO: "no",
6565
fa_IR: "fa",
6666
}
67+
CHINESE_LOCALE = "zh"
6768

6869
def self.access_token_key
6970
"google-translator"
@@ -84,16 +85,22 @@ def self.detect!(topic_or_post)
8485

8586
def self.translate_supported?(source, target)
8687
res = result(SUPPORT_URI, target: SUPPORTED_LANG_MAPPING[target])
87-
res["languages"].any? { |obj| obj["language"] == source }
88+
supported = res["languages"].any? { |obj| obj["language"] == source }
89+
return true if supported
90+
91+
normalized_source = source.split("-").first
92+
if (source.include?("-") && normalized_source != CHINESE_LOCALE)
93+
res["languages"].any? { |obj| obj["language"] == normalized_source }
94+
else
95+
false
96+
end
8897
end
8998

9099
def self.translate!(translatable, target_locale_sym = I18n.locale)
91-
detected_locale = detect(translatable)
92100
res =
93101
result(
94102
TRANSLATE_URI,
95103
q: text_for_translation(translatable),
96-
source: detected_locale,
97104
target: SUPPORTED_LANG_MAPPING[target_locale_sym],
98105
)
99106
res["translations"][0]["translatedText"]

spec/services/google_spec.rb

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -73,39 +73,44 @@
7373

7474
describe ".translate_supported?" do
7575
let(:topic) { Fabricate(:topic, title: "This title is in english") }
76-
it "should equate source language to target" do
76+
77+
it "equates source language to target" do
7778
source = "en"
7879
target = "fr"
79-
Excon.expects(:post).returns(
80-
mock_response.new(200, %{ { "data": { "languages": [ { "language": "#{source}" }] } } }),
80+
stub_request(:post, DiscourseTranslator::Google::SUPPORT_URI).to_return(
81+
status: 200,
82+
body: %{ { "data": { "languages": [ { "language": "#{source}" }] } } },
8183
)
8284
expect(described_class.translate_supported?(source, target)).to be true
8385
end
8486

85-
it "should pass through strings already in target language" do
86-
lang = I18n.locale
87-
topic.set_detected_locale(lang)
88-
expect(described_class.translate(topic)).to eq(["en", "This title is in english"])
87+
it "checks again without -* when the source language is not supported" do
88+
source = "en"
89+
target = "fr"
90+
stub_request(:post, DiscourseTranslator::Google::SUPPORT_URI).to_return(
91+
status: 200,
92+
body: %{ { "data": { "languages": [ { "language": "#{source}" }] } } },
93+
)
94+
95+
expect(described_class.translate_supported?("en-GB", target)).to be true
8996
end
9097
end
9198

92-
describe ".translate" do
99+
describe ".translate!" do
93100
let(:post) { Fabricate(:post) }
94101

95-
it "raise an error and warns admin on failure" do
102+
it "raises an error and warns admin on failure" do
96103
described_class.expects(:access_token).returns(api_key)
97104
described_class.expects(:detect).returns("__")
98105

99-
Excon.expects(:post).returns(
100-
mock_response.new(
101-
400,
102-
{
103-
error: {
104-
code: "400",
105-
message: "API key not valid. Please pass a valid API key.",
106-
},
107-
}.to_json,
108-
),
106+
stub_request(:post, DiscourseTranslator::Google::SUPPORT_URI).to_return(
107+
status: 400,
108+
body: {
109+
error: {
110+
code: "400",
111+
message: "API key not valid. Please pass a valid API key.",
112+
},
113+
}.to_json,
109114
)
110115

111116
ProblemCheckTracker[:translator_error].no_problem!
@@ -153,34 +158,27 @@
153158
post.set_detected_locale("de")
154159
body = {
155160
q: post.cooked.truncate(SiteSetting.max_characters_per_translation, omission: nil),
156-
source: "de",
157161
target: "en",
158162
key: api_key,
159163
}
160164

161165
translated_text = "hur dur hur dur"
162-
Excon
163-
.expects(:post)
164-
.with(
165-
DiscourseTranslator::Google::TRANSLATE_URI,
166-
body: URI.encode_www_form(body),
167-
headers: {
168-
"Content-Type" => "application/x-www-form-urlencoded",
169-
"Referer" => "http://test.localhost",
170-
},
171-
)
172-
.returns(
173-
mock_response.new(
174-
200,
175-
%{ { "data": { "translations": [ { "translatedText": "#{translated_text}" } ] } } },
176-
),
177-
)
178-
.once
179-
Excon.expects(:post).returns(
180-
mock_response.new(200, %{ { "data": { "languages": [ { "language": "de" }] } } }),
166+
stub_request(:post, DiscourseTranslator::Google::SUPPORT_URI).to_return(
167+
status: 200,
168+
body: %{ { "data": { "languages": [ { "language": "de" }] } } },
169+
)
170+
stub_request(:post, DiscourseTranslator::Google::TRANSLATE_URI).with(
171+
body: URI.encode_www_form(body),
172+
headers: {
173+
"Content-Type" => "application/x-www-form-urlencoded",
174+
"Referer" => "http://test.localhost",
175+
},
176+
).to_return(
177+
status: 200,
178+
body: %{ { "data": { "translations": [ { "translatedText": "#{translated_text}" } ] } } },
181179
)
182180

183-
expect(described_class.translate(post)).to eq(["de", translated_text])
181+
expect(described_class.translate!(post)).to eq(translated_text)
184182
end
185183
end
186184
end

0 commit comments

Comments
 (0)