# Supporting Multiple Languages in the Web UI The firmware uses a client-side i18n approach all translations are stored in a single JavaScript dictionary embedded in the firmware. No server-side changes are needed. ## Architecture All translation logic lives in `html/i18n.js`. The file contains: - A `LANG` object with one sub-object per language (`en`, `ja`, ...) - Language auto-detection (browser language → `localStorage` override) - `t(key)` — look up a translated string - `setLang(lang)` — switch language and update the page - `applyTranslation(el)` — apply translation to one DOM element Translation keys are **flat strings** (no nesting). The English keys in `LANG.en` also serve as the fallback when a key is missing in another language. ## How to Add a New Language ### 1. Add a dictionary entry in `html/i18n.js` Append a new sub-object to the `LANG` object. Every key from `LANG.en` must be present: ```js var LANG = { en: { nav_overview: 'Overview', nav_port_config: 'Port Configuration', // ... all keys for English }, ja: { nav_overview: '概要', nav_port_config: 'ポート設定', // ... all keys for Japanese }, LANGCODE: { // ← add your language here nav_overview: '...', nav_port_config: '...', // ... translate every key }, }; ``` ### 2. Add the language to the navigation sidebar In `html/navigation.js`, add an `" ``` Replace with: ```js + "" ``` ### 3. Verify auto-detection The language detection code in `i18n.js` reads `navigator.language` and normalises it to the first two characters: ```js var browser = (navigator.language || navigator.userLanguage || 'en').substring(0, 2); return LANG[browser] ? browser : 'en'; ``` If the two-letter code matches a key in `LANG`, it will be auto-selected. No changes needed here. ## Two Translation Mechanisms ### (A) `data-i18n` attribute (declarative — for HTML) Add `data-i18n="key_name"` to any HTML element. The English text goes in the element content as a fallback: ```html

Port Configuration

Port Configuration ``` On page load, `applyTranslation()` sets: - `el.value` for `` - `el.textContent` for `