From 950a3e3bf8a38c270e41bcd8f60c62c8efdc8913 Mon Sep 17 00:00:00 2001 From: Max Inno Date: Tue, 1 Sep 2026 14:41:06 +0300 Subject: [PATCH] feat: add TM Segment Batch Operations support Add PATCH /tms/{tmId}/segments (api.tms.segments.patchBatch) with add/replace/remove operations for TM segments and their records. --- .../api_resources/translation_memory/enums.py | 14 ++++++ .../translation_memory/resource.py | 26 ++++++++++ .../test_translation_memory_resources.py | 50 +++++++++++++++++++ .../api_resources/translation_memory/types.py | 25 +++++++++- 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/crowdin_api/api_resources/translation_memory/enums.py b/crowdin_api/api_resources/translation_memory/enums.py index f6fcfd1..7507fe8 100644 --- a/crowdin_api/api_resources/translation_memory/enums.py +++ b/crowdin_api/api_resources/translation_memory/enums.py @@ -17,6 +17,20 @@ class TranslationMemorySegmentRecordOperationPath(Enum): REMOVE = "/records/{recordId}" +class TranslationMemorySegmentBatchOperation(Enum): + ADD = "add" + REPLACE = "replace" + REMOVE = "remove" + + +class TranslationMemorySegmentBatchOperationPath(Enum): + ADD = "/-" + ADD_RECORD = "/{segmentId}/records/-" + REPLACE = "/{segmentId}/records/{recordId}/text" + REMOVE = "/{segmentId}" + REMOVE_RECORD = "/{segmentId}/records/{recordId}" + + class ListTmsOrderBy(Enum): ID = "id" NAME = "name" diff --git a/crowdin_api/api_resources/translation_memory/resource.py b/crowdin_api/api_resources/translation_memory/resource.py index c47df49..4a029f4 100644 --- a/crowdin_api/api_resources/translation_memory/resource.py +++ b/crowdin_api/api_resources/translation_memory/resource.py @@ -4,6 +4,9 @@ from crowdin_api.api_resources.enums import ExportFormat from crowdin_api.api_resources.translation_memory.types import ( TranslationMemoryPatchRequest, + TranslationMemorySegmentBatchOperationAdd, + TranslationMemorySegmentBatchOperationRemove, + TranslationMemorySegmentBatchOperationReplace, TranslationMemorySegmentRecord, TranslationMemorySegmentRecordOperationAdd, TranslationMemorySegmentRecordOperationReplace, @@ -207,6 +210,29 @@ def edit_tm_segment( request_data=data, ) + def tm_segment_batch_operations( + self, + tmId: int, + data: Iterable[ + Union[ + TranslationMemorySegmentBatchOperationAdd, + TranslationMemorySegmentBatchOperationReplace, + TranslationMemorySegmentBatchOperationRemove, + ] + ], + ): + """ + TM Segment Batch Operations. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.tms.segments.patchBatch + """ + return self.requester.request( + method="patch", + path=self.get_tm_segments_path(tmId=tmId), + request_data=data, + ) + # Export def get_tm_export_path(self, tmId: int, exportId: Optional[str] = None): if exportId is not None: diff --git a/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py b/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py index ec4037f..1b9803e 100644 --- a/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py +++ b/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py @@ -6,6 +6,8 @@ ListTmSegmentsOrderBy, ListTmsOrderBy, TranslationMemoryPatchPath, + TranslationMemorySegmentBatchOperation, + TranslationMemorySegmentBatchOperationPath, TranslationMemorySegmentRecordOperation, TranslationMemorySegmentRecordOperationPath, ) @@ -275,6 +277,54 @@ def test_edit_tm_segment( ], ) + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_tm_segment_batch_operations(self, m_request, base_absolut_url): + m_request.return_value = "response" + + data = [ + { + "op": TranslationMemorySegmentBatchOperation.ADD, + "path": TranslationMemorySegmentBatchOperationPath.ADD, + "value": { + "records": [ + { + "languageId": "uk", + "text": "Перекладений текст", + } + ] + }, + }, + { + "op": TranslationMemorySegmentBatchOperation.ADD, + "path": TranslationMemorySegmentBatchOperationPath.ADD_RECORD, + "value": { + "languageId": "it", + "text": "Ciao, mondo!", + }, + }, + { + "op": TranslationMemorySegmentBatchOperation.REMOVE, + "path": TranslationMemorySegmentBatchOperationPath.REMOVE, + }, + { + "op": TranslationMemorySegmentBatchOperation.REMOVE, + "path": TranslationMemorySegmentBatchOperationPath.REMOVE_RECORD, + }, + { + "op": TranslationMemorySegmentBatchOperation.REPLACE, + "path": TranslationMemorySegmentBatchOperationPath.REPLACE, + "value": "Testo tradotto", + }, + ] + + resource = self.get_resource(base_absolut_url) + assert resource.tm_segment_batch_operations(tmId=1, data=data) == "response" + m_request.assert_called_once_with( + method="patch", + path=resource.get_tm_segments_path(tmId=1), + request_data=data, + ) + # Export @pytest.mark.parametrize( "in_params, path", diff --git a/crowdin_api/api_resources/translation_memory/types.py b/crowdin_api/api_resources/translation_memory/types.py index 3fb0991..784dc83 100644 --- a/crowdin_api/api_resources/translation_memory/types.py +++ b/crowdin_api/api_resources/translation_memory/types.py @@ -1,8 +1,10 @@ -from typing import Any +from typing import Any, Iterable, Union from crowdin_api.api_resources.enums import PatchOperation from crowdin_api.api_resources.translation_memory.enums import ( TranslationMemoryPatchPath, + TranslationMemorySegmentBatchOperation, + TranslationMemorySegmentBatchOperationPath, TranslationMemorySegmentRecordOperation, TranslationMemorySegmentRecordOperationPath, ) @@ -20,6 +22,10 @@ class TranslationMemorySegmentRecord(TypedDict): text: str +class TranslationMemorySegment(TypedDict): + records: Iterable[TranslationMemorySegmentRecord] + + class TranslationMemorySegmentRecordOperationAdd(TypedDict): op: TranslationMemorySegmentRecordOperation path: TranslationMemorySegmentRecordOperationPath @@ -35,3 +41,20 @@ class TranslationMemorySegmentRecordOperationReplace(TypedDict): class TranslationMemorySegmentRecordOperationRemove(TypedDict): op: TranslationMemorySegmentRecordOperation path: TranslationMemorySegmentRecordOperationPath + + +class TranslationMemorySegmentBatchOperationAdd(TypedDict): + op: TranslationMemorySegmentBatchOperation + path: TranslationMemorySegmentBatchOperationPath + value: Union[TranslationMemorySegment, TranslationMemorySegmentRecord] + + +class TranslationMemorySegmentBatchOperationReplace(TypedDict): + op: TranslationMemorySegmentBatchOperation + path: TranslationMemorySegmentBatchOperationPath + value: str + + +class TranslationMemorySegmentBatchOperationRemove(TypedDict): + op: TranslationMemorySegmentBatchOperation + path: TranslationMemorySegmentBatchOperationPath