Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6573591
docs: add DeepL translator environment variables to .env-emple
BarbaraOliveira13 Sep 5, 2025
8146b2e
gem: add deepl-rb gem to integrate DeepL translation API
BarbaraOliveira13 Sep 5, 2025
8fe89d5
config secrets: wire translator settings (enabled, api_key, host, delay)
BarbaraOliveira13 Sep 5, 2025
2777556
config initializer: configure DeepL gem with API key and host
BarbaraOliveira13 Sep 5, 2025
bd20ad6
feat helper: add TranslatorConfigurationHelper to manage translation …
BarbaraOliveira13 Sep 5, 2025
fd04a41
config decidim: enable machine translation and set DeepL as translati…
BarbaraOliveira13 Sep 5, 2025
52471b2
feat service: implement DeeplTranslator service to call API and save …
BarbaraOliveira13 Sep 5, 2025
5f51ad0
clean by deleted deepl.rb and helper
BarbaraOliveira13 Sep 12, 2025
325fd85
update deepL gem
BarbaraOliveira13 Sep 12, 2025
0967f23
set machine translation in decidim.rb
BarbaraOliveira13 Sep 12, 2025
29ab8a9
update deepl_translator.rb
BarbaraOliveira13 Sep 12, 2025
e08cd19
update .env-example
BarbaraOliveira13 Sep 12, 2025
3f14d90
clean
BarbaraOliveira13 Sep 12, 2025
754efe4
add test for deepL
BarbaraOliveira13 Sep 15, 2025
ab40270
fix CI by update deepl_translator file
BarbaraOliveira13 Sep 15, 2025
5fe90cd
lint
BarbaraOliveira13 Sep 15, 2025
ee5104a
clean
BarbaraOliveira13 Sep 15, 2025
c2f4c39
clean .env-exemple
BarbaraOliveira13 Sep 16, 2025
9294acc
add trad key
BarbaraOliveira13 Sep 16, 2025
3378ee6
fix CI
BarbaraOliveira13 Sep 16, 2025
980210e
clean by delete old ENV Deepl api key
BarbaraOliveira13 Sep 19, 2025
d88a281
add trad key in ignore_unused part
BarbaraOliveira13 Sep 19, 2025
9cfe340
revert
BarbaraOliveira13 Sep 19, 2025
74cd814
add first letter as capital'
BarbaraOliveira13 Sep 19, 2025
f5cad79
adding a guard clause
BarbaraOliveira13 Sep 19, 2025
ba1c030
add more tests
BarbaraOliveira13 Sep 22, 2025
783aea0
Add - when DeepL raises an error logs the error and flow does not bre…
BarbaraOliveira13 Sep 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,6 @@ GEOCODER_UNITS=km # Units for geocoder results (e.g., km or m
# DECIDIM_AI_BASIC_AUTH="<USER>:<PASSWORD>" Required for the AI Request Handler
# DECIDIM_AI_REPORTING_USER_EMAIL="<EMAIL>"
# DECIDIM_AI_SECRET="<SECRET_KEY>" # Not required for the AI Request Handler

# Machine translation
DEEPL_AUTH_KEY=your_deepl_api_key_here
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ gem "decidim-initiatives", github: "decidim/decidim", tag: DECIDIM_TAG
gem "decidim-templates", github: "decidim/decidim", tag: DECIDIM_TAG

gem "bootsnap", "~> 1.4", require: false
gem "deepl-rb", "~> 3.2"
gem "puma", ">= 6.3.1"

gem "activerecord-postgis-adapter", "~> 8.0", ">= 8.0.3"
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ GEM
declarative-builder (0.2.0)
trailblazer-option (~> 0.1.0)
declarative-option (0.1.0)
deepl-rb (3.2.0)
deface (1.9.0)
actionview (>= 5.2)
nokogiri (>= 1.6)
Expand Down Expand Up @@ -1131,6 +1132,7 @@ DEPENDENCIES
decidim-survey_multiple_answers!
decidim-templates!
decidim-term_customizer!
deepl-rb (~> 3.2)
deface
dotenv-rails (~> 2.7)
faker (~> 3.2)
Expand Down
32 changes: 32 additions & 0 deletions app/services/deepl_translator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

require "deepl"

class DeeplTranslator
attr_reader :resource, :field_name, :text, :target_locale, :source_locale

def initialize(resource, field_name, text, target_locale, source_locale)
@resource = resource
@field_name = field_name
@text = text
@target_locale = target_locale
@source_locale = source_locale
end

