Skip to content
Open
Show file tree
Hide file tree
Changes from 23 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
31 changes: 31 additions & 0 deletions app/services/deepl_translator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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

Decidim::MachineTranslationSaveJob.perform_later(
resource,
field_name,
target_locale,
translation.text
)
Comment on lines 19 to 27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might consider adding a guard clause after the DeepL API call to prevent scheduling a job with empty/nil translation results:

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

Decidim::MachineTranslationSaveJob.perform_later(...)

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
45 changes: 45 additions & 0 deletions spec/services/deepl_translator_spec.rb
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great to include tests ! Personally, I think we're missing some test coverage here, especially around error scenarios. Since this class makes external API calls, it would be good to test what happens when:

  • The translation comes back nil or empty
  • We pass blank text

That would be a bonus (so if you can't do it, it's fine) to add some tests about:

  • The job scheduling fails
  • The DeepL API fails (auth errors, quota exceeded, etc.)

The current test only covers the happy path integration, which is great, but given the previous feedback about error handling, it would probably be worth adding some unit tests for the #translate method to make sure errors are logged properly and don't break the flow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your feedback It's great, I will add them !

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had them. About The job scheduling I think is almost test in the machine_translation_resource_job: https://github.com/decidim/decidim/blob/7d584a3cd73c93d8eb3bcdf8c0eb8e1b3562d9bf/decidim-core/spec/jobs/decidim/machine_translation_resource_job_spec.rb#L23
Do you think is still necessary here ? I'm not sure...

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 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 do
clear_enqueued_jobs
end

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
end
end
Loading