이 ZIP은 Whale용 바로보기 웹 번역 0.3.0입니다.
설치: 아래 [2. Naver Whale에 설치] 절을 순서대로 따르세요. 확장 페이지 주소: whale://extensions
압축을 푼 뒤 manifest.json이 바로 보이는 폴더를 고릅니다(ZIP 파일이나 그 위 폴더가 아님).
설치 후에는 툴바 아이콘 팝업의 [도움말]에서도 같은 안내를 볼 수 있습니다(help.html, 인터넷 불필요).

# 바로보기 웹 번역(Windows Chrome·Naver Whale) 0.3.0 — 배포 전 후보

Windows의 **Chrome**과 **네이버 웨일(Whale)**에서 쓰는 독립 확장(Manifest V3)입니다. 이 확장의 핵심은
**이미지 속 글자 번역**입니다. 웹페이지 이미지 속 글자를 이 PC 안에서 인식하고 번역해, 원래 이미지 위 같은 자리에
겹쳐 그립니다. 계정·API 키·별도 EXE·로컬 서버가 없고, 번역할 글자나 이미지를 서버로 보내지 않습니다.

0.3.0의 주요 변경:

- **별도 창 없이 동작** — 0.2.0의 "번역 엔진 창"·Chrome 사이드패널이 없어졌습니다. 번역·이미지 글자 인식·번역 파일 받기는
  화면에 보이지 않는 확장 내부 문서(offscreen 문서)에서 처리합니다. Chrome·Whale 모두 같은 방식이며, 설치해도 새 창이나 탭이 열리지 않습니다.
- **Mac 바로보기와 같은 사용 방식** — 툴바 아이콘을 누르면 번역 보기로 바뀌고(이미 번역 중·번역 보기면 다시 계산하지 않음),
  팝업의 **번역**은 모든 사이트 자동 번역 켜기, **원문**은 끄고 원래 화면으로 되돌리기입니다. 그림 속 글자 번역은 항상 켜져 있습니다.
- **쉬운 번역 준비** — 처음 한 번 팝업의 **번역 준비하기**를 누르면 필요한 파일(약 640MB)을 받습니다. 팝업에
  **번역 준비 중 35%**, 진행 막대, **받은 양 224MB / 640MB**, 연결 중·파일 확인 중·마무리 중·준비됨이 보이고, 팝업을 닫아도 계속 받습니다.
  준비가 끝나면 열려 있던 팝업에서 지금 페이지를 한 번 이어서 번역합니다.
- 팝업은 번역 언어·글꼴만 기본으로 보이고, 원문 언어·그림 글자 읽기 방식·페이지 글자 번역은 **추가 설정**에 접어 두었습니다.

페이지의 일반 글자는 브라우저 자체 번역(Chrome: 마우스 오른쪽 → "한국어로 번역", Whale: 주소창의 번역 버튼)으로
번역하는 것을 권장합니다. 이 확장은 **기본값이 "이미지 전용"**이라 브라우저가 번역해 둔 페이지 글자를 덮어쓰지 않습니다.
원하면 팝업 **추가 설정**의 "페이지 글자도 이 확장으로 번역"을 켤 수 있습니다(선택).

---

## 1. Chrome에 설치

Chrome에는 **`Barobogi-Windows-Chrome-0.3.0.zip`**을 씁니다(Whale용 ZIP과 다릅니다). Chrome 116 이상.

1. 파일 탐색기에서 **다운로드** 폴더를 열고 `Barobogi-Windows-Chrome-0.3.0.zip`을 찾습니다.
2. ZIP 파일을 **마우스 오른쪽 버튼**으로 누르고 **압축 풀기(모두 압축 풀기…)**를 고른 뒤, 위치를 정하고 **압축 풀기**를 누릅니다.
   앞으로 지우지 않을 곳(예: `문서\Barobogi\Chrome`)을 권장합니다. 브라우저가 이 폴더에서 확장을 실행하므로
   폴더를 지우거나 옮기면 확장이 멈춥니다.
3. 압축을 푼 폴더를 열어 **`manifest.json` 파일이 바로 보이는 폴더**인지 확인합니다. 안쪽에 폴더가 하나 더 있고 그 안에
   `manifest.json`이 있다면 그 안쪽 폴더가 고를 폴더입니다. **ZIP 파일 자체나 그 위 폴더를 고르면 설치되지 않습니다.**
4. Chrome 주소창에 `chrome://extensions`를 입력하고 Enter.
5. 오른쪽 위 **개발자 모드** 스위치를 켭니다.
6. 왼쪽 위 **압축해제된 확장 프로그램을 로드합니다**를 누르고, 3단계의 폴더(`manifest.json`이 들어 있는 폴더)를 고릅니다.
7. 목록에 **바로보기 웹 번역** 카드가 생기고 버전이 **0.3.0**인지 확인합니다. 오류가 보이면 대개 폴더를 잘못 고른 것입니다(3단계).
8. 툴바에 고정: 주소창 오른쪽 **퍼즐 모양(확장 프로그램)** 아이콘 → 바로보기 웹 번역 옆 **압정(고정)** 아이콘.
9. 설치해도 창이 열리지 않습니다. 이어서 "3. 처음 사용(3단계)"로 갑니다.

