deepl-rb 3.6.0 → 3.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +27 -0
  3. data/.github/workflows/add_issues_to_kanban.yml +16 -0
  4. data/.gitlab-ci.yml +172 -0
  5. data/.rubocop.yml +51 -0
  6. data/CHANGELOG.md +22 -3
  7. data/CODE_OF_CONDUCT.md +132 -0
  8. data/CONTRIBUTING.md +37 -0
  9. data/Gemfile +24 -0
  10. data/Rakefile +56 -0
  11. data/SECURITY.md +58 -0
  12. data/VERSION +1 -0
  13. data/deepl-rb.gemspec +140 -0
  14. data/lib/deepl/api.rb +22 -0
  15. data/lib/deepl/configuration.rb +59 -0
  16. data/lib/deepl/constants/base_constant.rb +18 -0
  17. data/lib/deepl/constants/formality.rb +16 -0
  18. data/lib/deepl/constants/model_type.rb +14 -0
  19. data/lib/deepl/constants/split_sentences.rb +14 -0
  20. data/lib/deepl/constants/tag_handling.rb +13 -0
  21. data/lib/deepl/constants/tone.rb +20 -0
  22. data/lib/deepl/constants/writing_style.rb +20 -0
  23. data/lib/deepl/document_api.rb +121 -0
  24. data/lib/deepl/exceptions/authorization_failed.rb +14 -0
  25. data/lib/deepl/exceptions/bad_request.rb +16 -0
  26. data/lib/deepl/exceptions/document_translation_error.rb +15 -0
  27. data/lib/deepl/exceptions/error.rb +14 -0
  28. data/lib/deepl/exceptions/limit_exceeded.rb +18 -0
  29. data/lib/deepl/exceptions/not_found.rb +16 -0
  30. data/lib/deepl/exceptions/not_supported.rb +14 -0
  31. data/lib/deepl/exceptions/quota_exceeded.rb +14 -0
  32. data/lib/deepl/exceptions/request_entity_too_large.rb +15 -0
  33. data/lib/deepl/exceptions/request_error.rb +21 -0
  34. data/lib/deepl/exceptions/server_error.rb +18 -0
  35. data/lib/deepl/glossary_api.rb +38 -0
  36. data/lib/deepl/requests/base.rb +196 -0
  37. data/lib/deepl/requests/document/download.rb +44 -0
  38. data/lib/deepl/requests/document/get_status.rb +44 -0
  39. data/lib/deepl/requests/document/upload.rb +74 -0
  40. data/lib/deepl/requests/glossary/create.rb +59 -0
  41. data/lib/deepl/requests/glossary/destroy.rb +37 -0
  42. data/lib/deepl/requests/glossary/entries.rb +37 -0
  43. data/lib/deepl/requests/glossary/find.rb +38 -0
  44. data/lib/deepl/requests/glossary/language_pairs.rb +38 -0
  45. data/lib/deepl/requests/glossary/list.rb +37 -0
  46. data/lib/deepl/requests/languages.rb +37 -0
  47. data/lib/deepl/requests/rephrase.rb +55 -0
  48. data/lib/deepl/requests/style_rule/list.rb +59 -0
  49. data/lib/deepl/requests/translate.rb +93 -0
  50. data/lib/deepl/requests/usage.rb +33 -0
  51. data/lib/deepl/resources/base.rb +17 -0
  52. data/lib/deepl/resources/document_handle.rb +57 -0
  53. data/lib/deepl/resources/document_translation_status.rb +54 -0
  54. data/lib/deepl/resources/glossary.rb +28 -0
  55. data/lib/deepl/resources/language.rb +30 -0
  56. data/lib/deepl/resources/language_pair.rb +23 -0
  57. data/lib/deepl/resources/style_rule.rb +85 -0
  58. data/lib/deepl/resources/text.rb +24 -0
  59. data/lib/deepl/resources/usage.rb +27 -0
  60. data/lib/deepl/style_rule_api.rb +17 -0
  61. data/lib/deepl/utils/backoff_timer.rb +46 -0
  62. data/lib/deepl/utils/exception_builder.rb +34 -0
  63. data/lib/deepl.rb +158 -0
  64. data/lib/http_client_options.rb +22 -0
  65. data/lib/version.rb +8 -0
  66. data/spec/api/api_spec.rb +20 -0
  67. data/spec/api/configuration_spec.rb +122 -0
  68. data/spec/api/deepl_spec.rb +460 -0
  69. data/spec/constants/constants_spec.rb +158 -0
  70. data/spec/fixtures/vcr_cassettes/deepl_document.yml +95 -0
  71. data/spec/fixtures/vcr_cassettes/deepl_document_download.yml +1214 -0
  72. data/spec/fixtures/vcr_cassettes/deepl_glossaries.yml +1163 -0
  73. data/spec/fixtures/vcr_cassettes/deepl_languages.yml +54 -0
  74. data/spec/fixtures/vcr_cassettes/deepl_rephrase.yml +87 -0
  75. data/spec/fixtures/vcr_cassettes/deepl_translate.yml +358 -0
  76. data/spec/fixtures/vcr_cassettes/deepl_usage.yml +129 -0
  77. data/spec/fixtures/vcr_cassettes/glossaries.yml +1702 -0
  78. data/spec/fixtures/vcr_cassettes/languages.yml +229 -0
  79. data/spec/fixtures/vcr_cassettes/rephrase_texts.yml +401 -0
  80. data/spec/fixtures/vcr_cassettes/style_rules.yml +92 -0
  81. data/spec/fixtures/vcr_cassettes/translate_texts.yml +10630 -0
  82. data/spec/fixtures/vcr_cassettes/usage.yml +171 -0
  83. data/spec/integration_tests/document_api_spec.rb +178 -0
  84. data/spec/integration_tests/integration_test_utils.rb +170 -0
  85. data/spec/integration_tests/style_rule_api_spec.rb +79 -0
  86. data/spec/requests/extra_body_parameters_types_spec.rb +82 -0
  87. data/spec/requests/glossary/create_spec.rb +65 -0
  88. data/spec/requests/glossary/destroy_spec.rb +66 -0
  89. data/spec/requests/glossary/entries_spec.rb +62 -0
  90. data/spec/requests/glossary/find_spec.rb +68 -0
  91. data/spec/requests/glossary/language_pairs_spec.rb +40 -0
  92. data/spec/requests/glossary/list_spec.rb +54 -0
  93. data/spec/requests/languages_spec.rb +68 -0
  94. data/spec/requests/rephrase_spec.rb +172 -0
  95. data/spec/requests/translate_spec.rb +493 -0
  96. data/spec/requests/usage_spec.rb +43 -0
  97. data/spec/resources/glossary_spec.rb +38 -0
  98. data/spec/resources/language_pair_spec.rb +23 -0
  99. data/spec/resources/language_spec.rb +45 -0
  100. data/spec/resources/text_spec.rb +23 -0
  101. data/spec/resources/usage_spec.rb +35 -0
  102. data/spec/spec_helper.rb +92 -0
  103. metadata +102 -2
