mirror of
https://github.com/steredbits/pelagia.git
synced 2026-10-20 01:01:37 +02:00
110 lines
3.0 KiB
C++
110 lines
3.0 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Copyright (C) 2026 steredbits and Pelagia contributors
|
|
#include "util/i18n.h"
|
|
|
|
#include <cstdarg>
|
|
#include <cstdio>
|
|
#include <iterator>
|
|
|
|
namespace util {
|
|
|
|
namespace {
|
|
|
|
const char* const kEnglish[] = {
|
|
#define STR(id, text) text,
|
|
#include "util/i18n/strings_en.def"
|
|
#undef STR
|
|
};
|
|
|
|
const char* const kFrench[] = {
|
|
#define STR(id, text) text,
|
|
#include "util/i18n/strings_fr.def"
|
|
#undef STR
|
|
};
|
|
|
|
constexpr size_t kCount = static_cast<size_t>(Str::Count);
|
|
static_assert(std::size(kEnglish) == kCount, "strings_en.def and the Str enum differ");
|
|
static_assert(std::size(kFrench) == kCount, "strings_fr.def lacks (or adds) strings");
|
|
|
|
std::atomic<uint8_t> g_language{static_cast<uint8_t>(Lang::En)};
|
|
|
|
std::string lowercase_base(const std::string& locale) {
|
|
std::string out;
|
|
for (char c : locale) {
|
|
if (c == '_' || c == '-' || c == '.' || c == '@') break;
|
|
out.push_back(c >= 'A' && c <= 'Z' ? static_cast<char>(c + 32) : c);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Lang current_language() { return static_cast<Lang>(g_language.load()); }
|
|
|
|
void set_current_language(Lang lang) { g_language.store(static_cast<uint8_t>(lang)); }
|
|
|
|
const char* language_code(Lang lang) { return lang == Lang::Fr ? "fr" : "en"; }
|
|
|
|
const char* tr(Str id, Lang lang) {
|
|
const size_t i = static_cast<size_t>(id);
|
|
if (i >= kCount) return "";
|
|
return lang == Lang::Fr ? kFrench[i] : kEnglish[i];
|
|
}
|
|
|
|
const char* tr(Str id) { return tr(id, current_language()); }
|
|
|
|
std::string trf(Str id, ...) {
|
|
const char* format = tr(id);
|
|
va_list args;
|
|
va_start(args, id);
|
|
va_list copy;
|
|
va_copy(copy, args);
|
|
const int n = std::vsnprintf(nullptr, 0, format, copy);
|
|
va_end(copy);
|
|
std::string out;
|
|
if (n > 0) {
|
|
out.resize(static_cast<size_t>(n) + 1);
|
|
std::vsnprintf(&out[0], out.size(), format, args);
|
|
out.resize(static_cast<size_t>(n));
|
|
}
|
|
va_end(args);
|
|
return out;
|
|
}
|
|
|
|
Lang language_from_locales(const std::vector<std::string>& locales, Lang fallback) {
|
|
for (const std::string& locale : locales) {
|
|
const std::string base = lowercase_base(locale);
|
|
if (base == "fr" || base == "fra" || base == "fre") return Lang::Fr;
|
|
if (base == "en" || base == "eng") return Lang::En;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
const char* language_setting_code(LanguageSetting setting) {
|
|
switch (setting) {
|
|
case LanguageSetting::English: return "en";
|
|
case LanguageSetting::French: return "fr";
|
|
case LanguageSetting::Auto: break;
|
|
}
|
|
return "auto";
|
|
}
|
|
|
|
bool parse_language_setting(const std::string& code, LanguageSetting* out) {
|
|
if (code == "auto") *out = LanguageSetting::Auto;
|
|
else if (code == "en") *out = LanguageSetting::English;
|
|
else if (code == "fr") *out = LanguageSetting::French;
|
|
else return false;
|
|
return true;
|
|
}
|
|
|
|
Lang resolve_language(LanguageSetting setting, const std::vector<std::string>& system_locales) {
|
|
switch (setting) {
|
|
case LanguageSetting::English: return Lang::En;
|
|
case LanguageSetting::French: return Lang::Fr;
|
|
case LanguageSetting::Auto: break;
|
|
}
|
|
return language_from_locales(system_locales, Lang::En);
|
|
}
|
|
|
|
} // namespace util
|