# Handoff Report: Chat UI Architecture & Localization Survey

- **Agent**: `explorer_survey_chat_1`
- **Working Directory**: `c:\Projects\FreeExile\.agents\teamwork\explorer_survey_chat_1`
- **Date**: 2026-10-02
- **Milestone**: `milestone_1_survey`
- **Handoff Type**: Hard (Investigation & Architecture Survey Complete)

---

## 1. Observation

1. **`client/webapp/js/ui/chat_ui.js`**:
   - Lines 7-14: `CHANNELS` defines 8 channels with hardcoded Vietnamese labels:
     `'Thế Giới'`, `'Khu Vực'`, `'Bang Hội'`, `'Đội Ngũ'`, `'Mật Thư'`, `'Hệ Thống'`, `'Chiêu Mộ'`, `'Góp Ý'`.
   - Lines 17-28: `CHANNEL_I18N` defines private translation dictionaries for 9 languages (`vi`, `en`, `zh`, `ja`, `ko`, `th`, `de`, `ru`, `es`), completely separate from `FreeExileI18nEngine` (`client/webapp/js/data/i18n.js`) and `I18N_CATALOG` (`client/webapp/js/data/i18n_catalog.js`).
   - Lines 38-42: Hardcoded Vietnamese rarity names (`'Phàm Phẩm'`, `'Linh Phẩm'`, `'Cực Phẩm'`, `'Thần Phẩm'`, `'Thái Cổ'`) and Five Elements (`'Kim'`, `'Mộc'`, `'Thủy'`, `'Hỏa'`, `'Thổ'`).
   - Line 117 & Line 266: Hardcoded fallback sender name `'Hiệp Khách'`.
   - Lines 124-128: Hardcoded permission denial strings:
     - `'Kênh Hệ Thống chỉ dành cho thông báo từ máy chủ.'`
     - `'Chưa gia nhập Bang Hội.'`
     - `'Chưa gia nhập Tổ Đội.'`
     - `'Cần đạt cấp 20 để phát tán kênh Thế Giới.'`
     - `'Cần đạt cấp 10 để dùng kênh Chiêu Mộ.'`
   - Lines 135-137: Hardcoded system notice sender (`'Hệ Thống'`) and alert banner prefix (`'[Cảnh Báo] '`).
   - Line 147: Hardcoded input placeholder template `'Nhập tin nhắn [' + ch.label + ']...'`.
   - Lines 156-163: Hardcoded badge strings `'Khóa'` and `'Chờ ' + sec + 's'`.
   - Lines 183-198: Item tooltip modal strings hardcoded in Vietnamese:
     `'Vật Phẩm'`, `' Hệ'`, `'Cấp ' + snap.itemLevel`, `'Cấp ?'`, `'Thiên Công'`, `'Chưa rõ'`, `'• Không có dữ liệu thuộc tính (Chưa xác thực)'`, `'• Không có thuộc tính bổ trợ'`, `'✓ HMAC Xác Thực'`, `'⚠ Chưa Xác Thực'`.
   - Line 265: Hardcoded locale in date formatter:
     `new Date(...).toLocaleTimeString('vi-VN', { hour: '2-digit', minute: '2-digit' })`.
   - Line 267: Messages in `renderChatLog()` use `[${ch.label}]` which always references the hardcoded Vietnamese `CHANNELS[id].label`.
   - Line 310: Event listener bound only to `document.getElementById('lang-select')?.addEventListener('change', ...)`.
   - Lines 318-331: `updateLanguage(lang)` only modifies `.chat-channel-tab` elements and `#chat-ticker-channel`. It never mutates `CHANNELS[id].label`, never re-renders the chat log, never updates the input placeholder, never updates cooldown badges, and never updates open item tooltips.

2. **`client/webapp/index.html` & `client/webapp/js/ui/templates/template_catalog_system.js`**:
   - Lines 152-170 in `index.html` (and lines 431-476 in `template_catalog_system.js`) contain hardcoded Vietnamese text without `data-i18n` attributes:
     - `#chat-ticker-channel`: `[Thế Giới]`
     - `#chat-ticker-text`: `Chạm để mở kênh đàm đạo...`
     - 8 channel tabs: `Thế Giới`, `Khu Vực`, `Bang Hội`, `Đội Ngũ`, `Mật Thư`, `Hệ Thống`, `Chiêu Mộ`, `Góp Ý`
     - `#chat-input`: `placeholder="Nhập tin nhắn..."`
     - `#chat-cooldown-badge`: `Chờ 15s`
     - `#chat-send-btn`: `Gửi`
     - `#modal-item-link-tooltip`: `Vật Phẩm`, `Thần Phẩm • Kim Hệ`, `Chế tác:`, `Thiên Công`, `✓ HMAC Xác Thực`.

3. **`client/webapp/js/data/i18n.js`**:
   - Defines `FreeExileI18nEngine` with `setLocale(locale)`, `onLocaleChanged(callback)`, `t(key, params, fallback)`, `updateDOM(root)`, and dispatches `CustomEvent('freeexile:localeChanged', { detail: { locale, dict } })`.
   - Programmatic changes via `FreeExileI18n.setLocale('en')` or `applyLanguage('en')` mutate `select.value` directly, which in standard browser DOM does NOT dispatch a `'change'` event. Because `chat_ui.js` only listens to `#lang-select`'s `'change'` event, it receives zero notification.