## 2. Naver Whale에 설치

Whale에는 **`Barobogi-Windows-Whale-0.3.0.zip`**을 씁니다(Chrome용 ZIP과 다릅니다. 최소 Chrome 버전 표시만 빠져 있습니다).

1. 파일 탐색기에서 **다운로드** 폴더를 열고 `Barobogi-Windows-Whale-0.3.0.zip`을 찾습니다.
2. ZIP 파일을 **마우스 오른쪽 버튼** → **압축 풀기(모두 압축 풀기…)**. 지우지 않을 위치(예: `문서\Barobogi\Whale`)에, Chrome용과 **다른 폴더**에 풉니다.
3. 압축을 푼 폴더를 열어 **`manifest.json` 파일이 바로 보이는 폴더**인지 확인합니다(안쪽에 폴더가 하나 더 있으면 그 안쪽 폴더).
4. Whale 주소창에 `whale://extensions`를 입력하고 Enter.
5. **개발자 모드** 스위치를 켭니다.
6. **압축 해제된 확장앱 로드** 버튼(Whale 버전에 따라 이름이 조금 다를 수 있음)을 누르고 3단계의 폴더를 고릅니다.
7. 목록에 **바로보기 웹 번역**이 생기고 버전이 **0.3.0**인지 확인합니다.
8. 툴바에 아이콘이 보이지 않으면 Whale의 확장앱 버튼(또는 확장앱 관리 메뉴)에서 툴바에 표시하도록 설정합니다
   (메뉴 위치는 Whale 버전에 따라 다를 수 있습니다).
9. Chrome과 같은 방식으로 씁니다(별도 창·사이드바 없음). 이어서 "3. 처음 사용(3단계)"로 갑니다.

**Chrome과 Whale은 저장소를 공유하지 않습니다.** 두 브라우저에 모두 설치하면 번역 파일을 브라우저마다 한 번씩 받고
(총 약 1.28GB 다운로드), 디스크도 각각 씁니다.

## 3. 처음 사용(3단계)

1. 이미지가 있는 일반 웹사이트(`http://`·`https://`)에서 툴바의 **바로보기 아이콘**을 누릅니다.
2. 처음 한 번 팝업에 "번역에 필요한 파일을 처음 한 번 받아요. 약 640MB이며 이 PC에 보관해요."와 큰 **번역 준비하기** 버튼이 보입니다.
   누르고, 브라우저가 묻는 창에서 **허용**을 누릅니다. **버튼을 누르기 전에는 아무것도 받지 않습니다.**
3. 팝업에 **연결 중 → 번역 준비 중 NN% → 파일 확인 중 → 마무리 중 → 준비됨**이 진행 막대와 **받은 양 NNNMB / 640MB**로 보입니다.
   준비됨이 되면 열려 있던 팝업에서 지금 페이지를 한 번 이어서 번역합니다. 다음부터는 아이콘만 누르면 번역 보기로 바뀝니다.

- **팝업을 닫아도 받기는 계속됩니다.** 다시 열면 실제 진행을 다시 읽어 보여 줍니다. 단, 준비가 끝났을 때 팝업이 닫혀 있었거나,
  그사이 **원문**을 눌렀거나, 다른 탭·주소로 옮겼으면 자동으로 번역하지 않습니다(다른 탭을 번역하지 않음).
- 허용을 거절하면 받지 않고 "허용하지 않아 파일을 받지 않았어요. 다시 누르고 '허용'을 선택해 주세요."가 보입니다.
- 받는 중에는 **취소**, 실패하면 **다시 시도**, 중간에 멈췄으면 **이어서 준비하기**가 보입니다. 크기·해시 확인을 마친 파일은
  다시 받지 않고, 받던 도중 끊긴 파일은 처음부터 다시 받습니다(HTTP Range 이어받기는 하지 않음). 큰 파일은 287,856,370바이트·344,128,178바이트입니다.
- 네트워크에서 20초 동안 바이트가 오지 않으면 "인터넷 응답을 기다리는 중이에요"를 보이고, 60초가 되면 요청을 끊고
  "인터넷 응답이 없어 멈췄어요"로 끝냅니다(**다시 시도** 가능). 진행률을 꾸며 올리지 않으며, 모든 파일 확인과 완료 표시 저장 전에는 99%를 넘지 않습니다.
- 이전 버전(0.1.x·0.2.0)에서 같은 폴더로 업데이트했고 이미 받아 둔 파일이 있으면 다시 받지 않고 바로 **준비됨**입니다.

받는 파일(고정 리비전 URL `https://huggingface.co/Xenova/m2m100_418M/resolve/9c374f0b…/`의 이 7개만):
`onnx/encoder_model_quantized.onnx`(287,856,370바이트), `onnx/decoder_model_merged_quantized.onnx`(344,128,178바이트),
`tokenizer.json`(7,988,527바이트), `config.json`, `generation_config.json`, `tokenizer_config.json`, `special_tokens_map.json`.
다운로드 요청에는 쿠키·리퍼러·번역할 글자·이미지가 들어가지 않습니다(`credentials: "omit"`, `referrerPolicy: "no-referrer"`). 모델은 확장 ZIP에 포함하지 않습니다.
받은 파일을 지우려면 확장을 제거하세요(0.3.0 팝업에는 삭제 버튼이 없습니다).

