한패 원제작자분.. 르낭님으로부터 연락이 드디어 닿았다!


보내주신 파일을 하나하나 뜯어보는데 경외감만이 들었다. 이걸 하셨다고?ㄷㄷ



무튼 내가 하고자 하는 것은 기존 한패 스크립트를 리메이크 스크립트로 이식하는 것.





omsg방식으로 뽑아낸 리메이크판 스크립트.






그리고 이건 오리지널 한패 완역 스크립트.







구조가 다르다. 물론 리메이크판 스크립트를 이런 구조로 뽑을 수 있지만, 막상 해보니 선택지 및 live2d관련 스크립트에 문제가 발생하게 되더라.


무튼.. 이걸 하나하나 긁어서 붙이는건 말도 안되는 행위라 판단..




1. 오리지널 한패 스크립트의 전처리.



import os
import sys

def preprocess_file_b(file_b_name):
# 파일 체크
if not os.path.isfile(file_b_name):
print(f"에러: {file_b_name} 를 찾을 수 없습니다.")
return

# 인코딩 확인
with open(file_b_name, 'r', encoding='utf-8') as file_b:
file_b_contents = file_b.readlines()

# 수정된 라인용 어레이
modified_lines = []

i = 0
while i < len(file_b_contents):
line_with_prefix = file_b_contents[i].lstrip('/').split('>>')[-1].strip()

if i + 1 < len(file_b_contents):
translated_line = file_b_contents[i + 1].lstrip('/').split('>>')[-1].strip()
else:
translated_line = ""


if '「' in line_with_prefix:
line_before_quote, line_after_quote = line_with_prefix.split('「', 1)
translated_before_quote, translated_after_quote = translated_line.split('「', 1)
if line_before_quote.strip(): # 괄호 앞 부분이 비었는지 체크 (인물 이름 없는 대사)
modified_lines.append('//' +line_before_quote)
modified_lines.append( translated_before_quote)
modified_lines.append('//「' +line_after_quote)
modified_lines.append('「' + translated_after_quote)
i += 2 # 원문, 번역문 두 줄 다 처리했으므로 한 줄 패스
elif '浩平(' in line_with_prefix:
line_before_quote, line_after_quote = line_with_prefix.split('(', 1)
translated_before_quote, translated_after_quote = translated_line.split('(', 1)
modified_lines.append('//' +line_before_quote)
modified_lines.append( translated_before_quote)
modified_lines.append('//(' +line_after_quote)
modified_lines.append('(' + translated_after_quote)
i += 2 # 원문, 번역문 두 줄 다 처리했으므로 한 줄 패스
else:
modified_lines.append('//' +line_with_prefix)
modified_lines.append(translated_line)
i += 2 # 원문, 번역문 두 줄 다 처리했으므로 한 줄 패스




# _processedB 붙여 저장
base_name, _ = os.path.splitext(file_b_name)
processed_file_b_name = f"{base_name}_processedB.txt"
with open(processed_file_b_name, 'w', encoding='utf-8') as processed_file_b:
processed_file_b.writelines(line + '\n' for line in modified_lines)

return processed_file_b_name

if __name__ == '__main__':
if len(sys.argv) != 2:
print("one 오리지널 번역문 스크립트 전처리기. 사용법: python one_process01.py originalscript.dg")
sys.exit(1)

file_b_name = sys.argv[1]
preprocess_file_b(file_b_name)





00000>>를 지워줬고,


// 00011>> 浩平「…6時…半か?」

00011>> 코헤이「…6시…반이라고?」


이렇게 한 줄로 된 대사를



//浩平

코헤이

//「…6時…半か?」

「…6시…반이라고?」



이렇게 바꿔줬다. 이래야 이후 작업이 가능해진다.




2. 스크립트 이식



1. 한패 스크립트는 원문도 반각문자로 되어 있는 반면 리메이크 원본 스크립트는 당연히 전각문자를 쓴다. 이 부분 대응 필요.


2. 인물/대사 분리


// 00680>> 浩平「…オレも帰るか」

00680>> 코헤이「…나도 가야지」


이런 일반적인 대사 말고도


// 00693>> 浩平(運動部の連中もさすがに休みか…)

00693>> 코헤이(운동부도 오늘은 쉬는 건가…)



