|
<?php |
|
/** |
|
* @var AppView $this |
|
* @var string $localeToTranslate |
|
* @var string $domainToTranslate |
|
* @var string[] $domains |
|
* @var Sepia\PoParser\Catalog\CatalogArray $translations |
|
*/ |
|
|
|
use App\Application; |
|
use App\Model\Entity\User; |
|
use App\View\AppView; |
|
|
|
if ($this->user['role'] === User::ROLE_SUPERADMIN) { |
|
echo $this->CustomForm->postLink( |
|
__('Regenerate active .po from .pot file'), |
|
['action' => 'rewriteCountryPos', $localeToTranslate, $domainToTranslate], |
|
[ |
|
'confirm' => __('This will merge this file with original .pot, may be little destructive'), |
|
'class' => 'button tiny warning' |
|
] |
|
); |
|
|
|
echo $this->CustomForm->postLink( |
|
__('Regenerate all .po from .pot files'), |
|
['action' => 'regenerateAll'], |
|
[ |
|
'confirm' => __('This will merge this file with original .pot, may be little destructive'), |
|
'class' => 'button tiny warning' |
|
] |
|
); |
|
|
|
echo $this->Html->link( |
|
__('Show log'), |
|
['action' => 'translationsLog'], |
|
['class' => 'button tiny warning'] |
|
); |
|
} ?> |
|
|
|
<ul class="menu expanded"> |
|
<?php foreach (Application::ALL_LOCALES as $code => $locale) { ?> |
|
<li> |
|
<?= $this->Html->link( |
|
$locale, |
|
[$code, $domainToTranslate], |
|
['class' => 'button tiny ' . ($code === $localeToTranslate ? 'primary' : 'secondary')] |
|
) ?> |
|
</li> |
|
<?php } ?> |
|
</ul> |
|
|
|
|
|
<ul class="menu expanded"> |
|
<?php foreach ($domains as $domain) { ?> |
|
<li> |
|
<?= $this->Html->link( |
|
$domain, |
|
[$localeToTranslate, $domain], |
|
['class' => 'button tiny ' . ($domain === $domainToTranslate ? 'primary' : 'secondary')] |
|
) ?> |
|
</li> |
|
<?php } ?> |
|
</ul> |
|
|
|
<?php |
|
foreach ($translations->getEntries() as $entry) { |
|
$msgId = $entry->getMsgId(); |
|
$msgIdPlural = $entry->getMsgIdPlural(); |
|
$msgInCurrentLocale = __d($domain, $msgId); |
|
?> |
|
<fieldset class="fieldset"> |
|
<legend><?= $msgId ?><small>(<?= $msgIdPlural ?: '' ?>)</small></legend> |
|
|
|
<?php if ($msgId !== $msgInCurrentLocale) { ?> |
|
<label> |
|
<span><?= __('Message in currently selected language') ?></span> |
|
<input type="text" disabled value="<?= $msgInCurrentLocale ?>"> |
|
</label> |
|
<?php } ?> |
|
|
|
<?php if ($comments = $entry->getDeveloperComments()) { |
|
echo "<blockquote>$comments</blockquote>"; |
|
} ?> |
|
<?php if ($comments = $entry->getTranslatorComments()) { |
|
echo '<blockquote>' . implode("\n<br>", $comments) . '</blockquote>'; |
|
} ?> |
|
<?php if ($references = $entry->getReference()) { |
|
echo '<pre>' . implode("\n", $references) . '</pre>'; |
|
} ?> |
|
|
|
<?php |
|
$common = [ |
|
'data-id' => $msgId, |
|
'rows' => 3, |
|
'type' => 'textarea', |
|
'label' => false |
|
]; |
|
?> |
|
|
|
<?php $msgStrPlurals = $entry->getMsgStrPlurals(); |
|
if (count($msgStrPlurals) > 0) { |
|
foreach ($msgStrPlurals as $count => $msgStrPlural) { |
|
$isLast = $count + 1 === count($msgStrPlurals); |
|
echo '<label><span>' . _('In count of') . ' ' . $count . ($isLast ? '+' : '') . '</span>'; |
|
echo $this->CustomForm->control( |
|
$count, |
|
['value' => $msgStrPlural] + $common |
|
); |
|
echo '</label>'; |
|
} |
|
} else { ?> |
|
<label><span><?= __('Translation') ?></span> |
|
<?= $this->CustomForm->control( |
|
'singular', |
|
['value' => $entry->getMsgStr()] + $common |
|
) ?> |
|
</label> |
|
<?php } ?> |
|
</fieldset> |
|
<?php } ?> |
|
|
|
<section class="tools callout"> |
|
<dl> |
|
<dd><?= __('Translated count') ?></dd> |
|
<dt> |
|
<span id="translated-count">xxx</span> |
|
/ |
|
<span id="all-count">xxx</span> |
|
</dt> |
|
</dl> |
|
|
|
<button class="button" id="goto-next-empty"><?= __('Next untranslated') ?></button> |
|
</section> |
|
|
|
<style> |
|
fieldset label { |
|
display: flex; |
|
|
|
} |
|
|
|
fieldset label span { |
|
flex-basis: 30%; |
|
} |
|
|
|
fieldset label > div { |
|
flex-grow: 1; |
|
} |
|
|
|
.input.textarea textarea.dirty { |
|
border-color: palevioletred; |
|
} |
|
|
|
.tools { |
|
position: fixed; |
|
top: 5rem; |
|
right: 0; |
|
} |
|
|
|
dt { |
|
width: 15%; |
|
display: inline-block; |
|
} |
|
|
|
dd { |
|
width: 80%; |
|
display: inline-block; |
|
} |
|
</style> |
|
|
|
<script nonce="<?= $this->nonce ?? '' ?>"> |
|
/** |
|
* Return hash of string |
|
* @returns {string} |
|
*/ |
|
String.prototype.hashCode = function () { |
|
var hash = 5381, i = this.length |
|
while (i) |
|
hash = (hash * 33) ^ this.charCodeAt(--i) |
|
return (hash >>> 0).toString(); |
|
} |
|
|
|
const textAreas = document.querySelectorAll('.input.textarea textarea'); |
|
const updateTranslatedCount = function () { |
|
|
|
const inputs = document.querySelectorAll('[name="singular"]'); |
|
|
|
const all = inputs.length; |
|
const translated = [...inputs].filter(input => input.value.trim()).length; |
|
|
|
document.getElementById('translated-count').textContent = translated; |
|
document.getElementById('all-count').textContent = all; |
|
}; |
|
|
|
updateTranslatedCount(); |
|
|
|
[...textAreas].forEach(item => { |
|
item.dataset.hash = item.value.hashCode(); // Prefill each string hash to determine if it changed |
|
|
|
item.addEventListener('input', e => { |
|
let target = e.target; |
|
|
|
if (target.dataset.hash !== target.value.hashCode()) { // When changed indicate |
|
target.classList.add('dirty'); |
|
} else { |
|
target.classList.remove('dirty'); |
|
} |
|
}); |
|
|
|
item.addEventListener('blur', e => { |
|
let target = e.target; |
|
|
|
if (!target.classList.contains('dirty')) { |
|
return; // Did not change |
|
} |
|
|
|
fetch(location.href, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'X-CSRF-Token': '<?= $this->request->getParam('_csrfToken'); ?>' |
|
}, |
|
body: JSON.stringify({ |
|
text: target.value, |
|
field: target.name, |
|
id: target.dataset.id |
|
}) |
|
}) |
|
.then(response => response.json()) |
|
.then((data) => { |
|
toastr.success('Zpráva uložena'); |
|
updateTranslatedCount(); |
|
target.dataset.hash = target.value.hashCode(); |
|
target.classList.remove('dirty'); |
|
}) |
|
.catch((error) => { |
|
console.log(error); |
|
alert('<?= __('Error, write to admin please') ?>'); |
|
}); |
|
}); |
|
}); |
|
|
|
/** |
|
* Next untranslated focus |
|
*/ |
|
document.getElementById('goto-next-empty').addEventListener('click', ev => { |
|
const untranslated = document.querySelector('[name="singular"]:empty:not(.skip)'); |
|
|
|
if(!untranslated) { // Cycle |
|
[...document.querySelectorAll('[name="singular"]')].forEach(el => el.classList.remove('skip')); |
|
} else { |
|
untranslated.scrollIntoView() |
|
untranslated.focus(); |
|
untranslated.classList.add('skip'); |
|
} |
|
}); |
|
</script> |
|
|