mirror of
https://gitflic.ru/project/photopea-v2/photopea-v-2.git
synced 2025-08-17 17:06:21 +00:00
392 lines
13 KiB
HTML
392 lines
13 KiB
HTML
<html>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0" />
|
|
<title>Translate Photopea</title>
|
|
|
|
<script src="UTIL.js"></script>
|
|
|
|
<style type="text/css">
|
|
body {
|
|
font-family:sans-serif;
|
|
background-color: #ceedf4;
|
|
margin:0;
|
|
padding:0;
|
|
line-height:1.6em;
|
|
color: rgb(51, 51, 51);
|
|
}
|
|
h1 {
|
|
font-size: 3em;
|
|
margin: 0;
|
|
padding: 0.7em;
|
|
color:#ffffff;
|
|
text-align:center;
|
|
background-image: linear-gradient(rgb(84, 180, 235), rgb(47, 164, 231));
|
|
}
|
|
h2 {
|
|
font-size: 1.8em;
|
|
margin-top:1em;
|
|
margin-bottom: 0.6em;
|
|
padding-bottom: 0.4em;
|
|
border-bottom-color: rgb(238, 238, 238);
|
|
border-bottom-style: solid;
|
|
border-bottom-width: 1px;
|
|
}
|
|
h3 { margin-top:1.0em; margin-bottom: 0.5em;}
|
|
p { margin: 0 0 0em 0;}
|
|
.main {
|
|
margin:0 auto;
|
|
max-width: 54em;
|
|
|
|
padding:0.5em 2em;
|
|
background-color: #ffffff;
|
|
}
|
|
#langcont span {
|
|
padding: 0.15em 0.5em;
|
|
margin: 0.3em;
|
|
border-radius:0.5em;
|
|
cursor:pointer;
|
|
color:#fff;
|
|
font-weight:bold;
|
|
display:inline-block;
|
|
min-width: 4.5em;
|
|
text-align:center;
|
|
}
|
|
#tsource, #tword {
|
|
font-size: 1.5em;
|
|
}
|
|
#tcomment { margin-left: 1em; opacity:0.6; font-size:1.0em; border:2px solid #aaa; padding:3px; }
|
|
button {
|
|
font-size: 1.4em;
|
|
margin: 0.5em 0.5em 0 0;
|
|
}
|
|
</style>
|
|
|
|
<script type="text/javascript">
|
|
|
|
var lfile;
|
|
var file;
|
|
var lang = -1; // index of table of the current language
|
|
var cword = 0;
|
|
var plists; // corresponding to tables
|
|
var wcnt; // counts of translated words (corresponding to tables)
|
|
var uptime = 10000;
|
|
var upTO = null; // update TimeOut
|
|
var fInput, ftext="", finds;
|
|
//*
|
|
function getParameterByName(name, url) {
|
|
if (!url) url = window.location.href;
|
|
name = name.replace(/[\[\]]/g, "\\$&");
|
|
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
|
|
results = regex.exec(url);
|
|
if (!results) return null;
|
|
if (!results[2]) return '';
|
|
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
|
}
|
|
//*/
|
|
function load(path, resp)
|
|
{
|
|
var request = new XMLHttpRequest();
|
|
request.open("GET", path, true);
|
|
//request.responseType = "arraybuffer";
|
|
request.onload = function(e){resp(e.target.response);};
|
|
request.send();
|
|
}
|
|
|
|
function go() {
|
|
fInput = document.getElementById("fInput");
|
|
fInput.addEventListener("input", findText, false);
|
|
var cnv = document.getElementById("cnv");
|
|
cnv.addEventListener("click", cnvClick);
|
|
loadFile();
|
|
}
|
|
function findText(e) {
|
|
ftext = fInput.value.toLowerCase();
|
|
fileLoaded();
|
|
if(finds.length!=0) cword = finds[0];
|
|
fileLoaded();
|
|
}
|
|
function loadFile() { load("versions/file.json"+"?rnd="+Math.random(), fileLoaded); }
|
|
function fileLoaded(str)
|
|
{
|
|
if(str)
|
|
{
|
|
upTO = setTimeout(loadFile, uptime);
|
|
if(lfile == str) { /* console.log("file is still the same"); */ return; }
|
|
lfile = str;
|
|
file = JSON.parse(str);
|
|
}
|
|
//*
|
|
if(lang==-1)
|
|
{
|
|
var lng = getParameterByName("lang");
|
|
if(lng) {
|
|
for(var i=0; i<file.langs.length; i++) if(file.langs[i].code==lng) lang = i;
|
|
}
|
|
if(lang==-1) lang = 0;
|
|
} //*/
|
|
|
|
wcnt = [];
|
|
plists = [[]];
|
|
var mainpl = plists[0];
|
|
UTIL.getPList(file.tables[0], mainpl, []);
|
|
wcnt.push(mainpl.length);
|
|
|
|
for(var i=1; i<file.tables.length; i++)
|
|
{
|
|
var pl = []; plists.push(pl);
|
|
var cnt = 0;
|
|
for(var j=0; j<mainpl.length; j++)
|
|
{
|
|
var mainw = mainpl[j];
|
|
var wrd = UTIL.getWord(mainw.path, file.tables[i]);
|
|
pl.push( {str:wrd, path:mainw.path} );
|
|
if(wrd!=null) cnt++;
|
|
}
|
|
wcnt.push(cnt);
|
|
}
|
|
|
|
var lcont = document.getElementById("langcont");
|
|
lcont.innerHTML = "";
|
|
|
|
var langs = JSON.parse(JSON.stringify(file.langs));
|
|
|
|
for(var i=0; i<langs.length; i++) {
|
|
var lng = langs[i];
|
|
lng.frac = wcnt[lng.table] / wcnt[0];
|
|
}
|
|
langs.sort(function(a,b) { return b.frac-a.frac; });
|
|
|
|
var clang;
|
|
for(var i=0; i<langs.length; i++)
|
|
{
|
|
var lng = langs[i];
|
|
var perc = Math.floor( 100 * lng.frac );
|
|
var el = document.createElement("span");
|
|
el.setAttribute("title", "#"+(i+1)+" - "+lng.code+" - " + perc + " %");
|
|
el.innerText = lng.name;
|
|
|
|
var grn = perc<=70 ? "150,200,0" : "0,200,0";
|
|
|
|
var bgstyle = "background: linear-gradient(to right, rgb("+grn+") " +perc+ "%, rgb(230,0,0) "+perc+".1%);";
|
|
if(lng.table==lang) bgstyle += "box-shadow: 0px 0px 10px #000;";
|
|
el.setAttribute("style", bgstyle);
|
|
if(lang==lng.table) clang = lng;
|
|
el.lang = lng.table;
|
|
lcont.appendChild(el);
|
|
el.addEventListener("click", langClick, false);
|
|
}
|
|
|
|
|
|
var missOnly = document.getElementById("missonly").checked;
|
|
var inLang = document.getElementById("inLang").selectedIndex;
|
|
var ewds = plists[[0,clang.table][inLang]], twds=plists[clang.table]; finds=[];
|
|
for(var i=0; i<ewds.length; i++) {
|
|
if(ewds[i].str && ewds[i].str.split("::")[0].toLowerCase().indexOf(ftext)!=-1)
|
|
if(!missOnly || twds[i].str==null) finds.push(i);
|
|
}
|
|
|
|
updateGraph(plists[clang.table], cword);
|
|
|
|
var phnum = document.getElementById("phrasenum");
|
|
phnum.innerText = "Phrase "+ (cword+1) + " / " + mainpl.length;
|
|
|
|
var tsource = document.getElementById("tsource");
|
|
var tcomment = document.getElementById("tcomment");
|
|
var epts = plists[0][cword].str.split("::");
|
|
tsource.innerText = epts[0];
|
|
tcomment.innerText = epts.length==1 ? "":"Hint: "+epts[1];
|
|
tcomment.style.display = epts.length==1 ? "none":"";
|
|
|
|
var tlang = document.getElementById("tlang");
|
|
tlang.innerText = clang.name+":";
|
|
|
|
var tword = document.getElementById("tword");
|
|
tword.value = plists[lang][cword].str == null ? "" : plists[lang][cword].str.split("::")[0];
|
|
|
|
document.body.setAttribute("style", "opacity:1.0;");
|
|
}
|
|
|
|
function updateGraph(words, cword)
|
|
{
|
|
var cnv = document.getElementById("cnv");
|
|
var ctx = cnv.getContext("2d");
|
|
ctx.clearRect(0,0,cnv.width,cnv.height);
|
|
|
|
var y = 8;
|
|
|
|
var rw = (2000 / words.length);
|
|
|
|
ctx.fillStyle = "#ee0000"; ctx.fillRect(0,y,2000,20);
|
|
|
|
|
|
var start = -1, estrt = -1;
|
|
for(var i=0; i<words.length; i++)
|
|
{
|
|
var gotE = finds.indexOf(i)!=-1;//ewds[i].str.split("::")[0].toLowerCase().indexOf(ftext.toLowerCase())!=-1;
|
|
if( gotE && estrt==-1) estrt = i;
|
|
if(!gotE && estrt!=-1) { ctx.fillStyle = "#333333"; ctx.fillRect(estrt*rw, 0, (i-estrt)*rw, 5); estrt = -1; }
|
|
|
|
var gotS = words[i].str!=null;
|
|
if( gotS && start==-1) start = i;
|
|
if(!gotS && start!=-1) { ctx.fillStyle = "#00dd00"; ctx.fillRect(start*rw, y, (i-start)*rw, 20); start = -1; }
|
|
}
|
|
if(estrt!=-1) { ctx.fillStyle = "#333333"; ctx.fillRect(estrt*rw, 0, (words.length-estrt)*rw, 5); }
|
|
if(start!=-1) { ctx.fillStyle = "#00dd00"; ctx.fillRect(start*rw, y, (words.length-start)*rw, 20); }
|
|
|
|
var curx = cword*rw+rw/2
|
|
ctx.fillStyle = "rgba(0,0,0,1)"; ctx.beginPath(); ctx.moveTo(curx, y+20); ctx.lineTo(curx+10, cnv.height); ctx.lineTo(curx-10, cnv.height); ctx.fill();
|
|
}
|
|
|
|
function langClick(e)
|
|
{
|
|
lang = e.target.lang;
|
|
fileLoaded();
|
|
}
|
|
function charOcc(s,c) { var occ=0; for(var i=0; i<s.length; i++) if(s[i]==c) occ++; return occ; }
|
|
|
|
function prev() { var fl=finds.length, fi=finds.indexOf(cword); if(fi==-1)fi=0; if(fl!=0) cword = finds[(fi-1+fl)%fl]; fileLoaded(); }
|
|
function next() { var fl=finds.length, fi=finds.indexOf(cword); if(fi==-1)fi=0; if(fl!=0) cword = finds[(fi+1+fl)%fl]; fileLoaded(); }
|
|
function save() {
|
|
if(lang==0) { alert("You can not edit this language."); return; }
|
|
var nword = document.getElementById("tword").value.trim();
|
|
var ostr = plists[0][cword].str.split("::")[0];
|
|
if(nword.length>ostr.length*3.2 && nword.length>17) { alert("Your phrase is too long. Please write a shorter phrase"); return; }
|
|
if(charOcc(nword,"<")!=charOcc(ostr,"<") || charOcc(nword,">")!=charOcc(ostr,">")) { alert("Incorrect brackets: < >"); return; }
|
|
if(charOcc(nword,"[")+charOcc(nword,"]")+charOcc(nword,";") >0) { alert("Forbidden characters: [ ] ;"); return; }
|
|
if(nword=="") nword = null;
|
|
if(nword==plists[lang][cword].str) return;
|
|
plists[lang][cword].str = nword;
|
|
|
|
var nfile = {};
|
|
nfile.langs = file.langs;
|
|
for(var i=0; i<nfile.langs.length; i++) if(nfile.langs[i].table!=i) { alert("An error occured. Please, reload the page."); return; }
|
|
nfile.tables = [];
|
|
for(var i=0; i<file.tables.length; i++)
|
|
{
|
|
var ntab = JSON.parse(JSON.stringify(file.tables[0]));
|
|
for(var j=0; j<plists[0].length; j++)
|
|
UTIL.setWord(plists[i][j].str, plists[i][j].path, ntab)
|
|
var nntab = UTIL.tryClear(ntab);
|
|
nfile.tables.push(ntab);
|
|
}
|
|
|
|
|
|
clearTimeout(upTO);
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
var params = "p="+ encodeURIComponent(JSON.stringify(nfile, null, "\t"));
|
|
xhr.open("POST", "saveFile2.php", true);
|
|
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
|
xhr.addEventListener("load" , saved );
|
|
xhr.send(params);
|
|
document.body.setAttribute("style", "opacity:0.4;");
|
|
}
|
|
function saved(e)
|
|
{
|
|
console.log("Data sent to server. Response: " + e.target.response);
|
|
fmi(true);
|
|
loadFile();
|
|
}
|
|
function fmi(onlyIfNext)
|
|
{
|
|
var cpl = plists[lang];
|
|
var ncw = -1;
|
|
for(var i=0; i<cpl.length; i++) if(cpl[i].str==null) { ncw=i; break; }
|
|
if(ncw!=-1) { if(ncw<cword) return; cword = ncw; fileLoaded(); }
|
|
}
|
|
function cnvClick(e)
|
|
{
|
|
var rct = e.currentTarget.getBoundingClientRect();
|
|
var x = (e.clientX - rct.left) / rct.width ;
|
|
var y = (e.clientY - rct.top ) / rct.height;
|
|
var tind = Math.floor(x * plists[0].length);
|
|
|
|
if(false)//y<0.3 && finds.length!=0)
|
|
{
|
|
cword = finds[0];
|
|
for(var i=0; i<finds.length; i++) if(Math.abs(finds[i]-tind)<Math.abs(cword-tind)) cword = finds[i];
|
|
}
|
|
else cword = tind;
|
|
fileLoaded();
|
|
}
|
|
|
|
function download(e)
|
|
{
|
|
var perc = document.getElementById("percnum").value / 100;
|
|
var out = {langs:[], tables:[]};
|
|
|
|
for(var i=0; i<file.langs.length; i++)
|
|
{
|
|
var lng = JSON.parse(JSON.stringify(file.langs[i]));
|
|
if(wcnt[lng.table]/wcnt[0] < perc) continue;
|
|
out.langs.push(lng);
|
|
out.tables.push(file.tables[lng.table]);
|
|
lng.table = out.tables.length-1;
|
|
}
|
|
|
|
if(document.getElementById("minify").checked) {
|
|
for(var i=0; i<out.tables.length; i++) out.tables[i]=UTIL.minify(out.tables[i]);
|
|
}
|
|
|
|
var pref = "", fname = "translation.json";
|
|
pref = "var LNG = "; fname = "LNG2.js";
|
|
|
|
var str = pref + JSON.stringify(out, null, "\t");
|
|
var a = document.createElement( "a" );
|
|
var blob = new Blob([str]);
|
|
var url = window.URL.createObjectURL( blob );
|
|
a.href = url;
|
|
a.download = fname;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
}
|
|
</script>
|
|
</head>
|
|
<body onload="go();">
|
|
|
|
<h1>Translate Photopea</h1>
|
|
|
|
<div class="main">
|
|
|
|
<h2>Choose the language</h2>
|
|
|
|
<div id="langcont"></div>
|
|
|
|
<h2>Translate <span style="font-size:0.6em">(keep the phrase empty, if you are not sure)</span></h2>
|
|
|
|
<canvas id="cnv" width="2000" height="42" style="width:100%; cursor:pointer;"></canvas>
|
|
|
|
<div style="margin-bottom:1em;">
|
|
<span id="phrasenum" style="font-size:1.5em; font-weight:bold; display:inline-block; width:10em; padding-left:0.0em;"></span>
|
|
<button onclick="prev()"><<<</button> <button onclick="next()">>>></button>
|
|
<!--<button onclick="fmi(true)">Find Missing Phrase</button>-->
|
|
<input type="checkbox" id="missonly" onchange="fileLoaded();fmi(false);"></input> <label for="missonly" style="margin-right:2em">Browse missing only</label>
|
|
Find: <input id="fInput" type="text" style="width:9em"></input>
|
|
<select onchange="fileLoaded();" id="inLang">
|
|
<option value="volvo">in English</option>
|
|
<option value="saab">in translated</option>
|
|
</select>
|
|
</div>
|
|
<span>English:</span>
|
|
<div style="margin-bottom:0.5em"><span id="tsource"></span><span id="tcomment"></span></div>
|
|
<span id="tlang">English:</span>
|
|
<input id="tword" type="text" style="width:100%;"></input>
|
|
|
|
<button onclick="save()">Save</button>
|
|
|
|
<!--
|
|
<p style="margin-top:1em">Your translation will become a part of <a href="https://github.com/photopea/OpenWord" target="_blank">OpenWord initiative</a>
|
|
and will be free to use for anybody for any purpose.</p>-->
|
|
<br/>
|
|
<span>Download translations with over</span>
|
|
<input id="percnum" type="text" style="width:30px;" value="70"></input> <span>%</span>
|
|
<input type="checkbox" id="minify" checked></input> <label for="minify">Minified</label> :
|
|
<button onclick="download()">Download</button>
|
|
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|