diff --git a/modules/json.py b/modules/json.py index ebbec13..8c513d2 100644 --- a/modules/json.py +++ b/modules/json.py @@ -162,6 +162,9 @@ def parseJSON(data, filename): # PSData format (Nupu_PSData.json - MailDatas, MemoryData, ShopDatas, hStData) elif any(k in data for k in ["MailDatas", "MemoryData", "ShopDatas", "hStData"]): result = translatePSData(data, filename) + # RdData format (RdData.json - dgnDatas with dungeon/dialogue data) + elif "dgnDatas" in data: + result = translateRdData(data, filename) else: result = translateJSON(data, filename, []) else: @@ -471,6 +474,258 @@ def translatePSData(data, filename): return tokens +def translateRdData(data, filename): + """Translate RdData JSON format (e.g. RdData.json). + + Handles dungeon data with nested dialogue, choices, and UI text. + Only translates player-visible text fields. + """ + global LOCK, ESTIMATE, FILENAME, PBAR, MISMATCH + tokens = [0, 0] + + def batchTranslate(stringList, context): + """Translate a list of strings and return translations. Returns [] on mismatch.""" + nonlocal tokens + if not stringList: + return [] + response = translateAI(stringList, context, True) + tokens[0] += response[1][0] + tokens[1] += response[1][1] + if len(stringList) != len(response[0]): + with LOCK: + if FILENAME not in MISMATCH: + MISMATCH.append(FILENAME) + return [] + return response[0] + + if "dgnDatas" not in data: + return tokens + + dgns = data["dgnDatas"] + + # ================================================================ + # PASS 1: Collect all translatable strings + # ================================================================ + + # -- Dungeon-level short fields -- + dgnNameS, dgnNameI = [], [] + clearTxtS, clearTxtI = [], [] + hosyuTxtS, hosyuTxtI = [], [] + firstHosyuTxtS, firstHosyuTxtI = [], [] + memoTxtS, memoTxtI = [], [] + appMemoTxtS, appMemoTxtI = [], [] + areaMemoS, areaMemoI = [], [] + + # -- Dungeon-level long text fields -- + naiyoTxtS, naiyoTxtI = [], [] + naiyoTxtExS, naiyoTxtExI = [], [] + johoTxtS, johoTxtI = [], [] + johoTxtExS, johoTxtExI = [], [] + + # -- Floor names -- + kaisoNameS, kaisoNameI = [], [] # (dgnIdx, kaisoIdx) + + # -- Dialogue (talkDatas / talkDatasEx) -- + talkNameS, talkNameI = [], [] # (dgnIdx, talkKey, talkIdx) + speakerNameS, speakerNameI = [], [] # (dgnIdx, talkKey, talkIdx, speechIdx) + dialogueS, dialogueI = [], [] # (dgnIdx, talkKey, talkIdx, speechIdx) + + # -- Choice events (sijiDatas) -- + sijiNameS, sijiNameI = [], [] # (dgnIdx, sijiIdx) + sijiChoiceS, sijiChoiceI = [], [] # (dgnIdx, sijiIdx) + + for di, dgn in enumerate(dgns): + if dgn is None: + continue + + # Dungeon short fields + if dgn.get("name") and re.search(LANGREGEX, dgn["name"]): + dgnNameS.append(dgn["name"]) + dgnNameI.append(di) + if dgn.get("clearTxt") and re.search(LANGREGEX, dgn["clearTxt"]): + clearTxtS.append(dgn["clearTxt"]) + clearTxtI.append(di) + if dgn.get("hosyuTxt") and re.search(LANGREGEX, dgn["hosyuTxt"]): + hosyuTxtS.append(dgn["hosyuTxt"]) + hosyuTxtI.append(di) + if dgn.get("firstHosyuTxt") and re.search(LANGREGEX, dgn["firstHosyuTxt"]): + firstHosyuTxtS.append(dgn["firstHosyuTxt"]) + firstHosyuTxtI.append(di) + if dgn.get("memoTxt") and re.search(LANGREGEX, dgn["memoTxt"]): + memoTxtS.append(dgn["memoTxt"]) + memoTxtI.append(di) + if dgn.get("appMemoTxt") and re.search(LANGREGEX, dgn["appMemoTxt"]): + appMemoTxtS.append(dgn["appMemoTxt"]) + appMemoTxtI.append(di) + if dgn.get("areaMemo") and re.search(LANGREGEX, dgn["areaMemo"]): + areaMemoS.append(dgn["areaMemo"]) + areaMemoI.append(di) + + # Dungeon long text fields (strip line breaks for translation) + if dgn.get("naiyoTxt") and re.search(LANGREGEX, dgn["naiyoTxt"]): + naiyoTxtS.append(dgn["naiyoTxt"].replace("\r\n", " ").replace("\n", " ").strip()) + naiyoTxtI.append(di) + if dgn.get("naiyoTxtEx") and re.search(LANGREGEX, dgn["naiyoTxtEx"]): + naiyoTxtExS.append(dgn["naiyoTxtEx"].replace("\r\n", " ").replace("\n", " ").strip()) + naiyoTxtExI.append(di) + if dgn.get("johoTxt") and re.search(LANGREGEX, dgn["johoTxt"]): + johoTxtS.append(dgn["johoTxt"].replace("\r\n", " ").replace("\n", " ").strip()) + johoTxtI.append(di) + if dgn.get("johoTxtEx") and re.search(LANGREGEX, dgn["johoTxtEx"]): + johoTxtExS.append(dgn["johoTxtEx"].replace("\r\n", " ").replace("\n", " ").strip()) + johoTxtExI.append(di) + + # Floor names + if "kaisoDatas" in dgn and isinstance(dgn["kaisoDatas"], list): + for ki, kaiso in enumerate(dgn["kaisoDatas"]): + if isinstance(kaiso, dict) and kaiso.get("kaisoName") and re.search(LANGREGEX, kaiso["kaisoName"]): + kaisoNameS.append(kaiso["kaisoName"]) + kaisoNameI.append((di, ki)) + + # Dialogue from talkDatas and talkDatasEx + for talkKey in ["talkDatas", "talkDatasEx"]: + if talkKey in dgn and isinstance(dgn[talkKey], list): + for ti, talk in enumerate(dgn[talkKey]): + if not isinstance(talk, dict): + continue + if talk.get("name") and re.search(LANGREGEX, talk["name"]): + talkNameS.append(talk["name"]) + talkNameI.append((di, talkKey, ti)) + if "speachDatas" in talk and isinstance(talk["speachDatas"], list): + for si, speech in enumerate(talk["speachDatas"]): + if not isinstance(speech, dict): + continue + if speech.get("name") and re.search(LANGREGEX, speech["name"]): + speakerNameS.append(speech["name"]) + speakerNameI.append((di, talkKey, ti, si)) + if speech.get("text") and re.search(LANGREGEX, speech["text"]): + dialogueS.append(speech["text"].replace("\r\n", " ").replace("\n", " ").strip()) + dialogueI.append((di, talkKey, ti, si)) + + # Choice events (sijiDatas) + if "sijiDatas" in dgn and isinstance(dgn["sijiDatas"], list): + for si, siji in enumerate(dgn["sijiDatas"]): + if not isinstance(siji, dict): + continue + if siji.get("name") and re.search(LANGREGEX, siji["name"]): + sijiNameS.append(siji["name"]) + sijiNameI.append((di, si)) + if siji.get("choiceSijiTxt") and re.search(LANGREGEX, siji["choiceSijiTxt"]): + sijiChoiceS.append(siji["choiceSijiTxt"].replace("\r\n", " ").replace("\n", " ").strip()) + sijiChoiceI.append((di, si)) + + # Set progress bar total + totalItems = ( + len(dgnNameS) + len(clearTxtS) + len(hosyuTxtS) + len(firstHosyuTxtS) + + len(memoTxtS) + len(appMemoTxtS) + len(areaMemoS) + + len(naiyoTxtS) + len(naiyoTxtExS) + len(johoTxtS) + len(johoTxtExS) + + len(kaisoNameS) + + len(talkNameS) + len(speakerNameS) + len(dialogueS) + + len(sijiNameS) + len(sijiChoiceS) + ) + PBAR.total = totalItems + PBAR.refresh() + + # ================================================================ + # PASS 2: Translate each batch and apply results back to data + # ================================================================ + + # -- Dungeon short fields -- + for tl, idx in zip(batchTranslate(dgnNameS, "Dungeon Name"), dgnNameI): + dgns[idx]["name"] = tl + if dgnNameS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(clearTxtS, "Clear Condition"), clearTxtI): + dgns[idx]["clearTxt"] = tl + if clearTxtS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(hosyuTxtS, "Reward Description"), hosyuTxtI): + dgns[idx]["hosyuTxt"] = tl + if hosyuTxtS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(firstHosyuTxtS, "First Clear Reward"), firstHosyuTxtI): + dgns[idx]["firstHosyuTxt"] = tl + if firstHosyuTxtS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(memoTxtS, "Memo Label"), memoTxtI): + dgns[idx]["memoTxt"] = tl + if memoTxtS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(appMemoTxtS, "App Memo"), appMemoTxtI): + dgns[idx]["appMemoTxt"] = tl + if appMemoTxtS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(areaMemoS, "Area Label"), areaMemoI): + dgns[idx]["areaMemo"] = tl + if areaMemoS: + save_progress_json(data, filename) + + # -- Dungeon long text fields (with word wrap) -- + for tl, idx in zip(batchTranslate(naiyoTxtS, "Mission Description"), naiyoTxtI): + dgns[idx]["naiyoTxt"] = dazedwrap.wrapText(tl, WIDTH) + if naiyoTxtS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(naiyoTxtExS, "Extended Mission Description"), naiyoTxtExI): + dgns[idx]["naiyoTxtEx"] = dazedwrap.wrapText(tl, WIDTH) + if naiyoTxtExS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(johoTxtS, "Info Text"), johoTxtI): + dgns[idx]["johoTxt"] = dazedwrap.wrapText(tl, WIDTH) + if johoTxtS: + save_progress_json(data, filename) + + for tl, idx in zip(batchTranslate(johoTxtExS, "Extended Info Text"), johoTxtExI): + dgns[idx]["johoTxtEx"] = dazedwrap.wrapText(tl, WIDTH) + if johoTxtExS: + save_progress_json(data, filename) + + # -- Floor names -- + for tl, (di, ki) in zip(batchTranslate(kaisoNameS, "Floor Name"), kaisoNameI): + dgns[di]["kaisoDatas"][ki]["kaisoName"] = tl + if kaisoNameS: + save_progress_json(data, filename) + + # -- Dialogue event names -- + for tl, (di, tk, ti) in zip(batchTranslate(talkNameS, "Event Label"), talkNameI): + dgns[di][tk][ti]["name"] = tl + if talkNameS: + save_progress_json(data, filename) + + # -- Speaker names -- + for tl, (di, tk, ti, si) in zip(batchTranslate(speakerNameS, "Character Name"), speakerNameI): + dgns[di][tk][ti]["speachDatas"][si]["name"] = tl + if speakerNameS: + save_progress_json(data, filename) + + # -- Dialogue text (with word wrap) -- + for tl, (di, tk, ti, si) in zip(batchTranslate(dialogueS, "Dialogue"), dialogueI): + dgns[di][tk][ti]["speachDatas"][si]["text"] = dazedwrap.wrapText(tl, WIDTH) + if dialogueS: + save_progress_json(data, filename) + + # -- Choice event names -- + for tl, (di, si) in zip(batchTranslate(sijiNameS, "Event Name"), sijiNameI): + dgns[di]["sijiDatas"][si]["name"] = tl + if sijiNameS: + save_progress_json(data, filename) + + # -- Choice text (with word wrap) -- + for tl, (di, si) in zip(batchTranslate(sijiChoiceS, "Choice Event Text"), sijiChoiceI): + dgns[di]["sijiDatas"][si]["choiceSijiTxt"] = dazedwrap.wrapText(tl, WIDTH) + if sijiChoiceS: + save_progress_json(data, filename) + + return tokens + + def translateJSON(data, filename, translatedList): global LOCK, ESTIMATE, FILENAME, PBAR, MISMATCH if translatedList: diff --git a/modules/rpgmakermvmz.py b/modules/rpgmakermvmz.py index 3396c70..feef24f 100644 --- a/modules/rpgmakermvmz.py +++ b/modules/rpgmakermvmz.py @@ -2543,13 +2543,14 @@ def searchCodes(page, pbar, jobList, filename): # "gameVariables.setValue": (r'\$gameVariables\.setValue\(\d+,\s*"([^"]*)"\)', False), # "BattleManager._logWindow.push('addText'": (r"BattleManager._logWindow.push\('addText',\s'(.+)'\)", False), # "BattleManager._logWindow.addText": (r"BattleManager._logWindow.addText\('(.+)'\)", False), - "this.BLogAdd": (r'this\.BLogAdd\(.+?\\?"(.+?)\\?"\)', False), + # "this.BLogAdd": (r'this\.BLogAdd\?(.+?\\?"(.+?)\\?"\)', False), # "Fuki_Set": (r'Fuki_Set\([\s,\d\w\W]+?"(.+?)",', False), # "_EventSetting": (r'_EventSetting[\s,\d\w\W]+?"(.+?)";', False), # "this.Menu_SexTxtSet(": (r'"(.+)"', True), # "Rn_RsltTxtArr": (r'"(.+)"', True), # "_章切り替えStart": (r'_章切り替えStart\(\s*\\?"(.+?)\\?"', False), # "MobNameSet": (r'MobNameSet\(\\?"(.+?)\\?"\)', False), + "AddAddress": (r'AddAddress\(\d+,\s*\\?"(.+?)\\?"', False), } @@ -2621,6 +2622,236 @@ def searchCodes(page, pbar, jobList, filename): codeList[i]["parameters"][0] = jaString.replace(match.group(1), translatedText) break + # AddCmnt handler - extract strings from array and name parameter + if "AddCmnt(" in jaString: + arrayMatch = re.search(r'AddCmnt\s*\(\s*\[(.+?)\]', jaString) + if arrayMatch: + arrayContent = arrayMatch.group(1) + strings = re.findall(r'\\?"(.+?)\\?"', arrayContent) + + # Also grab the name argument after the array: , "name") + nameMatch = re.search(r'AddCmnt\s*\(\s*\[.+?\]\s*,\s*\\?"(.+?)\\?"\s*\)', jaString) + + translatable = [] + for s in strings: + if not re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]', s): + continue + if IGNORETLTEXT and not re.search(LANGREGEX, s): + continue + translatable.append(s) + + # Translate and cache the speaker name via getSpeaker + nameStr = None + translatedName = "" + if nameMatch: + n = nameMatch.group(1) + if re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]', n): + if not (IGNORETLTEXT and not re.search(LANGREGEX, n)): + nameStr = n + response = getSpeaker(n) + translatedName = response[0] + totalTokens[0] += response[1][0] + totalTokens[1] += response[1][1] + + if translatable or nameStr: + # Use the translated speaker name for context prefix + speakerPrefix = translatedName if translatedName else "" + + if setData: + textHistory.append('"These comments are always about Romasha or her squad"') + for s in translatable: + if speakerPrefix: + list355655.append(f"[{speakerPrefix}]: {s}") + else: + list355655.append(s) + else: + for s in translatable: + if len(list355655) > 0: + translatedText = list355655[0] + list355655.pop(0) + # Strip speaker prefix if present + translatedText = re.sub(r'^\[.*?\]\s*[|:]\s*', '', translatedText) + # Replace double quotes to avoid breaking the JSON/JS syntax + translatedText = translatedText.replace('\\"', "'") + translatedText = translatedText.replace('"', "'") + jaString = jaString.replace(s, translatedText, 1) + # Replace the speaker name directly (already translated via getSpeaker) + if nameStr and translatedName: + translatedName = translatedName.replace('\\"', "'") + translatedName = translatedName.replace('"', "'") + jaString = jaString.replace(nameStr, translatedName, 1) + codeList[i]["parameters"][0] = jaString + + # AddMaill handler - translate sender name (3rd quoted arg) and title (4th quoted arg) + # Example: this.AddMaill("M_IcoMail","liliy","リリィ","お得なクーポン配布",_MTxt,[24],193,true,504,1) + if "AddMaill(" in jaString: + # Extract all quoted strings in order + allQuoted = re.findall(r'\\?"([^"]*?)\\?"', jaString) + # args: [0]=icon, [1]=id, [2]=sender, [3]=title, ... + translatable = [] + translatableIndices = [] + for idx in [2, 3]: + if idx < len(allQuoted): + s = allQuoted[idx] + if not s.strip(): + continue + if not re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]', s): + continue + if IGNORETLTEXT and not re.search(LANGREGEX, s): + continue + translatable.append(s) + translatableIndices.append(idx) + + if translatable: + if setData: + for s in translatable: + list355655.append(s) + else: + for s in translatable: + if len(list355655) > 0: + translatedText = list355655[0] + list355655.pop(0) + translatedText = translatedText.replace('\\"', "'") + translatedText = translatedText.replace('"', "'") + jaString = jaString.replace(s, translatedText, 1) + codeList[i]["parameters"][0] = jaString + + # # AddBbs handler - translate arrays of posts/replies, username, and location + # # Example: AddBbs(["この開発したパッチを..."], "コンピューターおじいちゃん","場所:猪鹿蝶",["良きパッチが..."],"patch_npc") + # if "AddBbs(" in jaString: + # translatable = [] + + # # Extract strings from the first array (topic posts) + # # Anchor with ],\s*\\?" after ] to skip past inner brackets like \\C[3] + # firstArrayMatch = re.search(r'AddBbs\s*\(\s*\[(.+?)\]\s*,\s*\\?"', jaString) + # firstArrayStrings = [] + # if firstArrayMatch: + # firstArrayStrings = re.findall(r'\\?"([^"]+?)\\?"', firstArrayMatch.group(1)) + # for s in firstArrayStrings: + # if not re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]', s): + # continue + # if IGNORETLTEXT and not re.search(LANGREGEX, s): + # continue + # translatable.append(s) + + # # After the first array, extract: "username","location",["replies"],"picture_id" + # afterFirstArray = re.search(r'AddBbs\s*\(\s*\[.+?\]\s*,\s*(.*)\)\s*;?\s*$', jaString) + # nameStr = None + # translatedName = "" + # locationStr = None + # secondArrayStrings = [] + + # if afterFirstArray: + # rest = afterFirstArray.group(1) + + # # Username (first quoted string after the array) + # nameMatch = re.match(r'\s*\\?"([^"]+?)\\?"', rest) + # if nameMatch: + # n = nameMatch.group(1) + # if re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]', n): + # if not (IGNORETLTEXT and not re.search(LANGREGEX, n)): + # nameStr = n + # response = getSpeaker(n) + # translatedName = response[0] + # totalTokens[0] += response[1][0] + # totalTokens[1] += response[1][1] + + # # Location (second quoted string after array, before second array) + # locMatch = re.match(r'\s*\\?"[^"]*?\\?"\s*,\s*\\?"([^"]+?)\\?"', rest) + # if locMatch: + # loc = locMatch.group(1) + # if re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]', loc): + # if not (IGNORETLTEXT and not re.search(LANGREGEX, loc)): + # locationStr = loc + # translatable.append(loc) + + # # Second array (replies) + # # Anchor with ],\s*\\?" after ] to skip past inner brackets like \\C[3] + # secondArrayMatch = re.search(r',\s*\[(.+?)\]\s*,\s*\\?"', rest) + # if secondArrayMatch: + # secondArrayStrings = re.findall(r'\\?"([^"]+?)\\?"', secondArrayMatch.group(1)) + # for s in secondArrayStrings: + # if not re.search(r'[a-zA-Z一-龠ぁ-ゔァ-ヴーa-zA-Z0-9\uFF61-\uFF9F]', s): + # continue + # if IGNORETLTEXT and not re.search(LANGREGEX, s): + # continue + # translatable.append(s) + + # if translatable or nameStr: + # speakerPrefix = translatedName if translatedName else "" + + # if setData: + # for s in translatable: + # if speakerPrefix: + # list355655.append(f"[{speakerPrefix}]: {s}") + # else: + # list355655.append(s) + # else: + # for s in translatable: + # if len(list355655) > 0: + # translatedText = list355655[0] + # list355655.pop(0) + # translatedText = re.sub(r'^\[.*?\]\s*[|:]\s*', '', translatedText) + # translatedText = translatedText.replace('\\"', "'") + # translatedText = translatedText.replace('"', "'") + # jaString = jaString.replace(s, translatedText, 1) + # # Replace the username directly (already translated via getSpeaker) + # if nameStr and translatedName: + # translatedName = translatedName.replace('\\"', "'") + # translatedName = translatedName.replace('"', "'") + # jaString = jaString.replace(nameStr, translatedName, 1) + # # Normalize \\C and \\N codes to always have exactly 4 backslashes + # jaString = re.sub(r'\\+([cCnN]\[\d+\])', r'\\\\\1', jaString) + # codeList[i]["parameters"][0] = jaString + + # _MTxt handler - translates var _MTxt = "text" + "\n"; across 355 + 655 lines + # Code 355: var _MTxt = "text" + "\n"; + # Code 655: _MTxt += "text" + "\n"; + if "_MTxt" in jaString and codeList[i]["code"] == 355: + mtxtRegex = r'"(.+?)"\s*\+\s*"\\n"' + textLines = [] + textLineIndices = [] + + # Extract text from the 355 line itself + match355 = re.search(mtxtRegex, jaString) + if match355: + text = match355.group(1) + if not (IGNORETLTEXT and not re.search(LANGREGEX, text)): + textLines.append(text) + textLineIndices.append(i) + + # Extract text from subsequent 655 lines + j = i + 1 + while j < len(codeList) and codeList[j]["code"] == 655: + param = codeList[j]["parameters"][0] if codeList[j]["parameters"] else "" + if "_MTxt" in param: + textMatch = re.search(mtxtRegex, param) + if textMatch: + text = textMatch.group(1) + if not (IGNORETLTEXT and not re.search(LANGREGEX, text)): + textLines.append(text) + textLineIndices.append(j) + j += 1 + + if textLines: + if setData: + for text in textLines: + list355655.append(text) + else: + for lineIdx in textLineIndices: + if len(list355655) > 0: + translatedText = list355655[0] + list355655.pop(0) + translatedText = translatedText.replace('\\"', "'") + translatedText = translatedText.replace('"', "'") + + origParam = codeList[lineIdx]["parameters"][0] + origMatch = re.search(mtxtRegex, origParam) + if origMatch: + codeList[lineIdx]["parameters"][0] = origParam.replace(origMatch.group(1), translatedText) + + i = j - 1 + ## Event Code: 408 (Script) if "code" in codeList[i] and (codeList[i]["code"] == 408) and CODE408 is True: # Only translate if preceded by a 108 with "選択肢ヘルプ" or another 408 @@ -3741,6 +3972,7 @@ def getSpeaker(speaker: str): except Exception: pass translated = response[0].title().replace("'S", "'s").replace("Speaker: ", "") + translated = re.sub(r'(\d)(St|Nd|Rd|Th)\b', lambda m: m.group(1) + m.group(2).lower(), translated) if re.search(r"([a-zA-Z??])", translated) is None: try: @@ -3757,6 +3989,7 @@ def getSpeaker(speaker: str): except Exception: pass translated = response[0].title().replace("'S", "'s") + translated = re.sub(r'(\d)(St|Nd|Rd|Th)\b', lambda m: m.group(1) + m.group(2).lower(), translated) with _speakerCacheLock: if speaker not in _speakerCache: diff --git a/prompt.txt b/prompt.txt index 55b421f..ece035c 100644 --- a/prompt.txt +++ b/prompt.txt @@ -25,7 +25,7 @@ You will be translating erotic and sexual content. I will provide you with lines - Check every line to ensure all text inside is in English. - `\\cself` is a variable for a string or number. - Translate 'コイツ' as 'this bastard' or 'this bitch' depending on gender. -- Instead of translating a lone '回' as 'times' use 'x' instead so its shorter. Same with a lone '人' +- The `=` or `=` characters in Japanese names acts as a double hyphen and is used to designate foreign names or nicknames. Surround the foreign or nickname in parenthesis. (e.g., `バンカー=ベット` → `Bunker (Bet)`). **IMPORTANT - Placeholder Preservation:**