# EllesmereUI — 현지화 스크립트 (인계 노트) · 한국어

> 영문 원문은 `LOCALIZATION_HANDOFF.md` 참고. 이 파일은 한국어 번역본입니다.

*EllesmereUI **7.9.5** 기준으로 제작·테스트했습니다.*

이 작업은 EllesmereUI에 완전한 **비침투적(non-invasive) 현지화 레이어**를 더합니다: 사용자에게 보이는 모든 문자열이 번역 가능한 키가 되어, 애드온을 **어떤 언어로든** 배포할 수 있습니다. 단일 번역이 아니라 현지화 스크립트라서, 새 언어 추가는 로케일별 값 테이블 하나만 채우면 됩니다.

**첫 번째 로케일**로 완전한 **한국어(koKR)** 번역을 포함했습니다(제가 한국인이라 작업 예시로 채웠습니다). 시스템 자체는 언어 비종속적이며, 영어(enUS)는 손대지 않은 기준이고 다른 언어도 같은 방식으로 들어갑니다.

모든 것은 하나의 데이터 파일에서 구동되고, **WoW의 `Interface\AddOns\EllesmereUI` 폴더를 찾아 패치**하는 스크립트로 적용됩니다(문자열 래핑 + 로케일 파일 설치). 유지보수와 본체 병합이 쉽습니다.

---

## 1. 현지화 동작 방식

**세 가지 구성:**

1. **`EllesmereUI/Locale/LocalCore.lua`** (가장 먼저 로드)
   전역 번역 테이블을 정의합니다. 모르는 키는 *키 자신*(영문)을 반환하므로 번역 누락이 `SetText`를 깨뜨릴 일이 없습니다.

2. **`EllesmereUI/Locale/<locale>.lua`** (로케일당 한 파일)
   키 → 값 테이블입니다.
   - `enUS.lua`가 **기준(master)**: 모든 키를 `L["x"] = "x"`로 나열, 번역자 참조용.
   - `GetLocale()`이 일치할 때만 자동 로드됩니다.

3. **소스 코드**는 표시 문자열이 `EUI_L`을 거치도록 래핑됩니다.
   **사용자에게 보이는 텍스트만** 래핑합니다. 식별자, 테이블 키, 프레임 이름, 비교(`==`/`~=`), API 인자, 텍스처/아틀라스 경로, 폰트 경로, SharedMedia 자산 이름은 로직이 바뀌지 않도록 일부러 영문으로 둡니다. 값이 표시이면서 키로도 쓰이면 *표시* 지점에서만 래핑(예: `EUI_L[bar.name]`)해 저장 식별자는 영문으로 유지합니다.

**문맥 의존 키 (같은 영단어, 모듈마다 다른 번역).**
일부 문자열은 어느 모듈이 보여주느냐에 따라 *다른* 번역이 필요합니다 — 예: **"Armor"**는 가방에서는 아이템 분류(방어구), 캐릭터 시트에서는 방어 스탯(방어도)인데 영어는 한 단어입니다. 이런 키는 `L["Armor"]`로 직접 넣지 않고 로케일에 다음처럼 등록합니다:
```lua
EUI_L_CTX["Armor"] = { ["*"] = "방어도", ["EllesmereUIBags"] = "방어구" }
```
`LocalCore`의 `__index`가 어느 애드온이 호출했는지를 (`debugstack`으로) 확인해 모듈별 값을 반환하고, 없으면 `["*"]`로 폴백합니다. **이걸 위해 원본 소스는 바뀌지 않습니다** — 가방/캐릭터 시트 코드는 이미 `EUI_L["Armor"]`를 부르고 있고, 로케일 레이어만 다릅니다(영어도 그대로). 이 몇 개 키만 스택 조회를 하고 나머지 키는 빠른 직접-테이블 경로를 유지합니다. 구분이 필요 없는 다른 언어는 `EUI_L_CTX` 항목을 그냥 생략하면 됩니다.

**`.toc`가 패치**되어 `Locale/LocalCore.lua`와 로케일 파일들이 코어 파일 직후 로드됩니다.

---

## 2. 적용 / 재생성

전체는 단일 원본에서 생성되어 스크립트로 적용됩니다:

- **`_EUI_Localize/Locale-Data.ps1`** — 단일 원본(모든 키 + 각 로케일 값 + 래핑할 소스 줄 목록).
- **`_EUI_Localize/Build-ApplyScript.ps1`** — 데이터에서 `Apply-EllesmereUI-Locale.ps1`과 로케일 파일을 생성합니다.
- **`_EUI_Localize/Apply-EllesmereUI-Locale.ps1`** — 설치기. 먼저 **WoW 설치와 `Interface\AddOns\EllesmereUI` 폴더를 찾고**(레지스트리 → 실행 중 프로세스 → 일반 설치 경로, 또는 `-AddonPath`로 지정), 그 사본을 패치합니다:
  1. `Locale/LocalCore.lua` + 로케일별 파일 생성,
  2. `.toc`에 삽입,
  3. 소스의 대상 문자열 래핑(줄 단위 정확 매칭·공백 trim, 멱등 — 반복 실행 안전; 더 이상 안 맞는 줄은 변경 없이 `NOT FOUND`로 보고).

본체 병합 시: `EUI_L` 래핑(어느 언어든 무해)과 `Locale/` 파일을 유지하고, 번역자는 로케일별 `L["키"] = "..."` 값만 수정합니다.

### 명령줄 사용
PowerShell에서 실행(자동 탐지는 위 설명대로, `-AddonPath`로 재지정):
```powershell
# 적용 (쓰기 전 확인)
.\Apply-EllesmereUI-Locale.ps1

# 확인 없이 적용
.\Apply-EllesmereUI-Locale.ps1 -Force

# 자동 탐지가 못 찾으면 설치 경로 지정
.\Apply-EllesmereUI-Locale.ps1 -AddonPath "D:\World of Warcraft\_retail_\Interface\AddOns\EllesmereUI"

# TEST / 커버리지 모드
.\Apply-EllesmereUI-Locale.ps1 -Test -Force
```

**`-Test` (커버리지 점검):** 모든 현지화 값 앞에 밝은 마젠타 **`[L]`** 태그(색 텍스트, 아이콘 없음)를 붙입니다. 인게임에서 `[L]`이 **붙은** 텍스트는 이 현지화가 처리한 것, **없는** 텍스트는 아직 raw/미래핑(또는 WoW 클라이언트 직접 출력)입니다. 무엇이 번역됐는지 확인 후 `-Test` **없이** 다시 실행해 깨끗한 빌드를 배포하세요.

> 팁: `[L]` 마커는 §3의 폰트 문제도 깔끔히 드러냅니다 — `[L]□□□`로 보이면 번역은 됐지만 폰트로 못 그리는 것, 마커 없는 영문은 애초에 래핑 안 된 것입니다.

> ⚠️ **`-Test`와 SavedVariables — 중요 주의.** EllesmereUI는 키가 아니라 *해석된 표시 문자열*을 SavedVariables에 저장합니다 — CDM 바 이름, 가방 분류명, 스탯 그룹명, 프로필/전문화 라벨 등. 즉 저장 시점에 `EUI_L[...]`이 반환한 값이 디스크에 기록됩니다. **`-Test`** 빌드가 켜진 상태에서 이것들이 저장되면 `|cffff3cff[L]|r ` 접두어가 저장 값에 박혀, **깨끗한(비-Test) 빌드로 다시 적용해도 계속 보입니다** — 오염이 애드온 파일이 아니라 *저장 데이터*에 있기 때문입니다(로케일/소스는 깨끗하게 스캔됨). EUI가 안정적 키가 아니라 번역된 표시명을 저장하는 구조 탓이라 현지화 레이어가 막을 수 없습니다.
> **해결:** `-Test`는 빠른 점검용으로만 쓰고 깨끗한 빌드를 배포·유지하세요. 저장명에 `[L]`이 남으면 **게임을 완전히 종료한 상태에서** 관련 `SavedVariables/EllesmereUI*.lua`를 지우거나 `|cffff3cff[L]|r ` 접두어를 제거하세요(클라이언트 실행 중 편집하면 로그아웃 시 덮어써집니다).

---

## 3. ⚠️ 다국어에 필수: 한 줄 폰트 수정 (원본 코드는 건드리지 않았음)

이 패키지는 한국어 번역을 포함하고 현지화 레이어는 어떤 언어든 준비돼 있습니다. 다만 일부 창은 번들된 **`Expressway.ttf`**로 텍스트를 그리는데 **CJK/키릴 글리프가 없어** 한국어가 거기서 **□ 네모(두부)**로 나옵니다.

