lingodotdev 0.1.0
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.
- checksums.yaml +7 -0
- data/.env.example +1 -0
- data/.github/workflows/publish.yml +63 -0
- data/README.md +485 -0
- data/Rakefile +4 -0
- data/lib/lingodotdev/version.rb +8 -0
- data/lib/lingodotdev.rb +938 -0
- data/sig/sdk/ruby.rbs +6 -0
- data/spec/lingo_dot_dev/configuration_spec.rb +146 -0
- data/spec/lingo_dot_dev/engine_spec.rb +688 -0
- data/spec/spec_helper.rb +36 -0
- metadata +112 -0
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe LingoDotDev::Engine do
|
|
6
|
+
let(:api_key) { ENV['LINGODOTDEV_API_KEY'] }
|
|
7
|
+
let(:api_url) { 'https://engine.lingo.dev' }
|
|
8
|
+
let(:target_locale) { 'es' }
|
|
9
|
+
let(:source_locale) { 'en' }
|
|
10
|
+
|
|
11
|
+
describe 'initialization' do
|
|
12
|
+
it 'creates an engine with valid api_key' do
|
|
13
|
+
engine = described_class.new(api_key: api_key)
|
|
14
|
+
expect(engine.config.api_key).to eq(api_key)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'creates engine with custom configuration' do
|
|
18
|
+
engine = described_class.new(
|
|
19
|
+
api_key: api_key,
|
|
20
|
+
api_url: 'https://custom.example.com',
|
|
21
|
+
batch_size: 50,
|
|
22
|
+
ideal_batch_item_size: 500
|
|
23
|
+
)
|
|
24
|
+
expect(engine.config.api_url).to eq('https://custom.example.com')
|
|
25
|
+
expect(engine.config.batch_size).to eq(50)
|
|
26
|
+
expect(engine.config.ideal_batch_item_size).to eq(500)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'allows block-based configuration' do
|
|
30
|
+
engine = described_class.new(api_key: api_key) do |config|
|
|
31
|
+
config.batch_size = 75
|
|
32
|
+
end
|
|
33
|
+
expect(engine.config.batch_size).to eq(75)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#localize_text' do
|
|
38
|
+
it 'localizes text to target locale' do
|
|
39
|
+
engine = described_class.new(api_key: api_key)
|
|
40
|
+
result = engine.localize_text(
|
|
41
|
+
'Hello world',
|
|
42
|
+
target_locale: target_locale
|
|
43
|
+
)
|
|
44
|
+
expect(result).to be_a(String)
|
|
45
|
+
expect(result.length).to be > 0
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'localizes text with source locale specified' do
|
|
49
|
+
engine = described_class.new(api_key: api_key)
|
|
50
|
+
result = engine.localize_text(
|
|
51
|
+
'Hello world',
|
|
52
|
+
target_locale: target_locale,
|
|
53
|
+
source_locale: source_locale
|
|
54
|
+
)
|
|
55
|
+
expect(result).to be_a(String)
|
|
56
|
+
expect(result.length).to be > 0
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'localizes text with fast flag' do
|
|
60
|
+
engine = described_class.new(api_key: api_key)
|
|
61
|
+
result = engine.localize_text(
|
|
62
|
+
'Hello world',
|
|
63
|
+
target_locale: target_locale,
|
|
64
|
+
fast: true
|
|
65
|
+
)
|
|
66
|
+
expect(result).to be_a(String)
|
|
67
|
+
expect(result.length).to be > 0
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'localizes text with reference context' do
|
|
71
|
+
engine = described_class.new(api_key: api_key)
|
|
72
|
+
reference = { context: 'greeting' }
|
|
73
|
+
result = engine.localize_text(
|
|
74
|
+
'Hello',
|
|
75
|
+
target_locale: target_locale,
|
|
76
|
+
reference: reference
|
|
77
|
+
)
|
|
78
|
+
expect(result).to be_a(String)
|
|
79
|
+
expect(result.length).to be > 0
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'supports progress callback block' do
|
|
83
|
+
engine = described_class.new(api_key: api_key)
|
|
84
|
+
progress_updates = []
|
|
85
|
+
result = engine.localize_text(
|
|
86
|
+
'Hello world',
|
|
87
|
+
target_locale: target_locale
|
|
88
|
+
) { |progress| progress_updates << progress }
|
|
89
|
+
expect(result).to be_a(String)
|
|
90
|
+
expect(progress_updates).not_to be_empty if result.length > 0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'supports on_progress callback parameter' do
|
|
94
|
+
engine = described_class.new(api_key: api_key)
|
|
95
|
+
progress_updates = []
|
|
96
|
+
result = engine.localize_text(
|
|
97
|
+
'Hello world',
|
|
98
|
+
target_locale: target_locale,
|
|
99
|
+
on_progress: proc { |progress| progress_updates << progress }
|
|
100
|
+
)
|
|
101
|
+
expect(result).to be_a(String)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'raises ValidationError when target_locale is nil' do
|
|
105
|
+
engine = described_class.new(api_key: api_key)
|
|
106
|
+
expect {
|
|
107
|
+
engine.localize_text('Hello', target_locale: nil)
|
|
108
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locale is required/)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'raises ValidationError when target_locale is empty' do
|
|
112
|
+
engine = described_class.new(api_key: api_key)
|
|
113
|
+
expect {
|
|
114
|
+
engine.localize_text('Hello', target_locale: '')
|
|
115
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locale is required/)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'raises ValidationError when text is nil' do
|
|
119
|
+
engine = described_class.new(api_key: api_key)
|
|
120
|
+
expect {
|
|
121
|
+
engine.localize_text(nil, target_locale: target_locale)
|
|
122
|
+
}.to raise_error(LingoDotDev::ValidationError, /Text cannot be nil/)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe '#localize_object' do
|
|
127
|
+
it 'localizes a hash object to target locale' do
|
|
128
|
+
engine = described_class.new(api_key: api_key)
|
|
129
|
+
obj = { greeting: 'Hello', farewell: 'Goodbye' }
|
|
130
|
+
result = engine.localize_object(
|
|
131
|
+
obj,
|
|
132
|
+
target_locale: target_locale
|
|
133
|
+
)
|
|
134
|
+
expect(result).to be_a(Hash)
|
|
135
|
+
expect(result.keys).to include('greeting', 'farewell')
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'localizes object with source locale' do
|
|
139
|
+
engine = described_class.new(api_key: api_key)
|
|
140
|
+
obj = { message: 'Hello world' }
|
|
141
|
+
result = engine.localize_object(
|
|
142
|
+
obj,
|
|
143
|
+
target_locale: target_locale,
|
|
144
|
+
source_locale: source_locale
|
|
145
|
+
)
|
|
146
|
+
expect(result).to be_a(Hash)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'localizes object with fast flag' do
|
|
150
|
+
engine = described_class.new(api_key: api_key)
|
|
151
|
+
obj = { greeting: 'Hi' }
|
|
152
|
+
result = engine.localize_object(
|
|
153
|
+
obj,
|
|
154
|
+
target_locale: target_locale,
|
|
155
|
+
fast: true
|
|
156
|
+
)
|
|
157
|
+
expect(result).to be_a(Hash)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'supports progress callback for objects' do
|
|
161
|
+
engine = described_class.new(api_key: api_key)
|
|
162
|
+
obj = { text: 'Hello' }
|
|
163
|
+
progress_updates = []
|
|
164
|
+
result = engine.localize_object(
|
|
165
|
+
obj,
|
|
166
|
+
target_locale: target_locale
|
|
167
|
+
) { |progress| progress_updates << progress }
|
|
168
|
+
expect(result).to be_a(Hash)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'raises ValidationError when target_locale is nil' do
|
|
172
|
+
engine = described_class.new(api_key: api_key)
|
|
173
|
+
expect {
|
|
174
|
+
engine.localize_object({ text: 'Hello' }, target_locale: nil)
|
|
175
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locale is required/)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'raises ValidationError when object is nil' do
|
|
179
|
+
engine = described_class.new(api_key: api_key)
|
|
180
|
+
expect {
|
|
181
|
+
engine.localize_object(nil, target_locale: target_locale)
|
|
182
|
+
}.to raise_error(LingoDotDev::ValidationError, /Object cannot be nil/)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it 'raises ValidationError when object is not a Hash' do
|
|
186
|
+
engine = described_class.new(api_key: api_key)
|
|
187
|
+
expect {
|
|
188
|
+
engine.localize_object('not a hash', target_locale: target_locale)
|
|
189
|
+
}.to raise_error(LingoDotDev::ValidationError, /Object must be a Hash/)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
describe '#localize_chat' do
|
|
194
|
+
it 'localizes chat messages to target locale' do
|
|
195
|
+
engine = described_class.new(api_key: api_key)
|
|
196
|
+
chat = [
|
|
197
|
+
{ name: 'user', text: 'Hello!' },
|
|
198
|
+
{ name: 'assistant', text: 'Hi there!' }
|
|
199
|
+
]
|
|
200
|
+
result = engine.localize_chat(
|
|
201
|
+
chat,
|
|
202
|
+
target_locale: target_locale
|
|
203
|
+
)
|
|
204
|
+
expect(result).to be_an(Array)
|
|
205
|
+
expect(result.length).to eq(2)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it 'localizes chat with source locale' do
|
|
209
|
+
engine = described_class.new(api_key: api_key)
|
|
210
|
+
chat = [{ name: 'user', text: 'Hello' }]
|
|
211
|
+
result = engine.localize_chat(
|
|
212
|
+
chat,
|
|
213
|
+
target_locale: target_locale,
|
|
214
|
+
source_locale: source_locale
|
|
215
|
+
)
|
|
216
|
+
expect(result).to be_an(Array)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it 'localizes chat with fast flag' do
|
|
220
|
+
engine = described_class.new(api_key: api_key)
|
|
221
|
+
chat = [{ name: 'user', text: 'Hi' }]
|
|
222
|
+
result = engine.localize_chat(
|
|
223
|
+
chat,
|
|
224
|
+
target_locale: target_locale,
|
|
225
|
+
fast: true
|
|
226
|
+
)
|
|
227
|
+
expect(result).to be_an(Array)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'supports progress callback for chat' do
|
|
231
|
+
engine = described_class.new(api_key: api_key)
|
|
232
|
+
chat = [{ name: 'user', text: 'Hello' }]
|
|
233
|
+
progress_updates = []
|
|
234
|
+
result = engine.localize_chat(
|
|
235
|
+
chat,
|
|
236
|
+
target_locale: target_locale
|
|
237
|
+
) { |progress| progress_updates << progress }
|
|
238
|
+
expect(result).to be_an(Array)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it 'raises ValidationError when target_locale is nil' do
|
|
242
|
+
engine = described_class.new(api_key: api_key)
|
|
243
|
+
expect {
|
|
244
|
+
engine.localize_chat([], target_locale: nil)
|
|
245
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locale is required/)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'raises ValidationError when chat is nil' do
|
|
249
|
+
engine = described_class.new(api_key: api_key)
|
|
250
|
+
expect {
|
|
251
|
+
engine.localize_chat(nil, target_locale: target_locale)
|
|
252
|
+
}.to raise_error(LingoDotDev::ValidationError, /Chat cannot be nil/)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it 'raises ValidationError when chat is not an Array' do
|
|
256
|
+
engine = described_class.new(api_key: api_key)
|
|
257
|
+
expect {
|
|
258
|
+
engine.localize_chat({}, target_locale: target_locale)
|
|
259
|
+
}.to raise_error(LingoDotDev::ValidationError, /Chat must be an Array/)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'raises ValidationError when chat messages lack name' do
|
|
263
|
+
engine = described_class.new(api_key: api_key)
|
|
264
|
+
expect {
|
|
265
|
+
engine.localize_chat(
|
|
266
|
+
[{ text: 'Hello' }],
|
|
267
|
+
target_locale: target_locale
|
|
268
|
+
)
|
|
269
|
+
}.to raise_error(LingoDotDev::ValidationError, /:name and :text keys/)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it 'raises ValidationError when chat messages lack text' do
|
|
273
|
+
engine = described_class.new(api_key: api_key)
|
|
274
|
+
expect {
|
|
275
|
+
engine.localize_chat(
|
|
276
|
+
[{ name: 'user' }],
|
|
277
|
+
target_locale: target_locale
|
|
278
|
+
)
|
|
279
|
+
}.to raise_error(LingoDotDev::ValidationError, /:name and :text keys/)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
describe '#localize_html' do
|
|
284
|
+
it 'correctly extracts, localizes, and reconstructs HTML content' do
|
|
285
|
+
input_html = <<~HTML.strip
|
|
286
|
+
<!DOCTYPE html>
|
|
287
|
+
<html>
|
|
288
|
+
<head>
|
|
289
|
+
<title>Test Page</title>
|
|
290
|
+
<meta name="description" content="Page description">
|
|
291
|
+
</head>
|
|
292
|
+
<body>
|
|
293
|
+
standalone text
|
|
294
|
+
<div>
|
|
295
|
+
<h1>Hello World</h1>
|
|
296
|
+
<p>
|
|
297
|
+
This is a paragraph with
|
|
298
|
+
<a href="/test" title="Link title">a link</a>
|
|
299
|
+
and an
|
|
300
|
+
<img src="/test.jpg" alt="Test image">
|
|
301
|
+
and some <b>bold <i>and italic</i></b> text.
|
|
302
|
+
</p>
|
|
303
|
+
<script>
|
|
304
|
+
const doNotTranslate = "this text should be ignored";
|
|
305
|
+
</script>
|
|
306
|
+
<input type="text" placeholder="Enter text">
|
|
307
|
+
</div>
|
|
308
|
+
</body>
|
|
309
|
+
</html>
|
|
310
|
+
HTML
|
|
311
|
+
|
|
312
|
+
engine = described_class.new(api_key: api_key)
|
|
313
|
+
extracted_content = nil
|
|
314
|
+
call_params = nil
|
|
315
|
+
|
|
316
|
+
allow(engine).to receive(:localize_raw) do |content, params, &block|
|
|
317
|
+
extracted_content = content
|
|
318
|
+
call_params = params
|
|
319
|
+
localized = {}
|
|
320
|
+
content.each do |key, value|
|
|
321
|
+
localized[key] = "ES:#{value}"
|
|
322
|
+
end
|
|
323
|
+
localized
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
result = engine.localize_html(input_html, target_locale: 'es', source_locale: 'en')
|
|
327
|
+
|
|
328
|
+
expect(call_params[:target_locale]).to eq('es')
|
|
329
|
+
expect(call_params[:source_locale]).to eq('en')
|
|
330
|
+
expect(extracted_content).to include(
|
|
331
|
+
'head/0/0' => 'Test Page',
|
|
332
|
+
'head/1#content' => 'Page description',
|
|
333
|
+
'body/0' => 'standalone text',
|
|
334
|
+
'body/1/0/0' => 'Hello World',
|
|
335
|
+
'body/1/1/0' => 'This is a paragraph with',
|
|
336
|
+
'body/1/1/1#title' => 'Link title',
|
|
337
|
+
'body/1/1/1/0' => 'a link',
|
|
338
|
+
'body/1/1/2' => 'and an',
|
|
339
|
+
'body/1/1/3#alt' => 'Test image',
|
|
340
|
+
'body/1/1/4' => 'and some',
|
|
341
|
+
'body/1/1/5/0' => 'bold',
|
|
342
|
+
'body/1/1/5/1/0' => 'and italic',
|
|
343
|
+
'body/1/1/6' => 'text.',
|
|
344
|
+
'body/1/3#placeholder' => 'Enter text'
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
expect(result).to include('lang="es"')
|
|
348
|
+
expect(result).to include('<title>ES:Test Page</title>')
|
|
349
|
+
expect(result).to include('content="ES:Page description"')
|
|
350
|
+
expect(result).to include('>ES:standalone text<')
|
|
351
|
+
expect(result).to include('<h1>ES:Hello World</h1>')
|
|
352
|
+
expect(result).to include('title="ES:Link title"')
|
|
353
|
+
expect(result).to include('alt="ES:Test image"')
|
|
354
|
+
expect(result).to include('placeholder="ES:Enter text"')
|
|
355
|
+
expect(result).to include('const doNotTranslate = "this text should be ignored"')
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it 'localizes HTML with source locale' do
|
|
359
|
+
html = '<html><head><title>Hello</title></head><body><p>World</p></body></html>'
|
|
360
|
+
engine = described_class.new(api_key: api_key)
|
|
361
|
+
call_params = nil
|
|
362
|
+
allow(engine).to receive(:localize_raw) do |content, params, &block|
|
|
363
|
+
call_params = params
|
|
364
|
+
{ 'head/0/0' => 'Hola', 'body/0/0' => 'Mundo' }
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
result = engine.localize_html(html, target_locale: 'es', source_locale: 'en')
|
|
368
|
+
|
|
369
|
+
expect(call_params[:source_locale]).to eq('en')
|
|
370
|
+
expect(call_params[:target_locale]).to eq('es')
|
|
371
|
+
expect(result).to include('lang="es"')
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
it 'localizes HTML with fast flag' do
|
|
375
|
+
html = '<html><head><title>Hello</title></head><body><p>World</p></body></html>'
|
|
376
|
+
engine = described_class.new(api_key: api_key)
|
|
377
|
+
call_params = nil
|
|
378
|
+
allow(engine).to receive(:localize_raw) do |content, params, &block|
|
|
379
|
+
call_params = params
|
|
380
|
+
{ 'head/0/0' => 'Hola', 'body/0/0' => 'Mundo' }
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
result = engine.localize_html(html, target_locale: 'es', fast: true)
|
|
384
|
+
|
|
385
|
+
expect(call_params[:fast]).to eq(true)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
it 'supports progress callback for HTML' do
|
|
389
|
+
html = '<html><head><title>Hello</title></head><body><p>World</p></body></html>'
|
|
390
|
+
engine = described_class.new(api_key: api_key)
|
|
391
|
+
progress_updates = []
|
|
392
|
+
allow(engine).to receive(:localize_raw) do |content, params, &block|
|
|
393
|
+
block&.call(100, {}, {})
|
|
394
|
+
{ 'head/0/0' => 'Hola', 'body/0/0' => 'Mundo' }
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
result = engine.localize_html(html, target_locale: 'es') { |progress| progress_updates << progress }
|
|
398
|
+
|
|
399
|
+
expect(progress_updates).not_to be_empty
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
it 'raises ValidationError when target_locale is nil' do
|
|
403
|
+
engine = described_class.new(api_key: api_key)
|
|
404
|
+
expect {
|
|
405
|
+
engine.localize_html('<html></html>', target_locale: nil)
|
|
406
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locale is required/)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
it 'raises ValidationError when target_locale is empty' do
|
|
410
|
+
engine = described_class.new(api_key: api_key)
|
|
411
|
+
expect {
|
|
412
|
+
engine.localize_html('<html></html>', target_locale: '')
|
|
413
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locale is required/)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it 'raises ValidationError when html is nil' do
|
|
417
|
+
engine = described_class.new(api_key: api_key)
|
|
418
|
+
expect {
|
|
419
|
+
engine.localize_html(nil, target_locale: 'es')
|
|
420
|
+
}.to raise_error(LingoDotDev::ValidationError, /HTML cannot be nil/)
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
describe '#batch_localize_text' do
|
|
425
|
+
it 'batch localizes text to multiple locales' do
|
|
426
|
+
engine = described_class.new(api_key: api_key)
|
|
427
|
+
results = engine.batch_localize_text(
|
|
428
|
+
'Hello world',
|
|
429
|
+
target_locales: ['es', 'fr']
|
|
430
|
+
)
|
|
431
|
+
expect(results).to be_an(Array)
|
|
432
|
+
expect(results.length).to eq(2)
|
|
433
|
+
expect(results.all? { |r| r.is_a?(String) }).to be true
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it 'batch localizes with source locale' do
|
|
437
|
+
engine = described_class.new(api_key: api_key)
|
|
438
|
+
results = engine.batch_localize_text(
|
|
439
|
+
'Hello',
|
|
440
|
+
target_locales: ['es', 'de'],
|
|
441
|
+
source_locale: source_locale
|
|
442
|
+
)
|
|
443
|
+
expect(results).to be_an(Array)
|
|
444
|
+
expect(results.length).to eq(2)
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
it 'batch localizes with fast flag' do
|
|
448
|
+
engine = described_class.new(api_key: api_key)
|
|
449
|
+
results = engine.batch_localize_text(
|
|
450
|
+
'Hi',
|
|
451
|
+
target_locales: ['es', 'fr'],
|
|
452
|
+
fast: true
|
|
453
|
+
)
|
|
454
|
+
expect(results).to be_an(Array)
|
|
455
|
+
expect(results.length).to eq(2)
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
it 'batch localizes concurrently' do
|
|
459
|
+
engine = described_class.new(api_key: api_key)
|
|
460
|
+
results = engine.batch_localize_text(
|
|
461
|
+
'Hello world',
|
|
462
|
+
target_locales: ['es', 'fr', 'de'],
|
|
463
|
+
concurrent: true
|
|
464
|
+
)
|
|
465
|
+
expect(results).to be_an(Array)
|
|
466
|
+
expect(results.length).to eq(3)
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
it 'raises ValidationError when text is nil' do
|
|
470
|
+
engine = described_class.new(api_key: api_key)
|
|
471
|
+
expect {
|
|
472
|
+
engine.batch_localize_text(nil, target_locales: ['es'])
|
|
473
|
+
}.to raise_error(LingoDotDev::ValidationError, /Text cannot be nil/)
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
it 'raises ValidationError when target_locales is not an Array' do
|
|
477
|
+
engine = described_class.new(api_key: api_key)
|
|
478
|
+
expect {
|
|
479
|
+
engine.batch_localize_text('Hello', target_locales: 'es')
|
|
480
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locales must be an Array/)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
it 'raises ValidationError when target_locales is empty' do
|
|
484
|
+
engine = described_class.new(api_key: api_key)
|
|
485
|
+
expect {
|
|
486
|
+
engine.batch_localize_text('Hello', target_locales: [])
|
|
487
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locales cannot be empty/)
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
describe '#batch_localize_objects' do
|
|
492
|
+
it 'batch localizes multiple objects to same locale' do
|
|
493
|
+
engine = described_class.new(api_key: api_key)
|
|
494
|
+
objects = [
|
|
495
|
+
{ greeting: 'Hello' },
|
|
496
|
+
{ farewell: 'Goodbye' }
|
|
497
|
+
]
|
|
498
|
+
results = engine.batch_localize_objects(
|
|
499
|
+
objects,
|
|
500
|
+
target_locale: target_locale
|
|
501
|
+
)
|
|
502
|
+
expect(results).to be_an(Array)
|
|
503
|
+
expect(results.length).to eq(2)
|
|
504
|
+
expect(results.all? { |r| r.is_a?(Hash) }).to be true
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
it 'batch localizes objects with source locale' do
|
|
508
|
+
engine = described_class.new(api_key: api_key)
|
|
509
|
+
objects = [{ text: 'Hello' }]
|
|
510
|
+
results = engine.batch_localize_objects(
|
|
511
|
+
objects,
|
|
512
|
+
target_locale: target_locale,
|
|
513
|
+
source_locale: source_locale
|
|
514
|
+
)
|
|
515
|
+
expect(results).to be_an(Array)
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
it 'batch localizes objects with fast flag' do
|
|
519
|
+
engine = described_class.new(api_key: api_key)
|
|
520
|
+
objects = [{ text: 'Hi' }]
|
|
521
|
+
results = engine.batch_localize_objects(
|
|
522
|
+
objects,
|
|
523
|
+
target_locale: target_locale,
|
|
524
|
+
fast: true
|
|
525
|
+
)
|
|
526
|
+
expect(results).to be_an(Array)
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
it 'batch localizes objects concurrently' do
|
|
530
|
+
engine = described_class.new(api_key: api_key)
|
|
531
|
+
objects = [
|
|
532
|
+
{ text: 'Hello' },
|
|
533
|
+
{ text: 'Hi' },
|
|
534
|
+
{ text: 'Hey' }
|
|
535
|
+
]
|
|
536
|
+
results = engine.batch_localize_objects(
|
|
537
|
+
objects,
|
|
538
|
+
target_locale: target_locale,
|
|
539
|
+
concurrent: true
|
|
540
|
+
)
|
|
541
|
+
expect(results).to be_an(Array)
|
|
542
|
+
expect(results.length).to eq(3)
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
it 'raises ValidationError when objects is not an Array' do
|
|
546
|
+
engine = described_class.new(api_key: api_key)
|
|
547
|
+
expect {
|
|
548
|
+
engine.batch_localize_objects(
|
|
549
|
+
{ text: 'Hello' },
|
|
550
|
+
target_locale: target_locale
|
|
551
|
+
)
|
|
552
|
+
}.to raise_error(LingoDotDev::ValidationError, /Objects must be an Array/)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
it 'raises ValidationError when objects is empty' do
|
|
556
|
+
engine = described_class.new(api_key: api_key)
|
|
557
|
+
expect {
|
|
558
|
+
engine.batch_localize_objects([], target_locale: target_locale)
|
|
559
|
+
}.to raise_error(LingoDotDev::ValidationError, /Objects cannot be empty/)
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
it 'raises ValidationError when target_locale is nil' do
|
|
563
|
+
engine = described_class.new(api_key: api_key)
|
|
564
|
+
expect {
|
|
565
|
+
engine.batch_localize_objects(
|
|
566
|
+
[{ text: 'Hello' }],
|
|
567
|
+
target_locale: nil
|
|
568
|
+
)
|
|
569
|
+
}.to raise_error(LingoDotDev::ValidationError, /Target locale is required/)
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
it 'raises ValidationError when object is not a Hash' do
|
|
573
|
+
engine = described_class.new(api_key: api_key)
|
|
574
|
+
expect {
|
|
575
|
+
engine.batch_localize_objects(
|
|
576
|
+
['not a hash'],
|
|
577
|
+
target_locale: target_locale
|
|
578
|
+
)
|
|
579
|
+
}.to raise_error(LingoDotDev::ValidationError, /Each object must be a Hash/)
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
describe '#recognize_locale' do
|
|
584
|
+
it 'recognizes locale of given text' do
|
|
585
|
+
engine = described_class.new(api_key: api_key)
|
|
586
|
+
locale = engine.recognize_locale('Hello world')
|
|
587
|
+
expect(locale).to be_a(String)
|
|
588
|
+
expect(locale.length).to be > 0
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
it 'raises ValidationError when text is nil' do
|
|
592
|
+
engine = described_class.new(api_key: api_key)
|
|
593
|
+
expect {
|
|
594
|
+
engine.recognize_locale(nil)
|
|
595
|
+
}.to raise_error(LingoDotDev::ValidationError, /Text cannot be empty/)
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
it 'raises ValidationError when text is empty' do
|
|
599
|
+
engine = described_class.new(api_key: api_key)
|
|
600
|
+
expect {
|
|
601
|
+
engine.recognize_locale('')
|
|
602
|
+
}.to raise_error(LingoDotDev::ValidationError, /Text cannot be empty/)
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
it 'raises ValidationError when text is only whitespace' do
|
|
606
|
+
engine = described_class.new(api_key: api_key)
|
|
607
|
+
expect {
|
|
608
|
+
engine.recognize_locale(' ')
|
|
609
|
+
}.to raise_error(LingoDotDev::ValidationError, /Text cannot be empty/)
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
describe '#whoami' do
|
|
614
|
+
it 'returns user information' do
|
|
615
|
+
engine = described_class.new(api_key: api_key)
|
|
616
|
+
result = engine.whoami
|
|
617
|
+
if result
|
|
618
|
+
expect(result).to be_a(Hash)
|
|
619
|
+
expect(result).to include(:email, :id)
|
|
620
|
+
end
|
|
621
|
+
end
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
describe '.quick_translate' do
|
|
625
|
+
it 'quickly translates a string' do
|
|
626
|
+
result = described_class.quick_translate(
|
|
627
|
+
'Hello world',
|
|
628
|
+
api_key: api_key,
|
|
629
|
+
target_locale: target_locale
|
|
630
|
+
)
|
|
631
|
+
expect(result).to be_a(String)
|
|
632
|
+
expect(result.length).to be > 0
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
it 'quickly translates a hash with concurrent processing' do
|
|
636
|
+
result = described_class.quick_translate(
|
|
637
|
+
{ greeting: 'Hello', farewell: 'Goodbye' },
|
|
638
|
+
api_key: api_key,
|
|
639
|
+
target_locale: target_locale
|
|
640
|
+
)
|
|
641
|
+
expect(result).to be_a(Hash)
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
it 'raises ValidationError for invalid content type' do
|
|
645
|
+
expect {
|
|
646
|
+
described_class.quick_translate(
|
|
647
|
+
123,
|
|
648
|
+
api_key: api_key,
|
|
649
|
+
target_locale: target_locale
|
|
650
|
+
)
|
|
651
|
+
}.to raise_error(LingoDotDev::ValidationError, /Content must be a String or Hash/)
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
describe '.quick_batch_translate' do
|
|
656
|
+
it 'quickly batch translates a string to multiple locales' do
|
|
657
|
+
results = described_class.quick_batch_translate(
|
|
658
|
+
'Hello',
|
|
659
|
+
api_key: api_key,
|
|
660
|
+
target_locales: ['es', 'fr']
|
|
661
|
+
)
|
|
662
|
+
expect(results).to be_an(Array)
|
|
663
|
+
expect(results.length).to eq(2)
|
|
664
|
+
expect(results.all? { |r| r.is_a?(String) }).to be true
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
it 'quickly batch translates a hash to multiple locales' do
|
|
668
|
+
results = described_class.quick_batch_translate(
|
|
669
|
+
{ greeting: 'Hello' },
|
|
670
|
+
api_key: api_key,
|
|
671
|
+
target_locales: ['es', 'fr']
|
|
672
|
+
)
|
|
673
|
+
expect(results).to be_an(Array)
|
|
674
|
+
expect(results.length).to eq(2)
|
|
675
|
+
expect(results.all? { |r| r.is_a?(Hash) }).to be true
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
it 'raises ValidationError for invalid content type' do
|
|
679
|
+
expect {
|
|
680
|
+
described_class.quick_batch_translate(
|
|
681
|
+
123,
|
|
682
|
+
api_key: api_key,
|
|
683
|
+
target_locales: ['es']
|
|
684
|
+
)
|
|
685
|
+
}.to raise_error(LingoDotDev::ValidationError, /Content must be a String or Hash/)
|
|
686
|
+
end
|
|
687
|
+
end
|
|
688
|
+
end
|