From 334ee19bc7bb885828b3bd76485b2af4e40495ad Mon Sep 17 00:00:00 2001 From: Max Inno Date: Tue, 1 Sep 2026 15:22:29 +0300 Subject: [PATCH] feat: add TM Segment Batch Operations support Add batchOperations() to TranslationMemoryApi to support the PATCH /tms/{tmId}/segments endpoint (api.tms.segments.patchBatch), allowing add/remove/replace JSON Patch operations on TM segments and their records in a single request. --- .../Api/TranslationMemoryApi.php | 26 +++++++ .../Api/TranslationMemoryApiTest.php | 74 +++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/CrowdinApiClient/Api/TranslationMemoryApi.php b/src/CrowdinApiClient/Api/TranslationMemoryApi.php index 47755a2a..b746be16 100644 --- a/src/CrowdinApiClient/Api/TranslationMemoryApi.php +++ b/src/CrowdinApiClient/Api/TranslationMemoryApi.php @@ -149,6 +149,32 @@ public function createSegment(int $tmId, array $data): ?TranslationMemorySegment return $this->_create($path, TranslationMemorySegment::class, $data); } + /** + * TM Segment Batch Operations + * @link https://developer.crowdin.com/api/v2/#operation/api.tms.segments.patchBatch API Documentation + * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.tms.segments.patchBatch API Documentation Enterprise + * + * @param int $tmId + * @param array $data JSON Patch array with operations (add, remove, replace) + * @return ModelCollection + */ + public function batchOperations(int $tmId, array $data): ModelCollection + { + $path = sprintf('tms/%d/segments', $tmId); + + $options = [ + 'body' => json_encode($data), + 'headers' => $this->getHeaders(), + ]; + + return $this->client->apiRequest( + 'patch', + $path, + new ResponseModelListDecorator(TranslationMemorySegment::class), + $options + ); + } + /** * Delete TM Segment * @link https://developer.crowdin.com/api/v2/#operation/api.tms.segments.delete API Documentation diff --git a/tests/CrowdinApiClient/Api/TranslationMemoryApiTest.php b/tests/CrowdinApiClient/Api/TranslationMemoryApiTest.php index 673353c3..49fdae5c 100644 --- a/tests/CrowdinApiClient/Api/TranslationMemoryApiTest.php +++ b/tests/CrowdinApiClient/Api/TranslationMemoryApiTest.php @@ -457,6 +457,80 @@ public function testCreateSegment() $this->assertEquals(4, $segment->getId()); } + public function testBatchOperations() + { + $data = [ + [ + 'op' => 'add', + 'path' => '/-', + 'value' => [ + 'records' => [ + [ + 'languageId' => 'uk', + 'text' => 'Перекладений текст', + ], + ], + ], + ], + [ + 'op' => 'add', + 'path' => '/4/records/-', + 'value' => [ + 'languageId' => 'it', + 'text' => 'Ciao, mondo!', + ], + ], + [ + 'op' => 'remove', + 'path' => '/5', + ], + [ + 'op' => 'remove', + 'path' => '/4/records/1', + ], + [ + 'op' => 'replace', + 'path' => '/4/records/1/text', + 'value' => 'Updated translation text', + ], + ]; + + $this->mockRequest([ + 'path' => '/tms/4/segments', + 'method' => 'patch', + 'body' => json_encode($data), + 'response' => json_encode([ + 'data' => [ + [ + 'data' => [ + 'id' => 4, + 'records' => [ + [ + 'id' => 1, + 'languageId' => 'uk', + 'text' => 'Updated translation text', + 'usageCount' => 13, + 'createdBy' => 1, + 'updatedBy' => 1, + 'createdAt' => '2019-09-16T13:48:04+00:00', + 'updatedAt' => '2019-09-16T13:48:04+00:00', + ], + ], + ], + ], + ], + ]), + ]); + + $segments = $this->crowdin->translationMemory->batchOperations(4, $data); + + $this->assertInstanceOf(ModelCollection::class, $segments); + $this->assertCount(1, $segments); + $this->assertInstanceOf(TranslationMemorySegment::class, $segments[0]); + $this->assertEquals(4, $segments[0]->getId()); + $this->assertEquals('Updated translation text', $segments[0]->getRecords()[0]->getText()); + } + public function testDeleteSegment() { $this->mockRequestDelete('/tms/4/segments/1');