107 lines
4.6 KiB
Python
107 lines
4.6 KiB
Python
|
|
import tkinter as tk
|
||
|
|
from tkinter import filedialog
|
||
|
|
import polib
|
||
|
|
import datetime
|
||
|
|
import os
|
||
|
|
import csv
|
||
|
|
|
||
|
|
def find_first_source_location(entry):
|
||
|
|
"""
|
||
|
|
POEntry 객체에서 첫 번째 SourceLocation을 찾아 반환합니다.
|
||
|
|
SourceLocation은 '#: FileOrPath' 형식의 주석(occurrence)에서 가져옵니다.
|
||
|
|
"""
|
||
|
|
# entry.occurrences는 (파일경로, 라인번호) 형태의 튜플 리스트입니다.
|
||
|
|
# 이 리스트에 값이 있는지 확인합니다.
|
||
|
|
if entry.occurrences:
|
||
|
|
# 첫 번째 occurrence 튜플의 첫 번째 요소(파일 경로)를 반환합니다.
|
||
|
|
return entry.occurrences[0][0]
|
||
|
|
|
||
|
|
return "" # occurrence 정보가 없으면 빈 문자열 반환
|
||
|
|
|
||
|
|
def extract_untranslated_to_csv():
|
||
|
|
"""
|
||
|
|
PO 파일을 선택하여 번역되지 않은 항목의 msgctxt, SourceLocation, msgid를
|
||
|
|
타임스탬프가 포함된 CSV 파일로 저장합니다.
|
||
|
|
줄바꿈 태그(\r\n)를 그대로 보존합니다.
|
||
|
|
"""
|
||
|
|
# --- 1. 파일 선택 GUI 실행 ---
|
||
|
|
root = tk.Tk()
|
||
|
|
root.withdraw() # tk의 기본 창은 숨깁니다.
|
||
|
|
|
||
|
|
print("PO 파일을 선택해주세요...")
|
||
|
|
# 파일 탐색기 창을 열어 사용자로부터 PO 파일 경로를 입력받습니다.
|
||
|
|
file_path = filedialog.askopenfilename(
|
||
|
|
title="번역을 추출할 PO 파일을 선택하세요",
|
||
|
|
filetypes=(("PO Files", "*.po"), ("All files", "*.*"))
|
||
|
|
)
|
||
|
|
|
||
|
|
if not file_path:
|
||
|
|
print("파일이 선택되지 않았습니다. 작업을 중단합니다.")
|
||
|
|
return
|
||
|
|
|
||
|
|
print(f"선택된 파일: {file_path}")
|
||
|
|
|
||
|
|
try:
|
||
|
|
# --- 2. PO 파일 로드 및 처리 ---
|
||
|
|
po = polib.pofile(file_path, encoding='utf-8')
|
||
|
|
|
||
|
|
# 번역되지 않은 항목 필터링 (msgstr이 비어있는 항목)
|
||
|
|
untranslated_entries = [entry for entry in po if not entry.msgstr.strip()]
|
||
|
|
|
||
|
|
if not untranslated_entries:
|
||
|
|
print("번역이 누락된 항목을 찾을 수 없습니다.")
|
||
|
|
return
|
||
|
|
|
||
|
|
# --- 3. 타임스탬프를 포함한 결과 CSV 파일 저장 ---
|
||
|
|
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
|
|
output_dir = os.path.dirname(file_path)
|
||
|
|
# 저장할 파일명을 .csv 확장자로 변경
|
||
|
|
output_filename = f"untranslated_{timestamp}.csv"
|
||
|
|
output_path = os.path.join(output_dir, output_filename)
|
||
|
|
|
||
|
|
# CSV 파일 쓰기 시작 (UTF-8 BOM 추가로 Excel 한글 깨짐 방지)
|
||
|
|
with open(output_path, 'w', newline='', encoding='utf-8-sig') as csvfile:
|
||
|
|
# 표준 CSV 라이터 생성 (쉼표 구분자 사용)
|
||
|
|
writer = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
|
||
|
|
|
||
|
|
# 헤더(컬럼명) 작성
|
||
|
|
writer.writerow(['msgctxt', 'SourceLocation', 'msgid'])
|
||
|
|
|
||
|
|
# 번역되지 않은 항목들을 순회하며 데이터 추출 및 저장
|
||
|
|
for entry in untranslated_entries:
|
||
|
|
# occurrence에서 SourceLocation 정보 추출
|
||
|
|
source_location = find_first_source_location(entry)
|
||
|
|
|
||
|
|
# msgid의 줄바꿈을 \r\n 문자열로 보존
|
||
|
|
# polib은 \r\n을 실제 줄바꿈로 해석하므로
|
||
|
|
# 다시 \r\n 문자열로 치환해야 함
|
||
|
|
msgid_escaped = entry.msgid
|
||
|
|
# 실제 줄바꿈을 \r\n 문자열로 치환
|
||
|
|
msgid_escaped = msgid_escaped.replace('\r\n', '\\r\\n')
|
||
|
|
msgid_escaped = msgid_escaped.replace('\n', '\\n')
|
||
|
|
msgid_escaped = msgid_escaped.replace('\r', '\\r')
|
||
|
|
|
||
|
|
# msgctxt와 msgstr에도 동일하게 적용 (필요시)
|
||
|
|
msgctxt_escaped = (entry.msgctxt or '').replace('\r\n', '\\r\\n').replace('\n', '\\n').replace('\r', '\\r')
|
||
|
|
|
||
|
|
# 요청된 3가지 컬럼의 데이터를 행으로 작성
|
||
|
|
writer.writerow([msgctxt_escaped, source_location, msgid_escaped])
|
||
|
|
|
||
|
|
print("-" * 50)
|
||
|
|
print(f"총 {len(untranslated_entries)}개의 번역되지 않은 항목을 추출했습니다.")
|
||
|
|
print(f"결과가 CSV 형식으로 다음 경로에 저장되었습니다: {output_path}")
|
||
|
|
print("-" * 50)
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"오류가 발생했습니다: {e}")
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
# --- 스크립트 실행 전 라이브러리 설치 확인 ---
|
||
|
|
try:
|
||
|
|
import polib
|
||
|
|
except ImportError:
|
||
|
|
print("스크립트 실행에 필요한 'polib' 라이브러리가 설치되지 않았습니다.")
|
||
|
|
print("터미널(cmd)에서 아래 명령어를 실행하여 설치해주세요.")
|
||
|
|
print("pip install polib")
|
||
|
|
else:
|
||
|
|
extract_untranslated_to_csv()
|