Description
Option 1 (A bit slower in runtime, but more universal)
Localization file
Each locale should have own .lilka_loc file or something similar. As a format could be used ini (I think this one would be better).
Storage
Potential place for storing localization files is our /spiffs filesystem, which isn't really utilized for now and could be used even without sdcard present.
Load
On boot Keira loads parameter from NVS storage, which refers to path of localization file to load.
Firmware should have a fallback translation strings, in case language file don't have all values, or redefine only part of them, those fallback strings loaded first, then rewritten.
Persistence in memory
Cause amount of strings/keys gonna be huge, and all the time comparing those key_names would be really problematic, while seeking needed value, suggest using some hashing function, make it work only in compile time, mb some minimal preprocessing of language file before actual feeding it to lilka, this would make all faster.
Option 2 (Fast, less universal, controllable by maintainers in future)
Store all language files as headers, provide LANG parameter on compile, this won't allow
changing language in runtime, which is maybe not that bad mentioning this wouldn't take any space in memory at all :)
Headers example
// file:ukrainian.h
#ifdef LANG_UA
#define LANG_OP_SUCCESS "Операцію успішно виконано."
#endif
// file:english.h
#ifdef LANG_EN
#define LANG_OP_SUCCESS "Operation success"
#endif