Skip to content

Commit 977d264

Browse files
committed
fix(LGT-167): Pre sync summary not displaying remote key count
1 parent 2d9bc23 commit 977d264

File tree

4 files changed

+187
-19
lines changed

4 files changed

+187
-19
lines changed

src/Commands/LinguistCommand.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,18 @@ private function renderKeyDiscoverySummary(string $projectSlug, LinguistApiClien
145145
->unique()
146146
->count();
147147

148-
$remoteKeyCount = 0;
148+
$remoteKeyCount = null;
149149

150150
try {
151151
$apiClient->setProjectSlug($projectSlug);
152152
$remoteKeyCount = $apiClient->countTranslationKeys();
153153
} catch (\Throwable) {
154-
$remoteKeyCount = 0;
154+
$remoteKeyCount = null;
155155
}
156156

157-
$this->components->info('Key discovery summary');
158-
$this->components->twoColumnDetail('Local keys discovered', (string) $localKeyCount);
159-
$this->components->twoColumnDetail('Remote keys', (string) $remoteKeyCount);
157+
$this->components->info('Translation key summary:');
158+
$this->components->twoColumnDetail('Local Translation Keys', (string) $localKeyCount);
159+
$this->components->twoColumnDetail('Linguist Project Translation Keys', $remoteKeyCount === null ? 'N/A' : (string) $remoteKeyCount);
160160
$this->newLine();
161161
}
162162

src/Commands/LinguistSetupCommand.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ private function renderKeyDiscoverySummary(string $apiToken, array $projectChoic
264264
->unique()
265265
->count();
266266

267-
$remoteKeyCount = 0;
267+
$remoteKeyCount = null;
268268

269269
if (($projectChoice['type'] ?? '') === 'existing' && isset($projectChoice['slug'])) {
270270
try {
@@ -275,13 +275,13 @@ private function renderKeyDiscoverySummary(string $apiToken, array $projectChoic
275275
);
276276
$remoteKeyCount = $client->countTranslationKeys();
277277
} catch (\Throwable) {
278-
$remoteKeyCount = 0;
278+
$remoteKeyCount = null;
279279
}
280280
}
281281

282-
$this->components->info('Key discovery summary');
282+
$this->components->info('Translation key summary');
283283
$this->components->twoColumnDetail('Local keys discovered', (string) $localKeyCount);
284-
$this->components->twoColumnDetail('Remote keys', (string) $remoteKeyCount);
284+
$this->components->twoColumnDetail('Remote keys', $remoteKeyCount === null ? 'N/A' : (string) $remoteKeyCount);
285285
$this->newLine();
286286
}
287287

src/Services/LinguistApiClient.php

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,28 +174,106 @@ public function triggerAutoTranslate(array $options = []): Response
174174

