Introduces a two-language (EN/VI) i18n system with hot-swap support.
All ~160 user-facing strings are centralised in gui/locales.py; views
retranslate in-place on language switch without restarting the app.
- gui/locales.py: new file — _EN/_VI dicts, t() lookup, set_language(),
get_language(); assert guard ensures EN/VI key parity
- gui/app.py: switch_language(), _apply_startup_language(),
_save_language_pref(), _rebuild_nav_labels(); language stored in
config.json under ui.language; pipeline step headers and run_tool
status lines translated
- gui/views/settings.py: Language dropdown card (English / Tiếng Việt)
- gui/views/dashboard.py: all strings via t(); static header widgets
stored and retranslated in refresh()
- gui/views/mods.py: all strings via t(); _STATUS dict built at call
time so server status labels update on language switch
- gui/views/tools.py: all strings via _translatable registry; tab names
and segmented-button values kept in English (CTkTabview constraint)
- gui/views/logs.py: title + Copy/Clear buttons stored, retranslated
- gui/wizard.py: all 3 pages fully translated
- docs/huong-dan-su-dung.md: full Vietnamese user guide
- CLAUDE.md: documents localization architecture and constraints
subprocess.run with capture_output=True blocked until process exit,
dumping all output at once. Now uses Popen with line-by-line reading,
-u flag, and PYTHONUNBUFFERED=1 so logs stream in real time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>