ESPLang is a small translation table helper for ESP32 firmware. The library owns only active-language state, fallback-language state, registered table pointers, and lookup logic, while users keep control of their own language IDs, key enums, and translation data.
- No hardcoded languages or translation keys in the library API.
- Pointer-only registration of user-owned translation tables.
- Linear lookup by default, with optional sorted-key tables for binary-search key lookup.
- Fallback-language lookup for missing translations.
- No heap allocation required by the library.
- Caller-buffer formatting through
format(...). - Public macro and helper for compact table definitions.
- PlatformIO: add
https://github.com/ESPToolKit/esp-lang.gittolib_deps. - Arduino IDE: install as ZIP from this repository.
#include <ESPLang.h>#include <Arduino.h>
#include <ESPLang.h>
namespace AppLanguage {
static constexpr LangLanguageId EN = 1;
static constexpr LangLanguageId HU = 2;
}
enum class AppText : uint16_t {
TestMessage = 1,
BatteryLow = 2,
};
static const LangTranslationEntry kEnglish[] = {
ESP_LANG_ENTRY(AppText::TestMessage, "Test message"),
ESP_LANG_ENTRY(AppText::BatteryLow, "Battery low: %d%%"),
};
static const LangTranslationEntry kHungarian[] = {
ESP_LANG_ENTRY(AppText::TestMessage, "Teszt uzenet"),
ESP_LANG_ENTRY(AppText::BatteryLow, "Alacsony akkuszint: %d%%"),
};
static const LangTranslationTable kTables[] = {
makeLangTable(AppLanguage::EN, kEnglish),
makeLangTable(AppLanguage::HU, kHungarian),
};
ESPLang lang;
void setup() {
Serial.begin(115200);
ESPLangConfig config{};
config.tables = kTables;
config.tableCount = sizeof(kTables) / sizeof(kTables[0]);
config.defaultLanguage = AppLanguage::EN;
config.useDefaultFallback = false;
config.fallbackLanguage = AppLanguage::EN;
config.missingText = "[missing]";
if (!lang.init(config)) {
Serial.println("ESPLang init failed");
return;
}
lang.setLanguage(AppLanguage::HU);
Serial.println(lang.translate(AppText::TestMessage));
char buffer[32];
if (lang.format(buffer, sizeof(buffer), AppText::BatteryLow, 17)) {
Serial.println(buffer);
}
}basic_translate: initialize ESPLang, switch languages, and print direct translations.fallback_and_format: demonstrate fallback lookup, caller-buffer formatting, and runtime missing-text overrides.sorted_lookup: register sorted tables withmakeSortedLangTable(...)and use binary-search key lookup.mixed_lookup_modes: combine sorted and linear tables in one config and rely on fallback across lookup modes.
Public types:
using LangLanguageId = uint16_tusing LangKeyId = uint16_tenum class LangLookupMode : uint8_t { Linear, SortedByKey }selects per-table key lookup strategy.LangTranslationEntry { key, text }maps one user-defined key to one translation string.LangTranslationTable { language, entries, entryCount, lookupMode }groups one language with its translation entries and lookup mode.ESPLangConfig { tables, tableCount, defaultLanguage, useDefaultFallback, fallbackLanguage, missingText }configures the pointer-owned table set, startup language, fallback behavior, and missing-text string.
Helpers:
ESP_LANG_ENTRY(key, text)creates aLangTranslationEntryfrom an enum key.makeLangTable(language, entries)builds a linearLangTranslationTablewith the correct entry count.makeSortedLangTable(language, entries)builds a sorted-keyLangTranslationTablethat uses binary search for key lookup.
Main API:
bool init(const ESPLangConfig& config)/void deinit()/bool isInitialized() constbool setLanguage(LangLanguageId language)/LangLanguageId getLanguage() constbool setFallbackLanguage(LangLanguageId language)/LangLanguageId getFallbackLanguage() constvoid setMissingText(const char* text)/const char* getMissingText() constbool hasLanguage(LangLanguageId language) constbool hasKey(LangKeyId key) constbool hasKeyInLanguage(LangLanguageId language, LangKeyId key) constconst char* translate(LangKeyId key) constconst char* translateFrom(LangLanguageId language, LangKeyId key) constbool format(char* outBuffer, size_t outBufferSize, LangKeyId key, ...) const
Validation and lookup behavior:
init(...)returnsfalsefor null tables, zero table count, missing default language, missing explicit fallback language, invalid table storage, duplicate language tables, duplicate keys within the same language, or null text pointers.makeSortedLangTable(...)requires entries to already be sorted by ascending key;init(...)rejects unsorted or duplicate keys in sorted tables.translate(key)checks the selected language first, then the fallback language if it differs, then returns the configured missing text.translateFrom(language, key)only searches the requested language.missingTextdefaults to"?"when omitted or reset withsetMissingText(nullptr).- Language-table resolution remains linear even when individual tables use sorted-key lookup.
translateFrom(...)does not use fallback lookup.format(...)treats the resolved translation text as avsnprintfformat string. Placeholder mistakes in translation data, or mismatched argument types at the call site, become runtime formatting bugs.format(...)returnsfalsewhen the formatted output does not fully fit, even though the buffer may still contain truncated output.useDefaultFallback = trueresolves the effective fallback language todefaultLanguage.- Duplicate keys are only invalid within the same language table; reusing the same key across different languages is expected.
- Sorted-key lookup is opt-in per table. The library never sorts caller data for you.
- Packaged as an ESP32 / Arduino-targeted library for ESPToolKit.
- C++17 is required.
- Translation tables and strings are caller-owned and must remain valid for the lifetime of the
ESPLanginstance.
include(FetchContent)
FetchContent_Declare(
esp_lang
GIT_REPOSITORY https://github.com/ESPToolKit/esp-lang.git
GIT_TAG main
)
FetchContent_MakeAvailable(esp_lang)
target_link_libraries(your_target PRIVATE ESPLang::esp_lang)If the source is vendored locally, add_subdirectory(path/to/esp-lang) exposes the same ESPLang::esp_lang target.
- Host-side tests in
test/test_esplangcover config validation, lifecycle, linear and sorted lookup rules, mixed fallback behavior, missing-text handling, and formatting behavior. - CI also builds the Arduino examples through both PlatformIO and Arduino CLI on the standard ESP32 board matrix.
This repository follows the firmware formatting baseline from esptoolkit-template:
.clang-formatis the source of truth for C/C++/INO layout..editorconfigenforces tabs (tab_width = 4), LF endings, and final newline.- Format all tracked firmware sources with
bash scripts/format_cpp.sh.
MIT - see LICENSE.md.
- Check out other libraries: https://github.com/orgs/ESPToolKit/repositories
- Hang out on Discord: https://discord.gg/WG8sSqAy
- Support the project: https://ko-fi.com/esptoolkit
- Visit the website: https://www.esptoolkit.hu/