## 4. 번역 보기와 원문

- **아이콘을 눌러 팝업을 열면** 번역 보기로 바뀝니다(토글 아님). 이미 번역 보기이거나 번역 중이면 다시 계산하지 않습니다.
  이때는 권한 창을 띄우지 않고, 아이콘을 누른 지금 탭에만 번역합니다.
- **번역** 버튼: 모든 웹사이트 접근(`<all_urls>`, 선택 권한)을 요청해 전역 자동 번역을 켭니다. 거절하면 지금 탭만 번역합니다.
- **원문** 버튼: 전역 자동 번역을 끄고, 이 확장이 바꾼 것만 원래대로 되돌립니다.
- 기본 화면: 번역 언어(한국어·영어·일본어·중국어(간체)), 번역 글꼴. **추가 설정**: 원문 언어(기본 자동), 그림 글자 읽기 방식(기본 자동),
  페이지 글자도 이 확장으로 번역(기본 끔).
- 브라우저 내부 페이지(`chrome://`, `whale://`), 확장 스토어, 새 탭·빈 페이지, 로컬 파일(`file://`)은 브라우저가 확장 접근을 막아 번역할 수 없습니다.
- 수동 번역은 누른 시점에 보이는 부분만 번역합니다. 스크롤을 따라 계속 번역하려면 **번역**으로 자동 번역을 켜세요.
- 느린 PC에서는 한 이미지에 시간이 걸릴 수 있습니다. 고정 60초에 끊지 않고 실제로 진행하는 동안 기다립니다. 번역 조각에서 2분 동안 새 토큰이
  없으면 번역 Worker를, OCR 인식 한 번이 2분을 넘기면 OCR Worker(가로·세로 모두)를 다시 만들어 대기열을 풉니다. 요청 하나의 절대 상한은 20분입니다.
- 번역 파일이 아직 준비되지 않았으면 그림 글자를 인식하지 않고 "번역 준비가 아직 안 됐어요" 안내만 보입니다(헛계산 없음).

## 5. 이미지 글자 자동 인식 — 실제 동작과 한계

**자동(기본값)** 인식은 다음 순서로 동작합니다(`extension/engine/ocr.js`).

1. **가로 다국어 패스:** Tesseract.js 7 다국어 모델 `jpn+jpn_vert+kor+chi_sim+eng`(LSTM, PSM 3 자동 배치)로 영역 전체를 읽습니다.
   Tesseract는 낱말마다 첫 언어(일본어)로 읽고 신뢰도가 낮으면 다른 언어 모델로 다시 시도합니다. `jpn` 데이터에는 하위 언어 설정
   (`tessedit_load_sublangs jpn_vert`)이 들어 있는데, 이 설정은 `jpn_vert` 파일이 같은 Worker에 있어야 동작합니다. 그래서 `jpn_vert`도 함께 실어,
   Tesseract 배치 분석이 세로 블록(`PT_VERTICAL_TEXT`)으로 본 곳은 이 패스 안에서 바로 세로 모델로 읽습니다.
   결과의 블록 종류(`blocktype`)는 버리지 않고 문단마다 함께 씁니다(값 7은 패키지 core wasm에서 직접 확인했고, `build.sh`가 빌드 때마다 다시 확인).
2. **세로 전체 스캔(항상):** 가로 패스 결과와 관계없이, 일본어 세로 모델 `jpn_vert`로 영역 전체를 **PSM 3(자동 배치)**으로 한 번 더 읽습니다.
   가로 패스가 아예 블록으로 잡지 못한 세로 열(그림·잡음으로 분류된 말풍선 등)도 여기서 찾습니다. 영역 전체를 PSM 5("세로 한 덩어리")로
   단정해 읽지 않으며, **페이지·이미지 전체에 세로 플래그를 씌우지 않습니다.**
3. **세로 정밀 인식(최대 6곳):** 실제 세로 근거가 강한 곳만 잘라 `jpn_vert` **PSM 5**로 다시 읽습니다. 근거는 Tesseract 블록 종류(세로),
   글자 상자의 위→아래 흐름, 세로로 긴 열, 그리고 **세로 열을 가로 줄로 가로질러 읽은 격자 모양**(한자·가나가 줄 간격 없이 같은 x에 정렬되고
   글자 사이가 벌어짐 — 신뢰도가 높아도 순서가 섞인 글)입니다. 근거가 강한 순으로 6곳까지만 하고, 6곳을 넘어도 큰 상자 하나로 합치지 않으며,
   정밀 인식하지 못한 곳의 전체 스캔 결과는 그대로 후보로 남습니다. 믿을 만한 가로 글이 들어 있는 곳(섞인 곳)은 PSM 5로 자르지 않습니다.
   두 Worker는 그대로 재사용하고, 사용은 한 번에 하나씩, PSM은 단계마다 다시 지정합니다.