이렇게 괄호 처리된 독백도 있다. 따라서 모든 「 뿐만 아니라 주인공 이름 뒤에 붙는( 이런 괄호도 처리해줘야 한다.


3. 인물 없는 대사 처리


인물 이름 없이 대사만 있는 라인도 있다.


// 00698>> 「…くしゅん」

00698>> 「…엣취」


4. 오리지널 한패 스크립트는 UTF-8, 리메이크 스크립트는 UTF-8-BOM이다. 인코딩 맞춰 불러오고, 맞춰서 저장되어야 함.


5. 리메이크 스크립트는 \@ 이런게 뒤에 붙어있는 경우가 있음.



import os
import sys
import codecs
import threading
import re

class TimeoutException(Exception):
pass

def normalize_line(line):
# 특수문자 처리
line = line.replace('、', ', ').replace('。', '.').replace('?', '?').replace('!', '!').replace('「', '').replace('」', '').replace('『', '').replace('』', '').replace('(', '').replace(')', '').replace(' ', '').replace(',', ', ').replace('.', '. ')
return re.sub(r'\s+', ' ', line.strip())

def transfer_lines(file_a_name, file_b_name, timeout=60):
# 파일 체크. file_a는 리메이크 스크립트, file_b는 전처리된 오리지널 한패 스크립트
if not os.path.isfile(file_a_name):
print(f"에러: {file_a_name} 를 찾을 수 없습니다.")
return
if not os.path.isfile(file_b_name):
print(f"에러: {file_b_name} 를 찾을 수 없습니다.")
return

# 타임아웃
timer = threading.Timer(timeout, raise_timeout)

try:
timer.start()

# 인코딩 적용하여 파일 열기
with codecs.open(file_a_name, 'r', encoding='utf-8-sig') as file_a, codecs.open(file_b_name, 'r', encoding='utf-8') as file_b:
file_a_contents = file_a.readlines()
file_b_contents = file_b.readlines()

# 라인 리스트 생성
modified_lines = []

# 원문-번역문 매핑 리스트 생성
translation_mapping = {}

# 전처리된 오리지널 한패 스크립트 반복처리
i = 0
while i < len(file_b_contents):
if file_b_contents[i].startswith('//'):
original_line = normalize_line(file_b_contents[i][2:].strip())
if i + 1 < len(file_b_contents):
translated_line = file_b_contents[i + 1].strip().replace(' ', '')
translation_mapping[original_line] = translated_line
i += 2
else:
i += 1
else:
i += 1

# 리메이크 스크립트 반복처리
for line_a in file_a_contents:
# 공백제거
leading_whitespace = re.match(r'^(\s*)', line_a).group(1)
# \@로 끝나는 라인 체크
ends_with_at = line_a.strip().endswith('\\@')
# 해당 라인 정규화
line_a_normalized = normalize_line(line_a.strip().rstrip('\\@'))
# 매핑 리스트에 정규화된 라인 있는지 확인
if line_a_normalized in translation_mapping:
translated_line = translation_mapping[line_a_normalized]
# 공백, \@ 및 번역문 적용
if ends_with_at:
modified_lines.append(leading_whitespace + translated_line + '\\@\n')
else:
modified_lines.append(leading_whitespace + translated_line + '\n')
else:
# 번역 매핑 못찾을 경우 원문 그대로 두기
modified_lines.append(line_a)

except TimeoutException:
print("타임아웃. 파일에 문제가 있을 수 있습니다. 전처리가 제대로 되었는지 확인이 필요합니다.")
except Exception as e:
print(f"에러: {e}")
finally:
timer.cancel()

base_name = os.path.splitext(file_a_name)[0]
processed_file_name = f"{base_name}_processed.txt"

with codecs.open(processed_file_name, 'w', encoding='utf-8-sig') as processed_file:
processed_file.writelines(modified_lines)

print(f"오리지널 한패 스크립트 {file_b_name} 내용을 반영, {processed_file_name} 로 저장하였습니다.")

def raise_timeout():
raise TimeoutException("타임아웃.")

if __name__ == '__main__':
if len(sys.argv) != 3:
print("one 오리지널 번역문 스크립트 to one 리메이크 스크립트 변환기. 오리지널 번역문 전처리가 필요합니다.")
print("사용법: python one_process02.py remake_script.txt originalscript_processedB.txt")
sys.exit(1)

file_a_name = sys.argv[1]
file_b_name = sys.argv[2]
transfer_lines(file_a_name, file_b_name)




신난다!


오리지널 스크립트 구조상 선택지까지 번역하기는 어려우므로 저정도는 직접 만지는걸로.


오리지널에서 男子学生였던 이름이 리메이크에서 男子学生A가 되는 등 소소한 차이점이 있어 검수하며 잡아가야 할 것 같다.


이로써 파일로만 118개, 만줄에 육박하는 스크립트 복붙 노가다를 하지 않아도 된다!



아 물론 이렇다고 한패가 막 금방 나오는건 아닙니다. 앞으로 무슨 문제가 생길지 모름

도와주시는 모든 분들께 무한 감사드립니다.


그럼 자러