You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 lines
2.1 KiB

  1. # frozen_string_literal: true
  2. class TranslationService::DeepL < TranslationService
  3. include JsonLdHelper
  4. def initialize(plan, api_key)
  5. super()
  6. @plan = plan
  7. @api_key = api_key
  8. end
  9. def translate(text, source_language, target_language)
  10. form = { text: text, source_lang: source_language&.upcase, target_lang: target_language, tag_handling: 'html' }
  11. request(:post, '/v2/translate', form: form) do |res|
  12. transform_response(res.body_with_limit)
  13. end
  14. end
  15. def supported?(source_language, target_language)
  16. source_language.in?(languages('source')) && target_language.in?(languages('target'))
  17. end
  18. private
  19. def languages(type)
  20. Rails.cache.fetch("translation_service/deepl/languages/#{type}", expires_in: 7.days, race_condition_ttl: 1.minute) do
  21. request(:get, "/v2/languages?type=#{type}") do |res|
  22. # In DeepL, EN and PT are deprecated in favor of EN-GB/EN-US and PT-BR/PT-PT, so
  23. # they are supported but not returned by the API.
  24. extra = type == 'source' ? [nil] : %w(en pt)
  25. languages = Oj.load(res.body_with_limit).map { |language| language['language'].downcase }
  26. languages + extra
  27. end
  28. end
  29. end
  30. def request(verb, path, **options)
  31. req = Request.new(verb, "#{base_url}#{path}", **options)
  32. req.add_headers(Authorization: "DeepL-Auth-Key #{@api_key}")
  33. req.perform do |res|
  34. case res.code
  35. when 429
  36. raise TooManyRequestsError
  37. when 456
  38. raise QuotaExceededError
  39. when 200...300
  40. yield res
  41. else
  42. raise UnexpectedResponseError
  43. end
  44. end
  45. end
  46. def base_url
  47. if @plan == 'free'
  48. 'https://api-free.deepl.com'
  49. else
  50. 'https://api.deepl.com'
  51. end
  52. end
  53. def transform_response(str)
  54. json = Oj.load(str, mode: :strict)
  55. raise UnexpectedResponseError unless json.is_a?(Hash)
  56. Translation.new(text: json.dig('translations', 0, 'text'), detected_source_language: json.dig('translations', 0, 'detected_source_language')&.downcase, provider: 'DeepL.com')
  57. rescue Oj::ParseError
  58. raise UnexpectedResponseError
  59. end
  60. end