4. **섞인 문단 나누기:** Tesseract는 다른 언어의 이웃 줄을 한 문단으로 묶을 수 있습니다. 문단을 **연속한 같은 문자 종류(한글 / 한자·가나 / 라틴)의
   줄끼리** 나누고, 한 줄 안에서도 크게 떨어지거나 길게 이어진 다른 문자 묶음은 나눕니다(문장 속 외래어 한 낱말은 나누지 않음). 한자와 가나는
   같은 일본어 계열로 묶습니다. 나눈 조각마다 **실제 낱말 상자의 합집합**을 상자로 쓰고, 원문 언어 힌트와 가로/세로를 따로 정합니다.
5. **병합·중복 제거(겹치는 쌍마다):** 가로·세로 후보가 겹치면(작은 쪽 면적의 40% 이상) 그 쌍만 비교합니다. 점수는 신뢰도에 글자 흐름
   (세로 패스가 가로 줄을 읽었으면 감점), 가로 패스가 세로 열을 읽은 모양(격자면 크게 감점), 문자 종류(세로 모델은 한글·라틴을 못 읽음)를 반영합니다.
   - 신뢰도 60 이상인 **라틴·한글 가로 글은 세로 후보가 지우지 못합니다.**
   - 진 쪽이 이긴 쪽보다 훨씬 크면 통째로 지우지 않고 **이긴 쪽에 걸친 낱말만 뺍니다**(큰 세로 문단 하나가 옆의 좋은 가로 글을 지우지 않게).
   - 같은 패스 안의 겹치는 결과(전체 스캔과 정밀 인식, 겹치는 잘라 읽기)는 하나만 남깁니다. 같은 글을 두 번 덮어 그리지 않습니다.
   - 가로 패스가 글자를 보지 못한 곳의 세로 단독 결과는 **신뢰도 55 이상, 글자 2개 이상, 한자·가나 80% 이상, 실제 세로 근거**가 모두 있을 때만 남깁니다.
6. **조각별 가로/세로(`v`)**는 실제 글자 배치에서 정합니다. 흐름을 알 수 없는 세로 패스 결과를 무조건 세로로 두지 않습니다
   (수동 "일본어 세로쓰기만"을 직접 고른 경우만 예외).
7. **조각별 원문 언어 힌트:** Tesseract는 낱말별 언어를 알려 주지 않으므로, 인식된 글자의 문자 종류로 정합니다 — 한글 위주 → 한국어,
   가나 포함 → 일본어, 라틴 위주 → 영어. 자동 OCR의 라틴 글자는 영어(`eng`) 데이터로만 읽히므로, 짧거나 OCR 오류가 섞인 글은 그대로 영어로 두고
   라틴 글자 40자 이상일 때만 franc-min이 다른 언어라고 판정하면 번역하지 않습니다. **가나 없는 한자만 있는 조각**은
   같은 이미지에 가나 문단이 있으면 일본어, 페이지 `lang`이 ja/zh이면 그 값을 쓰고, 근거가 없으면 힌트 없이 둡니다(8자 이상이면 franc-min
   중국어/일본어 판별, 짧으면 "판별 불가"로 남김 → 원문 언어를 직접 고르면 번역). 번역은 문단마다 이 힌트로 따로 판별합니다(전체를 일본어로 강제하지 않음).
8. Worker는 **최대 2개**(가로 다국어·일본어 세로)만 만들고 영역마다 다시 만들지 않습니다. 사용은 한 번에 하나씩 직렬화하며, 취소·정지 감시는
   두 Worker 모두에 적용됩니다. 언어 데이터 초기화가 실패하거나 90초 동안 진행이 없으면 그 준비를 실패로 끝냅니다(멈춘 채 기다리지 않음).
   - 인식 한 번이 2분을 넘기면 그 이미지는 "실패/중단"으로 경고하고 두 Worker를 다시 만들며, **다음 이미지는 계속 처리합니다**(사용자 취소로 오인하지 않음).
   - 인식 오류가 난 Worker는 그 슬롯만 끝내고 다음 요청 때 새로 준비합니다(망가진 Worker를 다시 쓰지 않음).
   - **세로 단계(준비·전체 스캔·정밀 인식)가 실패하거나 멈추면** 이미 읽은 가로 결과와 그때까지 읽은 세로 결과는 그대로 표시하고,
     페이지 상태에 "세로쓰기 인식 단계가 실패… 세로 글이 빠졌을 수 있습니다" 경고를 보입니다. 사용자가 취소한 경우에만 결과를 모두 버립니다.
9. 글자 상자는 Tesseract가 실제로 준 **글자(symbol) 상자**를 씁니다(문단당 128개 초과면 낱말 상자). 작은 영역은 최대 2배로 키워 인식합니다.

**수동 항목**(어려운 이미지용, 선택): 일본어 세로쓰기만(`jpn_vert`, PSM 5), 일본어 가로쓰기만, 영어만, 중국어 간체만, 한국어만.
수동 항목은 그 언어 하나로만 읽고, 그 언어를 원문 언어 힌트로 씁니다.

한계(확인하지 못한 것 포함):

