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.

60 lines
1.8 KiB

  1. # frozen_string_literal: true
  2. class TranslationService::LibreTranslate < TranslationService
  3. def initialize(base_url, api_key)
  4. super()
  5. @base_url = base_url
  6. @api_key = api_key
  7. end
  8. def translate(text, source_language, target_language)
  9. body = Oj.dump(q: text, source: source_language.presence || 'auto', target: target_language, format: 'html', api_key: @api_key)
  10. request(:post, '/translate', body: body) do |res|
  11. transform_response(res.body_with_limit, source_language)
  12. end
  13. end
  14. def supported?(source_language, target_language)
  15. languages.key?(source_language) && languages[source_language].include?(target_language)
  16. end
  17. private
  18. def languages
  19. Rails.cache.fetch('translation_service/libre_translate/languages', expires_in: 7.days, race_condition_ttl: 1.minute) do
  20. request(:get, '/languages') do |res|
  21. languages = Oj.load(res.body_with_limit).to_h { |language| [language['code'], language['targets']] }
  22. languages[nil] = languages.values.flatten.uniq
  23. languages
  24. end
  25. end
  26. end
  27. def request(verb, path, **options)
  28. req = Request.new(verb, "#{@base_url}#{path}", allow_local: true, **options)
  29. req.add_headers('Content-Type': 'application/json')
  30. req.perform do |res|
  31. case res.code
  32. when 429
  33. raise TooManyRequestsError
  34. when 403
  35. raise QuotaExceededError
  36. when 200...300
  37. yield res
  38. else
  39. raise UnexpectedResponseError
  40. end
  41. end
  42. end
  43. def transform_response(str, source_language)
  44. json = Oj.load(str, mode: :strict)
  45. raise UnexpectedResponseError unless json.is_a?(Hash)
  46. Translation.new(text: json['translatedText'], detected_source_language: source_language, provider: 'LibreTranslate')
  47. rescue Oj::ParseError
  48. raise UnexpectedResponseError
  49. end
  50. end