이중 언어 읽기 (Bilingual Reading)
개요
영어 기술 PDF를 문단 단위 영한 대역 오프라인 HTML 읽기 버전으로 만듭니다: 각 장은 자체 포함된 HTML(UTF-8, 이미지 base64 내장, 단일 파일로 오프라인 열기 가능), 왼쪽 고정 접이식 목차, 오른쪽 하단 🌐 플로팅 버튼으로 '영문만 / 한국어만 / 영한 대역'을 순환 전환하며, 페이지 이동 후에도 유지됩니다.
트리거 및 입력
- 입력: 영문 PDF (로컬 경로 또는 URL, 먼저 로컬에 다운로드).
- 출력:
index.html+ 머리말/맺음말 페이지 +chapter-NN.html(한 장 하나의 파일), 최종적으로 zip 패키지로 전달. - PDF에 책갈피(
get_toc())가 있으면, 장 구조는 책갈피를 기준으로 먼저 사용자와 확인하고, 사용자가 "분할하지 않음"을 확인한 후에 일괄 제작합니다.
핵심 규칙 (위반 불가)
- 원문 문단별 전체 번역, 요약/병합하지 않음.
- 한 장 하나의 파일, 장을 나누지 않음; 장 내에서는 원서 페이지 순서대로 문단별로 배치.
- 코드 블록(
<pre><code>)은 영어 원문 유지, 번역하지 않음; 중괄호가 포함된 코드는 f-string에 작성하지 않음. - 한국어 문단은 연한 파란색 배경 + 왼쪽 4px 컬러 바로 영문 문단과 구분; 목록 항목의 한국어도 동일한 형식.
- 이미지는 압축 후 base64로 내장; 원서 한 페이지를 모두 번역한 후, 별도의 행에 페이지 표시(
page_mark(pdf_page))를 추가하여 원본 PDF 페이지 번호를 표시. - 파일 이름은 소문자 하이픈 사용 (
chapter-01.html,front-matter.html). - 목차 항목은 책갈피 레벨(l2/l3)에 따라 생성; 이전/다음 장 링크 연결, 첫/마지막 장은 비활성화 처리.
작업 흐름 개요
① 페이지 범위 결정 → ② 텍스트 추출 → ③ 이미지 추출 → ④ 이미지 압축 후 base64 변환
→ ⑤ 원문 읽고 번역 → ⑥ build_chN.py 작성 → ⑦ 중괄호 보완 → ⑧ 실행하여 생성
→ ⑨ 탐색 연결 → 검증 → 전달
먼저 샘플 장(보통 ch1)을 만들어 사용자가 스타일을 승인하도록 하고, 승인 후 book_theme.py를 정착/재사용하여 연속 일괄 제작하며 중간에 추가 확인이 필요 없습니다. 머리말/맺음말 페이지와 index.html은 마지막에 일괄 마무리합니다.
상세 단계
① 페이지 범위 결정
입력: 전체 목차 / 장 번호. PyMuPDF로 책갈피 읽기:
import fitz
doc = fitz.open("book.pdf")
toc = doc.get_toc() # [[level, title, page_1based], ...]
1-based 페이지 번호를 PyMuPDF 0-based 범위로 변환합니다. 책갈피 페이지 번호는 실제 페이지와 종종 오프셋이 있으므로 책갈피를 기준으로 합니다; 사용자에게 장 구분을 나열하고 확인을 받은 후 작업을 시작합니다.
② 텍스트 추출
text = "".join(doc[p].get_text("text", sort=True) for p in range(start0, end0+1))
open("chN_raw.txt", "w", encoding="utf-8").write(text)
sort=True는 읽기 순서를 보장하며, 다단 혼동을 방지합니다. 각 장마다 chN_raw.txt에 원문 저장.
③ 이미지 추출
scripts/extract_assets.py 사용:
python3 extract_assets.py book.pdf <start_page_1based> <end_page_1based> --out assets
page.get_images(full=True)로 xref 기준 중복 제거 →extract_image(xref).- jpx(JPEG2000), RGBA, P 모드는 통일적으로 RGB로 변환 후 JPEG 저장 (브라우저 호환).
④ 이미지 압축 후 base64 변환
위 단계와 동시에 완료 (스크립트 내장): PIL로 열기; 너비 >800px이면 비율 유지하며 800으로 축소 (LANCZOS); JPEG q≈68로 다시 저장; base64를 assets/figN-M.txt에 기록. 단일 이미지를 30~80KB로 압축.
⑤ 원문 읽고 번역
chN_raw.txt를 분할하여 읽음 (한 번에 500~600줄), 문단별로 번역, 그림 설명 매핑 기록 (책 속 그림, 예: 까마귀 그림을 해당 텍스트 "노트"로 변환).- 코드 세그먼트는 번역 건너뜀; 표는 HTML table로 변환; 목록 형태 내용도 항목별로 번역하며 병합하지 않음.
⑥ 빌드 스크립트 작성
build_chN.py 상단에 from book_theme import P, LI, CODE, INLINE, H, img_b64, page_mark, page를 작성하고, 본문은 f-string body에 작성. f-string 내 P()/LI()는 반드시 {P(...)} 형식으로 써야 평가됨; 코드 블록은 일반 문자열 변수 CODE_X = '''...'''로 추출한 후 + CODE_X로 연결. 전체 템플릿은 scripts/book_theme.py 파일 헤더 docstring 참조.
⑦ 후처리: 중괄호 보완
python3 scripts/fix_braces.py build_chN.py
라인 순회: P('/LI('로 시작하는 줄의 시작에 {를 추가하고, 뒤에서 첫 번째로 )로 끝나는 줄의 끝에 }를 추가. img_b64(/page( 호출 줄은 처리하지 않아, 실수로 }가 끝 page() 줄에 추가되는 것을 방지.
⑧ 실행하여 생성
python3 build_chN.py # 스크립트가 파일 이름과 KB 수를 출력하면 성공
⑨ 탐색 연결
prev/next는 장 번호에 따라 채움 (ch1 prev=front-matter.html, 마지막 장 next=None), 첫/마지막 장은 disabled 자리 표시자 사용 (page() 내에서 처리됨).
마무리
- front-matter.html, closing.html (추천 도서 목록 포함/미포함은 먼저 사용자와 협의),
index.html전체 입구 (모든 장 링크). python3 -m zipfile -c bilingual_reading.zip *.html로 패키징하여 zip 전달.
분기 및 예외 처리
| 트리거 조건 | 처리 방식 |
|---|---|
| 이미지가 jpx / RGBA / P 모드인 경우 | extract_assets.py에서 통일적으로 convert하여 RGB로 변환 후 JPEG 저장 |
| f-string 내에 코드 블록 중괄호(JSON dict)가 있는 경우 | f-string에 작성하지 않음; CODE_X = '''...'''로 추출한 후 + CODE_X로 연결 |
{<P( 오기입 | sed 's/{<P(/{P(/g'로 수정 |
일괄 } 추가 시 끝 page() 줄에 실수로 추가된 경우 | fix_braces.py에서 이미 방지; 그래도 발생하면 해당 줄 끝의 불필요한 } 수동 삭제 |
| 사용자가 "효과를 먼저 보고 계속" 요청 | 샘플 장만 만들고, 피드백 기다리며 중단 |
| 사용자가 "코드는 번역하지 마세요" 요청 | 모든 <pre><code>는 영문 원문 유지 (기본값이 이미 이렇게 설정됨) |
| 추가 문제 해결 항목 | references/troubleshooting.md 참조 |
리소스 인덱스
scripts/book_theme.py— 핵심 공유 모듈: CSS/JS/페이지 스켈레톤 + P, LI, CODE, INLINE, H, img_b64, page_mark, page 함수. 스타일 변경은 여기서만 수정.scripts/extract_assets.py— 단계 ③④: 이미지 추출, 압축, base64 변환하여 assets/에 기록.scripts/fix_braces.py— 단계 ⑦: f-string 중괄호 일괄 보완.references/style-guide.md— 스타일 및 상호작용 규범 세부사항 (색상, 레이아웃, 구성 요소, 검증 대조).references/troubleshooting.md— 문제 해결 표와 재사용 가능한 경험.
검증 체크리스트
- 샘플 장 스타일이 사용자 승인 완료 (한국어 문단 연한 파란색 배경, 목록 항목 한국어 동일 형식, 페이지 표시 존재)
- 원문 문단별 전체 번역, 코드 블록 미번역, 이미지 base64 내장되어 오프라인 열기 가능
- 각 장 HTML 독립적으로 열기 가능, 목차 접이식 가능, 앵커 점프 정상 작동
- 🌐 버튼 세 가지 상태 순환, 페이지 이동 후 유지 (localStorage)
- 이전/다음 장 링크 연결 정확, 첫/마지막 장 버튼 비활성화
- 모든 파일 UTF-8, 파일 이름 소문자 하이픈, zip 패키지로 전달