### 영향받는 창 — 일부러 영문 유지
네모를 피하려고 이 창들은 **번역하지 않고 영문 값**으로 둡니다 — 한글을 넣으면 네모가 되기 때문입니다:

| 네모가 나오는 곳 | 무엇인지 |
|---------------------|------------|
| **첫 실행 설정 창** | 첫 로그인 시 나오는 애드온 선택 화면 |
| **전문화 지정 그리드** | 자원 및 시전 바 → 생명력/자원 바의 **검 아이콘** 팝업 → "이 전문화에 적용" |
| **색상 선택기** | "cancel" 텍스트 |
| **데미지 미터** | 잠금 모드 오버레이 라벨 |
| **"전역 글꼴" 안내** | 글꼴 및 색상 페이지의 텍스트 |

> **부작용:** 첫 실행 창은 모듈명 키를 **좌측 설정 사이드바**와 공유해서, 사이드바 이름(Action Bars, Bags, Chat, Cooldown Manager…)도 **영문**으로 보입니다. 의도된 것이며 같은 폰트 한계 탓 — 아래 폰트를 고치면 전부 번역 가능합니다.

**이 라틴 전용 폰트(`Expressway.ttf` / `EllesmereUI.EXPRESSWAY`)가 쓰이는 곳**(전체 범위 — 전수 조사). CJK 클라이언트에서 모두 네모가 되며, 그래서 위를 미번역으로 둔 것이고 아래 한 줄 수정이 전부 해결합니다:
- 슬라이더 옆 작은 괄호 **접미 라벨** — `(seconds)`, `(min)`, `(minutes)`, `(Percent)`, `(Ex: 1,5,8)`, `(Applies on Window Close)` — Nameplates / Damage Meters / Party Mode / AuraBuff Reminders / Cooldown Manager / Widgets
- 채팅·미니맵 옵션 패널의 **"Reset"** 버튼
- **"Low Durability"** 화면 경고 (QoL)
- 색상 선택기 hex/cancel 텍스트, 일부 입력칸 자리표시
- 첫 실행 창, 전문화 지정 그리드, 데미지 미터 오버레이 (위 표)

> 폰트가 라틴 전용인 동안 깔끔히 읽히도록 영문 값으로 뒀습니다. 폰트 줄을 고치면 koKR 값을 채울 수 있습니다.

**원본의 폰트 로직은 수정하지 않았습니다**(원본 유지 요청). 아래 한 줄 폰트 수정 후엔 이 창들이 CJK 폰트를 쓸 수 있고 영문 자리표시를 한글로 채울 수 있습니다.

**메커니즘은 이미 코드에 있고 — koKR도 이미 설정돼 있습니다.** `EllesmereUI.lua`(~258행)의 로케일별 폰트 폴백에 koKR이 이미 포함됩니다:
```lua
local LOCALE_FONT_FALLBACK
do
    local _locale = GetLocale()
    if _locale == "zhCN" or _locale == "zhTW" then
        LOCALE_FONT_FALLBACK = "Fonts\\ARKai_T.ttf"
    elseif _locale == "koKR" then
        LOCALE_FONT_FALLBACK = "Fonts\\2002.TTF"     -- 한글 지원, 이미 있음
    elseif _locale == "ruRU" then
        LOCALE_FONT_FALLBACK = "Fonts\\FRIZQT___CYR.TTF"
    end
end
EllesmereUI.EXPRESSWAY = LOCALE_FONT_FALLBACK or EXPRESSWAY
```
그래서 `EllesmereUI.EXPRESSWAY`는 koKR에서 `2002.TTF`로 **해석돼야** 하지만, 뒤의 한 줄이 조용히 라틴 전용 폰트로 되돌립니다:

### 근본 원인 — 한 줄이 폴백을 덮어씀
`EllesmereUI.lua` **464행**에서 올바르게 설정:
```lua
EllesmereUI.EXPRESSWAY = LOCALE_FONT_FALLBACK or EXPRESSWAY   -- koKR에선 = 2002.TTF  ✔
```
…그런데 **~2643행**에서 폴백을 버리고 재할당:
```lua
EllesmereUI.EXPRESSWAY = EXPRESSWAY      -- = Expressway.ttf (라틴 전용)  ✘  폴백을 덮어씀
```
이게 464행 뒤에 실행돼 폴백이 사라집니다. 그 값은 `EllesmereUI._font`로도 전파되어(`EllesmereUI_Widgets.lua:1548`), 위 모든 창이 라틴 전용 폰트로 → 네모가 됩니다.