def translate
return if text.blank?

translation = ::DeepL.translate text, source_locale.to_s, target_locale.to_s
return nil if translation.nil? || translation.text.blank?

Decidim::MachineTranslationSaveJob.perform_later(
resource,
field_name,
target_locale,
translation.text
)
rescue StandardError => e
Rails.logger.error("[DeeplTranslator] #{e.class} - #{e.message}")
nil
end
end
4 changes: 2 additions & 2 deletions config/i18n-tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,8 @@ search:
# translation:
# # Get an API key and set billing info at https://code.google.com/apis/console to use Google Translate
# api_key: "AbC-dEf5"

translation:
deepl_api_key: <%= ENV["DEEPL_API_KEY"] %>

# Do not consider these keys missing:
ignore_missing:
- decidim.admin.assembly_copies.new.select
Expand All @@ -104,6 +102,8 @@ ignore_missing:

# Consider these keys used:
ignore_unused:
- activemodel.attributes.organization.enable_machine_translations
- activemodel.attributes.organization.enable_machine_translations
- faker.*
- decidim.admin.models.assembly.fields.*
- decidim.events.proposals.author_confirmation_proposal_event.*
Expand Down
5 changes: 3 additions & 2 deletions config/initializers/decidim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@
# for more information about how it works and how to set it up.
#
# Enable machine translations
config.enable_machine_translations = false
config.enable_machine_translations = true
#
# If you want to enable machine translation you can create your own service
# to interact with third party service to translate the user content.
Expand All @@ -360,7 +360,8 @@
# end
# end
#
config.machine_translation_service = "Decidim::Dev::DummyTranslator"
config.machine_translation_service = "DeeplTranslator"
config.machine_translation_delay = 0.seconds

# Defines the social networking services used for social sharing
config.social_share_services = Rails.application.secrets.decidim[:social_share_services]
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ en:
attributes:
assembly:
copy_landing_page_blocks: Copy landing page blocks
organization:
enable_machine_translations: Enable machine translations
participatory_process:
copy_landing_page_blocks: Copy landing page blocks
date:
Expand Down
2 changes: 2 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ fr:
attributes:
assembly:
copy_landing_page_blocks: Copier les blocs de la page d'accueil
organization:
enable_machine_translations: Activer la traduction automatique
participatory_process:
copy_landing_page_blocks: Copier les blocs de la page d'accueil
date:
Expand Down
75 changes: 75 additions & 0 deletions spec/services/deepl_translator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# frozen_string_literal: true

require "spec_helper"
require "deepl"

module Decidim
describe DeeplTranslator do
let(:title) { { en: "New Title" } }
let(:process) { build(:participatory_process, title:) }
let(:target_locale) { "fr" }
let(:source_locale) { "en" }
let(:translation) { double("translation", text: "Nouveau Titre") }

before do
allow(Decidim).to receive(:machine_translation_service_klass).and_return(DeeplTranslator)
allow(::DeepL).to receive(:translate).with(title[source_locale.to_sym], source_locale, target_locale).and_return(translation)
end

describe "When fields job is executed" do
before { clear_enqueued_jobs }

it "calls DeeplTranslator to create machine translations" do
expect(DeeplTranslator).to receive(:new).with(
process,
"title",
process["title"][source_locale],
target_locale,
source_locale
).and_call_original

process.save

MachineTranslationFieldsJob.perform_now(
process,
"title",
process["title"][source_locale],
target_locale,
source_locale
)
end
end

describe "#translate" do
subject { DeeplTranslator.new(process, "title", text, target_locale, source_locale).translate }
let(:text) { title[source_locale.to_sym] }

context "when translation is nil" do
before { allow(::DeepL).to receive(:translate).and_return(nil) }

it "does not enqueue a job" do
expect(Decidim::MachineTranslationSaveJob).not_to receive(:perform_later)
expect(subject).to be_nil
end
end

context "when text is empty" do
let(:text) { "" }

it "does not enqueue a job" do
expect(Decidim::MachineTranslationSaveJob).not_to receive(:perform_later)
expect(subject).to be_nil
end
end

context "when DeepL raises an error" do
before { allow(::DeepL).to receive(:translate).and_raise(StandardError, "API failure") }

it "logs the error and flow does not break" do
expect(Rails.logger).to receive(:error).with(/\[DeeplTranslator\] StandardError - API failure/)
expect(subject).to be_nil
end
end
end
end
end
Loading