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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 14034dfe2c60a19185f6097951589bcf8e34791d10bb4ac8cc2ed120702d061b
4
+ data.tar.gz: 1405a8002ff6688494158e9da901bf58c7f1c60f144a1c5c287631a8cb4fc87e
5
+ SHA512:
6
+ metadata.gz: b4e21ba8cb795eaf703440583d42370ea6750b43a215a5dba2a4a908e19e4ef21b0afec9bc6b45b4ca382b32e13f0ab8dc1c33ab102dda6274f4fac95a5bab9d
7
+ data.tar.gz: 8b9efcb6a126f0c38f146c5b2125debd4fa14e2ab5a30baefec6703aefd7166330fdc1bc4f8b171b9a6b41697fad47c62e42bcb12e5d4b9e9734510080b30ad4
data/.env.example ADDED
@@ -0,0 +1 @@
1
+ LINGODOTDEV_API_KEY=your_api_key_here
@@ -0,0 +1,63 @@
1
+ name: Publish Gem
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: '3.2'
23
+
24
+ - name: Determine versions and decide if publish is needed
25
+ id: versions
26
+ shell: bash
27
+ run: |
28
+ set -euo pipefail
29
+
30
+ # Read gem name from gemspec
31
+ gem_name=$(ruby -e "require 'rubygems'; spec = Gem::Specification.load('sdk-ruby.gemspec'); puts spec.name")
32
+
33
+ # Read local version from the version file
34
+ local_version=$(ruby -e "require_relative 'lib/lingodotdev/version'; puts LingoDotDev::VERSION")
35
+
36
+ # Fetch latest published version from RubyGems (empty if not published yet)
37
+ remote_json=$(curl -sS "https://rubygems.org/api/v1/gems/$gem_name.json" || true)
38
+ remote_version=$(ruby -rjson -e 'puts JSON.parse(STDIN.read)["version"] rescue ""' <<< "$remote_json")
39
+
40
+ echo "gem_name=$gem_name" >> "$GITHUB_OUTPUT"
41
+ echo "local_version=$local_version" >> "$GITHUB_OUTPUT"
42
+ echo "remote_version=$remote_version" >> "$GITHUB_OUTPUT"
43
+
44
+ if [[ "$local_version" == "$remote_version" ]]; then
45
+ echo "should_publish=false" >> "$GITHUB_OUTPUT"
46
+ echo "Version $local_version already on RubyGems. Skipping publish."
47
+ else
48
+ echo "should_publish=true" >> "$GITHUB_OUTPUT"
49
+ echo "Will publish $gem_name $local_version to RubyGems."
50
+ fi
51
+
52
+ - name: Build gem
53
+ if: steps.versions.outputs.should_publish == 'true'
54
+ run: |
55
+ gem build sdk-ruby.gemspec
56
+
57
+ - name: Publish to RubyGems
58
+ if: steps.versions.outputs.should_publish == 'true'
59
+ env:
60
+ GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
61
+ run: |
62
+ gem push "${{ steps.versions.outputs.gem_name }}-${{ steps.versions.outputs.local_version }}.gem"
63
+
data/README.md ADDED
@@ -0,0 +1,485 @@
1
+ # Lingo.dev Ruby SDK
2
+
3
+ A Ruby SDK for integrating with the [Lingo.dev](https://lingo.dev) localization and translation API. Localize text, objects, and chat messages with support for batch operations, progress tracking, and concurrent processing.
4
+
5
+ ## Overview
6
+
7
+ The Lingo.dev Ruby SDK provides a simple and powerful interface for localizing content in your Ruby applications. It supports:
8
+
9
+ - Text, object (Hash), and chat message localization
10
+ - Batch operations for multiple locales or objects
11
+ - Automatic locale recognition
12
+ - Progress tracking with callbacks
13
+ - Concurrent processing for improved performance
14
+ - Comprehensive error handling and validation
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'lingodotdev'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ ```bash
27
+ bundle install
28
+ ```
29
+
30
+ Or install it yourself with:
31
+
32
+ ```bash
33
+ gem install lingodotdev
34
+ ```
35
+
36
+ ## Quick start
37
+
38
+ ```ruby
39
+ require 'lingodotdev'
40
+
41
+ # Create an engine instance
42
+ engine = LingoDotDev::Engine.new(api_key: 'your-api-key')
43
+
44
+ # Localize text
45
+ result = engine.localize_text('Hello world', target_locale: 'es')
46
+ puts result # => "Hola mundo"
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ### Basic text localization
52
+
53
+ Localize a simple string to a target locale:
54
+
55
+ ```ruby
56
+ engine = LingoDotDev::Engine.new(api_key: 'your-api-key')
57
+
58
+ result = engine.localize_text(
59
+ 'Hello world',
60
+ target_locale: 'es'
61
+ )
62
+ # => "Hola mundo"
63
+
64
+ # With source locale specified
65
+ result = engine.localize_text(
66
+ 'Hello world',
67
+ target_locale: 'fr',
68
+ source_locale: 'en'
69
+ )
70
+ # => "Bonjour le monde"
71
+
72
+ # Fast mode for quicker results
73
+ result = engine.localize_text(
74
+ 'Hello world',
75
+ target_locale: 'de',
76
+ fast: true
77
+ )
78
+ # => "Hallo Welt"
79
+ ```
80
+
81
+ ### Object localization
82
+
83
+ Localize all string values in a Hash:
84
+
85
+ ```ruby
86
+ data = {
87
+ greeting: 'Hello',
88
+ farewell: 'Goodbye',
89
+ message: 'Welcome to our app'
90
+ }
91
+
92
+ result = engine.localize_object(data, target_locale: 'es')
93
+ # => {
94
+ # greeting: "Hola",
95
+ # farewell: "Adiós",
96
+ # message: "Bienvenido a nuestra aplicación"
97
+ # }
98
+ ```
99
+
100
+ ### Chat message localization
101
+
102
+ Localize chat conversations while preserving structure:
103
+
104
+ ```ruby
105
+ chat = [
106
+ { name: 'user', text: 'Hello!' },
107
+ { name: 'assistant', text: 'Hi there! How can I help you?' },
108
+ { name: 'user', text: 'I need some information.' }
109
+ ]
110
+
111
+ result = engine.localize_chat(chat, target_locale: 'ja')
112
+ # => [
113
+ # { name: 'user', text: 'こんにちは!' },
114
+ # { name: 'assistant', text: 'こんにちは!どのようにお手伝いできますか?' },
115
+ # { name: 'user', text: '情報が必要です。' }
116
+ # ]
117
+ ```
118
+
119
+ ### HTML document localization
120
+
121
+ Localize HTML documents while preserving structure and formatting:
122
+
123
+ ```ruby
124
+ html = <<~HTML
125
+ <html>
126
+ <head>
127
+ <title>Welcome</title>
128
+ <meta name="description" content="Page description">
129
+ </head>
130
+ <body>
131
+ <h1>Hello World</h1>
132
+ <p>This is a paragraph with <a href="/test" title="Link title">a link</a>.</p>
133
+ <img src="/image.jpg" alt="Test image">
134
+ <input type="text" placeholder="Enter text">
135
+ </body>
136
+ </html>
137
+ HTML
138
+
139
+ result = engine.localize_html(html, target_locale: 'es')
140
+ # => HTML with localized text content and attributes, lang="es" attribute updated
141
+ ```
142
+
143
+ The method handles:
144
+
145
+ - Text content in all elements
146
+ - Localizable attributes: `meta` content, `img` alt, `input` placeholder, `a` title
147
+ - Preserves HTML structure and formatting
148
+ - Ignores content inside `script` and `style` tags
149
+ - Updates the `lang` attribute on the `html` element
150
+
151
+ ### Batch localization to multiple locales
152
+
153
+ Localize the same content to multiple target locales:
154
+
155
+ ```ruby
156
+ # Batch localize text
157
+ results = engine.batch_localize_text(
158
+ 'Hello world',
159
+ target_locales: ['es', 'fr', 'de']
160
+ )
161
+ # => ["Hola mundo", "Bonjour le monde", "Hallo Welt"]
162
+
163
+ # With concurrent processing for better performance
164
+ results = engine.batch_localize_text(
165
+ 'Hello world',
166
+ target_locales: ['es', 'fr', 'de', 'ja'],
167
+ concurrent: true
168
+ )
169
+ ```
170
+
171
+ ### Batch localization of multiple objects
172
+
173
+ Localize multiple objects to the same target locale:
174
+
175
+ ```ruby
176
+ objects = [
177
+ { title: 'Welcome', body: 'Hello there' },
178
+ { title: 'About', body: 'Learn more about us' },
179
+ { title: 'Contact', body: 'Get in touch' }
180
+ ]
181
+
182
+ results = engine.batch_localize_objects(
183
+ objects,
184
+ target_locale: 'es',
185
+ concurrent: true
186
+ )
187
+ # => [
188
+ # { title: "Bienvenido", body: "Hola" },
189
+ # { title: "Acerca de", body: "Aprende más sobre nosotros" },
190
+ # { title: "Contacto", body: "Ponte en contacto" }
191
+ # ]
192
+ ```
193
+
194
+ ### Locale recognition
195
+
196
+ Automatically detect the locale of a given text:
197
+
198
+ ```ruby
199
+ locale = engine.recognize_locale('Bonjour le monde')
200
+ # => "fr"
201
+
202
+ locale = engine.recognize_locale('こんにちは世界')
203
+ # => "ja"
204
+ ```
205
+
206
+ ### Progress tracking
207
+
208
+ Monitor localization progress with callbacks:
209
+
210
+ ```ruby
211
+ # Using a block
212
+ result = engine.localize_text('Hello world', target_locale: 'es') do |progress|
213
+ puts "Progress: #{progress}%"
214
+ end
215
+
216
+ # Using the on_progress parameter
217
+ callback = proc { |progress| puts "Progress: #{progress}%" }
218
+ result = engine.localize_text(
219
+ 'Hello world',
220
+ target_locale: 'es',
221
+ on_progress: callback
222
+ )
223
+ ```
224
+
225
+ ### Reference context
226
+
227
+ Provide additional context to improve translation accuracy:
228
+
229
+ ```ruby
230
+ reference = {
231
+ context: 'greeting',
232
+ tone: 'formal',
233
+ domain: 'business'
234
+ }
235
+
236
+ result = engine.localize_text(
237
+ 'Hello',
238
+ target_locale: 'ja',
239
+ reference: reference
240
+ )
241
+ ```
242
+
243
+ ### Quick translate convenience methods
244
+
245
+ For one-off translations without managing engine instances:
246
+
247
+ ```ruby
248
+ # Quick translate a string
249
+ result = LingoDotDev::Engine.quick_translate(
250
+ 'Hello world',
251
+ api_key: 'your-api-key',
252
+ target_locale: 'es'
253
+ )
254
+
255
+ # Quick translate a hash
256
+ result = LingoDotDev::Engine.quick_translate(
257
+ { greeting: 'Hello', farewell: 'Goodbye' },
258
+ api_key: 'your-api-key',
259
+ target_locale: 'fr'
260
+ )
261
+
262
+ # Quick batch translate to multiple locales
263
+ results = LingoDotDev::Engine.quick_batch_translate(
264
+ 'Hello',
265
+ api_key: 'your-api-key',
266
+ target_locales: ['es', 'fr', 'de']
267
+ )
268
+ ```
269
+
270
+ ### User information
271
+
272
+ Check the authenticated user details:
273
+
274
+ ```ruby
275
+ user = engine.whoami
276
+ # => { email: "user@example.com", id: "user-id" }
277
+ ```
278
+
279
+ ## Configuration
280
+
281
+ The SDK can be configured when creating an engine instance:
282
+
283
+ ```ruby
284
+ engine = LingoDotDev::Engine.new(
285
+ api_key: 'your-api-key', # Required: Your Lingo.dev API key
286
+ api_url: 'https://engine.lingo.dev', # Optional: API endpoint URL
287
+ batch_size: 25, # Optional: Max items per batch (1-250)
288
+ ideal_batch_item_size: 250 # Optional: Target word count per batch (1-2500)
289
+ )
290
+ ```
291
+
292
+ You can also configure using a block:
293
+
294
+ ```ruby
295
+ engine = LingoDotDev::Engine.new(api_key: 'your-api-key') do |config|
296
+ config.batch_size = 50
297
+ config.ideal_batch_item_size = 500
298
+ end
299
+ ```
300
+
301
+ ### Configuration options
302
+
303
+ | Option | Type | Default | Description |
304
+ | ----------------------- | ------- | -------------------------- | ----------------------------------------- |
305
+ | `api_key` | String | Required | Your Lingo.dev API key |
306
+ | `api_url` | String | `https://engine.lingo.dev` | API endpoint URL |
307
+ | `batch_size` | Integer | `25` | Maximum items per batch (1-250) |
308
+ | `ideal_batch_item_size` | Integer | `250` | Target word count per batch item (1-2500) |
309
+
310
+ ## API reference
311
+
312
+ ### Instance methods
313
+
314
+ #### `localize_text(text, target_locale:, source_locale: nil, fast: nil, reference: nil, on_progress: nil, concurrent: false, &block)`
315
+
316
+ Localizes a string to the target locale.
317
+
318
+ - **Parameters:**
319
+ - `text` (String): Text to localize
320
+ - `target_locale` (String): Target locale code (e.g., 'es', 'fr', 'ja')
321
+ - `source_locale` (String, optional): Source locale code
322
+ - `fast` (Boolean, optional): Enable fast mode
323
+ - `reference` (Hash, optional): Additional context for translation
324
+ - `on_progress` (Proc, optional): Progress callback
325
+ - `concurrent` (Boolean): Enable concurrent processing
326
+ - `&block`: Alternative progress callback
327
+ - **Returns:** Localized string
328
+
329
+ #### `localize_object(obj, target_locale:, source_locale: nil, fast: nil, reference: nil, on_progress: nil, concurrent: false, &block)`
330
+
331
+ Localizes all string values in a Hash.
332
+
333
+ - **Parameters:** Same as `localize_text`, with `obj` (Hash) instead of `text`
334
+ - **Returns:** Localized Hash
335
+
336
+ #### `localize_chat(chat, target_locale:, source_locale: nil, fast: nil, reference: nil, on_progress: nil, concurrent: false, &block)`
337
+
338
+ Localizes chat messages. Each message must have `:name` and `:text` keys.
339
+
340
+ - **Parameters:** Same as `localize_text`, with `chat` (Array) instead of `text`
341
+ - **Returns:** Array of localized chat messages
342
+
343
+ #### `localize_html(html, target_locale:, source_locale: nil, fast: nil, reference: nil, on_progress: nil, concurrent: false, &block)`
344
+
345
+ Localizes an HTML document while preserving structure and formatting. Handles both text content and localizable attributes (alt, title, placeholder, meta content).
346
+
347
+ - **Parameters:**
348
+ - `html` (String): HTML document string to localize
349
+ - `target_locale` (String): Target locale code (e.g., 'es', 'fr', 'ja')
350
+ - `source_locale` (String, optional): Source locale code
351
+ - `fast` (Boolean, optional): Enable fast mode
352
+ - `reference` (Hash, optional): Additional context for translation
353
+ - `on_progress` (Proc, optional): Progress callback
354
+ - `concurrent` (Boolean): Enable concurrent processing
355
+ - `&block`: Alternative progress callback
356
+ - **Returns:** Localized HTML document string with updated `lang` attribute
357
+
358
+ #### `batch_localize_text(text, target_locales:, source_locale: nil, fast: nil, reference: nil, concurrent: false)`
359
+
360
+ Localizes text to multiple target locales.
361
+
362
+ - **Parameters:**
363
+ - `text` (String): Text to localize
364
+ - `target_locales` (Array): Array of target locale codes
365
+ - Other parameters same as `localize_text`
366
+ - **Returns:** Array of localized strings
367
+
368
+ #### `batch_localize_objects(objects, target_locale:, source_locale: nil, fast: nil, reference: nil, concurrent: false)`
369
+
370
+ Localizes multiple objects to the same target locale.
371
+
372
+ - **Parameters:**
373
+ - `objects` (Array): Array of Hash objects
374
+ - `target_locale` (String): Target locale code
375
+ - Other parameters same as `localize_object`
376
+ - **Returns:** Array of localized Hash objects
377
+
378
+ #### `recognize_locale(text)`
379
+
380
+ Detects the locale of the given text.
381
+
382
+ - **Parameters:**
383
+ - `text` (String): Text to analyze
384
+ - **Returns:** Locale code string
385
+
386
+ #### `whoami`
387
+
388
+ Returns information about the authenticated user.
389
+
390
+ - **Returns:** Hash with `:email` and `:id` keys, or `nil` if authentication fails
391
+
392
+ ### Class methods
393
+
394
+ #### `Engine.quick_translate(content, api_key:, target_locale:, source_locale: nil, fast: true, api_url: 'https://engine.lingo.dev')`
395
+
396
+ One-off translation without managing engine lifecycle.
397
+
398
+ - **Parameters:**
399
+ - `content` (String or Hash): Content to translate
400
+ - Other parameters as in instance methods
401
+ - **Returns:** Translated String or Hash
402
+
403
+ #### `Engine.quick_batch_translate(content, api_key:, target_locales:, source_locale: nil, fast: true, api_url: 'https://engine.lingo.dev')`
404
+
405
+ One-off batch translation to multiple locales.
406
+
407
+ - **Parameters:**
408
+ - `content` (String or Hash): Content to translate
409
+ - `target_locales` (Array): Array of target locale codes
410
+ - Other parameters as in instance methods
411
+ - **Returns:** Array of translated results
412
+
413
+ ## Error handling
414
+
415
+ The SDK defines custom exception classes for different error scenarios:
416
+
417
+ ```ruby
418
+ begin
419
+ engine = LingoDotDev::Engine.new(api_key: 'your-api-key')
420
+ result = engine.localize_text('Hello', target_locale: 'es')
421
+ rescue LingoDotDev::ValidationError => e
422
+ # Invalid input or configuration
423
+ puts "Validation error: #{e.message}"
424
+ rescue LingoDotDev::AuthenticationError => e
425
+ # Invalid API key or authentication failure
426
+ puts "Authentication error: #{e.message}"
427
+ rescue LingoDotDev::ServerError => e
428
+ # Server-side error (5xx)
429
+ puts "Server error: #{e.message}"
430
+ rescue LingoDotDev::APIError => e
431
+ # General API error
432
+ puts "API error: #{e.message}"
433
+ rescue LingoDotDev::Error => e
434
+ # Base error class for all SDK errors
435
+ puts "Error: #{e.message}"
436
+ end
437
+ ```
438
+
439
+ ### Exception hierarchy
440
+
441
+ - `LingoDotDev::Error` (base class)
442
+ - `LingoDotDev::ArgumentError`
443
+ - `LingoDotDev::ValidationError` - Invalid input or configuration
444
+ - `LingoDotDev::APIError` - API request errors
445
+ - `LingoDotDev::AuthenticationError` - Authentication failures
446
+ - `LingoDotDev::ServerError` - Server-side errors (5xx)
447
+
448
+ ## Development
449
+
450
+ After checking out the repository, run `bin/setup` to install dependencies.
451
+
452
+ To run the test suite:
453
+
454
+ ```bash
455
+ # Set your API key
456
+ export LINGODOTDEV_API_KEY='your-api-key'
457
+
458
+ # Run tests
459
+ bundle exec rspec
460
+ ```
461
+
462
+ You can also run `bin/console` for an interactive prompt to experiment with the SDK.
463
+
464
+ To install this gem onto your local machine, run:
465
+
466
+ ```bash
467
+ bundle exec rake install
468
+ ```
469
+
470
+ ## Requirements
471
+
472
+ - Ruby >= 3.2.0
473
+
474
+ ## Dependencies
475
+
476
+ - `json` ~> 2.0
477
+ - `nokogiri` ~> 1.0
478
+
479
+ ## License
480
+
481
+ See the LICENSE file for details.
482
+
483
+ ## Contributing
484
+
485
+ Contributions are welcome! Please feel free to submit a Pull Request.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: %i[]
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Ruby SDK for Lingo.dev localization and translation API.
4
+ module LingoDotDev
5
+ # Current version of the LingoDotDev SDK.
6
+ VERSION = "0.1.0"
7
+ end
8
+