Skip to content

Commit 0498c1e

Browse files
committed
FIX: Don't double cook
1 parent 851eb80 commit 0498c1e

File tree

14 files changed

+357
-396
lines changed

14 files changed

+357
-396
lines changed

app/models/concerns/discourse_translator/translatable.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@ module Translatable
1111
has_one :content_locale, class_name: "DiscourseTranslator::#{name}Locale", dependent: :destroy
1212
end
1313

14-
def set_detected_locale(locale)
14+
def set_detected_locale(locale = I18n.locale)
1515
# locales should be "en-US" instead of "en_US" per https://www.rfc-editor.org/rfc/rfc5646#section-2.1
1616
locale = locale.to_s.gsub("_", "-")
1717
(content_locale || build_content_locale).update!(detected_locale: locale)
18+
locale
1819
end
1920

2021
# This method is used to create a translation for a translatable (Post or Topic) and a specific locale.
2122
# If a translation already exists for the locale, it will be updated.
2223
# Texts are put through a Sanitizer to clean them up before saving.
2324
# @param locale [String] the locale of the translation
2425
# @param text [String] the translated text
25-
def set_translation(locale, text)
26+
def set_translation(locale = I18n.locale, text)
2627
locale = locale.to_s.gsub("_", "-")
2728
translations.find_or_initialize_by(locale: locale).update!(translation: text)
2829
end

app/services/discourse_translator/provider/amazon.rb

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -120,38 +120,25 @@ def self.detect!(topic_or_post)
120120
end
121121
end
122122

123-
def self.translate_translatable!(translatable, target_locale_sym = I18n.locale)
124-
detected_lang = detect(translatable)
123+
def self.translate_post!(post, target_locale_sym = I18n.locale, opts = {})
124+
raw = opts.key?(:raw) ? opts[:raw] : !opts[:cooked]
125+
text = text_for_translation(post, raw:)
126+
translate_text!(text, target_locale_sym)
127+
end
125128

126-
begin
127-
client.translate_text(
128-
{
129-
text: truncate(text_for_translation(translatable)),
130-
source_language_code: "auto",
131-
target_language_code: SUPPORTED_LANG_MAPPING[target_locale_sym],
132-
},
133-
)
134-
rescue Aws::Translate::Errors::UnsupportedLanguagePairException
135-
raise I18n.t(
136-
"translator.failed.#{translatable.class.name.downcase}",
137-
source_locale: detected_lang,
138-
target_locale: target_locale_sym,
139-
)
140-
end
129+
def self.translate_topic!(topic, target_locale_sym = I18n.locale)
130+
text = text_for_translation(topic)
131+
translate_text!(text, target_locale_sym)
141132
end
142133

143134
def self.translate_text!(text, target_locale_sym = I18n.locale)
144-
begin
145-
client.translate_text(
146-
{
147-
text: truncate(text),
148-
source_language_code: "auto",
149-
target_language_code: SUPPORTED_LANG_MAPPING[target_locale_sym],
150-
},
151-
)
152-
rescue Aws::Translate::Errors::UnsupportedLanguagePairException
153-
raise I18n.t("translator.not_supported")
154-
end
135+
client.translate_text(
136+
{
137+
text: truncate(text),
138+
source_language_code: "auto",
139+
target_language_code: SUPPORTED_LANG_MAPPING[target_locale_sym],
140+
},
141+
)&.translated_text
155142
end
156143

157144
def self.client

app/services/discourse_translator/provider/base_provider.rb

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@ def self.cache_key
2525
"#{key_prefix}#{access_token_key}"
2626
end
2727

28-
# Returns the stored translation of a post or topic.
29-
# If the translation does not exist yet, it will be translated first via the API then stored.
28+
# Translates and saves it into a PostTranslation/TopicTranslation
3029
# If the detected language is the same as the target language, the original text will be returned.
3130
# @param translatable [Post|Topic]
31+
# @return [Array] the detected language and the translated text
3232
def self.translate(translatable, target_locale_sym = I18n.locale)
33-
return if text_for_translation(translatable).blank?
3433
detected_lang = detect(translatable)
3534

3635
if translatable.locale_matches?(target_locale_sym)
@@ -50,35 +49,46 @@ def self.translate(translatable, target_locale_sym = I18n.locale)
5049
)
5150
end
5251

53-
translated = translate_translatable!(translatable, target_locale_sym)
54-
save_translation(translatable, target_locale_sym) { translated }
55-
[detected_lang, translated]
56-
end
52+
begin
53+
begin
54+
translated =
55+
case translatable.class.name
56+
when "Post"
57+
translate_post!(translatable, target_locale_sym, { cooked: true })
58+
when "Topic"
59+
translate_topic!(translatable, target_locale_sym)
60+
end
61+
end
62+
rescue => e
63+
raise I18n.t(
64+
"translator.failed.#{translatable.class.name.downcase}",
65+
source_locale: detected_lang,
66+
target_locale: target_locale_sym,
67+
)
68+
end
5769

