mirror of
https://ghfast.top/https://github.com/discourse/discourse-translator.git
synced 2026-07-18 11:59:35 +08:00
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
147 lines
3.6 KiB
Ruby
147 lines
3.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "base"
|
|
require "json"
|
|
|
|
module DiscourseTranslator
|
|
class Google < Base
|
|
TRANSLATE_URI = "https://www.googleapis.com/language/translate/v2".freeze
|
|
DETECT_URI = "https://www.googleapis.com/language/translate/v2/detect".freeze
|
|
SUPPORT_URI = "https://www.googleapis.com/language/translate/v2/languages".freeze
|
|
|
|
# Hash which maps Discourse's locale code to Google Translate's locale code found in
|
|
# https://cloud.google.com/translate/docs/languages
|
|
SUPPORTED_LANG_MAPPING = {
|
|
en: "en",
|
|
en_GB: "en",
|
|
en_US: "en",
|
|
ar: "ar",
|
|
bg: "bg",
|
|
bs_BA: "bs",
|
|
ca: "ca",
|
|
cs: "cs",
|
|
da: "da",
|
|
de: "de",
|
|
el: "el",
|
|
es: "es",
|
|
et: "et",
|
|
fi: "fi",
|
|
fr: "fr",
|
|
he: "iw",
|
|
hi: "hi",
|
|
hr: "hr",
|
|
hu: "hu",
|
|
hy: "hy",
|
|
id: "id",
|
|
it: "it",
|
|
ja: "ja",
|
|
ka: "ka",
|
|
kk: "kk",
|
|
ko: "ko",
|
|
ky: "ky",
|
|
lv: "lv",
|
|
mk: "mk",
|
|
nl: "nl",
|
|
pt: "pt",
|
|
ro: "ro",
|
|
ru: "ru",
|
|
sk: "sk",
|
|
sl: "sl",
|
|
sq: "sq",
|
|
sr: "sr",
|
|
sv: "sv",
|
|
tg: "tg",
|
|
te: "te",
|
|
th: "th",
|
|
uk: "uk",
|
|
uz: "uz",
|
|
zh_CN: "zh-CN",
|
|
zh_TW: "zh-TW",
|
|
tr_TR: "tr",
|
|
pt_BR: "pt",
|
|
pl_PL: "pl",
|
|
no_NO: "no",
|
|
nb_NO: "no",
|
|
fa_IR: "fa",
|
|
}
|
|
CHINESE_LOCALE = "zh"
|
|
|
|
def self.access_token_key
|
|
"google-translator"
|
|
end
|
|
|
|
def self.access_token
|
|
return SiteSetting.translator_google_api_key if SiteSetting.translator_google_api_key.present?
|
|
raise ProblemCheckedTranslationError.new("NotFound: Google Api Key not set.")
|
|
end
|
|
|
|
def self.detect!(topic_or_post)
|
|
result(DETECT_URI, q: text_for_detection(topic_or_post))["detections"][0].max do |a, b|
|
|
a.confidence <=> b.confidence
|
|
end[
|
|
"language"
|
|
]
|
|
end
|
|
|
|
def self.translate_supported?(source, target)
|
|
res = result(SUPPORT_URI, target: SUPPORTED_LANG_MAPPING[target])
|
|
supported = res["languages"].any? { |obj| obj["language"] == source }
|
|
return true if supported
|
|
|
|
normalized_source = source.split("-").first
|
|
if (source.include?("-") && normalized_source != CHINESE_LOCALE)
|
|
res["languages"].any? { |obj| obj["language"] == normalized_source }
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
def self.translate!(translatable, target_locale_sym = I18n.locale)
|
|
res =
|
|
result(
|
|
TRANSLATE_URI,
|
|
q: text_for_translation(translatable),
|
|
target: SUPPORTED_LANG_MAPPING[target_locale_sym],
|
|
)
|
|
res["translations"][0]["translatedText"]
|
|
end
|
|
|
|
def self.result(url, body)
|
|
body[:key] = access_token
|
|
|
|
response =
|
|
Excon.post(
|
|
url,
|
|
body: URI.encode_www_form(body),
|
|
headers: {
|
|
"Content-Type" => "application/x-www-form-urlencoded",
|
|
"Referer" => Discourse.base_url,
|
|
},
|
|
)
|
|
|
|
body = nil
|
|
begin
|
|
body = JSON.parse(response.body)
|
|
rescue JSON::ParserError
|
|
end
|
|
|
|
if response.status != 200
|
|
if body && body["error"]
|
|
ProblemCheckTracker[:translator_error].problem!(
|
|
details: {
|
|
provider: "Google",
|
|
code: body["error"]["code"],
|
|
message: body["error"]["message"],
|
|
},
|
|
)
|
|
raise ProblemCheckedTranslationError.new(body["error"]["message"])
|
|
else
|
|
raise TranslatorError.new(response.inspect)
|
|
end
|
|
else
|
|
ProblemCheckTracker[:translator_error].no_problem!
|
|
body["data"]
|
|
end
|
|
end
|
|
end
|
|
end
|