-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Replace UI text with Chinese (zh) translation #5671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
foxlesbiao
wants to merge
17
commits into
wled:main
Choose a base branch
from
foxlesbiao:chinese-translation
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
733fe56
中文翻译:完成全部22个Web UI页面
foxlesbiao f03fc56
修复 CodeRabbit 审查发现的遗漏翻译
foxlesbiao 33a41c5
Merge branch 'main' into chinese-translation
softhack007 b070009
Merge branch 'main' into chinese-translation
softhack007 d31805a
Add i18n toolchain for Web UI localization
foxlesbiao d09bc9e
Complete zh_CN translations for all JS strings flagged by softhack007
foxlesbiao 65a70c6
Fix 4 critical bugs in build.py from coderabbitai review
foxlesbiao d88b975
Remove 'value' from translatable attributes
foxlesbiao dcb442f
Fix BUILD_FLAGS parsing to handle no-space form
foxlesbiao 4c72192
Add Layer 3/4 translations: effects (216) and palettes (72)
foxlesbiao f4055d9
docs: add i18n architecture documentation
foxlesbiao e7ae442
Merge branch 'i18n-toolchain' into chinese-translation
foxlesbiao 724ae6f
refactor: keep i18n toolchain only, move translations out-of-tree
foxlesbiao 43ac198
refactor: out-of-tree translation support via PlatformIO custom_usermods
foxlesbiao 15f0f9e
revert: remove direct HTM file changes, keep i18n tools only
foxlesbiao 303ec84
feat: add diff.py for version comparison, update README with limitations
foxlesbiao 73a1c2f
feat: add self-evolving translation scripts
foxlesbiao File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| # WLED i18n Architecture | ||
|
|
||
| ## Overview | ||
|
|
||
| Two-repository architecture separating **build toolchain** (core repo) from **translation files** (community repo). | ||
|
|
||
| ``` | ||
| ┌─────────────────────────────────────────────────────────────┐ | ||
| │ Core Repo (WLED/tools/i18n/) │ | ||
| │ ├── extract.py # Extract translatable strings from HTML │ | ||
| │ ├── build.py # Apply translations at build time │ | ||
| │ └── locales/ # Locale configuration │ | ||
| └─────────────────────────────────────────────────────────────┘ | ||
| ↓ calls | ||
| ┌─────────────────────────────────────────────────────────────┐ | ||
| │ Translation Repo (WLED-translations/<locale>/) │ | ||
| │ ├── static.json # Layer 1: Static HTML (429 entries) │ | ||
| │ ├── js.json # Layer 2: JS strings (45 entries) │ | ||
| │ ├── effects.json # Layer 3: Effect names (216 entries) │ | ||
| │ ├── palettes.json # Layer 4: Palette names (72 entries) │ | ||
| │ └── metadata.json # Version, coverage, maintainer │ | ||
| └─────────────────────────────────────────────────────────────┘ | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Four-Layer Translation Architecture | ||
|
|
||
| | Layer | Content | File | Implementation | Coverage | | ||
| |-------|---------|------|----------------|----------| | ||
| | **L1** | Static HTML | `static.json` | Regex replacement in HTML text | 429 strings | | ||
| | **L2** | JS strings | `js.json` | Replace JS string literals | 45 strings | | ||
| | **L3** | Effect names | `effects.json` | C++ PROGMEM `#undef` + redefine | 216/216 (100%) | | ||
| | **L4** | Palette names | `palettes.json` | C++ PROGMEM array replacement | 72/72 (100%) | | ||
|
|
||
| --- | ||
|
|
||
| ## Build Flow | ||
|
|
||
| ### PlatformIO Configuration | ||
|
|
||
| ```ini | ||
| # platformio_override.ini | ||
| [env:esp32dev_zh_CN] | ||
| extends = env:esp32dev | ||
| custom_usermods = https://github.com/foxlesbiao/WLED-translations | ||
| build_flags = ${env:esp32dev.build_flags} -D WLED_LOCALE=zh_CN | ||
| extra_scripts = pre:tools/i18n/build.py | ||
| ``` | ||
|
|
||
| PlatformIO automatically clones the translation repo to `.pio/libdeps/`. | ||
|
|
||
| ### Build Steps | ||
|
|
||
| 1. PlatformIO clones `WLED-translations` to `.pio/libdeps/<env>/WLED-translations/` | ||
| 2. `build.py` auto-detects translations in `.pio/libdeps/` | ||
| 3. Applies L1/L2 translations via regex replacement | ||
| 4. Generates `i18n_effects.h` / `i18n_palettes.h` for L3/L4 (PROGMEM replacement) | ||
| 5. Output to `build/i18n/<locale>/` | ||
|
|
||
| --- | ||
|
|
||
| ## How Dynamic Content Works | ||
|
|
||
| The key insight: **PROGMEM replacement happens at compile time**, so JSON endpoints return translated strings automatically. | ||
|
|
||
| ``` | ||
| Browser ESP32 Firmware | ||
| │ │ | ||
| ├─ GET /json/palettes ─────────→│ PROGMEM array was replaced at compile time | ||
| │ ← {"0":"默认","1":"* 随机循环",...} ↓ | ||
| │ │ palettes.json → i18n_palettes.h | ||
| ├─ GET /json/effects ─────────→│ #undef _data_FX_MODE_STATIC | ||
| │ ← {"0":"常亮","1":"闪烁",...}│ #define _data_FX_MODE_STATIC "常亮" | ||
| ``` | ||
|
|
||
| No firmware code changes needed. The C++ PROGMEM strings are the single source of truth. | ||
|
|
||
| --- | ||
|
|
||
| ## Grammar and Word Order | ||
|
|
||
| WLED UI uses **short labels**, not full sentences: | ||
|
|
||
| | Pattern | Example | i18n Impact | | ||
| |---------|---------|-------------| | ||
| | Single word | "Brightness", "Speed" | ✅ No issue | | ||
| | Label + value | "255 segments" | ✅ Works ("255 个段") | | ||
| | Full sentences | Almost none | ✅ N/A | | ||
| | Plural forms | Not used | ✅ N/A | | ||
| | Date formats | Not used in UI | ✅ N/A | | ||
|
|
||
| The architecture **intentionally avoids** complex i18n patterns (ICU MessageFormat, plural rules) because WLED's UI doesn't need them. | ||
|
|
||
| --- | ||
|
|
||
| ## What's NOT Translated (By Design) | ||
|
|
||
| | Content | Reason | | ||
| |---------|--------| | ||
| | User-defined preset names | Belongs to user | | ||
| | Usermod settings pages | Dynamic HTML from firmware, varies by hardware | | ||
| | System info (IP, memory) | Universal data | | ||
| | Effect slider tooltips | Generated from mode data arrays | | ||
|
|
||
| --- | ||
|
|
||
| ## Repository Structure | ||
|
|
||
| ### Core repo (WLED) | ||
|
|
||
| ``` | ||
| tools/i18n/ | ||
| ├── extract.py # String extraction tool | ||
| ├── build.py # Build-time translation applicator | ||
| ├── ARCHITECTURE.md # This file | ||
| ├── README.md # Usage documentation | ||
| └── locales/ | ||
| └── en_template.json # English template for translators | ||
| ``` | ||
|
|
||
| ### Translation repo (WLED-translations) | ||
|
|
||
| ``` | ||
| <locale>/ | ||
| ├── static.json # Layer 1: Static HTML text | ||
| ├── js.json # Layer 2: JavaScript strings | ||
| ├── effects.json # Layer 3: Effect names (PROGMEM) | ||
| ├── palettes.json # Layer 4: Palette names (PROGMEM) | ||
| └── metadata.json # {"version":"1.0","coverage":"100%","maintainer":"..."} | ||
| en_template/ # English template for translators | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Adding a New Language | ||
|
|
||
| 1. Fork `WLED-translations` | ||
| 2. Copy `en_template/` to `<locale>/` | ||
| 3. Translate JSON files | ||
| 4. Submit PR to translation repo | ||
|
|
||
| No changes to WLED core needed. | ||
|
|
||
| --- | ||
|
|
||
| ## Coverage Summary (zh_CN) | ||
|
|
||
| | Layer | Content | Count | Status | | ||
| |-------|---------|-------|--------| | ||
| | L1 | Static HTML | 429 | ✅ Complete | | ||
| | L2 | JS strings | 45 | ✅ Complete | | ||
| | L3 | Effect names | 216/216 | ✅ 100% | | ||
| | L4 | Palette names | 72/72 | ✅ 100% | | ||
| | **Total** | | **762** | **100%** | | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| # WLED i18n Toolchain | ||
|
|
||
| Build-time internationalization for WLED Web UI. Translates HTML/JS strings at compile time — replaces English text, does not add to it. | ||
|
|
||
| ## How It Works | ||
|
|
||
| ``` | ||
| English HTM files (wled00/data/) | ||
| ↓ | ||
| extract.py → en_template.json | ||
| ↓ | ||
| Translator creates locale repo (WLED-translations) | ||
| ↓ | ||
| build.py → Translated HTM files | ||
| ↓ | ||
| npm run build → html_*.h / js_*.h (C headers) | ||
| ↓ | ||
| pio run → Firmware with translated UI | ||
| ``` | ||
|
|
||
| ## Quick Start (User) | ||
|
|
||
| Add to `platformio_override.ini`: | ||
|
|
||
| ```ini | ||
| [env:esp32dev_zh_CN] | ||
| extends = env:esp32dev | ||
| custom_usermods = https://github.com/foxlesbiao/WLED-translations | ||
| build_flags = ${env:esp32dev.build_flags} -D WLED_LOCALE=zh_CN | ||
| extra_scripts = pre:tools/i18n/build.py | ||
| ``` | ||
|
|
||
| Then: `pio run -e esp32dev_zh_CN` | ||
|
|
||
| PlatformIO automatically clones the translations repo to `.pio/libdeps/`. The build script finds translations there automatically. | ||
|
|
||
| ## Quick Start (Translator) | ||
|
|
||
| Translations live in a separate repo: [WLED-translations](https://github.com/foxlesbiao/WLED-translations) | ||
|
|
||
| ``` | ||
| WLED-translations/ | ||
| ├── library.json # PlatformIO dependency manifest | ||
| ├── zh_CN/ | ||
| │ ├── static.json # Layer 1: static HTML (429 entries) | ||
| │ ├── js.json # Layer 2: JS strings (716 entries) | ||
| │ ├── effects.json # Layer 3: effect names (216 entries) | ||
| │ ├── palettes.json # Layer 4: palette names (72 entries) | ||
| │ └── metadata.json | ||
| ├── de_DE/ | ||
| │ └── ... | ||
| └── en_template/ # English template (generated by extract.py) | ||
| ``` | ||
|
|
||
| ### Adding a new language | ||
|
|
||
| ```bash | ||
| # 1. Clone translations repo | ||
| git clone https://github.com/foxlesbiao/WLED-translations | ||
| cd WLED-translations | ||
|
|
||
| # 2. Generate English template (from WLED source) | ||
| python3 /path/to/WLED/tools/i18n/extract.py --stats | ||
| cp -r /path/to/WLED/tools/i18n/locales/* en_template/ | ||
|
|
||
| # 3. Create your locale | ||
| mkdir de_DE | ||
| cp en_template/*.json de_DE/ | ||
|
|
||
| # 4. Fill in "translation" fields in each JSON file | ||
| # 5. Commit and push | ||
| ``` | ||
|
|
||
| ## Quick Start (Developer) | ||
|
|
||
| ### Extract strings (generate template) | ||
|
|
||
| ```bash | ||
| python3 tools/i18n/extract.py --stats | ||
| # Output: tools/i18n/locales/en_template.json | ||
| ``` | ||
|
|
||
| ### Build translated firmware | ||
|
|
||
| ```bash | ||
| # Build translated HTM files | ||
| python3 tools/i18n/build.py --locale zh_CN \ | ||
| --translations-dir /path/to/WLED-translations/zh_CN \ | ||
| --output-dir build/i18n/zh_CN | ||
|
|
||
| # Validate translations | ||
| python3 tools/i18n/build.py --locale zh_CN --validate | ||
|
|
||
| # Build web UI headers | ||
| npm ci && npm run build | ||
|
|
||
| # Build firmware | ||
| pio run -e esp32dev | ||
| ``` | ||
|
|
||
| ### Version updates (diff) | ||
|
|
||
| When WLED releases a new version, compare templates to find changes: | ||
|
|
||
| ```bash | ||
| # Generate old and new templates | ||
| python3 tools/i18n/extract.py --stats # on old version | ||
| cp tools/i18n/locales/en_template.json en_template_old.json | ||
|
|
||
| python3 tools/i18n/extract.py --stats # on new version | ||
| cp tools/i18n/locales/en_template.json en_template_new.json | ||
|
|
||
| # Compare | ||
| python3 tools/i18n/diff.py --old en_template_old.json --new en_template_new.json | ||
| ``` | ||
|
|
||
| Output shows added/removed/modified strings. Translators update only changed entries. | ||
|
|
||
| ## Translation Search Order | ||
|
|
||
| `build.py` searches for translations in this order: | ||
|
|
||
| 1. `--translations-dir` (explicit path) | ||
| 2. `.pio/libdeps/*/WLED-translations/<locale>/` (PlatformIO out-of-tree) | ||
| 3. `tools/i18n/locales/<locale>.json` (local fallback) | ||
|
|
||
| ## Coverage | ||
|
|
||
| | Layer | Content | Method | Count | | ||
| |-------|---------|--------|-------| | ||
| | 1. Static HTML | Labels, buttons, placeholders | DOM text matching | 429 | | ||
| | 2. JS strings | `alert()`, `innerHTML`, `innerText` | Script block regex | 716 | | ||
| | 3. Effect names | FX names in `FX.cpp` | PROGMEM replacement | 216 | | ||
| | 4. Palette names | Palette names in `FX_fcn.cpp` | PROGMEM replacement | 72 | | ||
|
|
||
| ## Known Limitations | ||
|
|
||
| ### Cannot translate (technical) | ||
|
|
||
| - **Dynamic runtime text** — OTA update errors, Info page content, usermod settings, Pin Info page | ||
| - **External tools** — PixelForge add-ons (always English, downloaded on-the-fly) | ||
| - **JavaScript template literals** — strings with `${...}` interpolation | ||
| - **C++ server-side strings** — ~12 strings in `xml.cpp` need `#ifdef WLED_LOCALE_*` | ||
|
|
||
| ### Language-specific issues (acknowledged) | ||
|
|
||
| - Word order differences (e.g., "X of Y" patterns) | ||
| - Number formats (decimal point vs comma) | ||
| - Grammar rules (singular/plural, countable/uncountable) | ||
| - Date formats | ||
|
|
||
| These are known limitations. The tool handles short labels and UI fragments, not full sentences. | ||
|
|
||
| ## Layer 3/4: Effect & Palette Names | ||
|
|
||
| Effect names (216) and palette names (72) are translated via C++ PROGMEM replacement: | ||
|
|
||
| ```c | ||
| // locale_effects.h (auto-generated) | ||
| #pragma once | ||
| #ifdef WLED_LOCALE | ||
| #undef _data_FX_MODE_STATIC | ||
| static const char _data_FX_MODE_STATIC[] PROGMEM = "常亮"; | ||
| // ... | ||
| #endif | ||
| ``` | ||
|
|
||
| The `.h` files are generated in the translation repo. Users copy them to their local build. | ||
|
|
||
| ## Architecture | ||
|
|
||
| ``` | ||
| WLED (core repo) | ||
| └── tools/i18n/ | ||
| ├── extract.py # Extract strings from HTML/JS | ||
| ├── build.py # Apply translations (pre-build script) | ||
| ├── diff.py # Compare template versions | ||
| └── README.md | ||
|
|
||
| WLED-translations (community repo) | ||
| ├── zh_CN/ | ||
| │ ├── static.json # Layer 1: HTML text | ||
| │ ├── js.json # Layer 2: JS strings | ||
| │ ├── effects.json # Layer 3: effect names | ||
| │ └── palettes.json # Layer 4: palette names | ||
| └── en_template/ # English template | ||
| ``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: wled/WLED
Length of output: 95
🏁 Script executed:
Repository: wled/WLED
Length of output: 2021
🏁 Script executed:
Repository: wled/WLED
Length of output: 3680
🏁 Script executed:
Repository: wled/WLED
Length of output: 7763
🏁 Script executed:
Repository: wled/WLED
Length of output: 2113
🏁 Script executed:
Repository: wled/WLED
Length of output: 4408
🏁 Script executed:
Repository: wled/WLED
Length of output: 2443
Fix inconsistent Layer 2 JS-string entry counts in i18n documentation
tools/i18n/ARCHITECTURE.mdstates Layer 2js.jsonhas 45 entries.tools/i18n/README.mdstates Layer 2js.jsonhas 716 entries.tools/i18n/locales/en_template.json) contains 43 uniquejs:*keys.Update both docs to the same count (or explicitly document the counting method if
716comes from a different metric/source).🤖 Prompt for AI Agents