Skip to content

Commit

Permalink
First version of TranslateAutomator plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
davidprovaznikj committed Jun 14, 2024
1 parent e70f760 commit 746b810
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 0 deletions.
45 changes: 45 additions & 0 deletions Plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php namespace DavidProvaznik\TranslateAutomator;

use RainLab\Translate\Classes\Locale;
use System\Classes\PluginBase;
use Event;
use Input;
use Response;
use DavidProvaznik\TranslateAutomator\Models\TranslateAutomator as HelperModel;

class Plugin extends PluginBase
{
/** @var string[] $require Required plugins. */
public $require = [
'Rainlab.Translate',
];
public function pluginDetails()
{
return [
'name' => 'Translate Automator',
'description' => 'Automate translation of untranslated strings using Google Translate.',
'author' => 'David Provaznik',
'icon' => 'icon-language'
];
}

public function boot()
{
// Extend the view to add custom button
Event::listen('backend.page.beforeDisplay', function($controller, $action, $params) {
if ($controller instanceof \RainLab\Translate\Controllers\Messages && $action == 'index') {
$controller->addJs('/plugins/davidprovaznik/translateautomator/assets/js/translateautomator.js');
$controller->addCss('/plugins/davidprovaznik/translateautomator/assets/css/translateautomator.css');
$controller->addDynamicMethod('onTranslate', function() {
$text = Input::get('text');
$localeTo = Input::get('locale_to');
$defaultLocale = Locale::getDefaultSiteLocale();

$translatedText = HelperModel::autoTranslate($text, $defaultLocale, $localeTo);

return Response::json(['translatedText' => $translatedText]);
});
}
});
}
}
Empty file.
152 changes: 152 additions & 0 deletions assets/js/translateautomator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
document.addEventListener('DOMContentLoaded', function () {
console.log('DOM fully loaded and parsed');
initTranslateButton();

// Regularly check for the presence of the button and re-add if necessary
setInterval(function () {
initTranslateButton();
}, 1000); // Check every second
});

let isTranslating = false;
let translateTimeouts = [];

function initTranslateButton() {
var toolbar = document.querySelector('.loading-indicator-container');
if (toolbar && !document.querySelector('.btn-translate')) {
addTranslateButton(toolbar);
} else {
// If the button already exists, reattach the click event to handle button state
var button = document.querySelector('.btn-translate');
if (button) {
button.removeEventListener('click', handleButtonClick);
button.addEventListener('click', handleButtonClick);
}
}
}

function addTranslateButton(toolbar) {
var button = document.createElement('button');
button.innerHTML = 'Start Automatic translate if empty';
button.className = 'btn btn-primary oc-icon-language btn-translate';
button.addEventListener('click', handleButtonClick);

toolbar.appendChild(button);
console.log('Translate button added');
}

function handleButtonClick() {
console.log('Translate button clicked');
var button = this;
if (isTranslating) {
stopTranslating(button);
} else {
startTranslating(button);
}
}

function startTranslating(button) {
isTranslating = true;
button.innerHTML = 'Stop translating...';
handleTranslateButtonClick(button);
}

function stopTranslating(button) {
isTranslating = false;
button.innerHTML = 'Translate "from" to "to" if "to" is empty';
translateTimeouts.forEach(clearTimeout);
translateTimeouts = [];
}