@@ -0,0 +1,171 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api-free.deepl.com/v2/usage
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Authorization:
11
+ - DeepL-Auth-Key VALID_TOKEN
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - "*/*"
16
+ User-Agent:
17
+ - deepl-ruby/3.0.2 (darwin23) ruby/3.3.3
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Server:
24
+ - nginx
25
+ Date:
26
+ - Mon, 17 May 2021 14:18:32 GMT
27
+ Content-Type:
28
+ - application/json
29
+ Content-Length:
30
+ - '48'
31
+ Connection:
32
+ - keep-alive
33
+ Access-Control-Allow-Origin:
34
+ - "*"
35
+ body:
36
+ encoding: UTF-8
37
+ string: '{"character_count":353,"character_limit":500000}'
38
+ recorded_at: Mon, 17 May 2021 14:18:32 GMT
39
+ - request:
40
+ method: get
41
+ uri: https://api-free.deepl.com/v2/usage
42
+ body:
43
+ encoding: US-ASCII
44
+ string: ''
45
+ headers:
46
+ Authorization:
47
+ - DeepL-Auth-Key VALID_TOKEN
48
+ User-Agent:
49
+ - deepl-ruby/3.0.2 (darwin23) ruby/3.3.3
50
+ Accept-Encoding:
51
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
52
+ Accept:
53
+ - "*/*"
54
+ response:
55
+ status:
56
+ code: 403
57
+ message: Forbidden
58
+ headers:
59
+ Date:
60
+ - Tue, 02 Jul 2024 13:54:07 GMT
61
+ Content-Type:
62
+ - application/json
63
+ Transfer-Encoding:
64
+ - chunked
65
+ Vary:
66
+ - Accept-Encoding
67
+ Access-Control-Allow-Origin:
68
+ - "*"
69
+ Strict-Transport-Security:
70
+ - max-age=63072000; includeSubDomains; preload
71
+ Server-Timing:
72
+ - l7_lb_tls;dur=101, l7_lb_idle;dur=0, l7_lb_receive;dur=0, l7_lb_total;dur=103
73
+ Access-Control-Expose-Headers:
74
+ - Server-Timing, X-Trace-ID
75
+ X-Trace-Id:
76
+ - 4dcf2a36b3f14ba89f107449f4b14919
77
+ body:
78
+ encoding: ASCII-8BIT
79
+ string: '{"message":"Wrong endpoint. Use https://api.deepl.com"}'
80
+ recorded_at: Tue, 02 Jul 2024 13:54:07 GMT
81
+ - request:
82
+ method: get
83
+ uri: https://api.deepl.com/v2/usage
84
+ body:
85
+ encoding: US-ASCII
86
+ string: ''
87
+ headers:
88
+ Authorization:
89
+ - DeepL-Auth-Key VALID_TOKEN
90
+ User-Agent:
91
+ - deepl-ruby/3.0.2 (darwin23) ruby/3.3.3
92
+ Accept-Encoding:
93
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
94
+ Accept:
95
+ - "*/*"
96
+ response:
97
+ status:
98
+ code: 200
99
+ message: OK
100
+ headers:
101
+ Date:
102
+ - Tue, 02 Jul 2024 14:52:05 GMT
103
+ Content-Type:
104
+ - application/json
105
+ Transfer-Encoding:
106
+ - chunked
107
+ Vary:
108
+ - Accept-Encoding
109
+ Access-Control-Allow-Origin:
110
+ - "*"
111
+ X-Cache-Status:
112
+ - MISS
113
+ Strict-Transport-Security:
114
+ - max-age=63072000; includeSubDomains; preload
115
+ Server-Timing:
116
+ - l7_lb_tls;dur=112, l7_lb_idle;dur=1, l7_lb_receive;dur=0, l7_lb_total;dur=115
117
+ Access-Control-Expose-Headers:
118
+ - Server-Timing, X-Trace-ID
119
+ X-Trace-Id:
120
+ - de53f558d38c43748bf83b27f4f0edc9
121
+ body:
122
+ encoding: ASCII-8BIT
123
+ string: '{"character_count":18593,"character_limit":1000000000000}'
124
+ recorded_at: Tue, 02 Jul 2024 14:52:05 GMT
125
+ - request:
126
+ method: get
127
+ uri: https://api.deepl.com/v2/usage
128
+ body:
129
+ encoding: UTF-8
130
+ string: "{}"
131
+ headers:
132
+ Authorization:
133
+ - DeepL-Auth-Key VALID_TOKEN
134
+ User-Agent:
135
+ - deepl-ruby/3.0.2 (darwin23) ruby/3.3.3
136
+ Content-Type:
137
+ - application/json
138
+ Accept-Encoding:
139
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
140
+ Accept:
141
+ - "*/*"
142
+ response:
143
+ status:
144
+ code: 200
145
+ message: OK
146
+ headers:
147
+ Date:
148
+ - Tue, 09 Jul 2024 01:35:37 GMT
149
+ Content-Type:
150
+ - application/json
151
+ Transfer-Encoding:
152
+ - chunked
153
+ Vary:
154
+ - Accept-Encoding
155
+ Access-Control-Allow-Origin:
156
+ - "*"
157
+ X-Cache-Status:
158
+ - MISS
159
+ Strict-Transport-Security:
160
+ - max-age=63072000; includeSubDomains; preload
161
+ Server-Timing:
162
+ - l7_lb_tls;dur=137, l7_lb_idle;dur=1, l7_lb_receive;dur=0, l7_lb_total;dur=140
163
+ Access-Control-Expose-Headers:
164
+ - Server-Timing, X-Trace-ID
165
+ X-Trace-Id:
166
+ - 543309f656244684bb59d30e9dc824b5
167
+ body:
168
+ encoding: ASCII-8BIT
169
+ string: '{"character_count":69328,"character_limit":1000000000000}'
170
+ recorded_at: Tue, 09 Jul 2024 01:35:37 GMT
171
+ recorded_with: VCR 6.2.0
@@ -0,0 +1,178 @@
1
+ # Copyright 2024 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::DocumentApi do
9
+ before do
10
+ VCR.turn_off!
11
+ WebMock.allow_net_connect!
12
+ end
13
+
14
+ after do
15
+ VCR.turn_on!
16
+ WebMock.disable_net_connect!
17
+ end
18
+
19
+ include_context 'with temp dir'
20
+
21
+ let(:default_lang_args) { { source_lang: 'EN', target_lang: 'DE' } }
22
+
23
+ describe '#translate_document' do
24
+ it 'Translates a document from a filepath' do
25
+ File.unlink(output_document_path)
26
+ source_lang = default_lang_args[:source_lang]
27
+ target_lang = default_lang_args[:target_lang]
28
+ example_doc_path = example_document_path(source_lang)
29
+ DeepL.document.translate_document(example_doc_path, output_document_path,
30
+ source_lang, target_lang, File.basename(example_doc_path),
31
+ {})
32
+ output_file_contents = File.read(output_document_path)
33
+
34
+ expect(example_document_translation(target_lang)).to eq(output_file_contents)
35
+ end
36
+
37
+ it 'Translates a document from a filepath without a filename' do
38
+ File.unlink(output_document_path)
39
+ source_lang = default_lang_args[:source_lang]
40
+ target_lang = default_lang_args[:target_lang]
41
+ example_doc_path = example_document_path(source_lang)
42
+ DeepL.document.translate_document(example_doc_path, output_document_path,
43
+ source_lang, target_lang)
44
+ output_file_contents = File.read(output_document_path)
45
+
46
+ expect(example_document_translation(target_lang)).to eq(output_file_contents)
47
+ end
48
+
49
+ it 'Translates a document using the lower-level methods and returns the correct status' do # rubocop:disable RSpec/ExampleLength
50
+ File.unlink(output_document_path)
51
+ source_lang = default_lang_args[:source_lang]
52
+ target_lang = default_lang_args[:target_lang]
53
+ example_doc_path = example_document_path(source_lang)
54
+
55
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
56
+ File.basename(example_doc_path), {})
57
+ doc_status = handle.wait_until_document_translation_finished
58
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
59
+ output_file_contents = File.read(output_document_path)
60
+
61
+ expect(example_document_translation(target_lang)).to eq(output_file_contents)
62
+ expect(doc_status.billed_characters).to eq(example_document_translation(source_lang).length)
63
+ expect(doc_status.status).to eq('done')
64
+ end
65
+
66
+ it 'Translates a document after retrying the upload once' do # rubocop:disable RSpec/ExampleLength
67
+ skip 'Only runs on mock server' if real_server?
68
+ File.unlink(output_document_path)
69
+ source_lang = default_lang_args[:source_lang]
70
+ target_lang = default_lang_args[:target_lang]
71
+ example_doc_path = example_document_path(source_lang)
72
+ doc_status = nil
73
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil, enable_ssl_verification: false,
74
+ read_timeout: 1.0)) do |_session|
75
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
76
+ File.basename(example_doc_path), {}, no_response_header(1))
77
+ doc_status = handle.wait_until_document_translation_finished
78
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
79
+ end
80
+ output_file_contents = File.read(output_document_path)
81
+
82
+ expect(output_file_contents).to eq(example_document_translation(target_lang))
83
+ expect(doc_status.billed_characters).to eq(example_document_translation(source_lang).length)
84
+ expect(doc_status.status).to eq('done')
85
+ end
86
+ end
87
+
88
+ it 'Translates a document after waiting' do # rubocop:disable RSpec/ExampleLength
89
+ skip 'Only runs on mock server' if real_server?
90
+ File.unlink(output_document_path)
91
+ source_lang = default_lang_args[:source_lang]
92
+ target_lang = default_lang_args[:target_lang]
93
+ example_doc_path = example_document_path(source_lang)
94
+ doc_status = nil
95
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil,
96
+ enable_ssl_verification: false)) do |_session|
97
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
98
+ File.basename(example_doc_path), {},
99
+ doc_translation_queue_time_header(2000).merge(doc_translation_translation_time_header(2000))) # rubocop:disable Layout/LineLength
100
+ doc_status = handle.wait_until_document_translation_finished
101
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
102
+ end
103
+ output_file_contents = File.read(output_document_path)
104
+
105
+ expect(output_file_contents).to eq(example_document_translation(target_lang))
106
+ expect(doc_status.billed_characters).to eq(example_document_translation(source_lang).length)
107
+ expect(doc_status.status).to eq('done')
108
+ end
109
+
110
+ it 'Translates a large document' do # rubocop:disable RSpec/ExampleLength
111
+ skip 'Only runs on mock server' if real_server?
112
+ File.unlink(output_document_path)
113
+ source_lang = default_lang_args[:source_lang]
114
+ target_lang = default_lang_args[:target_lang]
115
+ example_doc_path = example_large_document_path(source_lang)
116
+ doc_status = nil
117
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil,
118
+ enable_ssl_verification: false)) do |_session|
119
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
120
+ File.basename(example_doc_path), {})
121
+ doc_status = handle.wait_until_document_translation_finished
122
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
123
+ end
124
+ output_file_contents = File.read(output_document_path)
125
+
126
+ expect(output_file_contents).to eq(example_large_document_translation(target_lang))
127
+ expect(doc_status.billed_characters).to eq(
128
+ example_large_document_translation(source_lang).length
129
+ )
130
+ expect(doc_status.status).to eq('done')
131
+ end
132
+
133
+ it 'Translates a document with formality set' do # rubocop:disable RSpec/ExampleLength
134
+ skip 'Only runs on mock server' if real_server?
135
+ File.unlink(output_document_path)
136
+ source_lang = default_lang_args[:source_lang]
137
+ target_lang = default_lang_args[:target_lang]
138
+ example_doc_path = example_large_document_path(source_lang)
139
+ doc_status = nil
140
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil,
141
+ enable_ssl_verification: false)) do |_session|
142
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
143
+ File.basename(example_doc_path),
144
+ { 'formality' => 'prefer_more' })
145
+ doc_status = handle.wait_until_document_translation_finished
146
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
147
+ end
148
+ output_file_contents = File.read(output_document_path)
149
+
150
+ expect(output_file_contents).to eq(example_large_document_translation(target_lang))
151
+ expect(doc_status.billed_characters).to eq(
152
+ example_large_document_translation(source_lang).length
153
+ )
154
+ expect(doc_status.status).to eq('done')
155
+ end
156
+
157
+ it 'Translates a document with extra_body_parameters' do # rubocop:disable RSpec/ExampleLength
158
+ File.unlink(output_document_path)
159
+ source_lang = default_lang_args[:source_lang]
160
+ target_lang = default_lang_args[:target_lang]
161
+ example_doc_path = example_document_path(source_lang)
162
+
163
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
164
+ File.basename(example_doc_path),
165
+ {
166
+ extra_body_parameters: {
167
+ target_lang: 'FR',
168
+ debug: '1'
169
+ }
170
+ })
171
+ doc_status = handle.wait_until_document_translation_finished
172
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
173
+ output_file_contents = File.read(output_document_path)
174
+
175
+ expect(example_document_translation('FR')).to eq(output_file_contents)
176
+ expect(doc_status.status).to eq('done')
177
+ end
178
+ end
@@ -0,0 +1,170 @@
1
+ # Copyright 2024 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'securerandom'
7
+ require 'tempfile'
8
+
9
+ module IntegrationTestUtils # rubocop:disable Metrics/ModuleLength
10
+ EXAMPLE_TEXT = {
11
+ 'BG' => 'протонен лъч',
12
+ 'CS' => 'protonový paprsek',
13
+ 'DA' => 'protonstråle',
14
+ 'DE' => 'Protonenstrahl',
15
+ 'EL' => 'δέσμη πρωτονίων',
16
+ 'EN' => 'proton beam',
17
+ 'EN-US' => 'proton beam',
18
+ 'EN-GB' => 'proton beam',
19
+ 'ES' => 'haz de protones',
20
+ 'ET' => 'prootonikiirgus',
21
+ 'FI' => 'protonisäde',
22
+ 'FR' => 'faisceau de protons',
23
+ 'HU' => 'protonnyaláb',
24
+ 'ID' => 'berkas proton',
25
+ 'IT' => 'fascio di protoni',
26
+ 'JA' => '陽子ビーム',
27
+ 'KO' => '양성자 빔',
28
+ 'LT' => 'protonų spindulys',
29
+ 'LV' => 'protonu staru kūlis',
30
+ 'NB' => 'protonstråle',
31
+ 'NL' => 'protonenbundel',
32
+ 'PL' => 'wiązka protonów',
33
+ 'PT' => 'feixe de prótons',
34
+ 'PT-BR' => 'feixe de prótons',
35
+ 'PT-PT' => 'feixe de prótons',
36
+ 'RO' => 'fascicul de protoni',
37
+ 'RU' => 'протонный луч',
38
+ 'SK' => 'protónový lúč',
39
+ 'SL' => 'protonski žarek',
40
+ 'SV' => 'protonstråle',
41
+ 'TR' => 'proton ışını',
42
+ 'UK' => 'протонний пучок',
43
+ 'ZH' => '质子束'
44
+ }.freeze
45
+
46
+ def mock_server?
47
+ ENV.key?('DEEPL_MOCK_SERVER_PORT')
48
+ end
49
+
50
+ def mock_proxy_server?
51
+ ENV.key?('DEEPL_MOCK_PROXY_SERVER_PORT')
52
+ end
53
+
54
+ def real_server?
55
+ !mock_server?
56
+ end
57
+
58
+ def setup
59
+ @input_file = nil
60
+ @input_file_extension = nil
61
+ @output_file = nil
62
+ DeepL.configure do |config|
63
+ config.auth_key = 'your-api-token'
64
+ end
65
+ end
66
+
67
+ def teardown
68
+ unless @input_file.nil?
69
+ @input_file.close
70
+ @input_file.unlink
71
+ end
72
+ return if @output_file.nil?
73
+
74
+ @output_file.close
75
+ @output_file.unlink
76
+ end
77
+
78
+ def example_document_path(document_language)
79
+ setup_example_document(EXAMPLE_TEXT[document_language])
80
+ end
81
+
82
+ def example_large_document_path(document_language)
83
+ setup_example_document("#{EXAMPLE_TEXT[document_language]}\n" * 1000)
84
+ end
85
+
86
+ def setup_example_document(file_content)
87
+ @input_file_base_name = 'example_input_document' if @input_file_base_name.nil?
88
+ @input_file_extension = '.txt' if @input_file_extension.nil?
89
+ if @input_file.nil?
90
+ @input_file = Tempfile.new([@input_file_base_name, @input_file_extension])
91
+ @input_file.write(file_content)
92
+ @input_file.close
93
+ end
94
+ @input_file.path
95
+ end
96
+
97
+ def example_document_translation(document_language)
98
+ EXAMPLE_TEXT[document_language]
99
+ end
100
+
101
+ def example_large_document_translation(document_language)
102
+ "#{EXAMPLE_TEXT[document_language]}\n" * 1000
103
+ end
104
+
105
+ def output_document_path
106
+ @output_file = Tempfile.new('example_output_document') if @output_file.nil?
107
+ @output_file.path
108
+ end
109
+
110
+ # For detailed explanations of these header, check the deepl-mock README.md
111
+ def no_response_header(no_response_count)
112
+ { 'mock-server-session-no-response-count' => no_response_count.to_s,
113
+ 'mock-server-session' => SecureRandom.uuid }
114
+ end
115
+
116
+ def respond_with_429_header(response_count)
117
+ { 'mock-server-session-429-count' => response_count.to_s,
118
+ 'mock-server-session' => SecureRandom.uuid }
119
+ end
120
+
121
+ def set_character_limit_header(response_count) # rubocop:disable Naming/AccessorMethodName
122
+ { 'mock-server-session-init-character-limit' => response_count.to_s,
123
+ 'mock-server-session' => SecureRandom.uuid }
124
+ end
125
+
126
+ def set_document_limit_header(response_count) # rubocop:disable Naming/AccessorMethodName
127
+ { 'mock-server-session-init-document-limit' => response_count.to_s,
128
+ 'mock-server-session' => SecureRandom.uuid }
129
+ end
130
+
131
+ def set_team_document_limit_header(response_count) # rubocop:disable Naming/AccessorMethodName
132
+ { 'mock-server-session-init-team-document-limit' => response_count.to_s,
133
+ 'mock-server-session' => SecureRandom.uuid }
134
+ end
135
+
136
+ def fail_docs_header(response_count)
137
+ { 'mock-server-session-doc-failure' => response_count.to_s,
138
+ 'mock-server-session' => SecureRandom.uuid }
139
+ end
140
+
141
+ def doc_translation_queue_time_header(response_count)
142
+ { 'mock-server-session-doc-queue-time' => response_count.to_s,
143
+ 'mock-server-session' => SecureRandom.uuid }
144
+ end
145
+
146
+ def doc_translation_translation_time_header(response_count)
147
+ { 'mock-server-session-doc-translate-time' => response_count.to_s,
148
+ 'mock-server-session' => SecureRandom.uuid }
149
+ end
150
+
151
+ def expect_proxy_header(response_count)
152
+ { 'mock-server-session-expect-proxy' => response_count.to_s,
153
+ 'mock-server-session' => SecureRandom.uuid }
154
+ end
155
+ end
156
+
157
+ shared_context 'with temp dir' do
158
+ around do |example|
159
+ Dir.mktmpdir('deepl-rspec-') do |dir|
160
+ @temp_dir = dir
161
+ example.run
162
+ end
163
+ end
164
+
165
+ attr_reader :temp_dir, :input_file_base_name, :input_file_extension
166
+ end
167
+
168
+ RSpec.configure do |c|
169
+ c.include IntegrationTestUtils
170
+ end
@@ -0,0 +1,79 @@
1
+ # Copyright 2025 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::StyleRuleApi do
9
+ before do
10
+ VCR.turn_off!
11
+ WebMock.allow_net_connect!
12
+ end
13
+
14
+ after do
15
+ VCR.turn_on!
16
+ WebMock.disable_net_connect!
17
+ end
18
+
19
+ describe '#translate_with_style_rules' do
20
+ it 'when performing a request with style_id' do
21
+ skip 'Only runs on mock server' if real_server?
22
+
23
+ source_lang = 'DE'
24
+ target_lang = 'EN-US'
25
+ text = 'Hallo, Welt!'
26
+ style_id = 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4'
27
+
28
+ result = DeepL.translate(text, source_lang, target_lang, { style_rule: style_id })
29
+ expect(result).to be_a(DeepL::Resources::Text)
30
+ end
31
+
32
+ it 'when performing a request with style_rule object' do
33
+ skip 'Only runs on mock server' if real_server?
34
+
35
+ source_lang = 'DE'
36
+ target_lang = 'EN-US'
37
+ text = 'Hallo, Welt!'
38
+ style_rule = build_test_style_rule
39
+
40
+ result = DeepL.translate(text, source_lang, target_lang, { style_rule: style_rule })
41
+ expect(result).to be_a(DeepL::Resources::Text)
42
+ end
43
+ end
44
+
45
+ describe '#list_style_rules' do
46
+ it 'when requesting a list of all style rules' do
47
+ skip 'Only runs on mock server' if real_server?
48
+ style_rules = DeepL.style_rules.list(page: 0, page_size: 10, detailed: true)
49
+ expect(style_rules).to be_an(Array)
50
+ expect(style_rules.length).to eq(1)
51
+ expect(style_rules[0].style_id).to eq('dca2e053-8ae5-45e6-a0d2-881156e7f4e4')
52
+ expect(style_rules[0].name).to eq('Default Style Rule')
53
+ expect(style_rules[0].configured_rules).to be_a(DeepL::Resources::ConfiguredRules)
54
+ expect(style_rules[0].custom_instructions).to be_an(Array)
55
+ end
56
+
57
+ it 'when requesting a list of all style rules without detailed' do
58
+ skip 'Only runs on mock server' if real_server?
59
+ style_rules = DeepL.style_rules.list
60
+ expect(style_rules).to be_an(Array)
61
+ expect(style_rules.length).to eq(1)
62
+ expect(style_rules[0].style_id).to eq('dca2e053-8ae5-45e6-a0d2-881156e7f4e4')
63
+ expect(style_rules[0].configured_rules).to be_nil
64
+ expect(style_rules[0].custom_instructions).to be_nil
65
+ end
66
+ end
67
+
68
+ def build_test_style_rule
69
+ style_rule_data = {
70
+ 'style_id' => 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4',
71
+ 'name' => 'Default Style Rule',
72
+ 'creation_time' => '2025-01-01T00:00:00Z',
73
+ 'updated_time' => '2025-01-01T00:00:00Z',
74
+ 'language' => 'en',
75
+ 'version' => 1
76
+ }
77
+ DeepL::Resources::StyleRule.new(style_rule_data, nil, nil)
78
+ end
79
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright 2025 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe 'DeepL::Requests::Base extra_body_parameters type preservation' do
9
+ let(:api) { build_deepl_api }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
17
+ describe 'apply_extra_body_parameters_to_json' do
18
+ it 'preserves boolean true' do
19
+ request = DeepL::Requests::Translate.new(
20
+ api, 'test', 'EN', 'ES',
21
+ extra_body_parameters: { enable_beta_languages: true }
22
+ )
23
+
24
+ payload = {}
25
+ request.send(:apply_extra_body_parameters_to_json, payload)
26
+
27
+ expect(payload[:enable_beta_languages]).to be(true)
28
+ expect(payload[:enable_beta_languages]).to be_a(TrueClass)
29
+ end
30
+
31
+ it 'preserves boolean false' do
32
+ request = DeepL::Requests::Translate.new(
33
+ api, 'test', 'EN', 'ES',
34
+ extra_body_parameters: { some_flag: false }
35
+ )
36
+
37
+ payload = {}
38
+ request.send(:apply_extra_body_parameters_to_json, payload)
39
+
40
+ expect(payload[:some_flag]).to be(false)
41
+ expect(payload[:some_flag]).to be_a(FalseClass)
42
+ end
43
+
44
+ it 'preserves integers' do
45
+ request = DeepL::Requests::Translate.new(
46
+ api, 'test', 'EN', 'ES',
47
+ extra_body_parameters: { some_number: 42 }
48
+ )
49
+
50
+ payload = {}
51
+ request.send(:apply_extra_body_parameters_to_json, payload)
52
+
53
+ expect(payload[:some_number]).to eq(42)
54
+ expect(payload[:some_number]).to be_a(Integer)
55
+ end
56
+
57
+ it 'preserves strings' do
58
+ request = DeepL::Requests::Translate.new(
59
+ api, 'test', 'EN', 'ES',
60
+ extra_body_parameters: { some_string: 'hello' }
61
+ )
62
+
63
+ payload = {}
64
+ request.send(:apply_extra_body_parameters_to_json, payload)
65
+
66
+ expect(payload[:some_string]).to eq('hello')
67
+ expect(payload[:some_string]).to be_a(String)
68
+ end
69
+
70
+ it 'allows overriding standard parameters' do
71
+ request = DeepL::Requests::Translate.new(
72
+ api, 'test', 'EN', 'ES',
73
+ extra_body_parameters: { target_lang: 'FR' }
74
+ )
75
+
76
+ payload = { target_lang: 'ES' }
77
+ request.send(:apply_extra_body_parameters_to_json, payload)
78
+
79
+ expect(payload[:target_lang]).to eq('FR')
80
+ end
81
+ end
82
+ end