Some dits
This commit is contained in:
parent
0f7ee78a88
commit
696ee730a6
3 changed files with 490 additions and 2 deletions
255
modules/json.py
255
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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:**
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue