Merge pull request #5089 from consul/bing-translator

Use Bing Translator instead of TranslatorText
This commit is contained in:
Sebastia
2023-03-15 17:50:51 +01:00
committed by GitHub
8 changed files with 80 additions and 98 deletions

View File

@@ -9,6 +9,7 @@ gem "airbrake", "~> 13.0.2"
gem "ancestry", "~> 4.2.0"
gem "audited", "~> 5.0.2"
gem "autoprefixer-rails", "~> 8.2.0"
gem "bing_translator", "~> 6.2.0"
gem "cancancan", "~> 3.4.0"
gem "caxlsx", "~> 3.2.0"
gem "caxlsx_rails", "~> 0.6.3"
@@ -55,7 +56,6 @@ gem "savon", "~> 2.13.0"
gem "sitemap_generator", "~> 6.3.0"
gem "social-share-button", "~> 1.2.4"
gem "sprockets", "~> 4.1.1"
gem "translator-text", "~> 0.1.0"
gem "turbolinks", "~> 5.2.1"
gem "turnout", "~> 2.5.0"
gem "uglifier", "~> 4.2.0"

View File

@@ -96,6 +96,8 @@ GEM
parser (>= 2.4)
smart_properties
bindex (0.8.1)
bing_translator (6.2.0)
json
builder (3.2.4)
bullet (7.0.3)
activesupport (>= 3.0.0)
@@ -178,31 +180,6 @@ GEM
devise (>= 4.3.0, < 5.0)
diff-lcs (1.5.0)
docile (1.4.0)
dry-configurable (0.7.0)
concurrent-ruby (~> 1.0)
dry-container (0.6.0)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.1, >= 0.1.3)
dry-core (0.4.7)
concurrent-ruby (~> 1.0)
dry-equalizer (0.2.1)
dry-inflector (0.1.2)
dry-logic (0.4.2)
dry-container (~> 0.2, >= 0.2.6)
dry-core (~> 0.2)
dry-equalizer (~> 0.2)
dry-struct (0.5.1)
dry-core (~> 0.4, >= 0.4.3)
dry-equalizer (~> 0.2)
dry-types (~> 0.13)
ice_nine (~> 0.11)
dry-types (0.13.3)
concurrent-ruby (~> 1.0)
dry-container (~> 0.3)
dry-core (~> 0.4, >= 0.4.4)
dry-equalizer (~> 0.2)
dry-inflector (~> 0.1, >= 0.1.2)
dry-logic (~> 0.4, >= 0.4.2)
email_spec (2.2.0)
htmlentities (~> 4.3.3)
launchy (~> 2.1)
@@ -309,7 +286,6 @@ GEM
rails-i18n
rainbow (>= 2.2.2, < 4.0)
terminal-table (>= 1.5.1)
ice_nine (0.11.2)
image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
@@ -640,9 +616,6 @@ GEM
thread_safe (0.3.6)
tilt (2.0.10)
tomlrb (1.3.0)
translator-text (0.1.0)
dry-struct (~> 0.5.0)
httparty (~> 0.15)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
@@ -701,6 +674,7 @@ DEPENDENCIES
ancestry (~> 4.2.0)
audited (~> 5.0.2)
autoprefixer-rails (~> 8.2.0)
bing_translator (~> 6.2.0)
bullet (~> 7.0.3)
byebug (~> 11.1.3)
cancancan (~> 3.4.0)
@@ -785,7 +759,6 @@ DEPENDENCIES
spring (~> 2.1.1)
spring-commands-rspec (~> 1.0.4)
sprockets (~> 4.1.1)
translator-text (~> 0.1.0)
turbolinks (~> 5.2.1)
turnout (~> 2.5.0)
uglifier (~> 4.2.0)

View File

@@ -6,29 +6,32 @@ require "json"
class RemoteTranslations::Microsoft::AvailableLocales
def self.available_locales
daily_cache("locales") do
remote_available_locales.map(&:first)
remote_available_locales.map { |locale| remote_locale_to_app_locale(locale) }
end
end
def self.parse_locale(locale)
case locale
when :"pt-BR"
:pt
when :"zh-CN"
:"zh-Hans"
when :"zh-TW"
:"zh-Hant"
else
locale
end
def self.app_locale_to_remote_locale(locale)
app_locale_to_remote_locale_map[locale] || locale
end
def self.include_locale?(locale)
available_locales.include?(parse_locale(locale).to_s)
available_locales.include?(locale.to_s)
end
private
def self.remote_locale_to_app_locale(locale)
app_locale_to_remote_locale_map.invert[locale] || locale
end
def self.app_locale_to_remote_locale_map
{
"pt-BR" => "pt",
"zh-CN" => "zh-Hans",
"zh-TW" => "zh-Hant"
}
end
def self.remote_available_locales
host = "https://api.cognitive.microsofttranslator.com"
path = "/languages?api-version=3.0"
@@ -44,7 +47,7 @@ class RemoteTranslations::Microsoft::AvailableLocales
result = response.body.force_encoding("utf-8")
JSON.parse(result)["translation"]
JSON.parse(result)["translation"].map(&:first)
end
def self.daily_cache(key, &block)

