i18n: English/German from Switch system language

- Add I18n module: German when system language is DE, else English (ENUS/ENGB
  or any other language).
- Translate UI strings (tabs, settings, about, file browser, notifications,
  OC row titles, toggles Ein/Aus).
- Keep toggle/frequency/voltage list rows without subtitle descriptions
  like before.

Uses setGetSystemLanguage + setMakeLanguage; call I18n::init before
Application::init.

Made-with: Cursor
This commit is contained in:
Niklas Friesen
2026-03-30 20:09:38 +02:00
parent b5ba2d71df
commit b5296d6686
9 changed files with 361 additions and 47 deletions

View File

@@ -4,6 +4,7 @@
*/
#include "os_config_tab.h"
#include "i18n.h"
#include "oc_defs.h"
#include <algorithm>
@@ -13,18 +14,14 @@ OsConfigTab::OsConfigTab(const std::string& osName, const std::string& iniPath)
{
if (!this->ini.load(iniPath))
{
buildErrorUI("Could not load " + iniPath + "\n\n"
"Make sure the INI file exists at the expected path.\n"
"You can configure paths in the Settings tab.");
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniLoadErrorBody(iniPath));
return;
}
this->osSection = this->ini.findOsSection();
if (this->osSection.empty())
{
buildErrorUI("No OS section found in " + iniPath + "\n\n"
"The INI file should contain a section like\n"
"[" + osName + " OC] with your configuration.");
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniSectionErrorBody(iniPath, osName));
return;
}
@@ -41,30 +38,26 @@ void OsConfigTab::reload(const std::string& newIniPath)
if (!this->ini.load(iniPath))
{
buildErrorUI("Could not load " + iniPath + "\n\n"
"Make sure the INI file exists at the expected path.\n"
"You can configure paths in the Settings tab.");
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniLoadErrorBody(iniPath));
return;
}
this->osSection = this->ini.findOsSection();
if (this->osSection.empty())
{
buildErrorUI("No OS section found in " + iniPath + "\n\n"
"The INI file should contain a section like\n"
"[" + osName + " OC] with your configuration.");
buildErrorUI(I18n::errorListItemTitleIni(), I18n::iniSectionErrorBody(iniPath, osName));
return;
}
buildUI();
}
void OsConfigTab::buildErrorUI(const std::string& message)
void OsConfigTab::buildErrorUI(const std::string& title, const std::string& message)
{
this->setSpacing(15);
// Use a ListItem (focusable) so borealis doesn't crash on controller nav
brls::ListItem *errorItem = new brls::ListItem("\uE150 INI file not found", message);
brls::ListItem *errorItem = new brls::ListItem(title, message);
this->addView(errorItem);
}
@@ -76,44 +69,44 @@ void OsConfigTab::buildUI()
// Section name info
brls::Label *sectionInfo = new brls::Label(
brls::LabelStyle::DESCRIPTION,
"Editing section [" + this->osSection + "] from " + this->iniPath,
I18n::sectionEditLine(this->osSection, this->iniPath),
true
);
this->addView(sectionInfo);
// ── Toggle Options ──
this->addView(new brls::Header("Toggle Options"));
this->addView(new brls::Header(I18n::headerToggleOptions()));
for (const auto& def : OC_BOOL_KEYS)
{
bool val = this->ini.getBool(this->osSection, def.key, false);
addBooleanToggle(def.label, "", def.key, val);
addBooleanToggle(I18n::ocBoolLabel(def.key), "", def.key, val);
}
// ── Frequency Settings ──
brls::Rectangle* spacer1 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
spacer1->setHeight(30);
this->addView(spacer1);
this->addView(new brls::Header("Frequency Settings"));
this->addView(new brls::Header(I18n::headerFrequencySettings()));
for (const auto& def : OC_FREQ_KEYS)
{
int defVal = def.options.empty() ? 0 : (int)def.options.front();
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, defVal);
addFreqDropdown(def.label, "", def.key, val, def.options);
addFreqDropdown(I18n::ocFreqLabel(def.key), "", def.key, val, def.options);
}
// ── Voltage Settings ──
brls::Rectangle* spacer2 = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
spacer2->setHeight(30);
this->addView(spacer2);
this->addView(new brls::Header("Voltage Settings"));
this->addView(new brls::Header(I18n::headerVoltageSettings()));
for (const auto& def : OC_VOLTAGE_KEYS)
{
int defVal = def.options.empty() ? 0 : (int)def.options.front();
uint32_t val = (uint32_t)this->ini.getInt(this->osSection, def.key, defVal);
addVoltageDropdown(def.label, "", def.key, val, def.options);
addVoltageDropdown(I18n::ocVoltageLabel(def.key), "", def.key, val, def.options);
}
// ── Other Keys (read-only info) ──
@@ -141,7 +134,7 @@ void OsConfigTab::buildUI()
brls::Rectangle* spacerOther = new brls::Rectangle(nvgRGBA(0, 0, 0, 0));
spacerOther->setHeight(30);
this->addView(spacerOther);
this->addView(new brls::Header("Other"));
this->addView(new brls::Header(I18n::headerOther()));
hasOtherKeys = true;
}
@@ -156,11 +149,11 @@ void OsConfigTab::saveAndNotify()
{
if (this->ini.save())
{
brls::Application::notify("\uE14B Configuration saved");
brls::Application::notify(I18n::notifyConfigSaved());
}
else
{
brls::Application::notify("\uE150 Error saving configuration!");
brls::Application::notify(I18n::notifyConfigSaveError());
}
}
@@ -168,7 +161,7 @@ void OsConfigTab::addBooleanToggle(const std::string& label, const std::string&
const std::string& key, bool currentValue)
{
brls::ToggleListItem *toggle = new brls::ToggleListItem(
label, currentValue, description, "ON", "OFF"
label, currentValue, description, I18n::wordOn(), I18n::wordOff()
);
std::string keyCopy = key;