- **인식 품질은 실제 이미지로 검증하지 않았습니다.** 다국어 모델은 단일 언어 모델보다 느리고, 언어가 섞인 짧은 낱말에서 언어를 잘못 고를 수 있습니다.
- 세로 인식 데이터는 **일본어용(`jpn_vert`)뿐**이라 중국어·한국어 세로쓰기는 잘 읽지 못할 수 있습니다.
- 중국어는 **간체(`chi_sim`) 데이터만** 있습니다. 번체 글자 인식은 보장하지 않으며(일부 공통 한자는 읽힘), 번역 모델도 중국어를 하나의 `zh`로 다룹니다.
- 세로 전체 스캔(PSM 3)도 배치 분석이 글자로 보지 못한 열(그림과 겹친 글, 아주 작은 글, 장식 글꼴)은 놓칠 수 있습니다. 세로 근거가 강한 곳이
  6곳을 넘으면 나머지는 정밀 인식 없이 전체 스캔 결과만 씁니다. 이런 이미지는 수동 "일본어 세로쓰기만"이 나을 수 있습니다.
- 가로·세로가 아주 가깝게 붙어 있으면(겹침 40% 미만으로 일부만 겹침) 두 결과가 조금 겹쳐 그려지거나, 반대로 낱말 단위로 잘린 조각이 남을 수 있습니다.
- 세로 단계가 매 이미지마다 두 번 이상 더 돌므로 자동 인식은 0.2.0 이전 방식보다 느립니다.
- Tesseract 상자는 Mac 버전(Apple Vision)보다 거칠어 원문 가림과 글자 크기 추정이 덜 정확할 수 있습니다. 원문 가림은 단색 덮개입니다.

## 6. 새 버전으로 업데이트(받은 파일·설정 유지)

1. 새 버전 ZIP을 받아 압축을 풉니다.
2. **기존 확장 폴더(처음 설치 때 고른 폴더)의 내용**을 새 파일로 바꿉니다(그 폴더 안 파일을 지우고 새 파일을 복사). **폴더 위치·이름은 그대로** 둡니다.
3. `chrome://extensions`(Whale은 `whale://extensions`)에서 바로보기 웹 번역 카드의 **새로고침(↻)**을 누릅니다.
4. 카드의 버전이 0.3.0으로 바뀌었는지 확인합니다. 0.2.0에서 쓰던 번역 엔진 창이 열려 있었다면 닫으세요(0.3.0은 쓰지 않음).

- **확장을 "삭제"하지 마세요.** 삭제하면 이 확장의 저장소(번역 파일 약 640MB·설정)도 지워집니다.
- 다른 폴더를 새로 "압축해제된 확장 프로그램"으로 로드하면 브라우저가 별개의 확장(다른 확장 ID)으로 취급해 다시 받아야 합니다.
- 모델 캐시 이름(`barobogi-m2m100-418m-9c374f0b`)과 고정 리비전은 0.1.0·0.2.0과 같아 0.3.0에서 그대로 재사용됩니다.
- 0.2.0 → 0.3.0 설정 변화: 그림 속 글자 번역은 항상 켜집니다(예전에 꺼 두었어도 켜짐). 번역 언어 "중국어(번체)"는 공통 로컬 모델이 지원하지 않아
  없어졌고, 골라 두었다면 한국어로 돌아갑니다. "브라우저 내장 번역 우선" 설정은 쓰지 않습니다(자동 준비 없음, 공통 로컬 번역이 기본).

**0.1.x → 0.2.0 설정 이전(한 번만, 삭제 없음, 0.3.0에도 그대로):** 0.1.x는 이미지 글자 언어 기본값이 "일본어(가로쓰기)"(`jpn`)였고, 누가 정한 값인지 표시가 없었습니다.

- 저장된 값이 없으면(기본값을 쓰던 경우) 새 기본값 **자동**이 적용됩니다.
- 저장된 값이 `jpn`이면 한 번만 **자동**으로 바꿉니다. 0.1.x 화면에는 자동 항목이 없었고 `jpn`이 첫 기본 항목이었으며, 자동이 일본어 가로를 포함하기 때문입니다.
  일본어 가로만 쓰고 싶으면 다시 고르면 되고, 그 뒤로는 바꾸지 않습니다(0.2.0부터는 사용자가 고르면 `ocrLangOrigin: "user"`를 함께 저장).
- `jpn_vert`·`eng`·`chi_sim`·`kor`는 사용자가 일부러 고른 값이므로 그대로 둡니다. 다른 설정과 모델 캐시는 건드리지 않습니다.

## 7. 문제 해결(팝업에 보이는 말별)