58-
# TODO: Deprecate this in favour of translate_<model>
59-
def self.translate_translatable!(translatable, target_locale_sym = I18n.locale)
60-
raise "Not Implemented"
70+
translatable.set_translation(target_locale_sym, translated)
71+
[detected_lang, translated]
6172
end
6273

6374
def self.translate_text!(text, target_locale_sym = I18n.locale)
6475
raise "Not Implemented"
6576
end
6677

67-
def self.translate_post!(post, target_locale_sym = I18n.locale)
68-
translate_translatable!(post, target_locale_sym)
78+
def self.translate_post!(post, target_locale_sym = I18n.locale, opts = {})
79+
raise "Not Implemented"
6980
end
7081

7182
def self.translate_topic!(topic, target_locale_sym = I18n.locale)
72-
translate_translatable!(topic, target_locale_sym)
83+
raise "Not Implemented"
7384
end
7485

7586
# Returns the stored detected locale of a post or topic.
7687
# If the locale does not exist yet, it will be detected first via the API then stored.
7788
# @param translatable [Post|Topic]
7889
def self.detect(translatable)
7990
return if text_for_detection(translatable).blank?
80-
get_detected_locale(translatable) ||
81-
save_detected_locale(translatable) { detect!(translatable) }
91+
translatable.detected_locale || translatable.set_detected_locale(detect!(translatable))
8292
end
8393

8494
# Subclasses must implement this method to detect the text of a post or topic
@@ -94,29 +104,6 @@ def self.access_token
94104
raise "Not Implemented"
95105
end
96106

97-
def self.save_translation(translatable, target_locale_sym = I18n.locale)
98-
begin
99-
translation = yield
100-
rescue Timeout::Error
101-
raise TranslatorError.new(I18n.t("translator.api_timeout"))
102-
end
103-
translatable.set_translation(target_locale_sym, translation)
104-
translation
105-
end
106-
107-
def self.get_detected_locale(translatable)
108-
translatable.detected_locale
109-
end
110-
111-
def self.save_detected_locale(translatable)
112-
# sometimes we may have a user post that is just an emoji
113-
# in that case, we will just indicate the post is in the default locale
114-
detected_locale = yield.presence || SiteSetting.default_locale
115-
translatable.set_detected_locale(detected_locale)
116-
117-
detected_locale
118-
end
119-
120107
def self.language_supported?(detected_lang)
121108
raise NotImplementedError unless self.const_defined?(:SUPPORTED_LANG_MAPPING)
122109
supported_lang = const_get(:SUPPORTED_LANG_MAPPING)

app/services/discourse_translator/provider/discourse_ai.rb

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,22 @@ def self.detect!(topic_or_post)
1515
::DiscourseAi::LanguageDetector.new(text_for_detection(topic_or_post)).detect
1616
end
1717

18-
def self.translate_translatable!(translatable, target_locale_sym = I18n.locale)
19-
if (translatable.class.name == "Post")
20-
translate_post!(translatable, target_locale_sym)
21-
elsif (translatable.class.name == "Topic")
22-
translate_topic!(translatable, target_locale_sym)
23-
end
24-
end
25-
26-
def self.translate_post!(post, target_locale_sym = I18n.locale)
18+
def self.translate_post!(post, target_locale_sym = I18n.locale, opts = {})
2719
validate_required_settings!
2820

29-
text = text_for_translation(post, raw: true)
21+
raw = opts.key?(:raw) ? opts[:raw] : !opts[:cooked]
22+
text = text_for_translation(post, raw:)
3023
chunks = DiscourseTranslator::ContentSplitter.split(text)
31-
translated =
32-
chunks
33-
.map { |chunk| ::DiscourseAi::PostTranslator.new(chunk, target_locale_sym).translate }
34-
.join("")
35-
DiscourseTranslator::TranslatedContentNormalizer.normalize(post, translated)
24+
chunks
25+
.map { |chunk| ::DiscourseAi::PostTranslator.new(chunk, target_locale_sym).translate }
26+
.join("")
3627
end
3728

3829
def self.translate_topic!(topic, target_locale_sym = I18n.locale)
3930
validate_required_settings!
4031

4132
language = get_language_name(target_locale_sym)
42-
translated =
43-
::DiscourseAi::TopicTranslator.new(text_for_translation(topic), language).translate
44-
DiscourseTranslator::TranslatedContentNormalizer.normalize(topic, translated)
33+
::DiscourseAi::TopicTranslator.new(text_for_translation(topic), language).translate
4534
end
4635

4736
def self.translate_text!(text, target_locale_sym = I18n.locale)

app/services/discourse_translator/provider/google.rb

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,15 @@ def self.translate_supported?(source, target)
9696
end
9797
end
9898

