Currently each language is a hardcoded C struct (lang_en.c, lang_es.c) compiled into the binary. Adding a new language requires writing C code and recompiling, which is a barrier for translators who don't know C.
The standard Win32 approach is to store strings in .rc resource files (STRINGTABLE) and load them at runtime with LoadStringW(). This is used by Notepad++, 7-Zip, PuTTY and most professional Windows applications.
What this involves:
- Define string IDs in a new
include/string_ids.h (e.g. IDS_BTN_START, IDS_STATUS_READY…)
- Create one
.rc file per language with a STRINGTABLE block
- Replace all
g_lang.field accesses in src/gui.c with LoadStringW(hInstance, IDS_xxx, buf, len)
- Remove
src/lang.c, src/lang_en.c, src/lang_es.c and include/lang.h
Benefit: translators can contribute new languages by editing a single .rc text file — no C knowledge needed. Tools like ResEdit allow visual editing.
This is a medium-complexity refactor. A good starting point is auditing all g_lang. usages in src/gui.c and mapping them to string IDs.
Currently each language is a hardcoded C struct (
lang_en.c,lang_es.c) compiled into the binary. Adding a new language requires writing C code and recompiling, which is a barrier for translators who don't know C.The standard Win32 approach is to store strings in
.rcresource files (STRINGTABLE) and load them at runtime withLoadStringW(). This is used by Notepad++, 7-Zip, PuTTY and most professional Windows applications.What this involves:
include/string_ids.h(e.g.IDS_BTN_START,IDS_STATUS_READY…).rcfile per language with aSTRINGTABLEblockg_lang.fieldaccesses insrc/gui.cwithLoadStringW(hInstance, IDS_xxx, buf, len)src/lang.c,src/lang_en.c,src/lang_es.candinclude/lang.hBenefit: translators can contribute new languages by editing a single
.rctext file — no C knowledge needed. Tools like ResEdit allow visual editing.This is a medium-complexity refactor. A good starting point is auditing all
g_lang.usages insrc/gui.cand mapping them to string IDs.