Skip to content

Commit 1610073

Browse files
committed
Add third party translation (WIP)
1 parent a30dd36 commit 1610073

File tree

13 files changed

+429
-4
lines changed

13 files changed

+429
-4
lines changed

Module.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,14 @@ class Module extends \yii\base\Module
286286
*/
287287
public $scanners = [];
288288

289+
/**
290+
* @var array Configuration for a third-party translator (e.g.: Google, Yandex, etc.) that can be used for
291+
* text translation.
292+
*
293+
* The translator should implement the `lajax\translatemanager\translation\Translator` interface.
294+
*/
295+
public $translator;
296+
289297
/**
290298
* @inheritdoc
291299
*/

assets/javascripts/translate.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,27 @@ var translate = (function () {
4242
_translateLanguage($this);
4343
}
4444

45+
/**
46+
* @param {$} $btn
47+
*/
48+
function _translateText($btn) {
49+
var $translation = $btn.closest('tr').find('.translation');
50+
console.log($translation);
51+
52+
helpers.post('/translatemanager/language/translate-text', {
53+
id: $translation.data('id'),
54+
language_id: $('#language_id').val()
55+
});
56+
}
57+
4558
return {
4659
init: function () {
4760
$('#translates').on('click', '.source', function () {
4861
_copySourceToTranslation($(this));
4962
});
63+
$('#translates').on('click', '.js-translate-text', function () {
64+
_translateText($(this));
65+
});
5066
$('#translates').on('click', 'button', function () {
5167
_translateLanguage($(this));
5268
});

controllers/LanguageController.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ public function behaviors()
3535
return [
3636
'access' => [
3737
'class' => AccessControl::className(),
38-
'only' => ['list', 'change-status', 'optimizer', 'scan', 'translate', 'save', 'dialog', 'message', 'view', 'create', 'update', 'delete', 'delete-source', 'import', 'export'],
38+
'only' => ['list', 'change-status', 'optimizer', 'scan', 'translate', 'translate-text', 'save', 'dialog', 'message', 'view', 'create', 'update', 'delete', 'delete-source', 'import', 'export'],
3939
'rules' => [
4040
[
4141
'allow' => true,
42-
'actions' => ['list', 'change-status', 'optimizer', 'scan', 'translate', 'save', 'dialog', 'message', 'view', 'create', 'update', 'delete', 'delete-source', 'import', 'export'],
42+
'actions' => ['list', 'change-status', 'optimizer', 'scan', 'translate', 'translate-text', 'save', 'dialog', 'message', 'view', 'create', 'update', 'delete', 'delete-source', 'import', 'export'],
4343
'roles' => $this->module->roles,
4444
],
4545
],
@@ -71,6 +71,9 @@ public function actions()
7171
'translate' => [
7272
'class' => 'lajax\translatemanager\controllers\actions\TranslateAction',
7373
],
74+
'translate-text' => [
75+
'class' => 'lajax\translatemanager\controllers\actions\TranslateTextAction',
76+
],
7477
'save' => [
7578
'class' => 'lajax\translatemanager\controllers\actions\SaveAction',
7679
],

controllers/actions/TranslateAction.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function run()
4242
'dataProvider' => $dataProvider,
4343
'searchModel' => $searchModel,
4444
'searchEmptyCommand' => $this->controller->module->searchEmptyCommand,
45+
'isTranslationApiAvailable' => !empty($this->controller->module->translator),
4546
'language_id' => Yii::$app->request->get('language_id', ''),
4647
]);
4748
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace lajax\translatemanager\controllers\actions;
4+
5+
use Yii;
6+
use yii\web\Response;
7+
use yii\base\Exception as BaseException;
8+
use lajax\translatemanager\services\Generator;
9+
use lajax\translatemanager\models\LanguageTranslate;
10+
use lajax\translatemanager\models\LanguageSource;
11+
use lajax\translatemanager\translation\Translator;
12+
use lajax\translatemanager\translation\Exception as TranslationException;
13+
14+
/**
15+
* Text translation with third party service.
16+
*
17+
* @author moltam
18+
*/
19+
class TranslateTextAction extends \yii\base\Action
20+
{
21+
/**
22+
* @return array
23+
*/
24+
public function run()
25+
{
26+
Yii::$app->response->format = Response::FORMAT_JSON;
27+
28+
$id = Yii::$app->request->post('id', 0);
29+
$languageId = Yii::$app->request->post('language_id', Yii::$app->language);
30+
31+
$languageTranslate = LanguageTranslate::findOne(['id' => $id, 'language' => $languageId]) ?:
32+
new LanguageTranslate(['id' => $id, 'language' => $languageId]);
33+
34+
try {
35+
$languageTranslate->translation = $this->translateText($id, $languageId);
36+
} catch (BaseException $e) {
37+
Yii::error('Translation failed! ' . $e->getMessage(), 'translatemanager');
38+
$languageTranslate->addError('translation', 'API translation failed!');
39+
}
40+
41+
if ($languageTranslate->validate(null, false) && $languageTranslate->save()) {
42+
$generator = new Generator($this->controller->module, $languageId);
43+
$generator->run();
44+
}
45+
46+
return $languageTranslate->getErrors();
47+
}
48+
49+
/**
50+
* @param int $sourceId
51+
* @param string $languageId
52+
*
53+
* @return string
54+
*
55+
* @throws BaseException
56+
*/
57+
protected function translateText($sourceId, $languageId)
58+
{
59+
if (!$this->controller->module->translator) {
60+
throw new BaseException('No translator configured!');
61+
}
62+
63+
$source = LanguageSource::findOne($sourceId);
64+
if (!$source) {
65+
throw new BaseException('Invalid language source id!');
66+
}
67+
68+
/* @var $translator Translator */
69+
$translator = Yii::createObject($this->controller->module->translator);
70+
71+
try {
72+
return $translator->translate($source->message, $languageId);
73+
} catch (TranslationException $e) {
74+
throw new BaseException('Translation failed: ' . $e->getMessage(), 1, $e);
75+
}
76+
}
77+
}

translation/BaseTranslator.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace lajax\translatemanager\translation;
4+
5+
use Yii;
6+
use lajax\translatemanager\translation\client\TranslatorApiClient;
7+
8+
/**
9+
* Base class for translators.
10+
*
11+
* @author moltam
12+
*/
13+
abstract class BaseTranslator extends \yii\base\Object implements Translator
14+
{
15+
/**
16+
* @var array|TranslatorApiClient The client used for communication.
17+
*/
18+
public $apiClient = [
19+
'class' => 'lajax\translatemanager\translation\client\CurlApiClient',
20+
];
21+
22+
public function init()
23+
{
24+
parent::init();
25+
26+
$this->apiClient = Yii::createObject($this->apiClient);
27+
}
28+
}

translation/Exception.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace lajax\translatemanager\translation;
4+
5+
/**
6+
* Base exception for translation related errors.
7+
*
8+
* @author moltam
9+
*/
10+
class Exception extends \yii\base\Exception
11+
{
12+
}

translation/GoogleTranslator.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace lajax\translatemanager\translation;
4+
5+
use Yii;
6+
use yii\helpers\Json;
7+
8+
/**
9+
* Translator using the Google Cloud Translation API.
10+
*
11+
* More information on this service: https://cloud.google.com/translate/
12+
*
13+
* Required configuration:
14+
*
15+
* ```php
16+
* [
17+
* 'class' => 'lajax\translatemanager\translation\GoogleTranslator',
18+
* 'apiKey' => 'YOUR_API_KEY',
19+
* ]
20+
* ```
21+
*
22+
* @author moltam
23+
*/
24+
class GoogleTranslator extends BaseTranslator
25+
{
26+
/**
27+
* @var string The API key for authentication.
28+
*/
29+
public $apiKey;
30+
31+
/**
32+
* @var string
33+
*/
34+
private static $baseApiUrl = 'https://translation.googleapis.com';
35+
36+
/**
37+
* @inheritdoc
38+
*/
39+
public function translate($text, $target, $source = null, $format = 'html')
40+
{
41+
$response = $this->apiClient->send($this->buildApiUrl('/language/translate/v2'), 'POST', [
42+
'key' => $this->apiKey,
43+
'q' => $text,
44+
'target' => substr($target, 0, 2),
45+
'source' => substr($source, 0, 2),
46+
'format' => $format,
47+
]);
48+
49+
$decodesResponse = $this->decodeResponse($response);
50+
$this->checkResponse($decodesResponse);
51+
52+
return $decodesResponse['data']['translations'][0]['translatedText'];
53+
}
54+
55+
/**
56+
* @inheritdoc
57+
*/
58+
public function detect($text)
59+
{
60+
}
61+
62+
/**
63+
* @inheritdoc
64+
*/
65+
public function getLanguages()
66+
{
67+
}
68+
69+
/**
70+
* @param string $uri
71+
* @param array $queryParams [optional]
72+
*
73+
* @return string
74+
*/
75+
private function buildApiUrl($uri, array $queryParams = [])
76+
{
77+
return self::$baseApiUrl . $uri . '?' . http_build_query($queryParams);
78+
}
79+
80+
/**
81+
* @param string $response
82+
*
83+
* @return array
84+
*
85+
* @throws Exception
86+
*/
87+
private function decodeResponse($response)
88+
{
89+
$decodesResponse = Json::decode($response);
90+
if (!$decodesResponse) {
91+
throw new Exception('Invalid API response: json decode failed!');
92+
}
93+
94+
return $decodesResponse;
95+
}
96+
97+
/**
98+
* @param array $response
99+
*
100+
* @throws Exception
101+
*/
102+
private function checkResponse($response)
103+
{
104+
if (isset($response['error'])) {
105+
$error = $response['error'];
106+
Yii::error('API response: ' . var_export($response, true), 'translatemanager');
107+
108+
throw new Exception("API error: $error[message]", $error['code']);
109+
}
110+
}
111+
}

translation/Translator.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace lajax\translatemanager\translation;
4+
5+
/**
6+
* A translator that can translate arbitrary text.
7+
*
8+
* @author moltam
9+
*/
10+
interface Translator
11+
{
12+
/**
13+
* Translates the given text to the specified language.
14+
*
15+
* @param string $text The text to translate.
16+
* @param string $target The language code for translation.
17+
* @param string $source [optional]
18+
* <p>The language code of the source text. If not given, the translator tries to detect the language.</p>
19+
* @param string $format [optional]
20+
* <p>The format of the source text. Possible values:
21+
* - html: string with HTML markup,
22+
* - text: plain text without markup.
23+
* </p>
24+
*
25+
* @return string The translation.
26+
*
27+
* @throws Exception If the text cannot be translated, or an error occurred during translation.
28+
*/
29+
public function translate($text, $target, $source = null, $format = 'html');
30+
31+
/**
32+
* Detects the language of the specified text.
33+
*
34+
* @param string $text The analyzed text.
35+
*
36+
* @return string The language code for translation.
37+
*
38+
* @throws Exception If the language cannot be detected, or an error occurred during detection.
39+
*/
40+
public function detect($text);
41+
42+
/**
43+
* Returns the languages supported by the translator.
44+
*
45+
* @return string[] A list of language codes.
46+
*/
47+
public function getLanguages();
48+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace lajax\translatemanager\translation\client;
4+
5+
use lajax\translatemanager\translation\Exception;
6+
7+
/**
8+
* Exception for API communication errors.
9+
*
10+
* @author moltam
11+
*/
12+
class ClientException extends Exception
13+
{
14+
}

0 commit comments

Comments
 (0)