This commit is contained in:
Vaxry 2025-11-08 23:02:26 +00:00
parent 98a1d4f734
commit c012282933
Signed by: vaxry
GPG key ID: 665806380871D640
3 changed files with 54 additions and 8 deletions

View file

@ -31,6 +31,8 @@ namespace Hyprutils::I18n {
std::string localizeEntry(const std::string& locale, uint64_t key, const translationVarMap& map);
std::string getSystemLocale();
private:
Memory::CUniquePointer<SI18nEngineImpl> m_impl;
};

View file

@ -2,6 +2,7 @@
#include <algorithm>
#include <format>
#include <locale>
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::I18n;
@ -43,9 +44,10 @@ std::string CI18nEngine::localizeEntry(const std::string& locale, uint64_t key,
if (m_impl->entries.contains(locale) && m_impl->entries[locale].size() > key)
entry = &m_impl->entries[locale][key];
if (!entry || !entry->exists) {
// try to fall back to lang_LANG
if (locale.contains('_')) {
if (locale.contains('_')) {
if (!entry || !entry->exists) {
// try to fall back to lang_LANG
auto stem = locale.substr(0, locale.find('_'));
auto stemUpper = stem;
std::ranges::transform(stemUpper, stemUpper.begin(), ::toupper);
@ -53,11 +55,10 @@ std::string CI18nEngine::localizeEntry(const std::string& locale, uint64_t key,
if (m_impl->entries.contains(newLocale) && m_impl->entries[newLocale].size() > key)
entry = &m_impl->entries[newLocale][key];
}
}
if (!entry || !entry->exists) {
// try to fall back to any lang prefixed with our prefix
if (locale.contains('_')) {
if (!entry || !entry->exists) {
// try to fall back to any lang prefixed with our prefix
auto stem = locale.substr(0, locale.find('_') + 1);
for (const auto& [k, v] : m_impl->entries) {
if (k.starts_with(stem)) {
@ -69,6 +70,18 @@ std::string CI18nEngine::localizeEntry(const std::string& locale, uint64_t key,
}
}
}
} else {
// locale doesn't have a _, e.g. pl
// find any locale that has the same stem
for (const auto& [k, v] : m_impl->entries) {
if (k.starts_with(locale + "_") || k == locale) {
if (m_impl->entries.contains(k) && m_impl->entries[k].size() > key)
entry = &m_impl->entries[k][key];
if (entry && entry->exists)
break;
}
}
}
if (!entry || !entry->exists) {
@ -90,4 +103,30 @@ std::string CI18nEngine::localizeEntry(const std::string& locale, uint64_t key,
}
return rawStr;
}
}
std::string CI18nEngine::getSystemLocale() {
std::locale locale("");
auto localeStr = locale.name();
// localeStr is very arbitrary... from my testing, it can be:
// en_US.UTF-8
// LC_CTYPE=en_US
// POSIX
// *
//
// We only return e.g. en_US or pl_PL, or pl
if (localeStr == "POSIX")
return "en_US";
if (localeStr == "*")
return "en_US";
if (localeStr.contains('='))
localeStr = localeStr.substr(localeStr.find('=') + 1);
if (localeStr.contains('.'))
localeStr = localeStr.substr(0, localeStr.find('.'));
return localeStr;
}

View file

@ -1,5 +1,6 @@
#include <hyprutils/i18n/I18nEngine.hpp>
#include "shared.hpp"
#include <print>
using namespace Hyprutils::I18n;
@ -14,6 +15,8 @@ int main(int argc, char** argv, char** envp) {
CI18nEngine engine;
std::println("System locale: {}", engine.getSystemLocale());
engine.setFallbackLocale("en_US");
engine.registerEntry("en_US", TXT_KEY_HELLO, "Hello World!");
@ -50,6 +53,8 @@ int main(int argc, char** argv, char** envp) {
EXPECT(engine.localizeEntry("pl_PL", TXT_KEY_I_HAVE_APPLES, {{"count", "2"}}), "Mam 2 jabłka.");
EXPECT(engine.localizeEntry("pl_PL", TXT_KEY_I_HAVE_APPLES, {{"count", "5"}}), "Mam 5 jabłek.");
EXPECT(engine.localizeEntry("pl", TXT_KEY_I_HAVE_APPLES, {{"count", "5"}}), "Mam 5 jabłek.");
EXPECT(engine.localizeEntry("pl_XX", TXT_KEY_I_HAVE_APPLES, {{"count", "5"}}), "Mam 5 jabłek.");
EXPECT(engine.localizeEntry("en_XX", TXT_KEY_I_HAVE_APPLES, {{"count", "2"}}), "I have 2 apples.");