175175
/**
176176
* Count all remote translation keys for the current project.
177+
*
178+
* @throws \RuntimeException
177179
*/
178180
public function countTranslationKeys(): int
179181
{
180182
$response = $this->listTranslationKeys(['per_page' => 1, 'page' => 1]);
181183

182-
if (! $response->successful()) {
183-
return 0;
184+
if ($response->successful()) {
185+
foreach ([
186+
'meta.total',
187+
'pagination.total',
188+
'meta.pagination.total',
189+
'meta.total_count',
190+
'total',
191+
] as $path) {
192+
$total = $response->json($path);
193+
if (is_numeric($total)) {
194+
return (int) $total;
195+
}
196+
}
197+
198+
foreach (['x-total-count', 'x-pagination-total', 'x-pagination-total-count'] as $header) {
199+
$total = $response->header($header);
200+
if (is_numeric($total)) {
201+
return (int) $total;
202+
}
203+
}
204+
205+
foreach (['data', 'translation_keys', 'items'] as $path) {
206+
$list = $response->json($path, null);
207+
if (is_array($list)) {
208+
return count($list);
209+
}
210+
}
184211
}
185212

186-
$metaTotal = $response->json('meta.total');
187-
if (is_int($metaTotal)) {
188-
return $metaTotal;
213+
$fallbackCount = $this->countTranslationKeysFromExports();
214+
215+
if ($fallbackCount !== null) {
216+
return $fallbackCount;
217+
}
218+
219+
throw new \RuntimeException('Failed to fetch translation keys count.');
220+
}
221+
222+
private function countTranslationKeysFromExports(): ?int
223+
{
224+
$languagesResponse = $this->getLanguages();
225+
226+
if (! $languagesResponse->successful()) {
227+
return null;
228+
}
229+
230+
$languages = $languagesResponse->json('data', []);
231+
232+
if (! is_array($languages) || $languages === []) {
233+
return 0;
189234
}
190235

191-
$paginationTotal = $response->json('pagination.total');
192-
if (is_int($paginationTotal)) {
193-
return $paginationTotal;
236+
foreach ($languages as $language) {
237+
$languageCode = strtoupper((string) $language);
238+
if ($languageCode === '') {
239+
continue;
240+
}
241+
242+
$exportRouteResponse = $this->getExportUrl($languageCode);
243+
if (! $exportRouteResponse->successful()) {
244+
continue;
245+
}
246+
247+
$exportUrl = (string) $exportRouteResponse->json('url', '');
248+
if ($exportUrl === '') {
249+
continue;
250+
}
251+
252+
$exportResponse = $this->downloadExport($exportUrl);
253+
if (! $exportResponse->successful()) {
254+
continue;
255+
}
256+
257+
$decoded = json_decode($exportResponse->body(), true);
258+
if (! is_array($decoded)) {
259+
continue;
260+
}
261+
262+
return $this->countTranslationLeafs($decoded);
194263
}
195264

196-
$data = $response->json('data', []);
265+
return null;
266+
}
267+
268+
private function countTranslationLeafs(array $translations): int
269+
{
270+
$count = 0;
271+
272+
array_walk_recursive($translations, static function () use (&$count): void {
273+
$count++;
274+
});
197275

198-
return is_array($data) ? count($data) : 0;
276+
return $count;
199277
}
200278

201279
/**
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
use Hyperlinkgroup\Linguist\Services\LinguistApiClient;
4+
use Illuminate\Support\Facades\Http;
5+
6+
test('count translation keys reads numeric totals from nested metadata', function () {
7+
Http::preventStrayRequests();
8+
Http::fake([
9+
'https://api.linguist.eu/projects/test-project/translation-keys?per_page=1&page=1' => Http::response([
10+
'meta' => [
11+
'pagination' => [
12+
'total' => '758',
13+
],
14+
],
15+
], 200),
16+
]);
17+
18+
$client = new LinguistApiClient(
19+
baseUrl: 'https://api.linguist.eu',
20+
token: 'test-token',
21+
projectSlug: 'test-project',
22+
);
23+
24+
expect($client->countTranslationKeys())->toBe(758);
25+
});
26+
27+
test('count translation keys reads totals from pagination headers', function () {
28+
Http::preventStrayRequests();
29+
Http::fake([
30+
'https://api.linguist.eu/projects/test-project/translation-keys?per_page=1&page=1' => Http::response([
31+
'data' => [['id' => 1]],
32+
], 200, [
33+
'X-Total-Count' => '1514',
34+
]),
35+
]);
36+
37+
$client = new LinguistApiClient(
38+
baseUrl: 'https://api.linguist.eu',
39+
token: 'test-token',
40+
projectSlug: 'test-project',
41+
);
42+
43+
expect($client->countTranslationKeys())->toBe(1514);
44+
});
45+
46+
test('count translation keys throws when request fails', function () {
47+
Http::preventStrayRequests();
48+
Http::fake([
49+
'https://api.linguist.eu/projects/test-project/translation-keys?per_page=1&page=1' => Http::response([], 403),
50+
'https://api.linguist.eu/projects/test-project/languages' => Http::response([], 403),
51+
]);
52+
53+
$client = new LinguistApiClient(
54+
baseUrl: 'https://api.linguist.eu',
55+
token: 'test-token',
56+
projectSlug: 'test-project',
57+
);
58+
59+
$client->countTranslationKeys();
60+
})->throws(RuntimeException::class);
61+
62+
test('count translation keys falls back to export payload when list endpoint fails', function () {
63+
Http::preventStrayRequests();
64+
Http::fake([
65+
'https://api.linguist.eu/projects/test-project/translation-keys?per_page=1&page=1' => Http::response([], 403),
66+
'https://api.linguist.eu/projects/test-project/languages' => Http::response([
67+
'data' => ['EN', 'DE'],
68+
], 200),
69+
'https://api.linguist.eu/projects/test-project/export/json/EN?prefix=:' => Http::response([
70+
'url' => 'https://api.linguist.eu/export/en',
71+
], 200),
72+
'https://api.linguist.eu/export/en' => Http::response([
73+
'auth' => [
74+
'login' => 'Login',
75+
'logout' => 'Logout',
76+
],
77+
'common' => [
78+
'ok' => 'Ok',
79+
],
80+
], 200),
81+
]);
82+
83+
$client = new LinguistApiClient(
84+
baseUrl: 'https://api.linguist.eu',
85+
token: 'test-token',
86+
projectSlug: 'test-project',
87+
);
88+
89+
expect($client->countTranslationKeys())->toBe(3);
90+
});

0 commit comments

Comments
 (0)