Refactored LocoProviderTest

This commit is contained in:
Mathieu Santostefano 2021-05-05 19:27:23 +02:00
parent e03ab57139
commit 40041db7cb
No known key found for this signature in database
GPG Key ID: EB610773AF2B5B5B
2 changed files with 385 additions and 329 deletions

View File

@ -59,19 +59,13 @@ final class LocoProvider implements ProviderInterface
$catalogue = $translatorBag->getCatalogues()[0];
}
// Create keys on Loco
foreach ($catalogue->all() as $domain => $messages) {
$ids = [];
foreach ($messages as $id => $message) {
$ids[] = $id;
$this->createAsset($id);
}
if ($ids) {
$this->tagsAssets($ids, $domain);
$createdIds = $this->createAssets(array_keys($messages));
if ($createdIds) {
$this->tagsAssets($createdIds, $domain);
}
}
// Push translations in all locales and tag them with domain
foreach ($translatorBag->getCatalogues() as $catalogue) {
$locale = $catalogue->getLocale();
@ -79,10 +73,9 @@ final class LocoProvider implements ProviderInterface
$this->createLocale($locale);
}
foreach ($catalogue->all() as $messages) {
foreach ($messages as $id => $message) {
$this->translateAsset($id, $message, $locale);
}
foreach ($catalogue->all() as $domain => $messages) {
$ids = $this->getAssetsIds($domain);
$this->translateAssets(array_combine($ids, array_values($messages)), $locale);
}
}
}
@ -91,92 +84,142 @@ final class LocoProvider implements ProviderInterface
{
$domains = $domains ?: ['*'];
$translatorBag = new TranslatorBag();
$responses = [];
foreach ($locales as $locale) {
foreach ($domains as $domain) {
$response = $this->client->request('GET', sprintf('export/locale/%s.xlf?filter=%s&status=translated', $locale, $domain));
if (404 === $response->getStatusCode()) {
$this->logger->error(sprintf('Locale "%s" for domain "%s" does not exist in Loco.', $locale, $domain));
continue;
}
$responseContent = $response->getContent(false);
if (200 !== $response->getStatusCode()) {
throw new ProviderException('Unable to read the Loco response: '.$responseContent, $response);
}
$translatorBag->addCatalogue($this->loader->load($responseContent, $locale, $domain));
$responses[] = [
'response' => $this->client->request('GET', sprintf('export/locale/%s.xlf', rawurlencode($locale)), [
'query' => [
'filter' => $domain,
'status' => 'translated',
],
]),
'locale' => $locale,
'domain' => $domain,
];
}
}
foreach ($responses as $response) {
$locale = $response['locale'];
$domain = $response['domain'];
$response = $response['response'];
if (404 === $response->getStatusCode()) {
$this->logger->warning(sprintf('Locale "%s" for domain "%s" does not exist in Loco.', $locale, $domain));
continue;
}
$responseContent = $response->getContent(false);
if (200 !== $response->getStatusCode()) {
throw new ProviderException('Unable to read the Loco response: '.$responseContent, $response);
}
$translatorBag->addCatalogue($this->loader->load($responseContent, $locale, $domain));
}
return $translatorBag;
}
public function delete(TranslatorBagInterface $translatorBag): void
{
$deletedIds = [];
$catalogue = $translatorBag->getCatalogue($this->defaultLocale);
foreach ($translatorBag->getCatalogues() as $catalogue) {
foreach ($catalogue->all() as $messages) {
foreach ($messages as $id => $message) {
if (\in_array($id, $deletedIds, true)) {
continue;
}
if (!$catalogue) {
$catalogue = $translatorBag->getCatalogues()[0];
}
$this->deleteAsset($id);
$deletedIds[] = $id;
}
$responses = [];
foreach (array_keys($catalogue->all()) as $domain) {
foreach ($this->getAssetsIds($domain) as $id) {
$responses[$id] = $this->client->request('DELETE', sprintf('assets/%s.json', $id));
}
}
foreach ($responses as $key => $response) {
if (403 === $response->getStatusCode()) {
$this->logger->error('The API key used does not have sufficient permissions to delete assets.');
}
if (200 !== $response->getStatusCode() && 404 !== $response->getStatusCode()) {
$this->logger->error(sprintf('Unable to delete translation key "%s" to Loco: "%s".', $key, $response->getContent(false)));
}
}
}
private function createAsset(string $id): void
/**
* Returns array of internal Loco's unique ids.
*/
private function getAssetsIds(string $domain): array
{
$response = $this->client->request('POST', 'assets', [
'body' => [
'name' => $id,
'id' => $id,
'type' => 'text',
'default' => 'untranslated',
],
]);
if (409 === $response->getStatusCode()) {
$this->logger->info(sprintf('Translation key "%s" already exists in Loco.', $id), [
'id' => $id,
]);
} elseif (201 !== $response->getStatusCode()) {
$this->logger->error(sprintf('Unable to add new translation key "%s" to Loco: (status code: "%s") "%s".', $id, $response->getStatusCode(), $response->getContent(false)));
}
}
private function translateAsset(string $id, string $message, string $locale): void
{
$response = $this->client->request('POST', sprintf('translations/%s/%s', $id, $locale), [
'body' => $message,
]);
$response = $this->client->request('GET', 'assets', ['query' => ['filter' => $domain]]);
if (200 !== $response->getStatusCode()) {
$this->logger->error(sprintf('Unable to add translation message "%s" (for key: "%s" in locale "%s") to Loco: "%s".', $message, $id, $locale, $response->getContent(false)));
$this->logger->error(sprintf('Unable to get assets from Loco: "%s".', $response->getContent(false)));
}
return array_map(function ($asset) {
return $asset['id'];
}, $response->toArray(false));
}
private function createAssets(array $keys): array
{
$responses = $createdIds = [];
foreach ($keys as $key) {
$responses[$key] = $this->client->request('POST', 'assets', [
'body' => [
'text' => $key,
'type' => 'text',
'default' => 'untranslated',
],
]);
}
foreach ($responses as $key => $response) {
if (201 !== $response->getStatusCode()) {
$this->logger->error(sprintf('Unable to add new translation key "%s" to Loco: (status code: "%s") "%s".', $key, $response->getStatusCode(), $response->getContent(false)));
} else {
$createdIds[] = $response->toArray(false)['id'];
}
}
return $createdIds;
}
private function translateAssets(array $translations, string $locale): void
{
$responses = [];
foreach ($translations as $id => $message) {
$responses[$id] = $this->client->request('POST', sprintf('translations/%s/%s', $id, $locale), [
'body' => $message,
]);
}
foreach ($responses as $id => $response) {
if (200 !== $response->getStatusCode()) {
$this->logger->error(sprintf('Unable to add translation for key "%s" in locale "%s" to Loco: "%s".', $id, $locale, $response->getContent(false)));
}
}
}
private function tagsAssets(array $ids, string $tag): void
{
$idsAsString = implode(',', array_unique($ids));
if (!\in_array($tag, $this->getTags(), true)) {
$this->createTag($tag);
}
$response = $this->client->request('POST', sprintf('tags/%s.json', $tag), [
'body' => $idsAsString,
'body' => implode(',', $ids),
]);
if (200 !== $response->getStatusCode()) {
$this->logger->error(sprintf('Unable to add tag "%s" on translation keys "%s" to Loco: "%s".', $tag, $idsAsString, $response->getContent(false)));
$this->logger->error(sprintf('Unable to tag assets with "%s" on Loco: "%s".', $tag, $response->getContent(false)));
}
}
@ -233,13 +276,4 @@ final class LocoProvider implements ProviderInterface
return $carry;
}, []);
}
private function deleteAsset(string $id): void
{
$response = $this->client->request('DELETE', sprintf('assets/%s.json', $id));
if (200 !== $response->getStatusCode()) {
$this->logger->error(sprintf('Unable to delete translation key "%s" to Loco: "%s".', $id, $response->getContent(false)));
}
}
}

