#include "Localization.h" #include "external/nlohmann/json.hpp" #include "utils/Utils.h" #include // Платформозависимые инклюды для детекции языка #if defined(_WIN32) #include #elif defined(__EMSCRIPTEN__) #include #elif defined(__ANDROID__) #include #endif namespace FRG { Language g_currentLanguage = Language::Russian; std::string languageToCode(Language lang) { switch (lang) { case Language::English: return "en"; case Language::Russian: default: return "ru"; } } Language languageFromCode(const std::string& code) { if (code == "en") return Language::English; return Language::Russian; } std::string localizedConfigPath(const std::string& basePath, Language lang) { static const std::string marker = "/config/"; const size_t pos = basePath.find(marker); if (pos == std::string::npos) return basePath; return basePath.substr(0, pos) + "/config_" + languageToCode(lang) + "/" + basePath.substr(pos + marker.size()); } std::string readLocalizedConfigFile(const std::string& basePath, const std::string& zipFile) { const std::string localizedPath = localizedConfigPath(basePath, g_currentLanguage); if (localizedPath != basePath) { std::string content; if (zipFile.empty()) { content = readTextFile(localizedPath); } else { try { const auto buf = readFileFromZIP(localizedPath, zipFile); content.assign(buf.begin(), buf.end()); } catch (const std::exception&) { content.clear(); } } if (!content.empty()) return content; } if (zipFile.empty()) return readTextFile(basePath); try { const auto buf = readFileFromZIP(basePath, zipFile); return std::string(buf.begin(), buf.end()); } catch (const std::exception&) { return ""; } } void loadLanguageSetting() { const std::string content = readSavedTextFile("settings.json"); // Если файла настроек нет (content пустой), определяем язык системы и выходим if (content.empty()) { g_currentLanguage = detectSystemLanguage(); logger() << "[settings] No settings.json found. System language detected: " << languageToCode(g_currentLanguage) << std::endl; return; } try { const nlohmann::json root = nlohmann::json::parse(content); if (root.contains("language")) { g_currentLanguage = languageFromCode(root["language"].get()); } } catch (const std::exception& e) { std::cerr << "[settings] Failed to parse settings.json: " << e.what() << std::endl; } } Language detectSystemLanguage() { #if defined(__EMSCRIPTEN__) // Получаем первые два символа языка из браузера (0 - English, 1 - Russian, -1 - другой) int res = EM_ASM_INT({ var lang = (navigator.language || navigator.userLanguage || 'en').toLowerCase(); if (lang.startsWith('ru')) return 1; if (lang.startsWith('en')) return 0; return -1; }); if (res == 1) return Language::Russian; if (res == 0) return Language::English; #elif defined(_WIN32) LANGID langId = GetUserDefaultUILanguage(); WORD primaryLang = PRIMARYLANGID(langId); if (primaryLang == LANG_RUSSIAN) return Language::Russian; if (primaryLang == LANG_ENGLISH) return Language::English; #elif defined(__ANDROID__) SDL_Locale* locales = SDL_GetPreferredLocales(); if (locales) { Language detected = Language::English; for (SDL_Locale* l = locales; l->language; ++l) { std::string langCode = l->language; if (langCode == "ru") { detected = Language::Russian; break; } if (langCode == "en") { detected = Language::English; break; } } SDL_free(locales); return detected; } #else // Linux / SteamOS const char* langEnv = std::getenv("LC_ALL"); if (!langEnv || *langEnv == '\0') { langEnv = std::getenv("LANG"); } if (langEnv && *langEnv != '\0') { std::string langStr(langEnv); // Ищем префиксы "ru" или "en" в начале строки (например, ru_RU.UTF-8) if (langStr.rfind("ru", 0) == 0) return Language::Russian; if (langStr.rfind("en", 0) == 0) return Language::English; } #endif // Дефолтный фоллбек, если язык системы не поддерживается игрой (например, немецкий) return Language::English; } } // namespace FRG