From 7c77daa5052ca8f0b3f77541cf147a7e5c2c8ddf Mon Sep 17 00:00:00 2001 From: Bohdan Bobko <172895427+bhdnb@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:35:34 +0300 Subject: [PATCH] feat: Pre-Trasnslation Report API (#228) --- src/CrowdinApiClient/Api/TranslationApi.php | 12 +++ .../Model/PreTranslationReport.php | 42 ++++++++++ .../Model/PreTranslationReportFile.php | 37 +++++++++ .../PreTranslationReportFileStatistics.php | 37 +++++++++ .../Model/PreTranslationReportLanguage.php | 61 +++++++++++++++ .../Api/TranslationApiTest.php | 60 +++++++++++++- ...PreTranslationReportFileStatisticsTest.php | 28 +++++++ .../Model/PreTranslationReportFileTest.php | 35 +++++++++ .../PreTranslationReportLanguageTest.php | 71 +++++++++++++++++ .../Model/PreTranslationReportTest.php | 78 +++++++++++++++++++ 10 files changed, 459 insertions(+), 2 deletions(-) create mode 100644 src/CrowdinApiClient/Model/PreTranslationReport.php create mode 100644 src/CrowdinApiClient/Model/PreTranslationReportFile.php create mode 100644 src/CrowdinApiClient/Model/PreTranslationReportFileStatistics.php create mode 100644 src/CrowdinApiClient/Model/PreTranslationReportLanguage.php create mode 100644 tests/CrowdinApiClient/Model/PreTranslationReportFileStatisticsTest.php create mode 100644 tests/CrowdinApiClient/Model/PreTranslationReportFileTest.php create mode 100644 tests/CrowdinApiClient/Model/PreTranslationReportLanguageTest.php create mode 100644 tests/CrowdinApiClient/Model/PreTranslationReportTest.php diff --git a/src/CrowdinApiClient/Api/TranslationApi.php b/src/CrowdinApiClient/Api/TranslationApi.php index d59c11d4..478f5075 100644 --- a/src/CrowdinApiClient/Api/TranslationApi.php +++ b/src/CrowdinApiClient/Api/TranslationApi.php @@ -6,6 +6,7 @@ use CrowdinApiClient\Model\DownloadFile; use CrowdinApiClient\Model\DownloadFileTranslation; use CrowdinApiClient\Model\PreTranslation; +use CrowdinApiClient\Model\PreTranslationReport; use CrowdinApiClient\Model\TranslationProjectBuild; use CrowdinApiClient\Model\TranslationProjectDirectory; use CrowdinApiClient\ModelCollection; @@ -75,6 +76,17 @@ public function updatePreTranslation(int $projectId, PreTranslation $preTranslat return $this->_update($path, $preTranslation); } + /** + * Pre-Translation Report + * @link https://developer.crowdin.com/api/v2/#operation/api.projects.pre-translations.patch API Documentation + * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.pre-translations.patch API Documentation Enterprise + */ + public function getPreTranslationReport(int $projectId, string $preTranslationId): ?PreTranslationReport + { + $path = sprintf('projects/%d/pre-translations/%s/report', $projectId, $preTranslationId); + return $this->_get($path, PreTranslationReport::class); + } + /** * Build Project Directory Translation * @link https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.directories.post API Documentation diff --git a/src/CrowdinApiClient/Model/PreTranslationReport.php b/src/CrowdinApiClient/Model/PreTranslationReport.php new file mode 100644 index 00000000..64d1accf --- /dev/null +++ b/src/CrowdinApiClient/Model/PreTranslationReport.php @@ -0,0 +1,42 @@ +preTranslationType = (string)$this->getDataProperty('preTranslateType'); + $this->languages = array_map(static function (array $language): PreTranslationReportLanguage { + return new PreTranslationReportLanguage($language); + }, (array)$this->getDataProperty('languages')); + } + + public function getPreTranslationType(): string + { + return $this->preTranslationType; + } + + /** + * @return PreTranslationReportLanguage[] + */ + public function getLanguages(): array + { + return $this->languages; + } +} diff --git a/src/CrowdinApiClient/Model/PreTranslationReportFile.php b/src/CrowdinApiClient/Model/PreTranslationReportFile.php new file mode 100644 index 00000000..55b3721f --- /dev/null +++ b/src/CrowdinApiClient/Model/PreTranslationReportFile.php @@ -0,0 +1,37 @@ +id = (string)$this->getDataProperty('id'); + $this->statistics = new PreTranslationReportFileStatistics((array)$this->getDataProperty('statistics')); + } + + public function getId(): string + { + return $this->id; + } + + public function getStatistics(): PreTranslationReportFileStatistics + { + return $this->statistics; + } +} diff --git a/src/CrowdinApiClient/Model/PreTranslationReportFileStatistics.php b/src/CrowdinApiClient/Model/PreTranslationReportFileStatistics.php new file mode 100644 index 00000000..96b72275 --- /dev/null +++ b/src/CrowdinApiClient/Model/PreTranslationReportFileStatistics.php @@ -0,0 +1,37 @@ +phrases = (int)$this->getDataProperty('phrases'); + $this->words = (int)$this->getDataProperty('words'); + } + + public function getPhrases(): int + { + return $this->phrases; + } + + public function getWords(): int + { + return $this->words; + } +} diff --git a/src/CrowdinApiClient/Model/PreTranslationReportLanguage.php b/src/CrowdinApiClient/Model/PreTranslationReportLanguage.php new file mode 100644 index 00000000..8369f094 --- /dev/null +++ b/src/CrowdinApiClient/Model/PreTranslationReportLanguage.php @@ -0,0 +1,61 @@ + + */ + protected $skippedInfo; + + /** + * @var array + */ + protected $skippedQaCheckCategories; + + public function __construct(array $data = []) + { + parent::__construct($data); + + $this->id = (string)$this->getDataProperty('id'); + $this->files = array_map(static function (array $file): PreTranslationReportFile { + return new PreTranslationReportFile($file); + }, (array)$this->getDataProperty('files')); + $this->skippedInfo = (array)$this->getDataProperty('skipped'); + $this->skippedQaCheckCategories = (array)$this->getDataProperty('skippedQaCheckCategories'); + } + + public function getId(): string + { + return $this->id; + } + + public function getFiles(): array + { + return $this->files; + } + + public function getSkippedInfo(): array + { + return $this->skippedInfo; + } + + public function getSkippedQaCheckCategories(): array + { + return $this->skippedQaCheckCategories; + } +} diff --git a/tests/CrowdinApiClient/Api/TranslationApiTest.php b/tests/CrowdinApiClient/Api/TranslationApiTest.php index ead8bbf4..9cb60697 100644 --- a/tests/CrowdinApiClient/Api/TranslationApiTest.php +++ b/tests/CrowdinApiClient/Api/TranslationApiTest.php @@ -4,6 +4,9 @@ use CrowdinApiClient\Model\DownloadFile; use CrowdinApiClient\Model\PreTranslation; +use CrowdinApiClient\Model\PreTranslationReport; +use CrowdinApiClient\Model\PreTranslationReportFile; +use CrowdinApiClient\Model\PreTranslationReportLanguage; use CrowdinApiClient\Model\TranslationProjectBuild; use CrowdinApiClient\ModelCollection; @@ -146,7 +149,7 @@ public function testUpdatePreTranslation(): void 'op' => 'replace', 'path' => '/status', 'value' => 'canceled', - ] + ], ]), 'response' => json_encode([ 'data' => [ @@ -162,7 +165,7 @@ public function testUpdatePreTranslation(): void 'startedAt' => '2019-11-13T08:17:22Z', 'finishedAt' => '2019-11-13T08:17:22Z', ], - ]) + ]), ]); $preTranslation = new PreTranslation([ @@ -187,6 +190,59 @@ public function testUpdatePreTranslation(): void $this->assertSame(0, $actual->getProgress()); } + public function testGetPreTranslationReport(): void + { + $this->mockRequestGet( + '/projects/2/pre-translations/9e7de270-4f83-41cb-b606-2f90631f26e2/report', + json_encode([ + 'data' => [ + 'languages' => [ + [ + 'id' => 'es', + 'files' => [ + [ + 'id' => '10191', + 'statistics' => [ + 'phrases' => 6, + 'words' => 13, + ], + ], + ], + 'skipped' => [ + 'translation_eq_source' => 2, + 'qa_check' => 1, + 'hidden_strings' => 0, + 'ai_error' => 6, + ], + 'skippedQaCheckCategories' => [ + 'duplicate' => 1, + 'spellcheck' => 1, + ], + ], + ], + 'preTranslateType' => 'ai', + ], + ]) + ); + + $preTranslationReport = $this->crowdin->translation->getPreTranslationReport( + 2, + '9e7de270-4f83-41cb-b606-2f90631f26e2' + ); + + $this->assertInstanceOf(PreTranslationReport::class, $preTranslationReport); + $this->assertEquals('ai', $preTranslationReport->getPreTranslationType()); + $this->assertIsArray($preTranslationReport->getLanguages()); + $this->assertInstanceOf(PreTranslationReportLanguage::class, $preTranslationReport->getLanguages()[0]); + $this->assertSame('es', $preTranslationReport->getLanguages()[0]->getId()); + $this->assertInstanceOf( + PreTranslationReportFile::class, + $preTranslationReport->getLanguages()[0]->getFiles()[0] + ); + $this->assertIsArray($preTranslationReport->getLanguages()[0]->getSkippedInfo()); + $this->assertIsArray($preTranslationReport->getLanguages()[0]->getSkippedQaCheckCategories()); + } + public function testBuildProjectFileTranslation(): void { $this->mockRequest([ diff --git a/tests/CrowdinApiClient/Model/PreTranslationReportFileStatisticsTest.php b/tests/CrowdinApiClient/Model/PreTranslationReportFileStatisticsTest.php new file mode 100644 index 00000000..4f5a2c8a --- /dev/null +++ b/tests/CrowdinApiClient/Model/PreTranslationReportFileStatisticsTest.php @@ -0,0 +1,28 @@ + 6, + 'words' => 13, + ]; + + public function testLoadData(): void + { + $preTranslationReportFileStatistics = new PreTranslationReportFileStatistics($this->data); + + $this->assertEquals( + $this->data['phrases'], + $preTranslationReportFileStatistics->getPhrases() + ); + $this->assertEquals( + $this->data['words'], + $preTranslationReportFileStatistics->getWords() + ); + } +} diff --git a/tests/CrowdinApiClient/Model/PreTranslationReportFileTest.php b/tests/CrowdinApiClient/Model/PreTranslationReportFileTest.php new file mode 100644 index 00000000..80d75b03 --- /dev/null +++ b/tests/CrowdinApiClient/Model/PreTranslationReportFileTest.php @@ -0,0 +1,35 @@ + '10191', + 'statistics' => [ + 'phrases' => 6, + 'words' => 13, + ], + ]; + + public function testLoadData(): void + { + $preTranslationReportFile = new PreTranslationReportFile($this->data); + + $this->assertEquals( + $this->data['id'], + $preTranslationReportFile->getId() + ); + $this->assertEquals( + $this->data['statistics']['phrases'], + $preTranslationReportFile->getStatistics()->getPhrases() + ); + $this->assertEquals( + $this->data['statistics']['words'], + $preTranslationReportFile->getStatistics()->getWords() + ); + } +} diff --git a/tests/CrowdinApiClient/Model/PreTranslationReportLanguageTest.php b/tests/CrowdinApiClient/Model/PreTranslationReportLanguageTest.php new file mode 100644 index 00000000..712cad20 --- /dev/null +++ b/tests/CrowdinApiClient/Model/PreTranslationReportLanguageTest.php @@ -0,0 +1,71 @@ + 'es', + 'files' => [ + [ + 'id' => '10191', + 'statistics' => [ + 'phrases' => 6, + 'words' => 13, + ], + ], + ], + 'skipped' => [ + 'translation_eq_source' => 2, + 'qa_check' => 1, + 'hidden_strings' => 0, + 'ai_error' => 6, + ], + 'skippedQaCheckCategories' => [ + 'duplicate' => 1, + 'spellcheck' => 1, + ], + ]; + + public function testLoadData(): void + { + $preTranslationReportLanguage = new PreTranslationReportLanguage($this->data); + + $this->assertEquals($this->data['id'], $preTranslationReportLanguage->getId()); + $this->assertEquals( + $this->data['files'][0]['id'], + $preTranslationReportLanguage->getFiles()[0]->getId() + ); + $this->assertEquals( + $this->data['files'][0]['statistics']['phrases'], + $preTranslationReportLanguage->getFiles()[0]->getStatistics()->getPhrases() + ); + $this->assertEquals( + $this->data['files'][0]['statistics']['words'], + $preTranslationReportLanguage->getFiles()[0]->getStatistics()->getWords() + ); + $this->assertEquals( + $this->data['skipped']['translation_eq_source'], + $preTranslationReportLanguage->getSkippedInfo()['translation_eq_source'] + ); + $this->assertEquals( + $this->data['skipped']['qa_check'], + $preTranslationReportLanguage->getSkippedInfo()['qa_check'] + ); + $this->assertEquals( + $this->data['skipped']['hidden_strings'], + $preTranslationReportLanguage->getSkippedInfo()['hidden_strings'] + ); + $this->assertEquals( + $this->data['skipped']['ai_error'], + $preTranslationReportLanguage->getSkippedInfo()['ai_error'] + ); + $this->assertEquals( + $this->data['skippedQaCheckCategories'], + $preTranslationReportLanguage->getSkippedQaCheckCategories() + ); + } +} diff --git a/tests/CrowdinApiClient/Model/PreTranslationReportTest.php b/tests/CrowdinApiClient/Model/PreTranslationReportTest.php new file mode 100644 index 00000000..fa2f8a5e --- /dev/null +++ b/tests/CrowdinApiClient/Model/PreTranslationReportTest.php @@ -0,0 +1,78 @@ + [ + [ + 'id' => 'es', + 'files' => [ + [ + 'id' => '10191', + 'statistics' => [ + 'phrases' => 6, + 'words' => 13, + ], + ], + ], + 'skipped' => [ + 'translation_eq_source' => 2, + 'qa_check' => 1, + 'hidden_strings' => 0, + 'ai_error' => 6, + ], + 'skippedQaCheckCategories' => [ + 'duplicate' => 1, + 'spellcheck' => 1, + ], + ], + ], + 'preTranslateType' => 'ai', + ]; + + public function testLoadData(): void + { + $preTranslation = new PreTranslationReport($this->data); + + $this->assertEquals($this->data['preTranslateType'], $preTranslation->getPreTranslationType()); + $this->assertIsArray($preTranslation->getLanguages()); + $this->assertEquals($this->data['languages'][0]['id'], $preTranslation->getLanguages()[0]->getId()); + $this->assertEquals( + $this->data['languages'][0]['files'][0]['id'], + $preTranslation->getLanguages()[0]->getFiles()[0]->getId() + ); + $this->assertEquals( + $this->data['languages'][0]['files'][0]['statistics']['phrases'], + $preTranslation->getLanguages()[0]->getFiles()[0]->getStatistics()->getPhrases() + ); + $this->assertEquals( + $this->data['languages'][0]['files'][0]['statistics']['words'], + $preTranslation->getLanguages()[0]->getFiles()[0]->getStatistics()->getWords() + ); + $this->assertEquals( + $this->data['languages'][0]['skipped']['translation_eq_source'], + $preTranslation->getLanguages()[0]->getSkippedInfo()['translation_eq_source'] + ); + $this->assertEquals( + $this->data['languages'][0]['skipped']['qa_check'], + $preTranslation->getLanguages()[0]->getSkippedInfo()['qa_check'] + ); + $this->assertEquals( + $this->data['languages'][0]['skipped']['hidden_strings'], + $preTranslation->getLanguages()[0]->getSkippedInfo()['hidden_strings'] + ); + $this->assertEquals( + $this->data['languages'][0]['skipped']['ai_error'], + $preTranslation->getLanguages()[0]->getSkippedInfo()['ai_error'] + ); + $this->assertEquals( + $this->data['languages'][0]['skippedQaCheckCategories'], + $preTranslation->getLanguages()[0]->getSkippedQaCheckCategories() + ); + } +}