| Server IP : 188.114.96.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /polana/admin/ |
Upload File : |
<?php
declare(strict_types=1);
/** TKLM Menu V8 — batch translate missing PL→EN values for the selected menu bundle. */
require_once dirname(__DIR__).'/includes/tklm_word_v5.php';
require_once dirname(__DIR__).'/includes/tklm_menu_core.php';
require_admin_role();
header('Cache-Control: private, no-store, max-age=0');
header('X-Robots-Tag: noindex, nofollow', true);
$id=filter_input(INPUT_GET,'menu_id',FILTER_VALIDATE_INT);
if (!$id) $id=filter_input(INPUT_POST,'menu_id',FILTER_VALIDATE_INT);
if (!$id) {http_response_code(400);exit('Brak identyfikatora karty.');}
try {
tm_schema();
$bundle=tklm_v7_bundle_rows((int)$id);
$tasks=[];$list=[];
foreach ($bundle as $pack) {
$menu=$pack['menu'];
$list[]=['id'=>(int)$menu['id'],'type'=>tklm_v7_type_label((string)$menu['menu_type'],'pl')];
foreach ($pack['categories'] as $cat) {
if (empty($cat['active'])) continue;
$items=array_values(array_filter($cat['items']??[],static fn(array $item):bool=>!empty($item['active'])&&!empty($item['available'])));
if (!$items) continue;
$c=tm_task('menu_categories',(int)$cat['id'],'name');
if ($c['source']!=='' && $c['translated']==='') $tasks[]=['entity'=>'menu_categories','id'=>(int)$cat['id'],'field'=>'name','label'=>'Kategoria: '.$c['source']];
foreach ($items as $item) {
foreach (['name','description','allergens'] as $field) {
$task=tm_task('menu_items',(int)$item['id'],$field);
if ($task['source']==='' || $task['translated']!=='') continue;
$tasks[]=['entity'=>'menu_items','id'=>(int)$item['id'],'field'=>$field,
'label'=>'#'.(int)$item['id'].' · '.$field.' · '.(function_exists('mb_substr')?mb_substr($task['source'],0,60):substr($task['source'],0,60))];
}
}
}
}
if ($_SERVER['REQUEST_METHOD']==='POST') {
verify_csrf();
$action=(string)($_POST['action']??'');
try {
if ($action==='test') {
tm_json(['ok'=>true,'translated'=>tm_translate_text('Dzień dobry')]);
}
if ($action==='translate') {
$entity=(string)($_POST['entity']??'');
$eid=(int)($_POST['id']??0);
$field=(string)($_POST['field']??'');
$allowed=false;
foreach ($tasks as $t) {
if ($t['entity']===$entity && $t['id']===$eid && $t['field']===$field) {$allowed=true;break;}
}
if (!$allowed) tm_json(['ok'=>false,'error'=>'To pole nie jest już na liście brakujących tłumaczeń.'],409);
$result=tm_auto_one($entity,$eid,$field);
tm_json(['ok'=>true,'result'=>$result]);
}
tm_json(['ok'=>false,'error'=>'Nieznane działanie.'],400);
} catch(Throwable $e) {
error_log('[POLANA V8 translation] '.$e->getMessage());
tm_json(['ok'=>false,'error'=>$e->getMessage()],400);
}
}
} catch(Throwable $e) {
http_response_code(409);
exit('Nie można przygotować listy tłumaczeń: '.htmlspecialchars($e->getMessage(),ENT_QUOTES|ENT_SUBSTITUTE,'UTF-8'));
}
render_admin_header('Tłumaczenie menu PL → EN');
?>
<section style="max-width:1100px;margin:20px auto;padding:24px;border-radius:18px;background:#fff;border:1px solid #e5e7eb">
<h1>Tłumaczenie menu PL → EN</h1>
<p>Pracujemy na aktualnym zestawie: <?php foreach($list as $m): ?><strong><?=htmlspecialchars($m['type'],ENT_QUOTES,'UTF-8')?> #<?=(int)$m['id']?></strong> <?php endforeach; ?></p>
<p>API: <code>translate.tklm.pl</code> · prywatny klucz używany wyłącznie po stronie PHP. Ceny, oryginalne teksty PL i istniejące poprawki EN pozostają bez zmian.</p>
<p><strong>Brakujących pól EN: <span id="left"><?=count($tasks)?></span></strong></p>
<div style="display:flex;gap:10px;flex-wrap:wrap;margin:15px 0">
<button type="button" id="test" class="btn btn-light">Test API</button>
<button type="button" id="start" class="btn btn-primary" <?=count($tasks)===0?'disabled':''?>>Przetłumacz brakujące</button>
<button type="button" id="stop" class="btn btn-light">Zatrzymaj</button>
<a class="btn btn-light" href="/admin/tklm-word-jezyki.php?menu_id=<?=(int)$id?>">Word i PDF</a>
<a class="btn btn-light" href="/admin/tklm-menu.php?menu_id=<?=(int)$id?>">Ręczna korekta</a>
</div>
<progress id="progress" max="<?=max(1,count($tasks))?>" value="0" style="width:100%;max-width:700px"></progress>
<p id="state" role="status" aria-live="polite">Najpierw uruchom „Test API”. Tłumaczenia nie są publikowane automatycznie.</p>
<?php if (!$tasks):?><p>Wszystkie wymagane pola w wybranym zestawie mają już wartości EN. Przejrzyj nazwy gastronomiczne przed drukiem.</p><?php endif;?>
<details><summary>Lista braków (<?=count($tasks)?>)</summary><ol><?php foreach($tasks as $t):?><li><?=htmlspecialchars($t['label'],ENT_QUOTES|ENT_SUBSTITUTE,'UTF-8')?></li><?php endforeach;?></ol></details>
</section>
<script>
(()=>{
'use strict';
const tasks=<?=json_encode($tasks,JSON_UNESCAPED_UNICODE|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_INVALID_UTF8_SUBSTITUTE)?>;
const csrf=<?=json_encode(csrf_token(),JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT)?>;
const menu=<?=json_encode((int)$id)?>;
const msg=document.getElementById('state'), prog=document.getElementById('progress'), btn=document.getElementById('start');
let stop=false,busy=false;
const delay=ms=>new Promise(r=>setTimeout(r,ms));
async function call(action,task={}){
const body=new FormData();body.set('csrf_token',csrf);body.set('action',action);body.set('menu_id',String(menu));
for(const [k,v] of Object.entries(task))body.set(k,String(v));
const resp=await fetch(location.pathname+'?menu_id='+menu,{method:'POST',body,credentials:'same-origin'});
let data;try{data=await resp.json()}catch{throw new Error('Serwer nie zwrócił JSON (HTTP '+resp.status+').')}
if(!resp.ok||data.ok===false)throw new Error(data.error||'HTTP '+resp.status);
return data;
}
document.getElementById('test').addEventListener('click',async()=>{
try{msg.textContent='Sprawdzam API…';const r=await call('test');msg.textContent='API działa: Dzień dobry → '+r.translated;}
catch(e){msg.textContent='Błąd API: '+e.message;}
});
document.getElementById('stop').addEventListener('click',()=>{stop=true;msg.textContent='Zatrzymam po bieżącym polu.'});
btn.addEventListener('click',async()=>{
if(busy)return;busy=true;stop=false;btn.disabled=true;
let done=0;
try{
for(const t of tasks){
if(stop)break;
msg.textContent=`Tłumaczę ${done+1}/${tasks.length}: ${t.label}`;
try{await call('translate',t)}catch(e){
if(String(e.message).includes('429')){await delay(3000);await call('translate',t)}else throw e;
}
done++;prog.value=done;document.getElementById('left').textContent=String(tasks.length-done);
await delay(1350);
}
msg.textContent=stop?`Zatrzymano po ${done} polach.`:`Zakończono ${done} pól. Odśwież stronę, przejrzyj EN i pobierz Word.`;
}catch(e){msg.textContent='Zatrzymano na błędzie: '+e.message+' · Zapisane wcześniej tłumaczenia pozostają.';}
finally{busy=false;btn.disabled=false}
});
})();
</script>
<?php render_admin_footer(); ?>