From 7f527989b6898bbd0c85cc7ec71b49ff3b5e9310 Mon Sep 17 00:00:00 2001 From: martbost Date: Fri, 21 Aug 2026 15:46:47 -0500 Subject: [PATCH] Translate endpoint: numbered-marker protocol instead of JSON arrays - multi-line swipe strings with embedded quotes broke JSON.parse and poisoned whole batches --- server.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/server.js b/server.js index c2bc995..a5c9210 100644 --- a/server.js +++ b/server.js @@ -391,17 +391,22 @@ async function handleTranslate(req,res){ method:'POST',signal:ctrl.signal, headers:{'Authorization':`Bearer ${apiKey}`,'Content-Type':'application/json','HTTP-Referer':'https://rmcircle.team','X-Title':'RM Circle Translate'}, body:JSON.stringify({model:OPENROUTER_MODEL,max_tokens:6000,temperature:0,messages:[ - {role:'system',content:`You translate website UI strings from English to ${TR_LANG_NAMES[tl]}. Reply with ONLY a JSON array of the translated strings, same order and length as the input array. Keep these words untranslated wherever they appear: Scintilla, Ascensus, Fabrica, Culmen, Apex, Fastigium, Vertex, Corona, POL, Polygon, RM Circle, MoonPay, MetaMask, Trust Wallet. Keep numbers, #ids, emoji and punctuation intact. Natural, friendly tone.`}, - {role:'user',content:JSON.stringify(miss.map(i=>texts[i]))} + {role:'system',content:`You translate website UI strings from English to ${TR_LANG_NAMES[tl]}. The input is numbered items, each preceded by a line @@N@@. Reply with the SAME @@N@@ marker lines, each followed by that item's translation (multi-line items keep their line breaks). Output nothing except markers and translations — no preamble, no code fences. Keep these words untranslated wherever they appear: Scintilla, Ascensus, Fabrica, Culmen, Apex, Fastigium, Vertex, Corona, POL, Polygon, RM Circle, MoonPay, MetaMask, Trust Wallet. Keep numbers, #ids, emoji and punctuation intact. Natural, friendly tone.`}, + {role:'user',content:miss.map((i,j)=>`@@${j+1}@@ +${texts[i]}`).join(' +')} ]}) }); clearTimeout(timer); if(r.ok){ const d=await r.json(); let reply=d&&d.choices&&d.choices[0]&&d.choices[0].message&&d.choices[0].message.content||''; - reply=reply.replace(/^```(?:json)?\s*/,'').replace(/```\s*$/,'').trim(); - const arr=JSON.parse(reply); - if(Array.isArray(arr)&&arr.length===miss.length){ + reply=reply.replace(/^```[a-z]*\s*/,'').replace(/```\s*$/,'').trim(); + const parts=reply.split(/^@@(\d+)@@\s*$/m); + // parts: [lead, "1", text1, "2", text2, ...] + const arr=[]; + for(let k=1;k+1typeof x==='string'&&x.length)){ miss.forEach((idx,j)=>{ const tr=String(arr[j]).slice(0,600); out[idx]=tr; cache[keyOf(texts[idx])]=tr; }); trDirty=true; done=true; }