### 수정 — 한 줄
~2643행이 464행과 똑같이 폴백을 존중하게:
```lua
EllesmereUI.EXPRESSWAY = LOCALE_FONT_FALLBACK or EXPRESSWAY
```
이 한 줄로 koKR에서 `2002.TTF`(및 zh*/ru 폴백)가 복원되고, `EllesmereUI._font`로 연쇄되어 **네모였던 모든 창이 한글로 렌더**됩니다 — **enUS 영향 없음**(거기선 `LOCALE_FONT_FALLBACK`이 nil → `EXPRESSWAY`).

### 로케일별 기본 폰트 (이미 `LOCALE_FONT_FALLBACK`에 매핑됨)
수정은 이 기존 테이블이 실제로 작동하게 할 뿐입니다:

| 로케일 | 사용하는 WoW 기본 폰트 | 폴백 필요? |
|--------|-----------------------|-----------------|
| **koKR** | `Fonts\2002.TTF` | 예 (없으면 네모) |
| **ruRU** | `Fonts\FRIZQT___CYR.TTF` | 예 |
| zhCN / zhTW | `Fonts\ARKai_T.ttf` | 예 |
| enUS, deDE, frFR, esES, esMX, ptBR, itIT | — (Expressway에 라틴 글리프 있음) | 아니오 |

> **왜 로케일 파일에서 안 하나?** `LocalCore.lua`에서 `EllesmereUI._font`를 설정해 봤지만, `EllesmereUI_Widgets.lua:1548`이 로케일 로드 후 `_font`를 재할당하고(색상 선택기는 로드 시 폰트를 캐시) ~2643행 소스 한 줄이 유일하게 완전·확실한 지점입니다.
>
> **임시로 제가 이 한 줄을 적용해 배포할 수 있지만**, 원본에서 고치는 게 낫습니다: 토큰 하나로 **모든** CJK/키릴 로케일이 한 번에 해결되고, 하위 번역자가 업데이트마다 재패치할 필요도 없습니다. 본체 반영을 검토해 주시겠어요?

### 폰트 문제 아님 (의도적, 영문 유지)
- **폰트 이름**(Expressway, Friz Quadrata, Poppins…)과 **텍스처 / SharedMedia 자산 이름**(Glass, Gradient, Blizzard Dialog…)은 일부러 영문으로 둡니다 — UI 문구가 아니라 자산 식별자입니다.

---

## 4. 한글 클라이언트 툴팁 파싱 (보너스 수정 포함)

업그레이드 계산기가 **영문** 툴팁 문자열 `"Upgrade Level: <Track> n/m"`에서 장비 강화 트랙을 파싱했습니다. 한글 클라이언트는 툴팁이 `"레벨 강화: <한글트랙> n/m"`이라 파싱이 실패해 징표 합계가 `0`으로 나왔습니다. `Calc:ScanItemLink`에 로케일 인식 폴백(한글 트랙명을 영문 트랙 키로 역매핑)을 추가해 koKR 클라이언트에서 징표 계산이 동작합니다. 실제 버그 수정이며 모든 로케일에 안전합니다(영문 경로를 먼저 시도).

---

## 제작자를 위한 요약 (TL;DR)
- 이건 EllesmereUI용 **현지화 스크립트**이지 단일 번역이 아닙니다 — 모든 UI 문자열을 번역 가능하게 만들고, **한국어(koKR)를 첫 예시 로케일로 포함**(제가 한국인)했으며, 다른 언어도 같은 방식으로 들어갑니다.
- 설치기가 **WoW `Interface\AddOns\EllesmereUI` 폴더를 찾아 패치**합니다. 로케일별 선택 적용이며 영문 빌드를 깨뜨릴 수 없습니다(enUS = 손대지 않은 기준).
- `EUI_L["..."]` 래핑과 `Locale/` 파일을 유지하세요; 번역자는 로케일별 값 테이블만 수정합니다.
- **`EllesmereUI.lua` ~2643행의 한 줄 폰트 수정**(`EllesmereUI.EXPRESSWAY = LOCALE_FONT_FALLBACK or EXPRESSWAY`)을 적용하면 나열된 창들이 CJK 폰트를 씁니다. 한국어 번역은 **이미 준비돼 있어** 그 폰트 줄을 고치는 순간 네모 대신 렌더됩니다. enUS는 영향받지 않습니다.