View File

@@ -1,18 +1,11 @@
require "translator-text"
include RemoteTranslations::Microsoft::SentencesParser
class RemoteTranslations::Microsoft::Client
include SentencesParser
CHARACTERS_LIMIT_PER_REQUEST = 5000
PREVENTING_TRANSLATION_KEY = "notranslate".freeze
def initialize
api_key = Tenant.current_secrets.microsoft_api_key
@client = TranslatorText::Client.new(api_key)
end
def call(fields_values, locale)
texts = prepare_texts(fields_values)
valid_locale = RemoteTranslations::Microsoft::AvailableLocales.parse_locale(locale)
valid_locale = RemoteTranslations::Microsoft::AvailableLocales.app_locale_to_remote_locale(locale)
request_translation(texts, valid_locale)
end
@@ -28,12 +21,16 @@ class RemoteTranslations::Microsoft::Client
private
def client
@client ||= BingTranslator.new(Tenant.current_secrets.microsoft_api_key)
end
def request_translation(texts, locale)
response = []
split_response = false
if characters_count(texts) <= CHARACTERS_LIMIT_PER_REQUEST
response = @client.translate(texts, to: locale)
response = client.translate_array(texts, to: locale)
else
texts.each do |text|
response << translate_text(text, locale)
@@ -46,27 +43,26 @@ class RemoteTranslations::Microsoft::Client
def translate_text(text, locale)
fragments_for(text).map do |fragment|
@client.translate([fragment], to: locale)
client.translate_array([fragment], to: locale)
end.flatten
end
def parse_response(response, split_response)
response.map do |object|
response.map do |translation|
if split_response
build_translation(object)
build_translation(translation)
else
get_field_value(object)
get_field_value(translation)
end
end
end
def build_translation(objects)
objects.map { |object| get_field_value(object) }.join
def build_translation(translations)
translations.map { |translation| get_field_value(translation) }.join
end
def get_field_value(object)
text = object.translations[0].text
notranslate?(text) ? nil : text
def get_field_value(translation)
notranslate?(translation) ? nil : translation
end
def prepare_texts(texts)

View File

@@ -5,7 +5,7 @@ describe Layout::RemoteTranslationsButtonComponent do
let(:component) { Layout::RemoteTranslationsButtonComponent.new(translations) }
before do
allow(RemoteTranslations::Microsoft::AvailableLocales).to receive(:available_locales)
allow(RemoteTranslations::Microsoft::AvailableLocales).to receive(:remote_available_locales)
.and_return(%w[de en es fr pt zh-Hans])
end

View File

@@ -0,0 +1,13 @@
require "rails_helper"
describe RemoteTranslations::Microsoft::AvailableLocales do
describe ".available_locales" do
it "includes locales with the same format as I18n.available_locales" do
allow(RemoteTranslations::Microsoft::AvailableLocales).to receive(:remote_available_locales)
.and_return(%w[de en es fr pt zh-Hans])
available_locales = RemoteTranslations::Microsoft::AvailableLocales.available_locales
expect(available_locales).to eq %w[de en es fr pt-BR zh-CN]
end
end
end

View File

