Build-time internationalization for WLED Web UI. Translates HTML/JS strings at compile time with zero runtime overhead and zero flash overhead (replaces, not adds).
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
Add to 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.pyThen: pio run -e esp32dev_zh_CN
PlatformIO automatically clones the translations repo to .pio/libdeps/. The build script finds translations there automatically.
Translations live in a separate repo: 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 (45 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)
# 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 /path/to/WLED/tools/i18n/locales/en_template.json 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 pushpython3 tools/i18n/extract.py --stats
# Output: tools/i18n/locales/en_template.json# 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 esp32devbuild.py searches for translations in this order:
--translations-dir(explicit path).pio/libdeps/*/WLED-translations/<locale>/(PlatformIO out-of-tree)tools/i18n/locales/<locale>.json(local fallback)
{
"index.htm": {
"html:body > div#btns > a:nth-of-type(1):text": {
"en": "Power",
"translation": "电源",
"context": "index.htm: (html_text)"
},
"js:index.htm:45:a1b2c3d4": {
"en": "Loading...",
"translation": "加载中...",
"context": "index.htm:45 (js_innerHTML)"
}
}
}| Layer | Content | Method | Count |
|---|---|---|---|
| 1. Static HTML | Labels, buttons, placeholders | DOM text matching | 429 |
| 2. JS strings | alert(), innerHTML, innerText |
Script block regex | 45 |
| 3. Effect names | FX names in colors.cpp |
PROGMEM replacement | 216 |
| 4. Palette names | Palette names in colors.cpp |
PROGMEM replacement | 72 |
- No runtime language switching — language is fixed at build time
- JS template literals with
${...}— partial strings can't be safely replaced - C++ server-side strings — ~12 strings in
xml.cppneed#ifdef WLED_LOCALE_* - External tools (pixelforge, pixelmagic) — always English, downloaded on-the-fly