diff --git a/doc/support-multi-language.md b/doc/support-multi-language.md
index e5c53826..169758a4 100644
--- a/doc/support-multi-language.md
+++ b/doc/support-multi-language.md
@@ -1,135 +1,107 @@
# 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.
+The firmware uses a client-side i18n approach: all translations are stored
+in one JavaScript dictionary embedded in the firmware. No server-side
+changes are needed.
## Architecture
-All translation logic lives in `html/i18n.js`. The file contains:
+All translation logic lives at the top of `html/app.js`:
-- 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
+- A `LANG` object with one sub-object per language (`en`, `ja`, `zh`)
+- Language auto-detection (browser language, overridden by the
+ `rtl_lang` key in `localStorage`, which the language selector in the
+ page header writes)
+- `t(key, vars)` looks up a translated string; `{name}` placeholders in
+ the string are replaced from `vars`, e.g. `t("v_del_q", {n: vid})`
+- `i18nApply()` applies the dictionary to the static markup once at load
-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.
+Translation keys are flat strings. The English entry is the fallback when
+a key is missing in another language, and the key itself is the fallback
+when it is missing everywhere.
+
+Changing the language stores the choice and reloads the page, so every
+dynamically built table is rebuilt in the new language.
+
+`login.html` is served before authentication and does not load `app.js`;
+it carries its own five strings per language in an inline table.
## How to Add a New Language
-### 1. Add a dictionary entry in `html/i18n.js`
+### 1. Add a dictionary entry in `html/app.js`
-Append a new sub-object to the `LANG` object. Every key from `LANG.en` must be present:
+Append a sub-object to `LANG`. Every key from `LANG.en` should 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
- },
+var LANG={
+en:{
+nav_dash:"Dashboard",
+...
+},
+LANGCODE:{ // add your language here
+nav_dash:"...",
+...
+}
};
```
-### 2. Add the language to the navigation sidebar
+### 2. Add the language to the selector in `html/index.html`
-In `html/navigation.js`, add an `"
+```html
+
```
-Replace with:
+### 3. Add the login strings in `html/login.html`
-```js
-+ ""
-```
+The inline table there holds, per language: page title, subtitle,
+password label, button label, wrong-password message.
-### 3. Verify auto-detection
+### 4. 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.
+The detection normalises `navigator.language` to its first two
+characters and selects that language if `LANG` has it, otherwise English.
## 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:
+### (A) `data-i18n` attributes (declarative, for HTML)
```html
-
Port Configuration
-
-
-Port Configuration
+
Port configuration
+
+
```
-On page load, `applyTranslation()` sets:
+- `data-i18n` sets the element's text content
+- `data-i18n-t` sets the `title` attribute (tooltip)
+- `data-i18n-p` sets the `placeholder` attribute
-- `el.value` for ``
-- `el.textContent` for `