@@ -6,9 +6,9 @@ describe RemoteTranslations::Microsoft::Client do
describe "#call" do
context "when characters from request are less than the characters limit" do
it "response has the expected result" do
response = create_response("Nuevo título", "Nueva descripción")
response = ["Nuevo título", "Nueva descripción"]
expect_any_instance_of(TranslatorText::Client).to receive(:translate).and_return(response)
expect_any_instance_of(BingTranslator).to receive(:translate_array).and_return(response)
result = client.call(["New title", "New description"], :es)
@@ -16,9 +16,9 @@ describe RemoteTranslations::Microsoft::Client do
end
it "response nil has the expected result when request has nil value" do
response = create_response("Notranslate", "Nueva descripción")
response = ["Notranslate", "Nueva descripción"]
expect_any_instance_of(TranslatorText::Client).to receive(:translate).and_return(response)
expect_any_instance_of(BingTranslator).to receive(:translate_array).and_return(response)
result = client.call([nil, "New description"], :es)
@@ -34,15 +34,15 @@ describe RemoteTranslations::Microsoft::Client do
translated_text_es = Faker::Lorem.characters(number: 11)
another_translated_text_es = Faker::Lorem.characters(number: 11)
response_text = create_response(translated_text_es)
response_another_text = create_response(another_translated_text_es)
response_text = [translated_text_es]
response_another_text = [another_translated_text_es]
expect_any_instance_of(TranslatorText::Client).to receive(:translate).exactly(1)
.times
.and_return(response_text)
expect_any_instance_of(TranslatorText::Client).to receive(:translate).exactly(1)
.times
.and_return(response_another_text)
expect_any_instance_of(BingTranslator).to receive(:translate_array).exactly(1)
.times
.and_return(response_text)
expect_any_instance_of(BingTranslator).to receive(:translate_array).exactly(1)
.times
.and_return(response_another_text)
result = client.call([text_en, another_text_en], :es)
@@ -58,14 +58,14 @@ describe RemoteTranslations::Microsoft::Client do
start_translated_text_es = Faker::Lorem.characters(number: 10) + " "
end_translated_text_es = Faker::Lorem.characters(number: 10)
translated_text_es = start_translated_text_es + end_translated_text_es
response_start_text = create_response(start_translated_text_es)
response_end_text = create_response(end_translated_text_es)
response_start_text = [start_translated_text_es]
response_end_text = [end_translated_text_es]
expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([start_text_en], to: :es)
expect_any_instance_of(BingTranslator).to receive(:translate_array).with([start_text_en], to: :es)
.exactly(1)
.times
.and_return(response_start_text)
expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([end_text_en], to: :es)
expect_any_instance_of(BingTranslator).to receive(:translate_array).with([end_text_en], to: :es)
.exactly(1)
.times
.and_return(response_end_text)
@@ -77,14 +77,14 @@ describe RemoteTranslations::Microsoft::Client do
another_start_translated_text_es = Faker::Lorem.characters(number: 12) + "."
another_end_translated_text_es = Faker::Lorem.characters(number: 12)
another_translated_text_es = another_start_translated_text_es + another_end_translated_text_es
response_another_start_text = create_response(another_start_translated_text_es)
response_another_end_text = create_response(another_end_translated_text_es)
response_another_start_text = [another_start_translated_text_es]
response_another_end_text = [another_end_translated_text_es]
expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([start_another_text_en], to: :es)
expect_any_instance_of(BingTranslator).to receive(:translate_array).with([start_another_text_en], to: :es)
.exactly(1)
.times
.and_return(response_another_start_text)
expect_any_instance_of(TranslatorText::Client).to receive(:translate).with([end_another_text_en], to: :es)
expect_any_instance_of(BingTranslator).to receive(:translate_array).with([end_another_text_en], to: :es)
.exactly(1)
.times
.and_return(response_another_end_text)
@@ -146,16 +146,3 @@ describe RemoteTranslations::Microsoft::Client do
end
end
end
def create_response(*args)
# response = [#<TranslatorText::Types::TranslationResult translations=[#<TranslatorText::Types::Translation text="Nuevo título" to=:es>] detectedLanguage={"language"=>"en", "score"=>1.0}>, #<TranslatorText::Types::TranslationResult translations=[#<TranslatorText::Types::Translation text="Nueva descripción" to=:es>] detectedLanguage={"language"=>"en", "score"=>1.0}>]
translations = Struct.new(:translations)
text = Struct.new(:text)
response = []
args.each do |text_to_response|
response << translations.new([text.new(text_to_response)])
end
response
end

View File

@@ -49,6 +49,16 @@ describe RemoteTranslation, :remote_translations do
expect(remote_translation).to be_valid
end
it "is valid with a locale that uses a different name in the remote service" do
allow(RemoteTranslations::Microsoft::AvailableLocales).to receive(:available_locales).and_call_original
allow(RemoteTranslations::Microsoft::AvailableLocales).to receive(:remote_available_locales)
.and_return(["pt"])
remote_translation.locale = :"pt-BR"
expect(remote_translation).to be_valid
end
describe "#enqueue_remote_translation", :delay_jobs do
it "after create enqueue Delayed Job" do
expect { remote_translation.save }.to change { Delayed::Job.count }.by(1)