Skip to content

Commit

Permalink
Support mutiple strings in same request
Browse files Browse the repository at this point in the history
  • Loading branch information
Korbeil committed Jul 19, 2019
1 parent f659c8e commit 67ae8b1
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 64 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
],
"require": {
"php": "^5.5 || ^7.0",
"ext-mbstring": "*",
"php-http/httplug": "^1.0",
"php-http/client-implementation": "^1.0",
"php-http/discovery": "^1.0",
Expand Down
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<!-- API Keys -->
<env name="YANDEX_KEY" value=""/>
<env name="GOOGLE_KEY" value=""/>
<env name="BING_KEY" value=""/>
</php>

<filter>
Expand Down
107 changes: 107 additions & 0 deletions src/Service/BingTranslator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

/*
* This file is part of the PHP Translation package.
*
* (c) PHP Translation team <tobias.nyholm@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
*/

namespace Translation\Translator\Service;

use Http\Client\HttpClient;
use Http\Message\RequestFactory;
use Psr\Http\Message\ResponseInterface;
use Translation\Translator\Exception\ResponseException;

/**
* @author Baptiste Leduc <baptiste.leduc@gmail.com>
*/
class BingTranslator extends HttpTranslator
{
/**
* @var string
*/
private $key;

/**
* @param string $key Google API key
* @param HttpClient|null $httpClient
* @param RequestFactory|null $requestFactory
*/
public function __construct($key, HttpClient $httpClient = null, RequestFactory $requestFactory = null)
{
parent::__construct($httpClient, $requestFactory);
if (empty($key)) {
throw new \InvalidArgumentException('Bing "key" can not be empty');
}

$this->key = $key;
}

/**
* {@inheritdoc}
*/
public function translate($string, $from, $to)
{
$body = json_encode([['Text' => $string]]);
$url = $this->getUrl($from, $to);
$request = $this->getRequestFactory()->createRequest('POST', $url, [], $body);

$request = $request
->withHeader('Ocp-Apim-Subscription-Key', $this->key)
->withHeader('Content-Type', 'application/json')
->withHeader('X-ClientTraceId', $this->createGuid())
->withHeader('Content-length', strlen($body));

/** @var ResponseInterface $response */
$response = $this->getHttpClient()->sendRequest($request);

if (200 !== $response->getStatusCode()) {
throw ResponseException::createNonSuccessfulResponse($this->getUrl($string, $from, $to, '[key]'));
}

$responseBody = $response->getBody()->__toString();
$data = json_decode($responseBody, true);

if (!is_array($data)) {
throw ResponseException::createUnexpectedResponse($url, $responseBody);
}

foreach ($data as $details) {
return $this->format($string, $details['translations'][0]['text']);
}
}

/**
* @param string $from
* @param string $to
*
* @return string
*/
private function getUrl($from, $to)
{
return sprintf(
'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=%s&from=%s&textType=html',
$to,
$from
);
}

/**
* @return string
*/
private function createGuid()
{
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
}
23 changes: 1 addition & 22 deletions src/Service/GoogleTranslator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
use Http\Message\RequestFactory;
use Psr\Http\Message\ResponseInterface;
use Translation\Translator\Exception\ResponseException;
use Translation\Translator\TranslatorService;

/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class GoogleTranslator extends HttpTranslator implements TranslatorService
class GoogleTranslator extends HttpTranslator
{
/**
* @var string
Expand Down Expand Up @@ -88,24 +87,4 @@ private function getUrl($string, $from, $to, $key)
urlencode($string)
);
}

/**
* @param string $original
* @param string $translationHtmlEncoded
*
* @return string
*/
private function format($original, $translationHtmlEncoded)
{
$translation = html_entity_decode($translationHtmlEncoded, ENT_QUOTES | ENT_HTML401, 'UTF-8');

// if capitalized, make sure we also capitalize.
$firstChar = mb_substr($original, 0, 1);
if (mb_strtoupper($firstChar) === $firstChar) {
$first = mb_strtoupper(mb_substr($translation, 0, 1));
$translation = $first.mb_substr($translation, 1);
}

return $translation;
}
}
48 changes: 47 additions & 1 deletion src/Service/HttpTranslator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
use Http\Discovery\HttpClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Message\RequestFactory;
use Translation\Translator\TranslatorService;

/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
abstract class HttpTranslator
abstract class HttpTranslator implements TranslatorService
{
/**
* @var HttpClient
Expand Down Expand Up @@ -57,4 +58,49 @@ protected function getRequestFactory()
{
return $this->requestFactory;
}

/**
* {@inheritdoc}
*/
public function translateArray($strings, $from, $to)
{
$array = [];

foreach ($strings as $string) {
$array[] = $this->translate($string, $from, $to);
}

return $array;
}

/**
* @param string $original
* @param string $translationHtmlEncoded
*
* @return string
*/
protected function format($original, $translationHtmlEncoded)
{
$translation = htmlspecialchars_decode($translationHtmlEncoded);

// if capitalized, make sure we also capitalize.
$firstChar = \mb_substr($original, 0, 1);
$originalIsUpper = \mb_strtoupper($firstChar) === $firstChar;

if ($originalIsUpper) {
$first = \mb_strtoupper(\mb_substr($translation, 0, 1));
$translation = $first.\mb_substr($translation, 1);
}

// also check on translated if capitalize and original isn't
$transFirstChar = \mb_substr($translationHtmlEncoded, 0, 1);
$translationIsUpper = \mb_strtoupper($transFirstChar) === $transFirstChar;

if (!$originalIsUpper && $translationIsUpper) {
$first = \mb_strtolower(\mb_substr($translation, 0, 1));
$translation = $first.\mb_substr($translation, 1);
}

return $translation;
}
}
23 changes: 1 addition & 22 deletions src/Service/YandexTranslator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
use Http\Message\RequestFactory;
use Psr\Http\Message\ResponseInterface;
use Translation\Translator\Exception\ResponseException;
use Translation\Translator\TranslatorService;

/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class YandexTranslator extends HttpTranslator implements TranslatorService
class YandexTranslator extends HttpTranslator
{
/**
* @var string
Expand Down Expand Up @@ -88,24 +87,4 @@ private function getUrl($string, $from, $to, $key)
urlencode($string)
);
}

/**
* @param string $original
* @param string $translationHtmlEncoded
*
* @return string
*/
private function format($original, $translationHtmlEncoded)
{
$translation = htmlspecialchars_decode($translationHtmlEncoded);

// if capitalized, make sure we also capitalize.
$firstChar = mb_substr($original, 0, 1);
if (mb_strtoupper($firstChar) === $firstChar) {
$first = mb_strtoupper(mb_substr($translation, 0, 1));
$translation = $first.mb_substr($translation, 1);
}

return $translation;
}
}
16 changes: 15 additions & 1 deletion src/Translator.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,24 @@ final class Translator implements LoggerAwareInterface, TranslatorService
* @return null|string Null is return when all translators failed.
*/
public function translate($string, $from, $to)
{
list($result) = $this->translateArray([$string], $from, $to);

return $result;
}

/**
* @param array $strings
* @param string $from
* @param string $to
*
* @return null|array Null is return when all translators failed.
*/
public function translateArray($strings, $from, $to)
{
foreach ($this->translatorServices as $service) {
try {
return $service->translate($string, $from, $to);
return $service->translateArray($strings, $from, $to);
} catch (TranslatorException\NoTranslationFoundException $e) {
// Do nothing, try again.
} catch (TranslatorException $e) {
Expand Down
11 changes: 11 additions & 0 deletions src/TranslatorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,15 @@ interface TranslatorService
* @throws \Translation\Translator\Exception if we could not translate string
*/
public function translate($string, $from, $to);

/**
* @param array $strings array of strings to translate
* @param string $from from what locale
* @param string $to to what locale
*
* @return array Return the translated strings
*
* @throws \Translation\Translator\Exception if we could not translate string
*/
public function translateArray($strings, $from, $to);
}
60 changes: 60 additions & 0 deletions tests/Integration/AbstractTranslatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

/*
* This file is part of the PHP Translation package.
*
* (c) PHP Translation team <tobias.nyholm@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
*/

namespace Translation\translator\tests\Integration;

use PHPUnit\Framework\TestCase;
use Translation\Translator\TranslatorService;

/**
* @author Baptiste Leduc <baptiste.leduc@gmail.com>
*/
abstract class AbstractTranslatorTest extends TestCase
{
/**
* @var TranslatorService
*/
protected $translator = null;

/**
* @var array
*/
protected $requested = ['apple', 'cherry'];

/**
* @var array
*/
protected $expected = ['pomme', 'cerise'];

/**
* @var string
*/
protected $from = 'en';

/**
* @var string
*/
protected $to = 'fr';

public function testTranslate()
{
if (null === $this->translator) {
$this->markTestSkipped('No translator set.');
}

$result = $this->translator->translate($this->requested[0], $this->from, $this->to);
$this->assertEquals($this->expected[0], $result);

$results = $this->translator->translateArray($this->requested, $this->from, $this->to);
$this->assertEquals($this->expected, $results);
}
}
29 changes: 29 additions & 0 deletions tests/Integration/BingTranslatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/*
* This file is part of the PHP Translation package.
*
* (c) PHP Translation team <tobias.nyholm@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
*/

namespace Translation\translator\tests\Integration;

use Translation\Translator\Service\BingTranslator;

/**
* @author Baptiste Leduc <baptiste.leduc@gmail.com>
*/
class BingTranslatorTest extends AbstractTranslatorTest
{
public function setUp()
{
$key = getenv('BING_KEY');
if (!empty($key)) {
$this->translator = new BingTranslator($key);
}
}
}
Loading

0 comments on commit 67ae8b1

Please sign in to comment.