99-
def self.translate_translatable!(translatable, target_locale_sym = I18n.locale)
100-
res =
101-
result(
102-
TRANSLATE_URI,
103-
q: text_for_translation(translatable),
104-
target: SUPPORTED_LANG_MAPPING[target_locale_sym],
105-
)
106-
res["translations"][0]["translatedText"]
99+
def self.translate_post!(post, target_locale_sym = I18n.locale, opts = {})
100+
raw = opts.key?(:raw) ? opts[:raw] : !opts[:cooked]
101+
text = text_for_translation(post, raw:)
102+
translate_text!(text, target_locale_sym)
103+
end
104+
105+
def self.translate_topic!(topic, target_locale_sym = I18n.locale)
106+
text = text_for_translation(topic)
107+
translate_text!(text, target_locale_sym)
107108
end
108109

109110
def self.translate_text!(text, target_locale_sym = I18n.locale)

app/services/discourse_translator/provider/libre_translate.rb

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,19 @@ def self.translate_supported?(source, target)
9191
res.any? { |obj| obj["code"] == source } && res.any? { |obj| obj["code"] == lang }
9292
end
9393

94-
def self.translate_translatable!(translatable, target_locale_sym = I18n.locale)
95-
detected_lang = detect(translatable)
94+
def self.translate_post!(post, target_locale_sym = I18n.locale, opts = {})
95+
raw = opts.key?(:raw) ? opts[:raw] : !opts[:cooked]
96+
text = text_for_translation(post, raw:)
9697

97-
res =
98-
result(
99-
translate_uri,
100-
q: text_for_translation(translatable),
101-
source: detected_lang,
102-
target: SUPPORTED_LANG_MAPPING[target_locale_sym],
103-
format: "html",
104-
)
105-
res["translatedText"]
98+
detected_lang = detect(post)
99+
100+
send_for_translation(text, detected_lang, target_locale_sym)
101+
end
102+
103+
def self.translate_topic!(topic, target_locale_sym = I18n.locale)
104+
detected_lang = detect(topic)
105+
text = text_for_translation(topic)
106+
send_for_translation(text, detected_lang, target_locale_sym)
106107
end
107108

108109
def self.translate_text!(text, target_locale_sym = I18n.locale)
@@ -154,6 +155,20 @@ def self.result(url, body)
154155
body
155156
end
156157
end
158+
159+
private
160+
161+
def self.send_for_translation(text, source_locale, target_locale)
162+
res =
163+
result(
164+
translate_uri,
165+
q: text,
166+
source: source_locale,
167+
target: SUPPORTED_LANG_MAPPING[target_locale],
168+
format: "html",
169+
)
170+
res["translatedText"]
171+
end
157172
end
158173
end
159174
end

app/services/discourse_translator/provider/microsoft.rb

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -154,27 +154,24 @@ def self.detect!(topic_or_post)
154154
result(uri.to_s, body, default_headers).first["language"]
155155
end
156156

157-
def self.translate_translatable!(translatable, target_locale_sym = I18n.locale)
158-
detected_lang = detect(translatable)
157+
def self.translate_post!(post, target_locale_sym = I18n.locale, opts = {})
158+
raw = opts.key?(:raw) ? opts[:raw] : !opts[:cooked]
159+
text = text_for_translation(post, raw:)
159160

160-
if text_for_translation(translatable).length > LENGTH_LIMIT
161-
raise TranslatorError.new(I18n.t("translator.too_long"))
162-
end
163-
locale =
164-
SUPPORTED_LANG_MAPPING[target_locale_sym] || (raise I18n.t("translator.not_supported"))
161+
raise TranslatorError.new(I18n.t("translator.too_long")) if text.length > LENGTH_LIMIT
165162

166-
query = default_query.merge("from" => detected_lang, "to" => locale, "textType" => "html")
167-
body = [{ "Text" => text_for_translation(translatable) }].to_json
168-
uri = URI(translate_endpoint)
169-
uri.query = URI.encode_www_form(query)
170-
response_body = result(uri.to_s, body, default_headers)
171-
response_body.first["translations"].first["text"]
163+
translate_text!(text, target_locale_sym)
172164
end
173165

174-
def self.translate_text!(text, target_locale_sym = I18n.locale)
175-
locale =
176-
SUPPORTED_LANG_MAPPING[target_locale_sym] || (raise I18n.t("translator.not_supported"))
166+
def self.translate_topic!(topic, target_locale_sym = I18n.locale)
167+
text = text_for_translation(topic)
168+
raise TranslatorError.new(I18n.t("translator.too_long")) if text.length > LENGTH_LIMIT
169+
170+
translate_text!(text, target_locale_sym)
171+
end
177172

173+
def self.translate_text!(text, target_locale_sym = I18n.locale)
174+
locale = SUPPORTED_LANG_MAPPING[target_locale_sym]
178175
query = default_query.merge("to" => locale, "textType" => "html")
179176
body = [{ "Text" => text }].to_json
180177
uri = URI(translate_endpoint)

0 commit comments

Comments
 (0)