diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml new file mode 100644 index 0000000..25402cf --- /dev/null +++ b/.github/workflows/generate-docs.yml @@ -0,0 +1,55 @@ +name: Generate Markdown Docs + +on: + push: + branches: + - '*' + workflow_dispatch: + +permissions: + contents: write + +jobs: + generate: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + extensions: mbstring, intl + coverage: none + tools: composer:v2 + + - name: Install dependencies + run: composer install --prefer-dist --no-interaction --no-progress + + - name: Generate Markdown documentation + run: | + vendor/bin/phpdoc \ + --directory=src \ + --target=docs \ + --template="vendor/saggre/phpdocumentor-markdown/themes/markdown" \ + --title="PHP SDK for Lingo.dev" \ + --visibility=public + + - name: Commit and push updates + run: | + STATUS=$(git status --short docs) + if [ -z "$STATUS" ]; then + echo "Documentation already up to date" + exit 0 + fi + + echo "Docs updated, committing changes" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add docs + git commit -m "docs: update markdown API reference [skip ci]" + git push diff --git a/.gitignore b/.gitignore index e102943..c93f120 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .env /demo/vendor/ /demo/composer.lock +.phpdoc/cache \ No newline at end of file diff --git a/composer.json b/composer.json index 2399fef..fdaf1a1 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,12 @@ "require": { "php": "^8.1", "guzzlehttp/guzzle": "^7.0", - "respect/validation": "^2.0" + "respect/validation": "^2.0", + "phpdocumentor/shim": "^3.8" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.0", + "saggre/phpdocumentor-markdown": "^1.0" }, "autoload": { "psr-4": { @@ -26,5 +28,10 @@ "psr-4": { "LingoDotDev\\Sdk\\Tests\\": "tests/" } + }, + "config": { + "allow-plugins": { + "phpdocumentor/shim": true + } } } diff --git a/docs/Home.md b/docs/Home.md new file mode 100644 index 0000000..7d3a39e --- /dev/null +++ b/docs/Home.md @@ -0,0 +1,15 @@ + +This is an automatically generated documentation for **PHP SDK for Lingo.dev**. + +## Namespaces + +### \LingoDotDev\Sdk + +#### Classes + +| Class | Description | +|--------------------------------------------------------------------------------|---------------------------------------------------------------------------| +| [`BatchTranslationOptions`](./classes/LingoDotDev/Sdk/BatchTranslationOptions) | Options for batch text translation to multiple languages. | +| [`EngineConfig`](./classes/LingoDotDev/Sdk/EngineConfig) | Configuration for LingoDotDevEngine initialization. | +| [`LingoDotDevEngine`](./classes/LingoDotDev/Sdk/LingoDotDevEngine) | LingoDotDevEngine wraps the Lingo.dev localization API for PHP consumers. | +| [`TranslationOptions`](./classes/LingoDotDev/Sdk/TranslationOptions) | Options for text and object translation. | diff --git a/docs/classes/LingoDotDev/Sdk/BatchTranslationOptions.md b/docs/classes/LingoDotDev/Sdk/BatchTranslationOptions.md new file mode 100644 index 0000000..9f13249 --- /dev/null +++ b/docs/classes/LingoDotDev/Sdk/BatchTranslationOptions.md @@ -0,0 +1,106 @@ + +Options for batch text translation to multiple languages. + +*** + +* Full name: `\LingoDotDev\Sdk\BatchTranslationOptions` + +**See Also:** + +* https://lingo.dev + +## Properties + +### sourceLocale + +Source language code (e.g., 'en') +Required field. + +```php +public string $sourceLocale +``` + +*** + +### targetLocales + +Array of target language codes (e.g., ['es', 'fr', 'de']) +Required field. + +```php +public string[] $targetLocales +``` + +*** + +### fast + +Enable fast mode - trades translation quality for speed +Default: false (quality mode) + +```php +public bool $fast +``` + +*** + +## Methods + +### create + +Create a fluent builder for batch translation options. + +```php +public static create(string $sourceLocale): self +``` + +* This method is **static**. +**Parameters:** + +| Parameter | Type | Description | +|-----------------|------------|----------------------| +| `$sourceLocale` | **string** | Source language code | + +*** + +### to + +Set target locales. + +```php +public to(string[] $locales): self +``` + +**Parameters:** + +| Parameter | Type | Description | +|------------|--------------|-----------------------| +| `$locales` | **string[]** | Target language codes | + +*** + +### addTarget + +Add a single target locale. + +```php +public addTarget(string $locale): self +``` + +**Parameters:** + +| Parameter | Type | Description | +|-----------|------------|----------------------| +| `$locale` | **string** | Target language code | + +*** + +### withFastMode + +Enable fast translation mode. + +```php +public withFastMode(): self +``` + +*** diff --git a/docs/classes/LingoDotDev/Sdk/EngineConfig.md b/docs/classes/LingoDotDev/Sdk/EngineConfig.md new file mode 100644 index 0000000..883f1fb --- /dev/null +++ b/docs/classes/LingoDotDev/Sdk/EngineConfig.md @@ -0,0 +1,119 @@ + +Configuration for LingoDotDevEngine initialization. + +*** + +* Full name: `\LingoDotDev\Sdk\EngineConfig` + +**See Also:** + +* https://lingo.dev + +## Properties + +### apiKey + +Your Lingo.dev API token + +```php +public string $apiKey +``` + +*** + +### apiUrl + +API base URL (default: https://engine.lingo.dev) + +```php +public string $apiUrl +``` + +*** + +### batchSize + +Maximum records per request (1-250, default: 25) + +```php +public int $batchSize +``` + +*** + +### idealBatchItemSize + +Maximum words per request (1-2500, default: 250) + +```php +public int $idealBatchItemSize +``` + +*** + +## Methods + +### create + +Create configuration with API key. + +```php +public static create(string $apiKey): self +``` + +* This method is **static**. +**Parameters:** + +| Parameter | Type | Description | +|-----------|------------|--------------------------| +| `$apiKey` | **string** | Your Lingo.dev API token | + +*** + +### withApiUrl + +Set custom API URL. + +```php +public withApiUrl(string $url): self +``` + +**Parameters:** + +| Parameter | Type | Description | +|-----------|------------|------------------| +| `$url` | **string** | API endpoint URL | + +*** + +### withBatchSize + +Set batch size limit. + +```php +public withBatchSize(int $size): self +``` + +**Parameters:** + +| Parameter | Type | Description | +|-----------|---------|-----------------------------| +| `$size` | **int** | Records per request (1-250) | + +*** + +### withIdealBatchItemSize + +Set ideal batch item size. + +```php +public withIdealBatchItemSize(int $size): self +``` + +**Parameters:** + +| Parameter | Type | Description | +|-----------|---------|--------------------------------| +| `$size` | **int** | Max words per request (1-2500) | + +*** diff --git a/docs/classes/LingoDotDev/Sdk/LingoDotDevEngine.md b/docs/classes/LingoDotDev/Sdk/LingoDotDevEngine.md new file mode 100644 index 0000000..6780d95 --- /dev/null +++ b/docs/classes/LingoDotDev/Sdk/LingoDotDevEngine.md @@ -0,0 +1,243 @@ + +LingoDotDevEngine wraps the Lingo.dev localization API for PHP consumers. + +Use a single engine instance to translate strings, arrays, and chat logs, or +to detect the locale of free-form text. The engine handles request batching, +progress reporting, and surfacing validation or transport errors. + +Example (basic setup): + $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); + $engine = new LingoDotDevEngine($config); + +Example (Laravel integration): + $config = EngineConfig::create(config('services.lingodotdev.api_key')) + ->withBatchSize(100); + $engine = new LingoDotDevEngine($config); + + $options = TranslationOptions::create('es')->from('en'); + $engine->localizeText($request->message, $options); + +*** + +* Full name: `\LingoDotDev\Sdk\LingoDotDevEngine` + +**See Also:** + +* https://lingo.dev + +## Methods + +### __construct + +Build an engine with your configuration. + +```php +public __construct(\LingoDotDev\Sdk\EngineConfig $config): mixed +``` + +Example: +$config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']) + ->withBatchSize(100) + ->withIdealBatchItemSize(1000); +$engine = new LingoDotDevEngine($config); + +**Parameters:** + +| Parameter | Type | Description | +|-----------|-----------------------------------|----------------------| +| `$config` | **\LingoDotDev\Sdk\EngineConfig** | Engine configuration | + +**Throws:** + +Invalid configuration values +- [`InvalidArgumentException`](../../InvalidArgumentException) + +*** + +### localizeObject + +Localize every string in a nested array while keeping its shape intact. + +```php +public localizeObject(array $obj, \LingoDotDev\Sdk\TranslationOptions $options, callable|null $progressCallback = null): array +``` + +Example: +$config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); +$engine = new LingoDotDevEngine($config); +$options = TranslationOptions::create('fr')->from('en'); +$engine->localizeObject(['greeting' => 'Hello'], $options); + +**Parameters:** + +| Parameter | Type | Description | +|---------------------|-----------------------------------------|--------------------------------------| +| `$obj` | **array** | Nested data structure to translate | +| `$options` | **\LingoDotDev\Sdk\TranslationOptions** | Translation options | +| `$progressCallback` | **callable\|null** | Progress callback (%, batch, result) | + +**Return Value:** + +Translated data preserving structure + +**Throws:** + +API request failure +- [`RuntimeException`](../../RuntimeException) + +*** + +### localizeText + +Localize a single string and return the translated text. + +```php +public localizeText(string $text, \LingoDotDev\Sdk\TranslationOptions $options, callable|null $progressCallback = null): string +``` + +Examples: +$config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); +$engine = new LingoDotDevEngine($config); + +// Simple translation +$options = TranslationOptions::create('es')->from('en'); +$engine->localizeText('Hello, world!', $options); + +// With progress callback +$engine->localizeText( + 'This is a very long text...', + $options, + function (int $progress): void { + echo "Progress: {$progress}%%\n"; + } +); + +// Auto-detect source language +$options = TranslationOptions::create('en'); +$engine->localizeText('Bonjour le monde', $options); + +**Parameters:** + +| Parameter | Type | Description | +|---------------------|-----------------------------------------|----------------------------| +| `$text` | **string** | Text to translate | +| `$options` | **\LingoDotDev\Sdk\TranslationOptions** | Translation options | +| `$progressCallback` | **callable\|null** | Progress callback (0-100%) | + +**Return Value:** + +Translated text or empty string + +**Throws:** + +API request failure +- [`RuntimeException`](../../RuntimeException) + +*** + +### batchLocalizeText + +Localize a string into multiple languages and return texts in order. + +```php +public batchLocalizeText(string $text, \LingoDotDev\Sdk\BatchTranslationOptions $options): string[] +``` + +Example: +$config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); +$engine = new LingoDotDevEngine($config); + +$options = BatchTranslationOptions::create('en') + ->to(['es', 'fr', 'de']) + ->withFastMode(); +$engine->batchLocalizeText('Hello, world!', $options); + +**Parameters:** + +| Parameter | Type | Description | +|------------|----------------------------------------------|---------------------------| +| `$text` | **string** | Text to translate | +| `$options` | **\LingoDotDev\Sdk\BatchTranslationOptions** | Batch translation options | + +**Return Value:** + +Translated texts in targetLocales order + +**Throws:** + +Individual request failure +- [`RuntimeException`](../../RuntimeException) + +*** + +### localizeChat + +Localize a chat transcript while preserving speaker names. + +```php +public localizeChat(array $chat, \LingoDotDev\Sdk\TranslationOptions $options, callable|null $progressCallback = null): array +``` + +Example: +$conversation = [ + ['name' => 'Alice', 'text' => 'Hello, how are you?'], + ['name' => 'Bob', 'text' => 'I am fine, thank you!'], +]; + +$config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); +$engine = new LingoDotDevEngine($config); +$options = TranslationOptions::create('de')->from('en'); +$engine->localizeChat($conversation, $options); + +**Parameters:** + +| Parameter | Type | Description | +|---------------------|--------------------------------------------------|--------------------------------------| +| `$chat` | **array** | Conversation with names and messages | +| `$options` | **\LingoDotDev\Sdk\TranslationOptions** | Translation options | +| `$progressCallback` | **callable\|null** | Progress callback (0-100%) | + +**Return Value:** + +Translated chat preserving names + +**Throws:** + +Invalid chat entries +- [`InvalidArgumentException`](../../InvalidArgumentException) +API request failure +- [`RuntimeException`](../../RuntimeException) + +*** + +### recognizeLocale + +Identify the locale of the provided text. + +```php +public recognizeLocale(string $text): string +``` + +Example: +$config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); +$engine = new LingoDotDevEngine($config); +$engine->recognizeLocale('Bonjour le monde'); + +**Parameters:** + +| Parameter | Type | Description | +|-----------|------------|------------------------------------| +| `$text` | **string** | Sample text for language detection | + +**Return Value:** + +ISO language code (e.g., 'en', 'es', 'zh') + +**Throws:** + +Empty text provided +- [`InvalidArgumentException`](../../InvalidArgumentException) +Invalid API response or request failure +- [`RuntimeException`](../../RuntimeException) + +*** diff --git a/docs/classes/LingoDotDev/Sdk/TranslationOptions.md b/docs/classes/LingoDotDev/Sdk/TranslationOptions.md new file mode 100644 index 0000000..af57853 --- /dev/null +++ b/docs/classes/LingoDotDev/Sdk/TranslationOptions.md @@ -0,0 +1,117 @@ + +Options for text and object translation. + +*** + +* Full name: `\LingoDotDev\Sdk\TranslationOptions` + +**See Also:** + +* https://lingo.dev + +## Properties + +### targetLocale + +Target language code (e.g., 'es', 'fr') +Required field. + +```php +public string $targetLocale +``` + +*** + +### sourceLocale + +Source language code or null for auto-detection +Example: 'en', 'es', or null + +```php +public ?string $sourceLocale +``` + +*** + +### fast + +Enable fast mode - trades translation quality for speed +Default: false (quality mode) + +```php +public bool $fast +``` + +*** + +### reference + +Context data or glossary terms to guide translation +Can include domain-specific terminology or reference translations + +```php +public array|null $reference +``` + +*** + +## Methods + +### create + +Create a fluent builder for translation options. + +```php +public static create(string $targetLocale): self +``` + +* This method is **static**. +**Parameters:** + +| Parameter | Type | Description | +|-----------------|------------|----------------------| +| `$targetLocale` | **string** | Target language code | + +*** + +### from + +Set source locale. + +```php +public from(string|null $locale): self +``` + +**Parameters:** + +| Parameter | Type | Description | +|-----------|------------------|-------------------------------------------------| +| `$locale` | **string\|null** | Source language code or null for auto-detection | + +*** + +### withFastMode + +Enable fast translation mode. + +```php +public withFastMode(): self +``` + +*** + +### withReference + +Add reference data for context. + +```php +public withReference(array $reference): self +``` + +**Parameters:** + +| Parameter | Type | Description | +|--------------|-------------------------|--------------------------| +| `$reference` | **array** | Context or glossary data | + +*** diff --git a/src/BatchTranslationOptions.php b/src/BatchTranslationOptions.php new file mode 100644 index 0000000..1823d23 --- /dev/null +++ b/src/BatchTranslationOptions.php @@ -0,0 +1,89 @@ + + * @license MIT https://opensource.org/licenses/MIT + * @link https://lingo.dev + */ + +namespace LingoDotDev\Sdk; + +/** + * Options for batch text translation to multiple languages. + * + * @category Localization + * @package Lingodotdev\Sdk + * @author Lingo.dev Team + * @license MIT https://opensource.org/licenses/MIT + * @link https://lingo.dev + */ +class BatchTranslationOptions +{ + /** + * Source language code (e.g., 'en') + * Required field. + */ + public string $sourceLocale; + + /** + * Array of target language codes (e.g., ['es', 'fr', 'de']) + * Required field. + * + * @var string[] + */ + public array $targetLocales; + + /** + * Enable fast mode - trades translation quality for speed + * Default: false (quality mode) + */ + public bool $fast = false; + + + /** + * Create a fluent builder for batch translation options. + * + * @param string $sourceLocale Source language code + */ + public static function create(string $sourceLocale): self + { + $instance = new self(); + $instance->sourceLocale = $sourceLocale; + $instance->targetLocales = []; + return $instance; + } + + /** + * Set target locales. + * + * @param string[] $locales Target language codes + */ + public function to(array $locales): self + { + $this->targetLocales = $locales; + return $this; + } + + /** + * Add a single target locale. + * + * @param string $locale Target language code + */ + public function addTarget(string $locale): self + { + $this->targetLocales[] = $locale; + return $this; + } + + /** + * Enable fast translation mode. + */ + public function withFastMode(): self + { + $this->fast = true; + return $this; + } +} \ No newline at end of file diff --git a/src/EngineConfig.php b/src/EngineConfig.php new file mode 100644 index 0000000..e1b599a --- /dev/null +++ b/src/EngineConfig.php @@ -0,0 +1,89 @@ + + * @license MIT https://opensource.org/licenses/MIT + * @link https://lingo.dev + */ + +namespace LingoDotDev\Sdk; + +/** + * Configuration for LingoDotDevEngine initialization. + * + * @category Localization + * @package Lingodotdev\Sdk + * @author Lingo.dev Team + * @license MIT https://opensource.org/licenses/MIT + * @link https://lingo.dev + */ +class EngineConfig +{ + /** + * Your Lingo.dev API token + */ + public string $apiKey; + + /** + * API base URL (default: https://engine.lingo.dev) + */ + public string $apiUrl = 'https://engine.lingo.dev'; + + /** + * Maximum records per request (1-250, default: 25) + */ + public int $batchSize = 25; + + /** + * Maximum words per request (1-2500, default: 250) + */ + public int $idealBatchItemSize = 250; + + /** + * Create configuration with API key. + * + * @param string $apiKey Your Lingo.dev API token + */ + public static function create(string $apiKey): self + { + $instance = new self(); + $instance->apiKey = $apiKey; + return $instance; + } + + /** + * Set custom API URL. + * + * @param string $url API endpoint URL + */ + public function withApiUrl(string $url): self + { + $this->apiUrl = $url; + return $this; + } + + /** + * Set batch size limit. + * + * @param int $size Records per request (1-250) + */ + public function withBatchSize(int $size): self + { + $this->batchSize = $size; + return $this; + } + + /** + * Set ideal batch item size. + * + * @param int $size Max words per request (1-2500) + */ + public function withIdealBatchItemSize(int $size): self + { + $this->idealBatchItemSize = $size; + return $this; + } +} \ No newline at end of file diff --git a/src/LingoDotDevEngine.php b/src/LingoDotDevEngine.php index ea26a91..5d4458b 100644 --- a/src/LingoDotDevEngine.php +++ b/src/LingoDotDevEngine.php @@ -16,9 +16,23 @@ use Respect\Validation\Validator as v; /** - * LingoDotDevEngine class for interacting with the LingoDotDev API - * A powerful localization engine that supports various content types including - * plain text, objects, and chat sequences. + * LingoDotDevEngine wraps the Lingo.dev localization API for PHP consumers. + * + * Use a single engine instance to translate strings, arrays, and chat logs, or + * to detect the locale of free-form text. The engine handles request batching, + * progress reporting, and surfacing validation or transport errors. + * + * Example (basic setup): + * $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); + * $engine = new LingoDotDevEngine($config); + * + * Example (Laravel integration): + * $config = EngineConfig::create(config('services.lingodotdev.api_key')) + * ->withBatchSize(100); + * $engine = new LingoDotDevEngine($config); + * + * $options = TranslationOptions::create('es')->from('en'); + * $engine->localizeText($request->message, $options); * * @category Localization * @package Lingodotdev\Sdk @@ -29,85 +43,76 @@ class LingoDotDevEngine { /** - * Configuration options for the Engine + * Configuration options for the Engine. * - * @var array + * @var EngineConfig */ - protected $config; + protected EngineConfig $config; /** - * HTTP client for API requests + * HTTP client for API requests. * * @var Client */ private $_httpClient; /** - * Create a new LingoDotDevEngine instance - * - * @param array $config Configuration options for the Engine + * Build an engine with your configuration. + * + * Example: + * $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']) + * ->withBatchSize(100) + * ->withIdealBatchItemSize(1000); + * $engine = new LingoDotDevEngine($config); + * + * @param EngineConfig $config Engine configuration + * + * @throws \InvalidArgumentException Invalid configuration values */ - public function __construct(array $config = []) + public function __construct(EngineConfig $config) { - $this->config = array_merge( - [ - 'apiUrl' => 'https://engine.lingo.dev', - 'batchSize' => 25, - 'idealBatchItemSize' => 250 - ], $config - ); + $this->config = $config; - if (!isset($this->config['apiKey'])) { + if (empty($this->config->apiKey)) { throw new \InvalidArgumentException('API key is required'); } - if (!filter_var($this->config['apiUrl'], FILTER_VALIDATE_URL)) { + if (!filter_var($this->config->apiUrl, FILTER_VALIDATE_URL)) { throw new \InvalidArgumentException('API URL must be a valid URL'); } - if (!is_int($this->config['batchSize']) || $this->config['batchSize'] <= 0 || $this->config['batchSize'] > 250) { - throw new \InvalidArgumentException('Batch size must be an integer between 1 and 250'); + if ($this->config->batchSize <= 0 || $this->config->batchSize > 250) { + throw new \InvalidArgumentException('Batch size must be between 1 and 250'); } - if (!is_int($this->config['idealBatchItemSize']) || $this->config['idealBatchItemSize'] <= 0 || $this->config['idealBatchItemSize'] > 2500) { - throw new \InvalidArgumentException('Ideal batch item size must be an integer between 1 and 2500'); + if ($this->config->idealBatchItemSize <= 0 || $this->config->idealBatchItemSize > 2500) { + throw new \InvalidArgumentException('Ideal batch item size must be between 1 and 2500'); } $this->_httpClient = new Client( [ - 'base_uri' => $this->config['apiUrl'], + 'base_uri' => $this->config->apiUrl, 'headers' => [ 'Content-Type' => 'application/json; charset=utf-8', - 'Authorization' => 'Bearer ' . $this->config['apiKey'] + 'Authorization' => 'Bearer ' . $this->config->apiKey ] ] ); } /** - * Localize content using the Lingo.dev API - * - * @param array $payload The content to be localized - * @param array $params Localization parameters including source/target locales and fast mode option - * @param callable|null $progressCallback Optional callback function to report progress (0-100) - * - * @return array Localized content + * Localize content using the Lingo.dev API. + * + * @param array $payload Content to translate + * @param TranslationOptions $options Translation configuration + * @param callable|null $progressCallback Progress callback (0-100%, chunk, result) + * + * @return array Translated content + * * @internal */ - protected function localizeRaw(array $payload, array $params, ?callable $progressCallback = null): array + protected function localizeRaw(array $payload, TranslationOptions $options, ?callable $progressCallback = null): array { - if (!isset($params['targetLocale'])) { - throw new \InvalidArgumentException('Target locale is required'); - } - - if (isset($params['sourceLocale']) && !is_string($params['sourceLocale']) && $params['sourceLocale'] !== null) { - throw new \InvalidArgumentException('Source locale must be a string or null'); - } - - if (!is_string($params['targetLocale'])) { - throw new \InvalidArgumentException('Target locale must be a string'); - } - $chunkedPayload = $this->_extractPayloadChunks($payload); $processedPayloadChunks = []; @@ -118,14 +123,14 @@ protected function localizeRaw(array $payload, array $params, ?callable $progres $percentageCompleted = round((($i + 1) / count($chunkedPayload)) * 100); $processedPayloadChunk = $this->_localizeChunk( - $params['sourceLocale'] ?? null, - $params['targetLocale'], + $options->sourceLocale, + $options->targetLocale, [ - 'data' => $chunk, - 'reference' => $params['reference'] ?? null + 'data' => $chunk, + 'reference' => $options->reference ], $workflowId, - $params['fast'] ?? false + $options->fast ); if ($progressCallback) { @@ -139,15 +144,18 @@ protected function localizeRaw(array $payload, array $params, ?callable $progres } /** - * Localize a single chunk of content - * - * @param string|null $sourceLocale Source locale - * @param string $targetLocale Target locale - * @param array $payload Payload containing the chunk to be localized - * @param string $workflowId Workflow ID - * @param bool $fast Whether to use fast mode - * - * @return array Localized chunk + * Localize a single chunk of content. + * + * @param string|null $sourceLocale Source language code or null for auto-detect + * @param string $targetLocale Target language code + * @param array{data: array, reference?: array|null} $payload Content chunk with optional reference + * @param string $workflowId Workflow tracking ID + * @param bool $fast Fast mode flag + * + * @return array Translated chunk + * + * @throws \InvalidArgumentException Invalid reference format + * @throws \RuntimeException API request failure */ private function _localizeChunk(?string $sourceLocale, string $targetLocale, array $payload, string $workflowId, bool $fast): array { @@ -204,11 +212,11 @@ private function _localizeChunk(?string $sourceLocale, string $targetLocale, arr } /** - * Extract payload chunks based on the ideal chunk size - * - * @param array $payload The payload to be chunked - * - * @return array An array of payload chunks + * Extract payload chunks based on the ideal chunk size. + * + * @param array $payload The payload to be chunked + * + * @return array> Array of payload chunks */ private function _extractPayloadChunks(array $payload): array { @@ -227,9 +235,9 @@ private function _extractPayloadChunks(array $payload): array $currentChunkItemCount++; $currentChunkSize = $this->_countWordsInRecord($currentChunk); - - if ($currentChunkSize > $this->config['idealBatchItemSize'] - || $currentChunkItemCount >= $this->config['batchSize'] + + if ($currentChunkSize > $this->config->idealBatchItemSize + || $currentChunkItemCount >= $this->config->batchSize || $i === count($keys) - 1 ) { $result[] = $currentChunk; @@ -242,11 +250,11 @@ private function _extractPayloadChunks(array $payload): array } /** - * Count words in a record or array - * + * Count words in a record or array. + * * @param mixed $payload The payload to count words in - * - * @return int The total number of words + * + * @return int Total number of words */ private function _countWordsInRecord($payload): int { @@ -270,8 +278,8 @@ private function _countWordsInRecord($payload): int } /** - * Generate a unique ID - * + * Generate a unique ID. + * * @return string Unique ID */ private function _createId(): string @@ -280,24 +288,25 @@ private function _createId(): string } /** - * Localize a typical PHP array or object - * - * @param array $obj The object to be localized (strings will be extracted and translated) - * @param array $params Localization parameters: - * - sourceLocale: The source language code (e.g., 'en') - * - targetLocale: The target language code (e.g., 'es') - * - fast: Optional boolean to enable fast mode - * @param callable|null $progressCallback Optional callback function to report progress (0-100) - * - * @return array A new object with the same structure but localized string values + * Localize every string in a nested array while keeping its shape intact. + * + * Example: + * $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); + * $engine = new LingoDotDevEngine($config); + * $options = TranslationOptions::create('fr')->from('en'); + * $engine->localizeObject(['greeting' => 'Hello'], $options); + * + * @param array $obj Nested data structure to translate + * @param TranslationOptions $options Translation options + * @param callable|null $progressCallback Progress callback (%, batch, result) + * + * @return array Translated data preserving structure + * + * @throws \RuntimeException API request failure */ - public function localizeObject(array $obj, array $params, ?callable $progressCallback = null): array + public function localizeObject(array $obj, TranslationOptions $options, ?callable $progressCallback = null): array { - if (!isset($params['targetLocale'])) { - throw new \InvalidArgumentException('Target locale is required'); - } - - return $this->localizeRaw($obj, $params, function($progress, $chunk, $processedChunk) use ($progressCallback) { + return $this->localizeRaw($obj, $options, function($progress, $chunk, $processedChunk) use ($progressCallback) { if ($progressCallback) { $progressCallback($progress, $chunk, $processedChunk); } @@ -305,80 +314,108 @@ public function localizeObject(array $obj, array $params, ?callable $progressCal } /** - * Localize a single text string - * - * @param string $text The text string to be localized - * @param array $params Localization parameters: - * - sourceLocale: The source language code (e.g., 'en') - * - targetLocale: The target language code (e.g., 'es') - * - fast: Optional boolean to enable fast mode - * @param callable|null $progressCallback Optional callback function to report progress (0-100) - * - * @return string The localized text string + * Localize a single string and return the translated text. + * + * Examples: + * $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); + * $engine = new LingoDotDevEngine($config); + * + * // Simple translation + * $options = TranslationOptions::create('es')->from('en'); + * $engine->localizeText('Hello, world!', $options); + * + * // With progress callback + * $engine->localizeText( + * 'This is a very long text...', + * $options, + * function (int $progress): void { + * echo "Progress: {$progress}%\n"; + * } + * ); + * + * // Auto-detect source language + * $options = TranslationOptions::create('en'); + * $engine->localizeText('Bonjour le monde', $options); + * + * @param string $text Text to translate + * @param TranslationOptions $options Translation options + * @param callable|null $progressCallback Progress callback (0-100%) + * + * @return string Translated text or empty string + * + * @throws \RuntimeException API request failure */ - public function localizeText(string $text, array $params, ?callable $progressCallback = null): string + public function localizeText(string $text, TranslationOptions $options, ?callable $progressCallback = null): string { - if (!isset($params['targetLocale'])) { - throw new \InvalidArgumentException('Target locale is required'); - } - - $response = $this->localizeRaw(['text' => $text], $params, function($progress, $chunk, $processedChunk) use ($progressCallback) { + $response = $this->localizeRaw(['text' => $text], $options, function($progress, $chunk, $processedChunk) use ($progressCallback) { if ($progressCallback) { $progressCallback($progress); } }); - + return $response['text'] ?? ''; } /** - * Localize a text string to multiple target locales - * - * @param string $text The text string to be localized - * @param array $params Localization parameters: - * - sourceLocale: The source language code (e.g., 'en') - * - targetLocales: An array of target language codes (e.g., ['es', 'fr']) - * - fast: Optional boolean to enable fast mode - * - * @return array An array of localized text strings + * Localize a string into multiple languages and return texts in order. + * + * Example: + * $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); + * $engine = new LingoDotDevEngine($config); + * + * $options = BatchTranslationOptions::create('en') + * ->to(['es', 'fr', 'de']) + * ->withFastMode(); + * $engine->batchLocalizeText('Hello, world!', $options); + * + * @param string $text Text to translate + * @param BatchTranslationOptions $options Batch translation options + * + * @return string[] Translated texts in targetLocales order + * + * @throws \RuntimeException Individual request failure */ - public function batchLocalizeText(string $text, array $params): array + public function batchLocalizeText(string $text, BatchTranslationOptions $options): array { - if (!isset($params['sourceLocale'])) { - throw new \InvalidArgumentException('Source locale is required'); - } + $responses = []; + foreach ($options->targetLocales as $targetLocale) { + $translationOptions = TranslationOptions::create($targetLocale) + ->from($options->sourceLocale); - if (!isset($params['targetLocales']) || !is_array($params['targetLocales'])) { - throw new \InvalidArgumentException('Target locales must be an array'); - } + if ($options->fast) { + $translationOptions->withFastMode(); + } - $responses = []; - foreach ($params['targetLocales'] as $targetLocale) { - $responses[] = $this->localizeText( - $text, [ - 'sourceLocale' => $params['sourceLocale'], - 'targetLocale' => $targetLocale, - 'fast' => $params['fast'] ?? false - ] - ); + $responses[] = $this->localizeText($text, $translationOptions); } return $responses; } /** - * Localize a chat sequence while preserving speaker names - * - * @param array $chat Array of chat messages, each with 'name' and 'text' properties - * @param array $params Localization parameters: - * - sourceLocale: The source language code (e.g., 'en') - * - targetLocale: The target language code (e.g., 'es') - * - fast: Optional boolean to enable fast mode - * @param callable|null $progressCallback Optional callback function to report progress (0-100) - * - * @return array Array of localized chat messages with preserved structure + * Localize a chat transcript while preserving speaker names. + * + * Example: + * $conversation = [ + * ['name' => 'Alice', 'text' => 'Hello, how are you?'], + * ['name' => 'Bob', 'text' => 'I am fine, thank you!'], + * ]; + * + * $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); + * $engine = new LingoDotDevEngine($config); + * $options = TranslationOptions::create('de')->from('en'); + * $engine->localizeChat($conversation, $options); + * + * @param array $chat Conversation with names and messages + * @param TranslationOptions $options Translation options + * @param callable|null $progressCallback Progress callback (0-100%) + * + * @return array Translated chat preserving names + * + * @throws \InvalidArgumentException Invalid chat entries + * @throws \RuntimeException API request failure */ - public function localizeChat(array $chat, array $params, ?callable $progressCallback = null): array + public function localizeChat(array $chat, TranslationOptions $options, ?callable $progressCallback = null): array { foreach ($chat as $message) { if (!isset($message['name']) || !isset($message['text'])) { @@ -386,7 +423,7 @@ public function localizeChat(array $chat, array $params, ?callable $progressCall } } - $localized = $this->localizeRaw(['chat' => $chat], $params, function($progress, $chunk, $processedChunk) use ($progressCallback) { + $localized = $this->localizeRaw(['chat' => $chat], $options, function($progress, $chunk, $processedChunk) use ($progressCallback) { if ($progressCallback) { $progressCallback($progress); } @@ -408,11 +445,19 @@ public function localizeChat(array $chat, array $params, ?callable $progressCall } /** - * Detect the language of a given text - * - * @param string $text The text to analyze - * - * @return string Locale code (e.g., 'en', 'es', 'fr') + * Identify the locale of the provided text. + * + * Example: + * $config = EngineConfig::create($_ENV['LINGODOTDEV_API_KEY']); + * $engine = new LingoDotDevEngine($config); + * $engine->recognizeLocale('Bonjour le monde'); + * + * @param string $text Sample text for language detection + * + * @return string ISO language code (e.g., 'en', 'es', 'zh') + * + * @throws \InvalidArgumentException Empty text provided + * @throws \RuntimeException Invalid API response or request failure */ public function recognizeLocale(string $text): string { diff --git a/src/TranslationOptions.php b/src/TranslationOptions.php new file mode 100644 index 0000000..d4d6b3f --- /dev/null +++ b/src/TranslationOptions.php @@ -0,0 +1,94 @@ + + * @license MIT https://opensource.org/licenses/MIT + * @link https://lingo.dev + */ + +namespace LingoDotDev\Sdk; + +/** + * Options for text and object translation. + * + * @category Localization + * @package Lingodotdev\Sdk + * @author Lingo.dev Team + * @license MIT https://opensource.org/licenses/MIT + * @link https://lingo.dev + */ +class TranslationOptions +{ + /** + * Target language code (e.g., 'es', 'fr') + * Required field. + */ + public string $targetLocale; + + /** + * Source language code or null for auto-detection + * Example: 'en', 'es', or null + */ + public ?string $sourceLocale = null; + + /** + * Enable fast mode - trades translation quality for speed + * Default: false (quality mode) + */ + public bool $fast = false; + + /** + * Context data or glossary terms to guide translation + * Can include domain-specific terminology or reference translations + * + * @var array|null + */ + public ?array $reference = null; + + + /** + * Create a fluent builder for translation options. + * + * @param string $targetLocale Target language code + */ + public static function create(string $targetLocale): self + { + $instance = new self(); + $instance->targetLocale = $targetLocale; + return $instance; + } + + /** + * Set source locale. + * + * @param string|null $locale Source language code or null for auto-detection + */ + public function from(?string $locale): self + { + $this->sourceLocale = $locale; + return $this; + } + + /** + * Enable fast translation mode. + */ + public function withFastMode(): self + { + $this->fast = true; + return $this; + } + + /** + * Add reference data for context. + * + * @param array $reference Context or glossary data + */ + public function withReference(array $reference): self + { + $this->reference = $reference; + return $this; + } +} \ No newline at end of file