Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
TranslateI18nJob
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getJobType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2declare(strict_types=1);
3
4namespace App\Job;
5
6use App\Service\Api\AiService;
7use App\Service\Api\Google\GoogleApiService;
8use App\Utility\SettingsManager;
9use Cake\Queue\Job\Message;
10use Interop\Queue\Processor;
11
12/**
13 * TranslateI18nJob
14 *
15 * This job processes messages to update internationalizations using either AI (via Anthropic/OpenRouter) or Google API.
16 * It retrieves the internationalizations based on the provided IDs and updates them in batches.
17 */
18class TranslateI18nJob extends AbstractJob
19{
20    /**
21     * @var \App\Service\Api\AiService|\App\Service\Api\Google\GoogleApiService The API service instance.
22     */
23    private AiService|GoogleApiService $apiService;
24
25    /**
26     * Constructor to allow dependency injection for testing
27     *
28     * @param \App\Service\Api\AiService|null $aiService
29     * @param \App\Service\Api\Google\GoogleApiService|null $googleService
30     */
31    public function __construct(?AiService $aiService = null, ?GoogleApiService $googleService = null)
32    {
33        $apiProvider = SettingsManager::read('i18n.provider', 'google');
34
35        if ($apiProvider === 'google') {
36            $this->apiService = $googleService ?? new GoogleApiService();
37        } else {
38            $this->apiService = $aiService ?? new AiService();
39        }
40    }
41
42    /**
43     * Get the human-readable job type name for logging
44     *
45     * @return string The job type description
46     */
47    protected static function getJobType(): string
48    {
49        return 'i18n translation';
50    }
51
52    /**
53     * Executes the job to update internationalizations.
54     *
55     * This method processes the message, retrieves the internationalizations based on the provided IDs,
56     * and updates them in batches using the selected API service.
57     *
58     * @param \Cake\Queue\Job\Message $message The message containing internationalization IDs.
59     * @return string|null Returns Processor::ACK on success, Processor::REJECT on failure.
60     */
61    public function execute(Message $message): ?string
62    {
63        if (!$this->validateArguments($message, ['internationalisations', 'locale'])) {
64            return Processor::REJECT;
65        }
66
67        $internationalisations = $message->getArgument('internationalisations');
68        $locale = $message->getArgument('locale');
69
70        $i18nTable = $this->getTable('internationalisations');
71        $internationalizations = $i18nTable->find()
72            ->select(['id', 'locale', 'message_id'])
73            ->where(['id IN' => $internationalisations])
74            ->all();
75
76        if ($internationalizations->isEmpty()) {
77            $this->logJobError($locale, 'No internationalizations found for the provided IDs');
78
79            return Processor::REJECT;
80        }
81
82        $messageStrings = $internationalizations->extract('message_id')->toArray();
83
84        return $this->executeWithErrorHandling($locale, function () use ($messageStrings, $locale, $i18nTable) {
85            $translatedMessages = $this->apiService->translateStrings(
86                $messageStrings,
87                'en_GB',
88                $locale,
89            );
90
91            foreach ($translatedMessages['translations'] as $index => $translation) {
92                $originalMessage = $messageStrings[$index];
93
94                $existingTranslation = $i18nTable->find()
95                    ->where([
96                        'message_id' => $originalMessage,
97                        'locale' => $locale,
98                    ])
99                    ->first();
100
101                if ($existingTranslation) {
102                    $existingTranslation->message_str = $translation['translated'];
103                    $i18nTable->save($existingTranslation);
104                }
105            }
106
107            return true;
108        });
109    }
110}