| 보이는 말 | 뜻과 할 일 |
|---|---|
| "허용하지 않아 파일을 받지 않았어요" | **번역 준비하기**를 다시 누르고 브라우저 창에서 **허용**. 번역 파일 주소(`huggingface.co`, `*.hf.co`)에서 받을 때만 씁니다. |
| "인터넷 응답을 기다리는 중이에요" / "인터넷 응답이 없어 멈췄어요" | 실제로 바이트가 오지 않습니다. 인터넷·방화벽·프록시를 확인하고 **다시 시도**. |
| "파일을 받지 못했어요" | 서버 거절(HTTP 오류)·연결 끊김·크기/해시 불일치 등입니다. 불일치한 파일은 저장하지 않고 지웠습니다. **다시 시도**하면 나머지만 받습니다. |
| "저장 공간이 부족해요" | 브라우저 프로필 드라이브(보통 C:)에 1GB 이상 확보 후 다시 시도. |
| "준비가 중간에 멈췄어요" | 브라우저를 닫는 등으로 받기가 끊겼습니다. **이어서 준비하기**. |
| 팝업 "업데이트 필요" / "이 브라우저 버전에서는 바로보기를 쓸 수 없어요" | offscreen 문서를 지원하지 않는 오래된 브라우저입니다. 최신 버전으로 업데이트하세요(보이는 창으로 대신하지 않음). |
| 팝업 "연결 안 됨" | 확장 내부 문서가 응답하지 않았습니다. 팝업이 2초마다 다시 확인하며, 응답하지 않는 문서는 닫고 다음 요청 때 새로 만듭니다. 계속되면 브라우저를 다시 시작하세요. |
| "번역 준비가 아직 안 됐어요" | 툴바 아이콘 → **번역 준비하기**. |
| "번역 준비 파일을 열지 못했어요" | 메모리 부족 등입니다. 다른 프로그램을 닫고 다시 번역하세요. |
| "원문 언어를 판별하지 못한 문장은 번역하지 않았습니다" | 한자만 있는 짧은 문구 등 근거 부족. **추가 설정 → 원문 언어**를 직접 고르세요. |
| "일부 그림의 글자를 읽지 못했거나 2분을 넘겨 멈췄어요" | 다음 요청 때 인식기를 새로 준비합니다. 다시 **번역**. |
| "세로쓰기 인식 단계가 실패하거나 멈춰, 가로 인식 결과…만 표시했습니다" | 가로 결과는 정상 표시된 것입니다. 다시 **번역**하면 세로 인식기를 새로 준비합니다. |
| "이 페이지는 번역할 수 없어요" | 브라우저 내부 페이지·스토어·새 탭 등. 일반 웹사이트에서 사용하세요. |

## 동작 방식(채택한 구성)

| 부분 | 구성 | 비고 |
|---|---|---|
| 번역(기본, 두 브라우저 공통) | **M2M100 418M**(Meta, 2020, MIT) ONNX q8 양자화본 `Xenova/m2m100_418M`, 리비전 `9c374f0b7aca709787cea97b047bfbbd1559d177` 고정 | Transformers.js 3.8.1 + ONNX Runtime Web(WASM, CPU **단일 스레드**)을 패키지에 포함. 전용 Worker에서 실행 |
| 원문 언어 자동 감지 | 문단별 유니코드 문자 종류(한글·가나·한자·라틴) + **franc-min 6.2.0**(MIT, 패키지 포함) + 같은 이미지의 가나·페이지 `lang` 힌트 | 근거가 부족하면 "판별 불가"로 남기고 번역하지 않음(원문 언어를 직접 고를 수 있음) |
| 이미지 글자 인식 | **Tesseract.js 7.0.0**(WASM) + 패키지 포함 언어 데이터 `eng`·`kor`·`jpn`·`chi_sim`·`jpn_vert` | 기본 **자동**: 다국어 가로 패스(`jpn_vert` 하위 언어 포함) + 세로 전체 스캔(PSM 3) + 세로 정밀 인식(PSM 5, 최대 6곳) + 문자 종류별 나누기 + 쌍별 병합(위 5절). 수동 단일 언어 항목 선택 가능 |
| 엔진 문서 | `engine.html` — **offscreen 문서**(화면에 보이지 않음, 프로필당 하나, Chrome·Whale 공통) | 배경 서비스 워커가 번역·OCR·상태·준비 요청 직전에 `runtime.getContexts`로 정확한 문서 주소를 확인하고 없으면 `offscreen.createDocument`(reasons: `WORKERS`, `BLOBS`)로 만듦. 동시 생성은 하나로 묶음. 포트는 그 문서의 `documentId`가 맞을 때만 받음. offscreen 문서는 `chrome.runtime`만 쓰고, 설정·탭·권한·저장소는 배경이 맡음(진행 표시 `modelDownloadSession` 키 하나만 정해진 모양으로 중계). 지원하지 않는 브라우저는 업데이트 안내(보이는 창 대체 없음) |