View File

@ -4,6 +4,7 @@ namespace Symfony\Component\Translation\Bridge\Loco\Tests;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Component\Translation\Bridge\Loco\LocoProvider;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Loader\LoaderInterface;
@ -22,195 +23,201 @@ class LocoProviderTest extends ProviderTestCase
return new LocoProvider($client, $loader, $logger, $defaultLocale, $endpoint);
}
public function toStringProvider(): iterable
{
yield [
$this->createProvider($this->getClient()->withOptions([
'base_uri' => 'https://localise.biz/api/',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'),
'loco://localise.biz/api/',
];
yield [
$this->createProvider($this->getClient()->withOptions([
'base_uri' => 'https://example.com',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com'),
'loco://example.com',
];
yield [
$this->createProvider($this->getClient()->withOptions([
'base_uri' => 'https://example.com:99',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com:99'),
'loco://example.com:99',
];
}
public function testCompleteWriteProcess()
{
$createAssetResponse = $this->createMock(ResponseInterface::class);
$createAssetResponse->expects($this->exactly(4))
->method('getStatusCode')
->willReturn(201);
$getLocalesResponse = $this->createMock(ResponseInterface::class);
$getLocalesResponse->expects($this->exactly(4))
->method('getStatusCode')
->willReturn(200);
$getLocalesResponse->expects($this->exactly(2))
->method('getContent')
->with(false)
->willReturn('[{"code":"en"}]');
$createLocaleResponse = $this->createMock(ResponseInterface::class);
$createLocaleResponse->expects($this->exactly(2))
->method('getStatusCode')
->willReturn(201);
$translateAssetResponse = $this->createMock(ResponseInterface::class);
$translateAssetResponse->expects($this->exactly(8))
->method('getStatusCode')
->willReturn(200);
$getTagsEmptyResponse = $this->createMock(ResponseInterface::class);
$getTagsEmptyResponse->expects($this->exactly(2))
->method('getStatusCode')
->willReturn(200);
$getTagsEmptyResponse->expects($this->once())
->method('getContent')
->with(false)
->willReturn('[]');
$getTagsNotEmptyResponse = $this->createMock(ResponseInterface::class);
$getTagsNotEmptyResponse->expects($this->exactly(2))
->method('getStatusCode')
->willReturn(200);
$getTagsNotEmptyResponse->expects($this->once())
->method('getContent')
->with(false)
->willReturn('["messages"]');
$createTagResponse = $this->createMock(ResponseInterface::class);
$createTagResponse->expects($this->exactly(4))
->method('getStatusCode')
->willReturn(201);
$tagAssetResponse = $this->createMock(ResponseInterface::class);
$tagAssetResponse->expects($this->exactly(4))
->method('getStatusCode')
->willReturn(200);
$expectedAuthHeader = 'Authorization: Loco API_KEY';
$responses = [
'createAsset1' => function (string $method, string $url, array $options = []) use ($createAssetResponse, $expectedAuthHeader): ResponseInterface {
'createAsset1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$expectedBody = http_build_query([
'name' => 'a',
'id' => 'a',
'text' => 'a',
'type' => 'text',
'default' => 'untranslated',
]);
$this->assertEquals('POST', $method);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals($expectedBody, $options['body']);
$this->assertSame('POST', $method);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame($expectedBody, $options['body']);
return $createAssetResponse;
return new MockResponse('{"id": "1337"}', ['http_code' => 201]);
},
'getTags1' => function (string $method, string $url, array $options = []) use ($getTagsEmptyResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('GET', $method);
$this->assertEquals('https://localise.biz/api/tags.json', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
'getTags1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/tags.json', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
return $getTagsEmptyResponse;
return new MockResponse('[]');
},
'createTag1' => function (string $method, string $url, array $options = []) use ($createTagResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/tags.json', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals(http_build_query(['name' => 'messages']), $options['body']);
'createTag1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/tags.json', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame(http_build_query(['name' => 'messages']), $options['body']);
return $createTagResponse;
return new MockResponse('', ['http_code' => 201]);
},
'tagAsset1' => function (string $method, string $url, array $options = []) use ($tagAssetResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/tags/messages.json', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals('a', $options['body']);
'tagAsset1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/tags/messages.json', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame('1337', $options['body']);
return $tagAssetResponse;
return new MockResponse();
},
'createAsset2' => function (string $method, string $url, array $options = []) use ($createAssetResponse, $expectedAuthHeader): ResponseInterface {
'createAsset2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$expectedBody = http_build_query([
'name' => 'post.num_comments',
'id' => 'post.num_comments',
'text' => 'post.num_comments',
'type' => 'text',
'default' => 'untranslated',
]);
$this->assertEquals('POST', $method);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals($expectedBody, $options['body']);
$this->assertSame('POST', $method);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame($expectedBody, $options['body']);
return $createAssetResponse;
return new MockResponse('{"id": "1234"}', ['http_code' => 201]);
},
'getTags2' => function (string $method, string $url, array $options = []) use ($getTagsNotEmptyResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('GET', $method);
$this->assertEquals('https://localise.biz/api/tags.json', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
'getTags2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/tags.json', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
return $getTagsNotEmptyResponse;
return new MockResponse('["messages"]');
},
'createTag2' => function (string $method, string $url, array $options = []) use ($createTagResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/tags.json', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals(http_build_query(['name' => 'validators']), $options['body']);
'createTag2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/tags.json', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame(http_build_query(['name' => 'validators']), $options['body']);
return $createTagResponse;
return new MockResponse('', ['http_code' => 201]);
},
'tagAsset2' => function (string $method, string $url, array $options = []) use ($tagAssetResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/tags/validators.json', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals('post.num_comments', $options['body']);
'tagAsset2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/tags/validators.json', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame('1234', $options['body']);
return $tagAssetResponse;
return new MockResponse();
},
'getLocales1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/locales', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
'getLocales1' => function (string $method, string $url, array $options = []) use ($getLocalesResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('GET', $method);
$this->assertEquals('https://localise.biz/api/locales', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
return $getLocalesResponse;
return new MockResponse('[{"code":"en"}]');
},
'getAssetsIds1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/assets?filter=messages', $url);
$this->assertSame(['filter' => 'messages'], $options['query']);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
'translateAsset1' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/translations/a/en', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals('trans_en_a', $options['body']);
return $translateAssetResponse;
return new MockResponse('[{"id":"1337"}]');
},
'translateAsset2' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/translations/post.num_comments/en', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals('{count, plural, one {# comment} other {# comments}}', $options['body']);
'translateAsset1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/translations/1337/en', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame('trans_en_a', $options['body']);
return $translateAssetResponse;
return new MockResponse();
},
'getAssetsIds2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/assets?filter=validators', $url);
$this->assertSame(['filter' => 'validators'], $options['query']);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
'getLocales2' => function (string $method, string $url, array $options = []) use ($getLocalesResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('GET', $method);
$this->assertEquals('https://localise.biz/api/locales', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
return $getLocalesResponse;
return new MockResponse('[{"id":"1234"}]');
},
'translateAsset2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/translations/1234/en', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame('{count, plural, one {# comment} other {# comments}}', $options['body']);
'createLocale1' => function (string $method, string $url, array $options = []) use ($createLocaleResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/locales', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals('code=fr', $options['body']);
return $createLocaleResponse;
return new MockResponse();
},
'getLocales2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/locales', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
'translateAsset3' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/translations/a/fr', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals('trans_fr_a', $options['body']);
return $translateAssetResponse;
return new MockResponse('[{"code":"en"}]');
},
'translateAsset4' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface {
$this->assertEquals('POST', $method);
$this->assertEquals('https://localise.biz/api/translations/post.num_comments/fr', $url);
$this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertEquals('{count, plural, one {# commentaire} other {# commentaires}}', $options['body']);
'createLocale1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/locales', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame('code=fr', $options['body']);
return $translateAssetResponse;
return new MockResponse('', ['http_code' => 201]);
},
'getAssetsIds3' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/assets?filter=messages', $url);
$this->assertSame(['filter' => 'messages'], $options['query']);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
return new MockResponse('[{"id":"1337"}]');
},
'translateAsset3' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/translations/1337/fr', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame('trans_fr_a', $options['body']);
return new MockResponse();
},
'getAssetsIds4' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/assets?filter=validators', $url);
$this->assertSame(['filter' => 'validators'], $options['query']);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
return new MockResponse('[{"id":"1234"}]');
},
'translateAsset4' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://localise.biz/api/translations/1234/fr', $url);
$this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]);
$this->assertSame('{count, plural, one {# commentaire} other {# commentaires}}', $options['body']);
return new MockResponse();
},
];
@ -226,106 +233,126 @@ class LocoProviderTest extends ProviderTestCase
$provider = $this->createProvider((new MockHttpClient($responses))->withOptions([
'base_uri' => 'https://localise.biz/api/',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
'headers' => ['Authorization' => 'Loco API_KEY'],
]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/');
$provider->write($translatorBag);
}
/**
* @dataProvider getLocoResponsesForOneLocaleAndOneDomain
* @dataProvider getResponsesForOneLocaleAndOneDomain
*/
public function testReadForOneLocaleAndOneDomain(string $locale, string $domain, string $responseContent, TranslatorBag $expectedTranslatorBag)
{
$response = $this->createMock(ResponseInterface::class);
$response->expects($this->once())
->method('getContent')
->willReturn($responseContent);
$response->expects($this->exactly(2))
->method('getStatusCode')
->willReturn(200);
$loader = $this->getLoader();
$loader->expects($this->once())
->method('load')
->willReturn($expectedTranslatorBag->getCatalogue($locale));
->willReturn((new XliffFileLoader())->load($responseContent, $locale, $domain));
$locoProvider = $this->createProvider((new MockHttpClient($response))->withOptions([
$provider = $this->createProvider((new MockHttpClient(new MockResponse($responseContent)))->withOptions([
'base_uri' => 'https://localise.biz/api/',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $loader, $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/');
$translatorBag = $locoProvider->read([$domain], [$locale]);
$translatorBag = $provider->read([$domain], [$locale]);
// We don't want to assert equality of metadata here, due to the ArrayLoader usage.
foreach ($translatorBag->getCatalogues() as $catalogue) {
$catalogue->deleteMetadata('', '');
}
$this->assertEquals($expectedTranslatorBag->getCatalogues(), $translatorBag->getCatalogues());
}
/**
* @dataProvider getLocoResponsesForManyLocalesAndManyDomains
* @dataProvider getResponsesForManyLocalesAndManyDomains
*/
public function testReadForManyLocalesAndManyDomains(array $locales, array $domains, array $responseContents, array $expectedTranslatorBags)
public function testReadForManyLocalesAndManyDomains(array $locales, array $domains, array $responseContents, TranslatorBag $expectedTranslatorBag)
{
$responses = [];
$consecutiveLoadArguments = [];
$consecutiveLoadReturns = [];
foreach ($locales as $locale) {
foreach ($domains as $domain) {
$response = $this->createMock(ResponseInterface::class);
$response->expects($this->once())
->method('getContent')
->willReturn($responseContents[$domain][$locale]);
$response->expects($this->exactly(2))
->method('getStatusCode')
->willReturn(200);
$locoProvider = new LocoProvider((new MockHttpClient($response))->withOptions([
'base_uri' => 'https://localise.biz/api/',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), new XliffFileLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/');
$translatorBag = $locoProvider->read([$domain], [$locale]);
// We don't want to assert equality of metadata here, due to the ArrayLoader usage.
$translatorBag->getCatalogue($locale)->deleteMetadata('foo', '');
$this->assertEquals($expectedTranslatorBags[$domain]->getCatalogue($locale), $translatorBag->getCatalogue($locale));
$responses[] = new MockResponse($responseContents[$locale][$domain]);
$consecutiveLoadArguments[] = [$responseContents[$locale][$domain], $locale, $domain];
$consecutiveLoadReturns[] = (new XliffFileLoader())->load($responseContents[$locale][$domain], $locale, $domain);
}
}
$loader = $this->getLoader();
$loader->expects($this->exactly(\count($consecutiveLoadArguments)))
->method('load')
->withConsecutive(...$consecutiveLoadArguments)
->willReturnOnConsecutiveCalls(...$consecutiveLoadReturns);
$provider = $this->createProvider((new MockHttpClient($responses))->withOptions([
'base_uri' => 'https://localise.biz/api/',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $loader, $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/');
$translatorBag = $provider->read($domains, $locales);
// We don't want to assert equality of metadata here, due to the ArrayLoader usage.
foreach ($translatorBag->getCatalogues() as $catalogue) {
$catalogue->deleteMetadata('', '');
}
$this->assertEquals($expectedTranslatorBag->getCatalogues(), $translatorBag->getCatalogues());
}
public function toStringProvider(): iterable
public function testDeleteProcess()
{
yield [
new LocoProvider($this->getClient()->withOptions([
'base_uri' => 'https://localise.biz/api/',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'),
'loco://localise.biz/api/',
];
$translatorBag = new TranslatorBag();
$translatorBag->addCatalogue(new MessageCatalogue('en', [
'messages' => ['a' => 'trans_en_a'],
'validators' => ['post.num_comments' => '{count, plural, one {# comment} other {# comments}}'],
]));
$translatorBag->addCatalogue(new MessageCatalogue('fr', [
'messages' => ['a' => 'trans_fr_a'],
'validators' => ['post.num_comments' => '{count, plural, one {# commentaire} other {# commentaires}}'],
]));
yield [
new LocoProvider($this->getClient()->withOptions([
'base_uri' => 'https://example.com',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com'),
'loco://example.com',
];
$provider = $this->createProvider(
new MockHttpClient([
function (string $method, string $url, array $options = []): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/assets?filter=messages', $url);
$this->assertSame(['filter' => 'messages'], $options['query']);
yield [
new LocoProvider($this->getClient()->withOptions([
'base_uri' => 'https://example.com:99',
'headers' => [
'Authorization' => 'Loco API_KEY',
],
]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com:99'),
'loco://example.com:99',
];
return new MockResponse('[{"id":"1337"}]');
},
function (string $method, string $url): MockResponse {
$this->assertSame('DELETE', $method);
$this->assertSame('https://localise.biz/api/assets/1337.json', $url);
return new MockResponse();
},
function (string $method, string $url, array $options = []): ResponseInterface {
$this->assertSame('GET', $method);
$this->assertSame('https://localise.biz/api/assets?filter=validators', $url);
$this->assertSame(['filter' => 'validators'], $options['query']);
return new MockResponse('[{"id":"1234"}]');
},
function (string $method, string $url): MockResponse {
$this->assertSame('DELETE', $method);
$this->assertSame('https://localise.biz/api/assets/1234.json', $url);
return new MockResponse();
},
], 'https://localise.biz/api/'),
$this->getLoader(),
$this->getLogger(),
$this->getDefaultLocale(),
'localise.biz/api/'
);
$provider->delete($translatorBag);
}
public function getLocoResponsesForOneLocaleAndOneDomain(): \Generator
public function getResponsesForOneLocaleAndOneDomain(): \Generator
{
$arrayLoader = new ArrayLoader();
@ -333,7 +360,7 @@ class LocoProviderTest extends ProviderTestCase
$expectedTranslatorBagEn->addCatalogue($arrayLoader->load([
'index.hello' => 'Hello',
'index.greetings' => 'Welcome, {firstname}!',
], 'en', 'messages'));
], 'en'));
yield ['en', 'messages', <<<'XLIFF'
<?xml version="1.0" encoding="UTF-8"?>
@ -363,7 +390,7 @@ XLIFF
$expectedTranslatorBagFr->addCatalogue($arrayLoader->load([
'index.hello' => 'Bonjour',
'index.greetings' => 'Bienvenue, {firstname} !',
], 'fr', 'messages'));
], 'fr'));
yield ['fr', 'messages', <<<'XLIFF'
<?xml version="1.0" encoding="UTF-8"?>
@ -390,26 +417,24 @@ XLIFF
];
}
public function getLocoResponsesForManyLocalesAndManyDomains(): \Generator
public function getResponsesForManyLocalesAndManyDomains(): \Generator
{
$arrayLoader = new ArrayLoader();
$expectedTranslatorBagMessages = new TranslatorBag();
$expectedTranslatorBagMessages->addCatalogue($arrayLoader->load([
$expectedTranslatorBag = new TranslatorBag();
$expectedTranslatorBag->addCatalogue($arrayLoader->load([
'index.hello' => 'Hello',
'index.greetings' => 'Welcome, {firstname}!',
], 'en', 'messages'));
$expectedTranslatorBagMessages->addCatalogue($arrayLoader->load([
], 'en'));
$expectedTranslatorBag->addCatalogue($arrayLoader->load([
'index.hello' => 'Bonjour',
'index.greetings' => 'Bienvenue, {firstname} !',
], 'fr', 'messages'));
$expectedTranslatorBagValidators = new TranslatorBag();
$expectedTranslatorBagValidators->addCatalogue($arrayLoader->load([
], 'fr'));
$expectedTranslatorBag->addCatalogue($arrayLoader->load([
'firstname.error' => 'Firstname must contains only letters.',
'lastname.error' => 'Lastname must contains only letters.',
], 'en', 'validators'));
$expectedTranslatorBagValidators->addCatalogue($arrayLoader->load([
$expectedTranslatorBag->addCatalogue($arrayLoader->load([
'firstname.error' => 'Le prénom ne peut contenir que des lettres.',
'lastname.error' => 'Le nom de famille ne peut contenir que des lettres.',
], 'fr', 'validators'));
@ -418,8 +443,8 @@ XLIFF
['en', 'fr'],
['messages', 'validators'],
[
'messages' => [
'en' => <<<'XLIFF'
'en' => [
'messages' => <<<'XLIFF'
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="https://localise.biz/user/symfony-translation-provider" source-language="en" datatype="database" tool-id="loco">
@ -440,30 +465,7 @@ XLIFF
</xliff>
XLIFF
,
'fr' => <<<'XLIFF'
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="https://localise.biz/user/symfony-translation-provider" source-language="en" datatype="database" tool-id="loco">
<header>
<tool tool-id="loco" tool-name="Loco" tool-version="1.0.25 20201211-1" tool-company="Loco"/>
</header>
<body>
<trans-unit id="loco:5fd89b853ee27904dd6c5f67" resname="index.hello" datatype="plaintext">
<source>index.hello</source>
<target state="translated">Bonjour</target>
</trans-unit>
<trans-unit id="loco:5fd89b8542e5aa5cc27457e2" resname="index.greetings" datatype="plaintext" extradata="loco:format=icu">
<source>index.greetings</source>
<target state="translated">Bienvenue, {firstname} !</target>
</trans-unit>
</body>
</file>
</xliff>
XLIFF
,
],
'validators' => [
'en' => <<<'XLIFF'
'validators' => <<<'XLIFF'
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="https://localise.biz/user/symfony-translation-provider" source-language="en" datatype="database" tool-id="loco">
@ -484,7 +486,30 @@ XLIFF
</xliff>
XLIFF
,
'fr' => <<<'XLIFF'
],
'fr' => [
'messages' => <<<'XLIFF'
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="https://localise.biz/user/symfony-translation-provider" source-language="en" datatype="database" tool-id="loco">
<header>
<tool tool-id="loco" tool-name="Loco" tool-version="1.0.25 20201211-1" tool-company="Loco"/>
</header>
<body>
<trans-unit id="loco:5fd89b853ee27904dd6c5f67" resname="index.hello" datatype="plaintext">
<source>index.hello</source>
<target state="translated">Bonjour</target>
</trans-unit>
<trans-unit id="loco:5fd89b8542e5aa5cc27457e2" resname="index.greetings" datatype="plaintext" extradata="loco:format=icu">
<source>index.greetings</source>
<target state="translated">Bienvenue, {firstname} !</target>
</trans-unit>
</body>
</file>
</xliff>
XLIFF
,
'validators' => <<<'XLIFF'
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="https://localise.biz/user/symfony-translation-provider" source-language="en" datatype="database" tool-id="loco">
@ -505,12 +530,9 @@ XLIFF
</xliff>
XLIFF
,
],
],
],
[
'messages' => $expectedTranslatorBagMessages,
'validators' => $expectedTranslatorBagValidators,
],
$expectedTranslatorBag,
];
}
}