feat(libSceSystemService): read the host locales of a POSIX system

PosixHostLocales takes an injectable environment reader and returns the locales
in order of preference: LC_ALL, then LC_MESSAGES, then LANG, the first one that
is set and not empty, as the C library chooses the locale of the messages
category. When that locale is a real one (not C, POSIX or unset) the entries of
LANGUAGE, the GNU preference list, come before it, as gettext ignores LANGUAGE
under the C locale.
This commit is contained in:
MarcZX10 committed 2026-10-29 08:51:17 +00:00
1 parent 79692c44ef
commit c3fa50327c
1 file changed
+29
@@ -2,10 +2,13 @@
#define CORE_LIBS_PRX_LIBSCESYSTEMSERVICE_LANGUAGELOCALE_HPP
#include <cstddef>
#include <cstdlib>
#include <functional>
#include <span>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace SystemServiceLocale {
@@ -278,6 +281,32 @@ inline Match MatchLocale(std::string_view locale) {
return {id, true};
}
using Environment = std::function<const char*(const char*)>;
inline std::vector<std::string> PosixHostLocales(const Environment& environment) {
const auto read = [&environment](const char* name) {
const char* value = environment(name);
return std::string_view(value != nullptr ? value : "");
};
std::string_view effective;
for (const char* name : {"LC_ALL", "LC_MESSAGES", "LANG"}) {
effective = read(name);
if (!effective.empty()) break;
}
std::vector<std::string> locales;
if (!NormalizePosixLocale(effective).empty()) {
std::string_view preferred = read("LANGUAGE");
while (!preferred.empty()) {
const std::size_t colon = preferred.find(':');
const std::string_view entry = preferred.substr(0, colon);
if (!entry.empty()) locales.emplace_back(entry);
preferred = colon == std::string_view::npos ? std::string_view{} : preferred.substr(colon + 1);
}
}
if (!effective.empty()) locales.emplace_back(effective);
return locales;
}
}
#endif