@@ -119,9 +119,51 @@ def validate!
119119 end
120120 end
121121
122+ # Main engine for localizing content via the Lingo.dev API.
123+ #
124+ # The Engine class provides methods for text, object, and chat localization
125+ # with support for batch operations, progress tracking, and concurrent processing.
126+ #
127+ # @example Basic text localization
128+ # engine = LingoDotDev::Engine.new(api_key: 'your-api-key')
129+ # result = engine.localize_text('Hello', target_locale: 'es')
130+ # # => "Hola"
131+ #
132+ # @example Object localization
133+ # data = { greeting: 'Hello', farewell: 'Goodbye' }
134+ # result = engine.localize_object(data, target_locale: 'fr')
135+ # # => { greeting: "Bonjour", farewell: "Au revoir" }
136+ #
137+ # @example Batch localization
138+ # results = engine.batch_localize_text('Hello', target_locales: ['es', 'fr', 'de'])
139+ # # => ["Hola", "Bonjour", "Hallo"]
122140 class Engine
141+ # @return [Configuration] the engine's configuration
123142 attr_reader :config
124143
144+ # Creates a new Engine instance.
145+ #
146+ # @param api_key [String] your Lingo.dev API key (required)
147+ # @param api_url [String] the API endpoint URL (default: 'https://engine.lingo.dev')
148+ # @param batch_size [Integer] maximum items per batch, 1-250 (default: 25)
149+ # @param ideal_batch_item_size [Integer] target word count per batch item, 1-2500 (default: 250)
150+ #
151+ # @yield [config] optional block for additional configuration
152+ # @yieldparam config [Configuration] the configuration instance
153+ #
154+ # @raise [ValidationError] if any parameter is invalid
155+ #
156+ # @example Basic initialization
157+ # engine = LingoDotDev::Engine.new(api_key: 'your-api-key')
158+ #
159+ # @example With custom configuration
160+ # engine = LingoDotDev::Engine.new(api_key: 'your-api-key', batch_size: 50)
161+ #
162+ # @example With block configuration
163+ # engine = LingoDotDev::Engine.new(api_key: 'your-api-key') do |config|
164+ # config.batch_size = 50
165+ # config.ideal_batch_item_size = 500
166+ # end
125167 def initialize ( api_key :, api_url : 'https://engine.lingo.dev' , batch_size : 25 , ideal_batch_item_size : 250 )
126168 @config = Configuration . new (
127169 api_key : api_key ,
@@ -134,6 +176,36 @@ def initialize(api_key:, api_url: 'https://engine.lingo.dev', batch_size: 25, id
134176 @config . send ( :validate! )
135177 end
136178
179+ # Localizes a string to the target locale.
180+ #
181+ # @param text [String] the text to localize
182+ # @param target_locale [String] the target locale code (e.g., 'es', 'fr', 'ja')
183+ # @param source_locale [String, nil] the source locale code (optional, auto-detected if not provided)
184+ # @param fast [Boolean, nil] enable fast mode for quicker results (optional)
185+ # @param reference [Hash, nil] additional context for translation (optional)
186+ # @param on_progress [Proc, nil] callback for progress updates (optional)
187+ # @param concurrent [Boolean] enable concurrent processing (default: false)
188+ #
189+ # @yield [progress] optional block for progress tracking
190+ # @yieldparam progress [Integer] completion percentage (0-100)
191+ #
192+ # @return [String] the localized text
193+ #
194+ # @raise [ValidationError] if target_locale is missing or text is nil
195+ # @raise [APIError] if the API request fails
196+ #
197+ # @example Basic usage
198+ # result = engine.localize_text('Hello', target_locale: 'es')
199+ # # => "Hola"
200+ #
201+ # @example With source locale
202+ # result = engine.localize_text('Hello', target_locale: 'fr', source_locale: 'en')
203+ # # => "Bonjour"
204+ #
205+ # @example With progress tracking
206+ # result = engine.localize_text('Hello', target_locale: 'de') do |progress|
207+ # puts "Progress: #{progress}%"
208+ # end
137209 def localize_text ( text , target_locale :, source_locale : nil , fast : nil , reference : nil , on_progress : nil , concurrent : false , &block )
138210 raise ValidationError , 'Target locale is required' if target_locale . nil? || target_locale . empty?
139211 raise ValidationError , 'Text cannot be nil' if text . nil?
@@ -154,6 +226,28 @@ def localize_text(text, target_locale:, source_locale: nil, fast: nil, reference
154226 response [ :text ] || ''
155227 end
156228
229+ # Localizes all string values in a Hash.
230+ #
231+ # @param obj [Hash] the Hash object to localize
232+ # @param target_locale [String] the target locale code (e.g., 'es', 'fr', 'ja')
233+ # @param source_locale [String, nil] the source locale code (optional, auto-detected if not provided)
234+ # @param fast [Boolean, nil] enable fast mode for quicker results (optional)
235+ # @param reference [Hash, nil] additional context for translation (optional)
236+ # @param on_progress [Proc, nil] callback for progress updates (optional)
237+ # @param concurrent [Boolean] enable concurrent processing (default: false)
238+ #
239+ # @yield [progress] optional block for progress tracking
240+ # @yieldparam progress [Integer] completion percentage (0-100)
241+ #
242+ # @return [Hash] a new Hash with localized string values
243+ #
244+ # @raise [ValidationError] if target_locale is missing, obj is nil, or obj is not a Hash
245+ # @raise [APIError] if the API request fails
246+ #
247+ # @example Basic usage
248+ # data = { greeting: 'Hello', farewell: 'Goodbye' }
249+ # result = engine.localize_object(data, target_locale: 'es')
250+ # # => { greeting: "Hola", farewell: "Adiós" }
157251 def localize_object ( obj , target_locale :, source_locale : nil , fast : nil , reference : nil , on_progress : nil , concurrent : false , &block )
158252 raise ValidationError , 'Target locale is required' if target_locale . nil? || target_locale . empty?
159253 raise ValidationError , 'Object cannot be nil' if obj . nil?
@@ -172,6 +266,37 @@ def localize_object(obj, target_locale:, source_locale: nil, fast: nil, referenc
172266 )
173267 end
174268
269+ # Localizes chat messages while preserving structure.
270+ #
271+ # Each message must have :name and :text keys. The structure of messages
272+ # is preserved while all text content is localized.
273+ #
274+ # @param chat [Array<Hash>] array of chat messages, each with :name and :text keys
275+ # @param target_locale [String] the target locale code (e.g., 'es', 'fr', 'ja')
276+ # @param source_locale [String, nil] the source locale code (optional, auto-detected if not provided)
277+ # @param fast [Boolean, nil] enable fast mode for quicker results (optional)
278+ # @param reference [Hash, nil] additional context for translation (optional)
279+ # @param on_progress [Proc, nil] callback for progress updates (optional)
280+ # @param concurrent [Boolean] enable concurrent processing (default: false)
281+ #
282+ # @yield [progress] optional block for progress tracking
283+ # @yieldparam progress [Integer] completion percentage (0-100)
284+ #
285+ # @return [Array<Hash>] array of localized chat messages
286+ #
287+ # @raise [ValidationError] if target_locale is missing, chat is nil, not an Array, or messages are invalid
288+ # @raise [APIError] if the API request fails
289+ #
290+ # @example Basic usage
291+ # chat = [
292+ # { name: 'user', text: 'Hello!' },
293+ # { name: 'assistant', text: 'Hi there!' }
294+ # ]
295+ # result = engine.localize_chat(chat, target_locale: 'ja')
296+ # # => [
297+ # # { name: 'user', text: 'こんにちは!' },
298+ # # { name: 'assistant', text: 'こんにちは!' }
299+ # # ]
175300 def localize_chat ( chat , target_locale :, source_locale : nil , fast : nil , reference : nil , on_progress : nil , concurrent : false , &block )
176301 raise ValidationError , 'Target locale is required' if target_locale . nil? || target_locale . empty?
177302 raise ValidationError , 'Chat cannot be nil' if chat . nil?
@@ -199,6 +324,26 @@ def localize_chat(chat, target_locale:, source_locale: nil, fast: nil, reference
199324 response [ :chat ] || [ ]
200325 end
201326
327+ # Localizes text to multiple target locales.
328+ #
329+ # @param text [String] the text to localize
330+ # @param target_locales [Array<String>] array of target locale codes
331+ # @param source_locale [String, nil] the source locale code (optional, auto-detected if not provided)
332+ # @param fast [Boolean, nil] enable fast mode for quicker results (optional)
333+ # @param reference [Hash, nil] additional context for translation (optional)
334+ # @param concurrent [Boolean] enable concurrent processing (default: false)
335+ #
336+ # @return [Array<String>] array of localized strings in the same order as target_locales
337+ #
338+ # @raise [ValidationError] if text is nil, target_locales is not an Array, or target_locales is empty
339+ # @raise [APIError] if any API request fails
340+ #
341+ # @example Basic usage
342+ # results = engine.batch_localize_text('Hello', target_locales: ['es', 'fr', 'de'])
343+ # # => ["Hola", "Bonjour", "Hallo"]
344+ #
345+ # @example With concurrent processing
346+ # results = engine.batch_localize_text('Hello', target_locales: ['es', 'fr', 'de', 'ja'], concurrent: true)
202347 def batch_localize_text ( text , target_locales :, source_locale : nil , fast : nil , reference : nil , concurrent : false )
203348 raise ValidationError , 'Text cannot be nil' if text . nil?
204349 raise ValidationError , 'Target locales must be an Array' unless target_locales . is_a? ( Array )
@@ -230,6 +375,30 @@ def batch_localize_text(text, target_locales:, source_locale: nil, fast: nil, re
230375 end
231376 end
232377
378+ # Localizes multiple objects to the same target locale.
379+ #
380+ # @param objects [Array<Hash>] array of Hash objects to localize
381+ # @param target_locale [String] the target locale code (e.g., 'es', 'fr', 'ja')
382+ # @param source_locale [String, nil] the source locale code (optional, auto-detected if not provided)
383+ # @param fast [Boolean, nil] enable fast mode for quicker results (optional)
384+ # @param reference [Hash, nil] additional context for translation (optional)
385+ # @param concurrent [Boolean] enable concurrent processing (default: false)
386+ #
387+ # @return [Array<Hash>] array of localized Hash objects in the same order as input
388+ #
389+ # @raise [ValidationError] if objects is not an Array, objects is empty, target_locale is missing, or any object is not a Hash
390+ # @raise [APIError] if any API request fails
391+ #
392+ # @example Basic usage
393+ # objects = [
394+ # { title: 'Welcome', body: 'Hello there' },
395+ # { title: 'About', body: 'Learn more' }
396+ # ]
397+ # results = engine.batch_localize_objects(objects, target_locale: 'es')
398+ # # => [
399+ # # { title: "Bienvenido", body: "Hola" },
400+ # # { title: "Acerca de", body: "Aprende más" }
401+ # # ]
233402 def batch_localize_objects ( objects , target_locale :, source_locale : nil , fast : nil , reference : nil , concurrent : false )
234403 raise ValidationError , 'Objects must be an Array' unless objects . is_a? ( Array )
235404 raise ValidationError , 'Objects cannot be empty' if objects . empty?
@@ -267,6 +436,22 @@ def batch_localize_objects(objects, target_locale:, source_locale: nil, fast: ni
267436 end
268437 end
269438
439+ # Detects the locale of the given text.
440+ #
441+ # @param text [String] the text to analyze
442+ #
443+ # @return [String] the detected locale code (e.g., 'en', 'es', 'ja')
444+ #
445+ # @raise [ValidationError] if text is nil or empty
446+ # @raise [APIError] if the API request fails
447+ #
448+ # @example Basic usage
449+ # locale = engine.recognize_locale('Bonjour le monde')
450+ # # => "fr"
451+ #
452+ # @example Japanese text
453+ # locale = engine.recognize_locale('こんにちは世界')
454+ # # => "ja"
270455 def recognize_locale ( text )
271456 raise ValidationError , 'Text cannot be empty' if text . nil? || text . strip . empty?
272457
@@ -284,6 +469,13 @@ def recognize_locale(text)
284469 end
285470 end
286471
472+ # Returns information about the authenticated user.
473+ #
474+ # @return [Hash, nil] a Hash with :email and :id keys if authenticated, nil otherwise
475+ #
476+ # @example Basic usage
477+ # user = engine.whoami
478+ # # => { email: "user@example.com", id: "user-id" }
287479 def whoami
288480 begin
289481 response = http_client . post ( "#{ config . api_url } /whoami" )
@@ -300,6 +492,34 @@ def whoami
300492 end
301493 end
302494
495+ # One-off translation without managing engine lifecycle.
496+ #
497+ # Creates a temporary engine instance, performs the translation, and returns the result.
498+ # Suitable for single translations where engine configuration is not needed.
499+ #
500+ # @param content [String, Hash] the content to translate (String for text, Hash for object)
501+ # @param api_key [String] your Lingo.dev API key
502+ # @param target_locale [String] the target locale code (e.g., 'es', 'fr', 'ja')
503+ # @param source_locale [String, nil] the source locale code (optional, auto-detected if not provided)
504+ # @param fast [Boolean] enable fast mode for quicker results (default: true)
505+ # @param api_url [String] the API endpoint URL (default: 'https://engine.lingo.dev')
506+ #
507+ # @return [String, Hash] localized content (String if input was String, Hash if input was Hash)
508+ #
509+ # @raise [ValidationError] if content is not a String or Hash, or other validation fails
510+ # @raise [APIError] if the API request fails
511+ #
512+ # @example Translate text
513+ # result = LingoDotDev::Engine.quick_translate('Hello', api_key: 'your-api-key', target_locale: 'es')
514+ # # => "Hola"
515+ #
516+ # @example Translate object
517+ # result = LingoDotDev::Engine.quick_translate(
518+ # { greeting: 'Hello', farewell: 'Goodbye' },
519+ # api_key: 'your-api-key',
520+ # target_locale: 'fr'
521+ # )
522+ # # => { greeting: "Bonjour", farewell: "Au revoir" }
303523 def self . quick_translate ( content , api_key :, target_locale :, source_locale : nil , fast : true , api_url : 'https://engine.lingo.dev' )
304524 engine = new ( api_key : api_key , api_url : api_url )
305525 case content
@@ -323,6 +543,38 @@ def self.quick_translate(content, api_key:, target_locale:, source_locale: nil,
323543 end
324544 end
325545
546+ # One-off batch translation to multiple locales without managing engine lifecycle.
547+ #
548+ # Creates a temporary engine instance, performs batch translations, and returns the results.
549+ # Suitable for single batch translations where engine configuration is not needed.
550+ #
551+ # @param content [String, Hash] the content to translate (String for text, Hash for object)
552+ # @param api_key [String] your Lingo.dev API key
553+ # @param target_locales [Array<String>] array of target locale codes
554+ # @param source_locale [String, nil] the source locale code (optional, auto-detected if not provided)
555+ # @param fast [Boolean] enable fast mode for quicker results (default: true)
556+ # @param api_url [String] the API endpoint URL (default: 'https://engine.lingo.dev')
557+ #
558+ # @return [Array<String>, Array<Hash>] array of localized results (Strings if input was String, Hashes if input was Hash)
559+ #
560+ # @raise [ValidationError] if content is not a String or Hash, or other validation fails
561+ # @raise [APIError] if any API request fails
562+ #
563+ # @example Batch translate text
564+ # results = LingoDotDev::Engine.quick_batch_translate(
565+ # 'Hello',
566+ # api_key: 'your-api-key',
567+ # target_locales: ['es', 'fr', 'de']
568+ # )
569+ # # => ["Hola", "Bonjour", "Hallo"]
570+ #
571+ # @example Batch translate object
572+ # results = LingoDotDev::Engine.quick_batch_translate(
573+ # { greeting: 'Hello' },
574+ # api_key: 'your-api-key',
575+ # target_locales: ['es', 'fr']
576+ # )
577+ # # => [{ greeting: "Hola" }, { greeting: "Bonjour" }]
326578 def self . quick_batch_translate ( content , api_key :, target_locales :, source_locale : nil , fast : true , api_url : 'https://engine.lingo.dev' )
327579 engine = new ( api_key : api_key , api_url : api_url )
328580 case content
0 commit comments