Whale 공식 문서(https://developers.whale.naver.com/api/)는 `whale.offscreen`이 Chrome과 차이 없이 지원되고 `chrome.*` 별칭을 쓸 수 있다고 밝히며,
Chrome 문서(https://developer.chrome.com/docs/extensions/reference/api/offscreen)는 offscreen 문서에서 `runtime` 외 확장 API(storage·tabs·permissions 등)를 쓸 수 없다고 밝힙니다.
**Whale에서의 실제 동작은 확인하지 않았습니다.**

지원 언어(번역): 한국어·영어·일본어·중국어(간체). 공통 모델은 중국어를 하나의 `zh`로 다루므로 번체 출력은 지원하지 않습니다.
Chrome 내장 Translator API 코드는 남아 있지만 0.3.0은 자동으로 준비·사용하지 않습니다.

## 개인정보와 처리 경계

- 번역·OCR은 모두 이 PC 안의 숨은 엔진 문서(전용 Worker)에서 처리합니다. 외부 번역 서버를 쓰지 않습니다(Google·DeepL 등 외부 전송 기능 없음).
- 네트워크 사용은 **처음 번역 파일 받기**뿐이며, 고정 목록의 모델 데이터 파일만 받습니다. 번역 모델 Worker는 확장 패키지 밖으로 요청을 보내지
  못하게 막혀 있고(검증된 캐시에서만 읽음), 실행 코드(JS·Worker·WASM)는 모두 패키지 안의 것만 씁니다.
- 저장하는 것: 설정값(`chrome.storage.local` — 번역/원문/OCR 언어와 "사용자가 골랐음" 표시, 페이지 글자 번역 여부, 글꼴, 자동 번역,
  설정 이전 버전 번호), 모델 파일(Cache API), 받는 중 진행 표시(`modelDownloadSession`: 단계·받은 바이트 수·시각 — 브라우저가 닫혀 멈춘 것을
  알리기 위함, 끝나면 지움). 페이지 글자·이미지·번역 결과·방문 기록은 저장하지 않습니다.
- 화면 캡처는 번역할 때 보이는 탭만, 메모리에서 잠깐 쓰고 버립니다.

## 권한

- 필수: `activeTab`, `scripting`(사용자가 누른 탭에만 번역 스크립트·캡처), `storage`(설정값), `unlimitedStorage`(약 640MB 모델이
  저장소 정리로 지워지지 않게), `offscreen`(숨은 엔진 문서). 0.2.0의 `sidePanel` 권한·`side_panel` 설정은 없어졌습니다.
- 선택(사용자가 누를 때만 요청): `<all_urls>`(팝업 **번역** — 모든 사이트 자동 번역), `https://huggingface.co/*`·`https://*.hf.co/*`(**번역 준비하기**).
  팝업을 여는 것만으로는 어떤 권한 창도 띄우지 않습니다.

## 실제 한계(확인된 사실과 확인하지 못한 것)

- **Windows 실기기 동작은 아직 확인하지 않았습니다.** 이 패키지는 macOS에서 소스·manifest·자원·문법 수준으로만 검증했습니다(테스트 러너 없음).
  Windows Chrome·Whale에서의 설치, offscreen 문서 생성·재연결, 번역 파일 받기 완료, 모델 불러오기, 자동 다국어 OCR 결과, 번역 속도, 메모리·디스크 사용량은
  실제 PC에서 확인해야 하며, 이 문서는 측정하지 않은 속도·품질 수치를 적지 않습니다. 모델 파일 크기(639,977,588바이트)만 확인된 숫자입니다.
- **번역 품질:** M2M100 418M은 2020년 공개된 비교적 작은 다국어 모델입니다. 최신 클라우드 번역기와 같은 품질을 기대할 수 없고,
  특히 구어체·만화 대사·짧은 문구에서 어색할 수 있습니다. 탐욕(greedy) 디코딩으로 번역합니다.
- **속도·메모리:** CPU 단일 스레드 WASM입니다. 자동 OCR은 다국어 가로 Worker(일본어 세로 하위 언어 포함)와 일본어 세로 Worker를 함께 두고,
  이미지마다 가로 1회 + 세로 전체 스캔 1회 + 정밀 인식 최대 6회를 하므로 단일 언어 OCR보다 메모리를 더 쓰고 느립니다(실측 전).
- **자동 OCR 정확도(일본어 가로·세로 혼합 포함)는 실제 Windows 브라우저와 실제 이미지로 검증하지 않았습니다.**
- 인식 범위는 **지금 화면에 보이는 이미지**뿐이고, 브라우저 밖 다른 프로그램 화면은 번역할 수 없습니다.
- 자동 감지: 가나 없는 짧은 한자 문구(8자 미만)는 같은 이미지의 가나·페이지 `lang` 근거가 없으면 판별하지 않습니다. 영어가 아닌 라틴 문자 언어는 번역하지 않습니다.
- 배경 서비스 워커가 쉬면 엔진 문서와의 연결이 끊깁니다. 받기·불러오기·번역 중이면 엔진 문서가 곧바로 다시 잇고, 아니면 다음 요청 때 배경이 깨워 다시 잇습니다.
  권한 확인 창 때문에 팝업이 먼저 닫혀도 모델 주소 접근이 허용되면 배경이 준비를 시작합니다(실기기 확인 전).

## 폴더 구조

```
extension/                  확장 소스(Chrome manifest). build.sh가 Whale manifest를 따로 만든다
  manifest.json
  background.js             배경 서비스 워커: 요청 검증·캡처·offscreen 엔진 문서 생성·확인·포트 검증·진행 표시 중계·설정 이전
  content.js                페이지 내용 스크립트: 이미지 후보·캡처 요청·이미지 위 번역 배치(문단별 세로쓰기)·원문 복원
  popup.html/js/css         팝업(두 브라우저 공통): 번역/원문, 번역 언어·글꼴, 추가 설정, 번역 준비(진행 막대)
  engine.html               숨은 엔진 문서(offscreen 문서 전용, 화면 없음)
  help.html, help.css       확장 안 도움말(팝업에서 열기)
  engine/page.js            엔진 문서 제어: 포트·요청 대기열·취소·정지 감시 신호·모델 준비 시작/취소·상태(runtime API만)
  engine/model-status.js    번역 준비 상태를 팝업용 짧은 말로 바꿈(실제 바이트·단계만)
  engine/model-spec.js      고정 모델 명세(리비전·파일 7개·크기·해시)
  engine/download-worker.js 모델 다운로드 Worker(단계 알림, 무활동 60초 중단, 스트리밍 SHA-256, Cache API 저장)
  engine/sha256.js          스트리밍 SHA-256
  engine/model-worker.js    번역 모델 Worker(module, Transformers.js, 네트워크 차단)
  engine/local-model.js     다운로드 상태 기계(Web Locks 소유권)·진행 표시 저장(호스트가 넘긴 저장소)·불러오기·조각 번역·정지 감시 제어
  engine/langdetect.js      원문 언어 판별(franc-min + 문자 종류 + 힌트)
  engine/translate.js       번역 라우터(로컬 모델 기본, 항목별 언어 힌트)
  engine/ocr.js             Tesseract.js 래퍼: 다국어 가로(세로 하위 언어) + 세로 전체 스캔·정밀 인식 + 문자 종류별 나누기·쌍별 병합, 배경색 표본화
  vendor/                   Transformers.js·ONNX Runtime Web·franc-min 번들과 라이선스
  ocr/                      Tesseract.js·코어·언어 데이터(eng·kor·jpn·jpn_vert·chi_sim)+라이선스
  fonts/, icons/
scripts/
  fetch-ocr-assets.sh        OCR 자원을 공식 npm에서 받음
  fetch-local-engine-assets.sh 로컬 번역 엔진 실행 파일·franc-min·라이선스를 받음(모델 가중치는 받지 않음)
  build.sh                   문법·자원·원격 코드·모델 명세·버전·offscreen 경계 검사 + Chrome/Whale ZIP(브라우저별 README.txt 포함) 생성
output/                      배포용 ZIP
```

## 빌드 방법(재현 가능)

```sh
cd Barobogi-Win
bash scripts/fetch-ocr-assets.sh            # OCR 자원(최초 1회)
bash scripts/fetch-local-engine-assets.sh   # 로컬 번역 엔진 자원(최초 1회)
bash scripts/build.sh                       # 검사 + output/Barobogi-Windows-Chrome-0.3.0.zip, Barobogi-Windows-Whale-0.3.0.zip
```

테스트 코드·러너는 두지 않았습니다. `build.sh`의 검사(문법, 참조 파일, 원격 실행 코드 없음, 모델 Worker의 로컬 WASM 경로·
단일 스레드·네트워크 차단 설정, 고정 모델 명세, 자동 OCR 언어 데이터 존재, manifest·README·도움말 버전 일치, 브라우저별 manifest 권한,
엔진 문서의 runtime 외 확장 API 사용 금지, 보이는 창·사이드패널 경로 없음)가 자동 검증의 전부입니다. 다른 버전의 기존 ZIP은 지우지 않고 같은 버전 ZIP만 다시 만듭니다.

## 라이선스가 있는 포함 자산

- 번역 모델(내려받는 데이터): facebook/m2m100_418M — MIT(원본 fairseq 저장소 LICENSE를 `vendor/licenses/m2m100-fairseq-LICENSE.txt`에 동봉). ONNX 변환본 Xenova/m2m100_418M.
- `vendor/transformers/` — @huggingface/transformers 3.8.1(Apache-2.0), 번들 안 onnxruntime-web 1.22.0-dev(MIT, 제3자 고지 동봉).
- `vendor/franc/` — franc-min 6.2.0과 의존 패키지 trigram-utils·n-gram·collapse-white-space(MIT).
- `ocr/` — Tesseract.js·tesseract.js-core(Apache-2.0), 언어 데이터(@tesseract.js-data, Apache-2.0).
- `fonts/` — 나눔고딕·나눔명조·나눔펜(OFL-1.1), 조선궁서체(조선일보 무료 배포 글꼴, 동봉 라이선스).

## 소스 참고(Mac 작업본에서 가져온 설계·코드)

- 이 Windows 빌드는 Mac 앱 0.7.69 작업 시점의 미커밋 BrowserExtension 소스(DOM/이미지 처리, 취소, 렌더러, `sampleColors`)를 참고해 이식했습니다.
  이후 Mac 쪽 변경은 따라가지 않았고, 네이티브 OCR(Apple Vision) 및 Mac과의 완전한 기능 동일성은 보장하지 않습니다.
  배포 목적지는 hanstree.com/apps/barobogi입니다(웹사이트 게시는 별도 작업).
- `BrowserExtension/shared/content.js` — DOM 글자 수집·복원, 이미지 후보 탐지, 이미지 위 번역 배치, 동적 페이지 대응, 세대(epoch) 무효화.
- `BrowserExtension/shared/background.js` — 자동 번역 세대 관리, 탭별 요청 추적·취소, 캡처 빈도 제한, 응답 검증 패턴.
- `Sources/ImageTextRecognizer.swift`(`sampleColors`) — 배경·글자색 다수결 표본화를 Canvas로 이식.
