Skip to content

Commit fee6f0b

Browse files
committed
[Translation][Lokalise] fix "Project too big for sync export"
1 parent 4433ffc commit fee6f0b

File tree

1 file changed

+109
-1
lines changed

1 file changed

+109
-1
lines changed

src/Symfony/Component/Translation/Bridge/Lokalise/LokaliseProvider.php

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Translation\Bridge\Lokalise;
1313

1414
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\Translation\Exception\LogicException;
1516
use Symfony\Component\Translation\Exception\ProviderException;
1617
use Symfony\Component\Translation\Loader\LoaderInterface;
1718
use Symfony\Component\Translation\MessageCatalogueInterface;
@@ -96,7 +97,11 @@ public function write(TranslatorBagInterface $translatorBag): void
9697
public function read(array $domains, array $locales): TranslatorBag
9798
{
9899
$translatorBag = new TranslatorBag();
99-
$translations = $this->exportFiles($locales, $domains);
100+
if (\extension_loaded('zip')) {
101+
$translations = $this->exportFilesAsync($locales, $domains);
102+
} else {
103+
$translations = $this->exportFiles($locales, $domains);
104+
}
100105

101106
foreach ($translations as $locale => $files) {
102107
foreach ($files as $filename => $content) {
@@ -176,6 +181,109 @@ private function exportFiles(array $locales, array $domains): array
176181
return array_combine($reformattedLanguages, $responseContent['files']);
177182
}
178183

184+
/**
185+
* @see https://app.lokalise.com/api2docs/curl/#transition-download-files-post
186+
*/
187+
private function exportFilesAsync(array $locales, array $domains): array
188+
{
189+
$response = $this->client->request('POST', 'files/async-download', [
190+
'json' => [
191+
'format' => 'symfony_xliff',
192+
'original_filenames' => true,
193+
'filter_langs' => array_values($locales),
194+
'filter_filenames' => array_map($this->getLokaliseFilenameFromDomain(...), $domains),
195+
'export_empty_as' => 'skip',
196+
'replace_breaks' => false,
197+
],
198+
]);
199+
200+
if (200 !== $response->getStatusCode()) {
201+
throw new ProviderException(\sprintf('Unable to export translations from Lokalise: "%s".', $response->getContent(false)), $response);
202+
}
203+
204+
$processId = $response->toArray()['process_id'];
205+
$attempt = 1;
206+
while (true) {
207+
usleep(500000 * $attempt);
208+
$response = $this->client->request('GET', \sprintf('processes/%s', $processId));
209+
$process = $response->toArray()['process'];
210+
if ('failed' === $process['status']) {
211+
throw new ProviderException(\sprintf('Unable to export translations from Lokalise: "%s".', $response->getContent(false)), $response);
212+
}
213+
if ('finished' === $process['status']) {
214+
$downloadUrl = $process['details']['download_url'];
215+
break;
216+
}
217+
++$attempt;
218+
}
219+
220+
try {
221+
$newfile = \sprintf('/tmp/%s.zip', uniqid());
222+
$extractPath = \sprintf('/tmp/%s', uniqid());
223+
224+
if (!copy($downloadUrl, $newfile)) {
225+
throw new LogicException(\sprintf('failed to copy "%s".', $downloadUrl));
226+
}
227+
228+
$zip = new \ZipArchive();
229+
if (!$zip->open($newfile, \ZipArchive::CREATE)) {
230+
throw new LogicException(\sprintf('failed to open zip file "%s".', $newfile));
231+
}
232+
233+
try {
234+
if (!$zip->extractTo($extractPath)) {
235+
throw new LogicException(\sprintf('failed to extract content from zip file "%s".', $newfile));
236+
}
237+
} finally {
238+
$zip->close();
239+
}
240+
241+
$fileContents = $this->getFileContents($extractPath);
242+
243+
// Lokalise returns languages with "-" separator, we need to reformat them to "_" separator.
244+
$reformattedLanguages = array_map(function ($language) {
245+
return str_replace('-', '_', $language);
246+
}, array_keys($fileContents));
247+
248+
return array_combine($reformattedLanguages, $fileContents);
249+
} finally {
250+
unlink($newfile);
251+
$this->removeDir($extractPath);
252+
}
253+
}
254+
255+
private function getFileContents(string $dirName, string $baseDirName = ''): array
256+
{
257+
$fileContents = [];
258+
foreach (scandir($dirName) as $filename) {
259+
if (\in_array($filename, ['.', '..'])) {
260+
continue;
261+
}
262+
$path = \sprintf('%s/%s', $dirName, $filename);
263+
if (is_dir($path)) {
264+
$fileContents = array_merge($fileContents, $this->getFileContents($path, $filename));
265+
continue;
266+
}
267+
$fileContents[$baseDirName][$filename]['content'] = file_get_contents($path);
268+
}
269+
270+
return $fileContents;
271+
}
272+
273+
private function removeDir(string $dir): void
274+
{
275+
$it = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
276+
$files = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
277+
foreach ($files as $file) {
278+
if ($file->isDir()) {
279+
rmdir($file->getPathname());
280+
} else {
281+
unlink($file->getPathname());
282+
}
283+
}
284+
rmdir($dir);
285+
}
286+
179287
private function createKeys(array $keys, string $domain): array
180288
{
181289
$keysToCreate = [];

0 commit comments

Comments
 (0)