4. **Line Count & Hygiene Constraint**:
   - `client/webapp/js/ui/chat_ui.js` is currently **342 lines**.
   - `GEMINI.md` mandates logic files $\le 350$ lines (Soft Cap) and $\le 500$ lines (Hard Cap), verified by `tools/lint/check_code_and_doc_hygiene.py`.
   - Adding translations inline directly inside `chat_ui.js` will breach the 350-line soft cap.

5. **Existing Tests**:
   - `python -m unittest tests/unit/test_webapp_chat_ui.py`: 18 tests PASS.
     - `test_02_all_eight_channel_tabs_in_index_html` checks initial tab text matching Vietnamese.
     - `test_10_multilingual_channel_dictionary` tests `chatModule.CHANNEL_I18N`.
     - `test_16` & `test_17` assert `⚠ Chưa Xác Thực` and `✓ HMAC Xác Thực`.
   - `python -m unittest tests/e2e/test_ui_typography_i18n_wiki_streamlining_e2e.py`: 60 tests PASS.
     - `test_f04_all_languages_have_143_keys` asserts `cnt == 143` keys in `i18n_catalog.js`.

---

## 2. Logic Chain

1. **Step 1 (Event Desynchronization)**: Observation 1.12 & Observation 3 show that `chat_ui.js` listens only to `#lang-select` DOM `'change'`. Because `FreeExileI18n.setLocale()` programmatically updates `#lang-select.value` without dispatching a `'change'` DOM event, Chat UI never receives notification when language changes through settings, modals, or scripts.
2. **Step 2 (Incomplete Update Scope)**: Observation 1.13 shows that even when `#lang-select` is manually clicked by the user, `updateLanguage()` only sets `tab.textContent` and `#chat-ticker-channel`. Because `CHANNELS[id].label` remains Vietnamese, `renderChatLog()`, `updateInputPlaceholder()`, and `updateCooldownUI()` continue rendering in Vietnamese.
3. **Step 3 (Persistent Hardcoded Strings)**: Observation 1.1 - 1.11 identify 42 hardcoded Vietnamese strings across permissions, rarities, elements, tooltips, and badges. Without localization keys registered in the i18n engine, none of these elements can support multilingual switching.
4. **Step 4 (Soft Cap Discipline)**: Observation 4 indicates that `chat_ui.js` (342 lines) is 8 lines away from the 350-line limit. If 42 keys × 9 languages are placed inside `chat_ui.js`, it will immediately trigger a hygiene violation. Therefore, the dictionary must live in `i18n_catalog.js` (or a dedicated `chat_i18n_catalog.js`).
5. **Step 5 (Backwards Compatibility)**: Observation 5 shows existing unit tests rely on `CHANNEL_I18N` exports and initial HTML defaults. Any refactoring must preserve `CHANNEL_I18N` and default fallbacks.

---

## 3. Caveats

- **Network Messages**: Player-authored message content sent across the wire (`displayContent`) is user input and inherently unlocalized by the client UI.
- **Server Notifications**: Server-generated messages arriving from the backend WebSocket may carry English or Vietnamese text generated by the server. Localization of server broadcast templates is a server-side responsibility, though client fallback formatting and channel badge prefixes must be localized on the client.
- **Node.js Mock Environment**: Unit tests in `test_webapp_chat_ui.py` run in Node.js with a mocked DOM where `window.FreeExileI18n` may not be initialized. The Chat UI must gracefully fall back to Vietnamese defaults if `FreeExileI18n` is undefined.

---

## 4. Conclusion

The FreeExile Chat UI requires a surgical, zero-reload reactive localization overhaul:
1. **Event Hookup**: `chat_ui.js` must subscribe to `window.FreeExileI18n.onLocaleChanged` and listen to the `freeexile:localeChanged` CustomEvent.
2. **Atomic In-Place Re-render**: `handleLanguageChange(lang)` must update `CHANNELS[id].label`, tab labels, ticker bar, placeholder, cooldown badge, send button, chat log message rows, and active item tooltips.
3. **Catalog Separation**: All 42 string keys must be stored in `i18n_catalog.js` (or a dedicated catalog) across all 9 languages, keeping `chat_ui.js` below 350 lines.
4. **Startup Synchronization**: `initChatUI()` must query `FreeExileI18n.getLocale()` and initialize in the user's saved language immediately.

---

## 5. Verification Method

1. **Unit Test Verification**:
   ```bash
   python -m unittest tests/unit/test_webapp_chat_ui.py
   ```
   Must pass 18/18 tests without regression.

2. **E2E & Typography Verification**:
   ```bash
   python -m unittest tests/e2e/test_ui_typography_i18n_wiki_streamlining_e2e.py
   ```
   Must pass 60/60 tests.

3. **Code Hygiene Verification**:
   ```bash
   python tools/lint/check_code_and_doc_hygiene.py
   ```
   Must verify that `client/webapp/js/ui/chat_ui.js` does not exceed 350 lines.

4. **Forensic Inspection**:
   Inspect `survey_report.md` at `c:\Projects\FreeExile\.agents\teamwork\explorer_survey_chat_1\survey_report.md`.