function handleTranslateButtonClick(button) {
console.log('handleTranslateButtonClick function called');
var fromCells = document.querySelectorAll('td[data-column="from"]');
var localeTo = document.querySelector('input[name="locale_to"]').value;

var delay = 1000; // 1 second delay

var translatableCells = [];

// Filter out cells that need translation
fromCells.forEach(function (fromCell) {
var toCell = fromCell.parentNode.querySelector('td[data-column="to"]');
if (toCell) {
var toValue = toCell.querySelector('input[data-container="data-container"]').value;
if (!toValue) {
translatableCells.push({ fromCell: fromCell, toCell: toCell });
}
}
});

console.log('Translatable cells:', translatableCells);

// Translate and save each cell
translatableCells.forEach(function (cells, index) {
let timeout = setTimeout(function () {
if (!isTranslating) return; // Stop if translation was stopped
var fromValue = cells.fromCell.querySelector('input[data-container="data-container"]').value;
var key = cells.fromCell.parentNode.getAttribute('data-row');

console.log('From value:', fromValue);
console.log('Key:', key);

if (key) {
$.request('onTranslate', {
data: {
text: fromValue,
locale_to: localeTo
},
success: function(data) {
console.log('Translation response:', data);
var inputElement = cells.toCell.querySelector('input[data-container="data-container"]');
var divElement = cells.toCell.querySelector('div[data-view-container="data-view-container"]');
if (inputElement && divElement) {
inputElement.value = data.translatedText;
divElement.innerText = data.translatedText;

// Call function to save translated data
saveTranslatedData(fromValue, data.translatedText, localeTo, key);
}
},
error: function(error) {
console.error('Error translating text:', error);
}
});
}
}, index * delay);
translateTimeouts.push(timeout);
});

// Reset the button state and text when translation completes
if (translatableCells.length > 0) {
let lastTimeout = setTimeout(function () {
stopTranslating(button);
}, translatableCells.length * delay);
translateTimeouts.push(lastTimeout);
}
}

function saveTranslatedData(fromValue, toValue, localeTo, key) {
var sessionKey = document.querySelector('input[name="_session_key"]').value;
var token = document.querySelector('input[name="_token"]').value;

var payload = {
_session_key: sessionKey,
_token: token,
search: '',
locale_to: localeTo,
key: key,
'recordData[from]': fromValue,
'recordData[to]': toValue
};

$.request('onServerUpdateRecord', {
data: payload,
success: function(response) {
console.log('Translation saved successfully:', response);
},
error: function(error) {
console.error('Error saving translation:', error);
}
});
}
21 changes: 21 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "davidprovaznik/translateautomator-plugin",
"description": "Automate translation of untranslated strings using Google Translate.",
"type": "october-plugin",
"keywords": ["traslate", "automatic translate"],
"require": {
"php": ">=8.2",
"ext-json": "*",
"composer/installers": "^1.10",
"rainlab/translate-plugin": "^2.1",
"stichoza/google-translate-php": "^5.1"
},
"license": "MIT",
"authors": [
{
"name": "David Provaznik",
"email": "[email protected]"
}
],
"minimum-stability": "stable"
}
25 changes: 25 additions & 0 deletions models/TranslateAutomator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php namespace DavidProvaznik\TranslateAutomator\Models;

use Model;
use Stichoza\GoogleTranslate\GoogleTranslate;
use Log;
use Exception;

class TranslateAutomator extends Model
{
public static function autoTranslate($text, $sourceLocale, $targetLocale)
{
try {
$tr = new GoogleTranslate();
$tr->setSource($sourceLocale);
$tr->setTarget($targetLocale);

$translatedText = $tr->translate($text);

return $translatedText;
} catch (Exception $e) {
Log::error('Google Translate API error: ' . $e->getMessage());
throw new Exception("Error communicating with Google Translate API: " . $e->getMessage());
}
}
}
6 changes: 6 additions & 0 deletions plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
plugin:
name: 'Translate Automator'
description: 'Automate translation of untranslated strings using Google Translate.'
author: 'David Provaznik'
icon: oc-icon-cogs
homepage: 'https://davidprovaznik.cz'
2 changes: 2 additions & 0 deletions updates/version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1.0.0:
- First version of TranslateAutomator plugin.
12 changes: 12 additions & 0 deletions views/translateautomator/index.htm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="layout">
<div class="layout-row">
<div class="layout-cell">
<button
class="btn btn-primary"
data-request="onTranslate"
data-load-indicator="Translating...">
Translate Untranslated Strings
</button>
</div>
</div>
</div>

0 comments on commit 746b810

Please sign in to comment.